Skip to content

rtk rewrite "rtk <builtin>" returns unchanged (exit 3) instead of stripping prefix — cd and other builtins silently no-op #2508

Description

@Starefossen

Bug

rtk rewrite treats a command that already starts with rtk as a valid rewrite target and returns it unchanged with exit 3 ("handled"). When the inner command is a shell builtin (cd, export, source, etc.) this silently breaks the builtin's effect, because the model's manually-prefixed rtk cd /path executes rtk as a subprocess — the directory change is lost when that subprocess exits.

Reproduction

$ rtk rewrite "rtk cd /tmp"
rtk cd /tmp          # ← same as input, exit 3 ("handled")

$ rtk rewrite "cd /tmp"
                     # exit 1 (passthrough — correct)

$ rtk cd /tmp; pwd
/original/dir        # ← directory unchanged despite exit 0

Expected behaviour

rtk rewrite "rtk <builtin> ..." should either:

  • Return passthrough (exit 1) so the shell runs the bare builtin, or
  • Strip the redundant prefix and return cd /tmp (exit 3)

Either way, the shell builtin should execute in the current process rather than a dead-end subprocess.

Context

The opencode plugin calls rtk rewrite on every bash tool call and replaces the command if the output differs from input. When a model manually prefixes rtk cd (following the "always use rtk" instruction in AGENTS.md), rtk rewrite returns the same string with exit 3 — so the plugin leaves the command as rtk cd /path, which executes with no net directory change.

Observed during GLM-4.7-Flash evaluation (2026-06-19): model ran rtk cd /path && rtk npm init -y, npm init ran in the wrong directory, model then invented a non-existent --workdir flag to compensate.

Workaround (local opencode plugin)

const SHELL_BUILTINS = /^rtk\s+(cd|pushd|popd|export|source|alias|unset|ulimit|umask)\b/
if (SHELL_BUILTINS.test(command)) {
  command = command.replace(/^rtk\s+/, "")
  ;(args as Record<string, unknown>).command = command
  return
}

Version

rtk 0.42.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions