Public: anyone can read this; the crew can change it.
A /talk conversation resumes its own session across a real forge restart #8780
Check · Review · Land · Live done — Landed and live in production.
I added the restart test, but it has not run against the real `claude` yet. This sandbox has the binary but no `ANTHROPIC_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN`, so it skipped here and printed why. `bun x tsc --noEmit`, `bun scripts/gate.ts` and `test/conversation-turn.test.ts` (19 pass) are green. The third checklist item is open: I have no log lines to show, and the check's first real run will ha…
shipped production is serving it deploy 7042057
I added the restart test, but it has not run against the real claude yet. This sandbox has the binary but no ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN, so it skipped here and printed why. bun x tsc --noEmit, bun scripts/gate.ts and test/conversation-turn.test.ts (19 pass) are green. The third checklist item is open: I have no log lines to show, and the check's first real run will have to supply them.
What changed
test/conversation-restart.test.ts(new) runs two forge lifetimes on one data directory, each withcreateApp,serve,say, then stop. It runs onhaiku, with each turn capped at $0.25.
- The first message is "Remember the word PELICAN", and the second asks which word it was. Resuming the same session is what lets the model answer.
- After the restart it asserts the second turn's run log says resuming session <first id> and never says no session to resume. It also asserts claude_session_id is unchanged and the agent's answer contains "pelican".
- It finds <session id>.jsonl under dataDir/claude-config, checks that directory is owner-only, and checks no .jsonl appears under a temporary HOME it sets for the test.
- It skips with a console reason when claude or the credential is missing. The check's cells have both, so it runs there.
- It prints both runs' logs and the session file paths, so the check log carries the lines.
src/crew/conversation.tsnow writesresuming session <id>to the run log before each resumedrunClaude. Without it, a resume and a silent fresh start would look the same in the log. The existing fresh-start log line is unchanged.
Not done
- I didn't tag the test to run only in the check. Two tiny turns stay well inside the per-file budget (300 s cap).
- I didn't simulate a crash mid-turn;
resumeInterruptedalready has tests with a stub binary.
To try it: with ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN set and claude on PATH, run bun test test/conversation-restart.test.ts.
🤖 Generated with Claude Code
The test is well-shaped: two real lifetimes on one data dir, asserting the resume log line, an unchanged session id, the answer, owner-only claude-config, and no .jsonl under a temp HOME. The one-line run-log addition is small and makes resume distinguishable from a silent fresh start. Nothing touches the page, so there is no UI, keyboard or phone surface to fault. No new dependency, no README edit. Caveat: it has never run against the real claude (skipped here), so its first run is in the check; if it goes red, read that log first. Next: (1) after the first green check, paste the printed log lines into the pull description to close box 3; (2) confirm the spawned claude inherits the test HOME and CLAUDE_CONFIG_DIR, so the no-.jsonl-under-HOME assertion cannot pass vacuously.
Left #8776 open: 1 unticked item remain (The pull says what the test showed, with the log lines.).
I added the restart test, but it has not run against the real
claudeyet. This sandbox has the binary but noANTHROPIC_API_KEYorCLAUDE_CODE_OAUTH_TOKEN, so it skipped here and printed why.bun x tsc --noEmit,bun scripts/gate.tsandtest/conversation-turn.test.ts(19 pass) are green. The third checklist item is open: I have no log lines to show, and the check's first real run will have to supply them.What changed
test/conversation-restart.test.ts(new) runs two forge lifetimes on one data directory, each withcreateApp,serve,say, then stop. It runs onhaiku, with each turn capped at $0.25.- The first message is "Remember the word PELICAN", and the second asks which word it was. Resuming the same session is what lets the model answer. - After the restart it asserts the second turn's run log says
resuming session <first id>and never saysno session to resume. It also assertsclaude_session_idis unchanged and the agent's answer contains "pelican". - It finds<session id>.jsonlunderdataDir/claude-config, checks that directory is owner-only, and checks no.jsonlappears under a temporaryHOMEit sets for the test. - It skips with a console reason whenclaudeor the credential is missing. The check's cells have both, so it runs there. - It prints both runs' logs and the session file paths, so the check log carries the lines.src/crew/conversation.tsnow writesresuming session <id>to the run log before each resumedrunClaude. Without it, a resume and a silent fresh start would look the same in the log. The existing fresh-start log line is unchanged.Not done
resumeInterruptedalready has tests with a stub binary.To try it: with
ANTHROPIC_API_KEYorCLAUDE_CODE_OAUTH_TOKENset andclaudeon PATH, runbun test test/conversation-restart.test.ts.🤖 Generated with Claude Code
Closes #8776