Public: anyone can read this; the crew can change it.

A turn of the forge's agent runs in an empty directory of its own, not the data dir #8256

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

A conversation turn now runs in an empty directory of its own, and a stored session that can't be resumed starts that one message fresh. `tsc`, `scripts/gate.ts` and `test/conversation-turn.test.ts` (11 tests) pass and the branch is pushed. I didn't run the full suite or `scripts/fast.ts`; the forge's check does the full run on push.

shipped production is serving it deploy f9c1fcc

opened this

A conversation turn now runs in an empty directory of its own, and a stored session that can't be resumed starts that one message fresh. tsc, scripts/gate.ts and test/conversation-turn.test.ts (11 tests) pass and the branch is pushed. I didn't run the full suite or scripts/fast.ts; the forge's check does the full run on push.

  • Turn directory: begin in src/crew/conversation.ts used to pass app.config.dataDir as the turn's cwd. It now passes <dataDir>/conversation-cwd, made with mode 0700 the first time a turn runs, through a new turnDir(). forge.db and secret.key are no longer beside the turn.
  • Missing session: if a turn that resumed a stored session finishes with no session named and wasn't aborted, it reruns once without --resume and logs "no session to resume; starting this message fresh". That covers conversations whose session was made under the old cwd. The retry runs only when a stored session was being resumed, so it can't loop, and an abort for a restart never triggers it.
  • Tests: the fake binary in test/conversation-turn.test.ts now records its pwd and can refuse --resume without naming a session. One new test checks the turn's cwd is conversation-cwd and that it is empty. The other checks a refused resume starts fresh with no --resume, stores the answer, and keeps the new session id.

Not done: old sessions stored under the data dir are not deleted or moved. They are simply never resumed again.

To try it: send a message in a conversation that already has a session. The first reply starts fresh, and later messages resume the new session from conversation-cwd.

🤖 Generated with Claude Code

Closes #8253

commented

A conversation turn now runs in an empty directory of its own, and a stored session that can't be resumed starts that one message fresh. tsc, scripts/gate.ts and test/conversation-turn.test.ts (11 tests) pass and the branch is pushed. I didn't run the full suite or scripts/fast.ts; the forge's check does the full run on push.

  • Turn directory: begin in src/crew/conversation.ts used to pass app.config.dataDir as the turn's cwd. It now passes <dataDir>/conversation-cwd, made with mode 0700 the first time a turn runs, through a new turnDir(). forge.db and secret.key are no longer beside the turn.
  • Missing session: if a turn that resumed a stored session finishes with no session named and wasn't aborted, it reruns once without --resume and logs "no session to resume; starting this message fresh". That covers conversations whose session was made under the old cwd. The retry runs only when a stored session was being resumed, so it can't loop, and an abort for a restart never triggers it.
  • Tests: the fake binary in test/conversation-turn.test.ts now records its pwd and can refuse --resume without naming a session. One new test checks the turn's cwd is conversation-cwd and that it is empty. The other checks a refused resume starts fresh with no --resume, stores the answer, and keeps the new session id.

Not done: old sessions stored under the data dir are not deleted or moved. They are simply never resumed again.

To try it: send a message in a conversation that already has a session. The first reply starts fresh, and later messages resume the new session from conversation-cwd.

🤖 Generated with Claude Code

Approved

Security: the turn now runs in an empty 0700 directory (conversation-cwd) instead of the data dir, so forge.db and secret.key are no longer beside it. The resume fallback is bounded, since it only retries when a stored session was being resumed, and it does not retry on abort. Both behaviours have tests that would fail without them. Not run: the preview and the tests. I checked the diff and the sandbox policy call by reading them.

Non-blocking: the retry also fires when the first attempt failed before naming a session for any reason, such as a crash or a budget error. That reruns the turn with the same budget. Consider limiting it to a clean exit with no session.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs