Repository navigation
feat(agents): open Claude Code's agent view with Left and show agent status in the footer - #443
ayush5harma wants to merge 16 commits into
Conversation
- move the release, spawn, cancel and restore sequence from the /login and /logout executor into terminal_runtime::run_with_terminal - parameterise it by release reason, argv, working directory and labels so a second interactive child (the stock agent view) reuses it instead of copying it - keep the auth error strings unchanged; the auth PTY tests pass as before
- poll `claude agents --json` at start and every 10 s, one call at a time, each run and parsed on a runtime worker and killed after 5 s - run the session's own CLAUDE_CODE_EXECUTABLE (falling back to `claude` on PATH, as /login does) so the listing comes from the same stock build - count background sessions only, with stock's "blocked" state shown as awaiting input and "working" as working - render `<- N agents . K awaiting input . W working` after the mode badges while the composer is empty, dropping whole segments on narrow widths - hide it when there are none, the listing fails, or stock's global leftArrowOpensAgents setting is false
- add app.open_agents_or_move_left, bound to Left in chat input: from an empty composer it hands the terminal to `<claude> agents` through the shared child hand-over, otherwise it moves the cursor as before - honour stock's global leftArrowOpensAgents setting, read at each use - keep the session running while the view owns the terminal, and poll the agent status again as soon as it exits (Esc, or Ctrl+C twice) - report a missing CLI, a spawn failure or a failing exit in the chat - the action is rebindable and appears in /help and /docs shortcuts; Ctrl+B still moves left unconditionally
- teach the native fake claude `agents --json` (a listing the test places in the profile) and `agents` (records argv and cwd, reads one line of inherited stdin, exits) - check that Left with text edits the draft, that Left on an empty prompt gives the child the terminal with the TUI silent, and that the next prompt reaches the bridge afterwards - log each agent status poll with its trigger so the test proves the footer counts came from the poll the return triggered, not the interval
- describe Left on an empty prompt, how the agent view returns (Esc or Ctrl+C twice), and that the session keeps running meanwhile - explain the footer status, its refresh, when it hides, and the stock leftArrowOpensAgents setting that turns both off - note that /agents stays Claude Code's subagent configuration - record the fake claude's agents modes in the PTY fixture notes
- the harness inherited CLAUDE_CODE_EXECUTABLE and PATH, so inside a claude-rs session the agent view test ran the real binary and timed out, and every other PTY test ran the developer's `claude agents --json` against its temp profile every 10 s, unlike CI - always set CLAUDE_CODE_EXECUTABLE: a missing path turns the poller off, and the agent view tests point it at the compiled fake
…e child - claim the terminal synchronously in the shared hand-over: a second request (key repeat, batched keys, /login) while one is claimed or running is refused instead of overwriting the first child's cancel sender, and a dropped sender no longer kills the child as "shutdown" - start the bridge in its own process group so a Ctrl+C typed while a cooked-mode child owns the terminal cannot reach the session, and do not treat that SIGINT as a shutdown request in claude-rs; an agent view ended by SIGINT is not reported as an error - show the footer status only when the key would open the view (one predicate for both), naming the bound key after a rebinding - read leftArrowOpensAgents on the poller's worker instead of on the UI thread at every Left press; start the poller once trust is settled - check that a timed-out poll child is really killed; test the repeated Left, Ctrl+C during the hand-over, the claim rules and the footer gate
- spawning the 236 MB stock binary for `claude agents --json` cost about 0.21 s of CPU per call, every 10 s, in every claude-rs window; a poll now stats jobs/*/state.json, the daemon roster and the session registry and re-parses only files whose mtime or size changed (about 0.06 ms of CPU) - port the counting of `claude agents --json` without --all: job liveness through live roster workers and bg sessions, the 5 s grace for new jobs, unclaimed jobs shown as blocked or failed, recurring done jobs, and bg sessions without a job - fall back to the CLI only for a job layout this reader does not know, at most once a minute, time-boxed and killed as before - cache leftArrowOpensAgents by the config file's mtime and size, and drop the idle backoff now that a poll is nearly free - pin the file format with fixtures for every state, live sessions, the roster, garbage and the cache; add an ignored real-profile parity check
- say what happens while the agent view is open: turns continue, prompts wait but their timers run, notifications are still delivered - explain that Ctrl+C while the view starts closes only the view and that repeated presses open one view - describe the file-based status, its refresh, the CLI fallback, when the hint hides and that it names a rebound key
- Left and Ctrl+C arriving in one read reached claude-rs before it released the terminal, so the Ctrl+C was taken as clear-or-quit and claude-rs exited (seen in a real run); from the claim on, input belongs to the child and the TUI ignores everything but resizes - unit test and PTY test (Left+Ctrl+C in one write keeps claude-rs and the session running; fails with the guard removed) - docs: a Ctrl+C while the view starts closes the view or is dropped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ship - retain OS signal receivers throughout the TUI event loop - prioritize pending signals before input and child-return events in both phases - preserve later parent shutdown and active-child SIGTERM behavior in regressions - link the parity report to cross-platform CI follow-up results
…reliably - bypass the CLI cache after agent-view return while retaining routine polling limits - supply equivalent job fixtures and observed command entry for Windows terminal tests - capture early bridge-test child completion and bound slow-reader cleanup - document the cross-platform refresh behavior and preserve regression coverage
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Windows-safe submit_command helper only serves the session name and colour test, which is not on this branch; clippy flagged it as unused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-ups: the bridge gets CREATE_NEW_PROCESS_GROUP on Windows, as it gets its own process group on Unix, and a Ctrl+C exit of the agent view (STATUS_CONTROL_C_EXIT) is a normal close there. The CLI dependency list in about.md gains claude agents and claude agents --json, shortcuts.md says Windows reads the status through the CLI, the spawn comment records that a background group stops /dev/tty readers, and the fixtures README and harness comment say a missing executable disables the CLI fallback rather than the poller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
srothgan
left a comment
There was a problem hiding this comment.
I don't want claude-rs launching Claude Code's agent UI or reimplementing its private job-state logic, so this architecture won't be merged. Please have your agent look into the Anthropic SDK we're already using. In agent-sdk/node_modules/@anthropic-ai/claude-agent-sdk/sdk.d.ts (currently 0.3.288), read:
- SDKTaskStartedMessage, SDKTaskProgressMessage, SDKTaskUpdatedMessage, and SDKTaskNotificationMessage around lines 5993–6084.
- listSubagents() at line 1152 and getSubagentMessages() at line 939.
- Query.stopTask() at line 3219.
These provide the foundation for a native view of the current session's agents. They aren't a replacement for Claude Code's global background-session roster, so please scope the feature accordingly.
|
And please, for the next version of this pr: follow the architecture we have and read some documentation (at least have your agent read it)!!! |
|
Understood. Launching Scope: the active session's subagents and background tasks only. No other sessions, no global roster, and nothing from Claude Code's UI or private files. Source of truth: the task lifecycle state the bridge already normalizes ( Bridge (
Rust: a tab next to Status and Usage in the config view lists the session's tasks, grouped by Questions:
Before relying on it, I'll check at runtime whether the agent ids from |
Summary
Lefton an empty prompt hands the terminal to Claude Code's ownclaude agentsview, and claude-rs takes it back when the view exits (Esc, orCtrl+Ctwice). The claude-rs session keeps running meanwhile: a turn in progress continues, and its output is there on return. Claude Code'sleftArrowOpensAgentssetting turns this off. The key is the rebindable actionapp.open_agents_or_move_left,Ctrl+Balways moves left, and/agentsstays Claude Code's subagent configuration./loginused moves intoterminal_runtime/child_command.rs, so both commands go through one path. Only one hand-over runs at a time, and repeated presses open one view. Keys read in the batch that started the child are dropped rather than replayed into the composer. ACtrl+Cwhile the view starts closes only the view: the bridge now runs in its own process group (CREATE_NEW_PROCESS_GROUPon Windows), so the interrupt never reaches the session, and pending interrupts are handled before claude-rs takes the terminal back. A Ctrl+C exit of the view counts as a normal close on both platforms.Leftwould open the view, the footer shows the background sessions after the mode badges, as← N agents · K awaiting input · W working. These are the countsclaude agents --jsongives, minus completed sessions. claude-rs reads them from Claude Code's own files (jobs/*/state.json, the daemon roster and the session registry) every 10 seconds, and again right after the view closes, re-reading only files that changed.claude agents --jsonis a once-a-minute fallback for a file layout it does not recognise, so the status costs a few file checks rather than a process per poll. On Windows, where claude-rs cannot yet check whether a job's process is alive, it always uses the CLI, at most once a minute. If the action is rebound, the footer names that key in place of←.claude agents --jsonon a real profile; PTY tests that hand the terminal to a fake agent view and back, coverCtrl+Cduring start-up, and keep the status poller away from the developer's real Claude Code.Why
See #439. Claude Code opens the agent view with
Lefton an empty prompt and shows background agent status in its footer. In claude-rs, someone running background agents has to leave the app, or open a second terminal, to see or answer them.Closes #439
Validation
cargo fmt --all -- --check: passescargo clippy --all-targets --all-features -- -D warnings: passes, with five lints new in clippy 1.98 allowed (collapsible_match,manual_is_multiple_of,manual_is_variant_and,map_unwrap_or,while_let_loop). Across all targets, clippy 1.98 reports the same seven warnings onmainand on this branch, none of them in this diff.cargo fetch --locked: passescargo test --locked --all-features: all targets pass, 2034 tests (lib 1914,terminal_resize39), plus the serialterminal_resizerun. I ran it withCLAUDE_RUST_NO_UPDATE_CHECKunset: my environment sets it, which makes twoupdate_checktests fail on every branch.npm --prefix agent-sdk test(162) andnpm --prefix agent-sdk run lint: passcargo deny, the MSRV check, the duplicate-code scan, Linux and Windows. I'm leaving those to CI. The two Windows-only additions from review (CREATE_NEW_PROCESS_GROUPand theSTATUS_CONTROL_C_EXITcheck) have not been compiled locally; the Windows clippy job is their first build. Before the review fixes, these commits, together with the session name and mascot ones, passed this repository's CI on all three runners in my fork (feat(parity): preserve session identity and expose stock agent workflows ayush5harma/claude-code-rust#1).← 1 agent · 1 awaiting input.Lefton the empty prompt opened Claude Code's agent view, which listed that session under "Needs input".Escreturned to the same claude-rs session, with its transcript and footer intact. Onmain, the same keys only move the cursor.Notes
Lefton an empty prompt used to do nothing; with text in the input it still moves the cursor.docs/src/shortcuts.md(the key, the agent view hand-over and its limits, and the footer status and where it is read from),docs/src/about.md(claude agentsandclaude agents --jsonadded to the CLI dependency list),tests/fixtures/README.md.Lefton an empty prompt, and return to the session when it closes. Fixes [Feature]: Show the current session's subagents and background tasks, with stop and transcript view #439.← N agents · K awaiting input · W workingwhile the input is empty.src/app/events/mod.rsandtests/terminal_resize.rs. They merge without conflicts (checked withgit merge-tree)./dev/tty(a sudo or ssh prompt) is stopped by SIGTTIN instead of competing with claude-rs for keys. Neither worked before; this is noted in a comment at the spawn.claudeonPATHand noCLAUDE_CODE_EXECUTABLE,Lefton an empty prompt now shows "claude CLI not found" instead of doing nothing. I kept the message because it says how to enable the view, but it can fall back to moving the cursor if you prefer.🤖 Generated with Claude Code