feat(cli): add /set-workspace command to change session cwd#23535
Open
xiaoquisme wants to merge 1 commit into
Open
feat(cli): add /set-workspace command to change session cwd#23535xiaoquisme wants to merge 1 commit into
xiaoquisme wants to merge 1 commit into
Conversation
Adds a /set-workspace slash command (with aliases /workspace, /cd, /setworkspace) that changes the working directory used by the terminal, file, and code-execution tools for the current session. Effect is immediate -- no /reset required -- because the implementation updates the single source of truth (TERMINAL_CWD env var) plus all downstream caches that read from it on tool invocation: 1. os.environ[TERMINAL_CWD]: read by every tool path that resolves cwd, including file_tools relative-path anchoring, code_execution sandbox cwd, runtime footer, checkpoint manager, subagent inheritance. 2. tools.terminal_tool._active_environments[*].cwd: the cwd actually fed to subprocess for every long-lived shell or sandbox. Normally maintained by the cwd-marker mechanism on each cd, force-synced here because the user is changing it out-of-band. 3. tools.file_tools._file_ops_cache[*].cwd: ShellFileOperations prefers env.cwd (already updated above) and falls back to self.cwd, so we keep both in sync. The change is session-scoped and does NOT write to config.yaml. Path arguments support ~ expansion, $VAR expansion, single/double quotes (for paths with spaces), and relative paths (anchored on the current TERMINAL_CWD, not os.getcwd, so chained /cd subdir works intuitively from the new workspace). Validation rejects nonexistent paths, files, and directories without read+exec permission. Failures during cache sync (e.g. a remote backend that refuses cwd reassignment) are swallowed per-cache so they cannot block the env var update or other downstream caches. Tests: tests/cli/test_cli_set_workspace.py covers arg parsing (no-arg/blank/quoted), path resolution (~ / $VAR / relative anchor on TERMINAL_CWD), validation (nonexistent / file / unreadable / no-op same-dir), cache sync (terminal envs, file_ops, partial failure isolation), and registry wiring (all 4 aliases resolve to the canonical name with cli_only=True). 15 tests, all pass. Files: - hermes_cli/commands.py: register CommandDef - cli.py: add _handle_set_workspace_command and dispatch in process_command - tests/cli/test_cli_set_workspace.py: new
|
Heads-up on a related gap — I've opened #29531 for per-session working directories on gateway / OpenAI-compatible API sessions. The open design question in #29531 is whether a gateway-routable, per-session cwd should reuse a command like this one or be a separate mechanism. Linking it here so the author and maintainers can weigh in if |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
/set-workspaceslash command to change the working directory used by the terminal, file, and code-execution tools for the current CLI session. Aliases:/workspace,/cd,/setworkspace.The change takes effect immediately — no
/resetrequired — because all downstream caches that read cwd are kept in sync.Why
Switching projects mid-session currently means either restarting Hermes (losing context) or relying on
cdinside a terminal call (only updates the active terminal env, not file_tools' relative-path anchor or new sandboxes)./set-workspacemakes this a first-class operation.Behavior
Implementation
Updates the single source of truth (
TERMINAL_CWDenv var) plus all downstream caches that read from it on tool invocation:os.environ["TERMINAL_CWD"]— read by every tool path that resolves cwd: file_tools relative-path anchoring, code_execution sandbox cwd, runtime footer, checkpoint manager, subagent inheritance viadelegate_tool.tools.terminal_tool._active_environments[*].cwd— the cwd actually fed to subprocesses for every long-lived shell or sandbox. Normally maintained by the cwd-marker mechanism on eachcd; force-synced here because the user is changing it out-of-band.tools.file_tools._file_ops_cache[*].cwd—ShellFileOperationsprefersenv.cwd(already updated above) and falls back toself.cwd, so we keep both in sync.Session-scoped only; does not write to
config.yaml. Failures during cache sync (e.g. a remote backend that refuses cwd reassignment) are isolated per-cache so they cannot block the env var update or other downstream caches.Validation: rejects nonexistent paths, files, and directories without read+exec permission. Same-dir detected and reported as no-op.
Related Issues
This PR doesn't directly close any of these, but
/set-workspaceprovides a manual escape hatch / mitigation for several long-standing pain points around session cwd handling:hermes updateresetsterminal.cwdto a broken value,/set-workspacelets you recover the session in-place instead of restarting and losing context.pwdreturns~/.hermes/hermes-agent);/set-workspaceis a usable workaround until the underlying profile-cwd discovery is fixed.terminal.cwdis overridden by invalid per-callworkdir; orthogonal cause but same symptom (terminal lands in the wrong place), and/set-workspacelets the user re-anchor./set-workspaceis a minimal manual precursor: explicit user-driven cwd switching as a building block toward automatic per-session pinning.Test Plan
tests/cli/test_cli_set_workspace.py— 15 tests, all pass:~expansion,$VARexpansion, relative paths anchored onTERMINAL_CWDnotos.getcwd(load-bearing invariant — explicitly tested by moving the process cwd elsewhere)set-workspace,setworkspace,workspace,cd) resolve to canonical name withcli_only=TrueFull local regression:
tests/cli/+tests/hermes_cli/test_commands.py— 812 passed (8 unrelatedruamel-missing tests deselected, exists onmainindependent of this PR).Files Changed
hermes_cli/commands.py— registerCommandDef(1 entry, 3 aliases)cli.py— add_handle_set_workspace_command(~95 lines including docstring + per-cache try/except blocks) and one-line dispatch inprocess_commandtests/cli/test_cli_set_workspace.py— new, 15 testsNotes
localterminal backends (docker/ssh/modal/etc.),TERMINAL_CWDstill updates sofile_toolsrelative-path resolution moves, but the recommendation in the docstring is to docdvia the terminal tool inside the remote session for shell-state correctness.cron/scheduler.pyalready usesTERMINAL_CWDto bridge per-jobworkdirinto the agent process.