feat: remember agent cli options when resuming sessions - #2614
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
🚧 Files skipped from review as they are similar to previous changes (6)
📝 WalkthroughWalkthroughThe change captures agent startup arguments, stores them in terminal state and pane snapshots, filters incompatible options, and replays matching arguments when restored sessions start. ChangesAgent launch replay
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant AgentProcess
participant PaneDetection
participant AppState
participant Snapshot
participant ResumePlanner
AgentProcess->>PaneDetection: Provide foreground argv
PaneDetection->>AppState: Send AgentLaunchArgsDetected
AppState->>Snapshot: Store agent launch metadata
Snapshot->>ResumePlanner: Provide matching saved metadata
ResumePlanner->>ResumePlanner: Filter replayable options
ResumePlanner-->>AppState: Return resume command
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/persist/restore.rs (1)
543-549: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winFilter
saved_agent_launchby agent match before storing it on the restored terminal.
restore_plan_for_snapshotfilterslaunch_argsbylaunch.agent == session.agentbefore building the resume argv, with a comment noting that a pane which later ran a different agent must not reuse the previous agent's options. This block does not apply the same filter: it storessaved_agent_launchonto the restoredTerminalStateeven whensaved_agent_launch.agentdiffers from the session's agent.In the normal case the agents match, so this has no effect. If the pane later ran a different agent than the one whose options were last saved, and the server restarts again before the next process probe refreshes
agent_launch_args, a subsequent snapshot could re-persist the mismatched agent's stale launch options.🔧 Proposed fix to mirror the existing agent-match filter
if let Some(plan) = pending_native_agent_restore { let terminal_id = TerminalId::alloc(); let mut terminal = TerminalState::new(terminal_id.clone(), cwd.clone()) .with_pending_agent_resume_plan(plan); - if let Some(launch) = saved_agent_launch { + if let Some(launch) = saved_agent_launch.filter(|launch| { + saved_agent_session.is_some_and(|session| session.agent == launch.agent) + }) { terminal.set_agent_launch_args(&launch.agent, launch.args.clone()); }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a589c0e1-c53d-416d-80c5-20b9fbb1a538
📒 Files selected for processing (11)
docs/next/website/src/content/docs/session-state.mdxsrc/agent_launch_args.rssrc/agent_resume.rssrc/app/actions.rssrc/detect/mod.rssrc/events.rssrc/main.rssrc/pane.rssrc/persist/restore.rssrc/persist/snapshot.rssrc/terminal/state.rs
|
Good catch, fixed in 29eba78. I went slightly wider than the suggested diff on two points:
Both sites and |
Greptile SummaryThe PR captures agent CLI launch options, persists them with pane snapshots, and filters and replays them when restoring native agent sessions.
Confidence Score: 4/5The PR is not yet safe to merge because restored launch options can still be associated with a newer same-agent session when the first post-restore argv probe is unreadable. The previously reported restored-options issue remains reachable: restored arguments live in TerminalState while detector-local history starts empty, and an unreadable first probe returns without clearing those arguments, allowing a later snapshot and resume to replay stale permissions, model, sandbox, or approval settings. Files Needing Attention: src/pane.rs, src/persist/restore.rs, src/persist/snapshot.rs
|
| Filename | Overview |
|---|---|
| src/pane.rs | Adds process-probe publication and deduplication for launch arguments, but the restored-state unreadable-argv path remains unresolved. |
| src/detect/mod.rs | Extracts arguments following the detected agent token from foreground-process argv, including wrapped invocations. |
| src/terminal/state.rs | Adds per-agent launch-argument state used by snapshot persistence and resume planning. |
| src/persist/snapshot.rs | Serializes nonempty agent launch arguments into pane snapshots. |
| src/persist/restore.rs | Restores matching per-agent launch arguments and supplies them to the resume planner. |
| src/agent_launch_args.rs | Implements documented filtering of session selectors, one-shot options, positional arguments, and option values. |
| src/agent_resume.rs | Extends native resume commands with filtered launch arguments. |
Sequence Diagram
sequenceDiagram
participant Probe as Foreground process probe
participant Detector as Pane detector
participant State as TerminalState
participant Snapshot as Session snapshot
participant Resume as Resume planner
Probe->>Detector: agent identity + argv
Detector->>State: AgentLaunchArgsDetected
State->>Snapshot: persist agent and arguments
Snapshot->>State: restore saved arguments
State->>Resume: session reference + matching launch arguments
Resume->>Resume: drop session/one-shot options
Resume-->>State: agent resume command
Reviews (3): Last reviewed commit: "fix: drop agent options a later invocati..." | Re-trigger Greptile
|
Fixed in 2fa655c. Confirmed: with unreadable argv the early return left the previous invocation's options in The probe already knew which job it was looking at, so
That last case matters — clearing unconditionally would have wiped the options this PR restores from the snapshot before the first successful probe. Tests: |
Native agent session restore rebuilt the resume command from the session reference alone, so a pane started as `claude --permission-mode bypassPermissions` came back with default permissions. Capture the options the agent process was started with during foreground process detection, persist them per agent in the session snapshot, and replay them after the session reference on resume. Two rules decide what survives. Options that select a conversation or a one-shot run are dropped per agent, and a bare word is kept only when it directly follows a kept option, where it is that option's value. The second rule is what makes the first cheap: the value of a dropped option disappears because it follows no kept option, so `--resume <id>` loses the id without Herdr knowing that `--resume` takes one, and a subcommand form such as `codex resume <id>` needs no special case. Everything else is replayed, including options Herdr does not know about.
2fa655c to
0766aa5
Compare
|
i'm working on a new agent resume manifest system which is going to supersede this, so closing for now. |
Native agent session restore rebuilds the resume command from the session reference alone, so a pane started as
claude --permission-mode bypassPermissionscomes back as plainclaude --resume <id>with default permissions. The same applies tocodex -s danger-full-access -a neverand any other option a pane was started with.Flagging the process point first: this touches persistence and resume behavior rather than being a focused bug fix, so per CONTRIBUTING.md it is the kind of change that wants maintainer alignment. Happy to move it to a Discussion if you would rather shape the approach before looking at code.
What changed
Capture — the foreground process probe already reads each process's argv, so when it identifies an agent it also extracts the command line after the agent token (
detect::agent_launch_args_in_job, which handles wrapped invocations likenode .../cli.js --flag). A newAgentLaunchArgsDetectedevent records it on the terminal, deduped so it fires once per change rather than once per probe. No new process inspection or filesystem work is added to the detection loop; it reuses the argv the probe already has.Persist — a new optional
agent_launch: {agent, args}field on the pane snapshot, stored per agent so a pane that later ran a different agent never resumes with the previous agent's options. Old snapshots deserialize with the field absent.Replay —
agent_resume::plan_with_launch_args()appends the surviving options after the session reference.src/agent_launch_args.rsdecides what survives, with two rules:--resume,--continue,--session,--print,--prompt). Herdr supplies its own session reference.Everything else is replayed, including options Herdr has never heard of, so a new flag in a future agent release survives a resume without anyone touching Herdr.
The second rule is what makes the first cheap. The value of a dropped option disappears for free, because it is a bare word following no kept option:
--resume <id>loses the id without Herdr knowing that--resumetakes a value. The same falls out for agents that select a session through a subcommand and a positional id, socodex resume <id> --full-autoneeds no special case. That means the only per-agent data is a list of option names, with no arity table to drift as the agent CLIs change.It also stops a resume from compounding: after Herdr resumes a pane once, the live process argv contains the
--resume <id>Herdr itself appended, and the next restore drops it before adding the current one.Deliberate limits
--add-dir /a /bresumes as--add-dir /a.claude "fix the bug"and a prompt following a value are both dropped;claude --dangerously-skip-permissions "fix the bug"is not.Both are documented in the module header and on the session-state page. Distinguishing those cases needs a per-agent table of every option and its arity; an earlier revision had one and it was not worth its weight.
Verification
cargo nextest runpasses (3376 tests).cargo fmt --checkis clean. Unit tests cover the argument rules, the argv extraction including wrapped invocations, the event recording, the snapshot capture, and the restore plan including the per-agent guard.Also verified live in a throwaway session on a debug build, since unit tests do not cover the probe to snapshot to resume chain:
claude --permission-mode bypassPermissionsrecordedagent_launch: {agent: "claude", args: ["--permission-mode", "bypassPermissions"]}insession.jsonverify-session-idand args["--model", "sonnet", "--resume", "stale-session", "some prompt"]resumed ashermes --resume verify-session-id --model sonnet— option replayed, stale session flag and its id dropped, trailing prompt left behindTwo notes on
just cifrom my machine:clippy -D warningsfails on two pre-existing lints insrc/server/handoff.rs:381andsrc/terminal_theme.rs:136, both files untouched by this change and both flagged only because my toolchain is newer than the pinned 1.96.1.integration-assets-testandplugin-marketplace-testneed bun, which I do not have installed; neither covers this change.