Repository navigation
Conversation
dl <ws> recreate ends every agent in the container. herdr already saves, per pane, the line that starts the pane's agent again. agent_sessions::collect reads it for each pane attached to the workspace, and herdr agent get decides whether the agent in that pane is still live. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
agent_sessions::restart runs herdr pane run with the saved line, and asks again for up to ten seconds while the old transport exits. The pane this dl runs in is handed its line instead of typed into. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
Before the up, the recreate reads which herdr panes hold an agent in the workspace. After the up, it types each saved line back into its pane, and then attaches. Outside herdr, or when herdr does not answer, or when the up fails, it says so, and hands over any line it did not type. None of this refuses the recreate. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
…/recreate-keeps-agent
A pane attached to the workspace being recreated can still hold the resume line an earlier `dl other -- claude` saved in it, because a plain attach saves nothing. collect took that line as the pane's session, so the restart started an agent in the other workspace and the notice said the agent here was kept. A saved line now counts only when its workspace word is the id of the workspace being recreated, which is the word dl writes there from the launch and the container hook. A live agent with a line for another workspace is reported as unresumable. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
…uild could not read herdr's agent get answer with /result/agent present but no string name read as NoAgent, so collect dropped the pane's saved line. Such an answer now reads as Unanswered, which keeps the line; NoAgent stays for an agent that is absent or null. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
…ive agent again When the OS refused to start `devpod up` for a recreate, the old container and its agents were untouched, yet every held pane got a line to run `claude --resume` by hand: a second claude on a session that still ran. A spawn refusal (`NotRun::Blocked`) now says nothing about the held agents. `NotInstalled` and a devpod refusal keep the hand-back, since both can follow a container the recreate already removed. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
…panes The CHANGELOG said a recreate outside herdr prints the line to run by hand; there is no line there, and dl says to run 'claude --resume'. docs/cli.md said a pane counts unless herdr reports its agent done; collect also drops a pane where herdr reports no agent. The module doc made the same no-line promise, and a render.rs comment gave the agent notices severities that nothing maps. Docs and comments only: no red test is possible beyond the existing prose guards. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
…create's agent restart Pins a pane run refused twice then taken (two ticks of waiting), a saved word with a space or a quote typed back as the same word, a pane herdr will not describe skipped without losing the rest, a live agent with no session file reported unresumable, a stopped workspace's recreate asking herdr nothing, a pane list that fails saying AgentSessionsUnanswered, and the four agent-session notices that had no word test. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
…ane gained its agent e0fca22 wrote a word-for-word test of the AgentSessionUnresumable line and a collect test of a live agent with no session file, both against the shape before b47d65d gave the notice an `agent` field and made `HeldSessions.unresumable` a list of `UnresumablePane`. Cherry-picked together, neither test compiled. Name the agent in both. The claude sentence keeps its exact words, and the word test now also pins the sentence a codex pane gets, so the test still says every unresumable line word for word. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
Reviewer's GuideRunning-workspace Sequence diagram for recreating a workspace and restoring agent sessionssequenceDiagram
participant User
participant Launch
participant Herdr
participant Devpod
participant Pane
User->>Launch: run_rebuild(Recreate)
Launch->>Herdr: pane list
Herdr-->>Launch: panes
loop each pane
Launch->>Herdr: process-info(pane)
Herdr-->>Launch: foreground process
Launch->>Herdr: agent get(pane)
Herdr-->>Launch: agent status
Launch->>Launch: read saved_argv(session.json)
end
Launch->>Devpod: bring_up(--recreate)
Devpod-->>Launch: up result
alt up succeeded
loop each held session
Launch->>Herdr: pane run(pane, shell-quoted line)
Herdr-->>Launch: accepted or pane busy
opt pane busy
Launch->>Herdr: pane run retry after 500 ms
end
end
else up failed after starting
Launch-->>User: print saved lines for manual recovery
end
Launch->>User: attach
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Codecov Report❌ Patch coverage is Additional details and impacted files
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Copied from the public-api CI job's diff. public-api.api.txt gains the seven LaunchNotice variants, which is a change to the promised API: a caller that matches LaunchNotice exhaustively needs an arm for each, as for every notice added before them. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
…rt it again herdr's own docs say idle and done both mean the agent is ready for input. done only says nobody has looked at the pane since the turn ended. collect read done as an agent the user had quit, so it dropped the pane's saved line, and the recreate ended that agent for good. Claude-Session: https://claude.ai/code/session_01Ro7QyyAtHmrh9oxyyK6h9m
This branch has not been deployed
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.
Part of #673 — A workspace keeps its old image after a pull, and a recreate ends its agent. This PR is part 2 of 3:
dl <ws> recreatestarts the agents that it ends again, in the panes that they held.What this changes
flows/agent_sessions.rs, has two steps:collectasks herdr for every pane. It keeps a pane when the pane's foreground is adlsession into this workspace, and herdr'ssession.jsonholds a saved line for the pane that starts an agent. The word afterdlin the saved line must be this workspace id.herdr agent getremoves a pane whose agent isdoneor absent.restarttypes each saved line, shell-quoted, into its pane withherdr pane run. herdr refuses a pane until the old session has exited, sorestarttries again every 500 ms, up to 20 times for each pane. It never types into the pane thatdlitself runs in. It returns that pane's line fordlto print.run_rebuildinflows/launch.rsuses these steps forLaunchVerb::Recreateon a running workspace only.resetandcodedo not change.LaunchNoticevariants carry each outcome. Their words are inrust/dl/src/render.rs. No outcome refuses the recreate.herdr agent getparser is now in core (herdr::agent_reading_in,AgentStatus,PaneAgent), so part 3 can read whether an agent is idle.docs/cli.mdhas a new section, "A recreate starts the agents it ends again".CHANGELOG.mdhas an entry.Where this fits
A saved line looks like
dl <ws> -- ... claude ... --remote-control=<ws> --resume <uuid>. The container'sSessionStarthook reports a new id after/clear, so the line holds the session that the pane is in now. The transcripts are in~/.claude, which outlives the container, so--resumefinds the conversation.How I checked it
All tests run on
FakeRunner. This devcontainer has no herdr and no docker daemon.collectbefore theup,restartafter it, and then the attach.dl other -- claudeno longer gets that line on a recreate ofmyws.devpod upnever started tells the user nothing about the agents, because they still run.claude --resume.session.json, a stopped workspace, andpane listfailing.Commands that I ran in the devcontainer:
cargo test --workspace: 3044 passed.cargo clippy --locked --all-targets -- -D warningsandcargo fmt --check: clean.pytest test/against the debug build: 846 passed.prek run --from-ref origin/main --to-ref HEAD: passed.I did not run:
herdr pane runtakes the line as one string and presses Enter, the shape ofagent getfor a pane with no agent, and that a pane falls back to its shell when thedlsession dies.scripts/public-api-snapshots.sh. The tools are not in the container. I copied the diff from thepublic-apiCI job into the snapshot files.Merge danger
Door: two-way. A revert gives back the old recreate. The promised API (
public-api.api.txt) gains sevenLaunchNoticevariants.LaunchNoticeis not#[non_exhaustive], so a caller with an exhaustivematchneeds an arm for each, as for each notice added before.Blast radius: medium. If
collectpicks the wrong pane,dltypes adl <ws> -- claude ...line into a shell prompt where it does not belong. The workspace id check limits this to panes whose saved line names this workspace. If a pane stays busy, the attach waits up to about 10 s for that pane, and up to about 50 s if herdr hangs. The panes run one after another.Review notes
claude --resumepicks a conversation up again. Reading the Claude processes in the container would cover this case, but the session id in a process's arguments is wrong after/clear. Part 3 skips such workspaces, sodl --refresh-stalenever ends an agent that herdr cannot see.up(DevpodNotRun(NotInstalled)),dlcannot tell this from a recreate that removed the container. It then prints the lines to run by hand although the agents may still run. A fix needs a new error variant inworkspace_up.Stack
🤖 Generated with Claude Code