You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
emrg: the shell tools tell the model to pass workdir, which the daemon replaces on every call #2698
Both shell tools' descriptions carry this sentence:
Each call is a fresh process — no state (working directory, variables, functions) persists between calls, so pass workdir instead of using cd.
The action it advises cannot work. In the daemon path EmrgServer._inject_tool_arguments writes the session's cwd into a shell call's workdirunconditionally — the if tc_name in SHELL_TOOL_NAMES: branch in emrg/server/daemon.py — and when a sandbox tier is configured it also writes workspace, which the executors read first (emrg/tools/bash_tool_v2.py, emrg/tools/pwsh_tool_v2.py: arguments.get("workspace") or arguments.get("workdir") or os.getcwd()). So a caller's directory is discarded twice over, and the command runs in the session's working directory while the description has told the caller it would run somewhere else.
That the injection is unconditional is deliberate and has to stay: with and "workdir" not in args a model could name the root it was trusted in — measured, workdir=<home> plus a write to .zshrc was allowed, because the home directory became "the workspace" (that method's docstring, design §2.4). The defect is not the injection. It is the sentence.
Observed
On this host, in a session whose working directory was the project checkout: a shell call carrying workdir=<session>/tmp — a directory that exists, Test-Path answers true — answered Get-Location = the session root. A second call naming a directory that holds a package.json answered Test-Path package.json = false, though that file is there. Every other argument of those calls arrived unchanged; only the directory did not.
What a fix must satisfy
The two shell descriptions stop advising a parameter the daemon replaces, and say what to do instead: the command changes directory itself, because the run always starts in the session's working directory.
The workdir field's own description states that the daemon supplies it and replaces any value given, so a reader who sees the field is not left thinking it is theirs to set.
The guard that reads this sentence reads it against the injection, not against the schema. Today tests/test_shell_tool_descriptions.py::test_the_fresh_process_sentence_advises_a_parameter_that_exists only asserts that workdir is a declared property of the definition — an assertion that cannot fail while the parameter exists, whatever the daemon does with its value. Read against the behaviour, the same guard reddens if a description offers the directory again.
Both dialects state it in the same words, which is what the rest of that file already requires of every shared sentence.
glob and grep keep honouring the directory their caller names. Their workdir/path decides a preference rather than a boundary, and the two classes must not be conflated by a fix aimed at the shell tools.
Correction to the pointer above: #2701 is closed and folded into #2700, which is the PR that finishes this issue — it was opened 14 minutes earlier, and one issue is finished by one PR. Nothing else about this issue changes; it stays open until #2700 lands.
Landed as 84b84ef (#2700). Master's tree after the merge is 8abe16e90083124ad30c7fcfae0bf55375f2cf81, byte-identical to the landing tree the suite measured at 6111 passed / 37 skipped, so the reading that cleared the merge applies to master itself. Closed here because the pull request's closing keyword did not fire — the issue was opened after the pull request, so the reference predates it.
Activity
argszero commentedon Nov 3, 2026
Handled by #2700
pm25coder commentedon Nov 3, 2026
Handled by #2701
pm25coder commentedon Nov 3, 2026
Correction to the pointer above: #2701 is closed and folded into #2700, which is the PR that finishes this issue — it was opened 14 minutes earlier, and one issue is finished by one PR. Nothing else about this issue changes; it stays open until #2700 lands.
how2how2how2-arch commentedon Nov 3, 2026
Landed as 84b84ef (#2700). Master's tree after the merge is
8abe16e90083124ad30c7fcfae0bf55375f2cf81, byte-identical to the landing tree the suite measured at 6111 passed / 37 skipped, so the reading that cleared the merge applies to master itself. Closed here because the pull request's closing keyword did not fire — the issue was opened after the pull request, so the reference predates it.