Skip to content

fix(agents): refuse codex resume-adopt explicitly + document why#125

Merged
oratis merged 1 commit into
mainfrom
fix/codex-resume-adopt-refusal
Jun 19, 2026
Merged

fix(agents): refuse codex resume-adopt explicitly + document why#125
oratis merged 1 commit into
mainfrom
fix/codex-resume-adopt-refusal

Conversation

@oratis

@oratis oratis commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Resume-adopt (claude --resume under a PTY) is claude-only because its non-bypassable liveness guard — which refuses to resume a live session and corrupt its transcript via a second writer — relies on claude's pid-file (~/.claude/sessions/<pid>.json + kill -0).

I checked codex parity: the codex CLI does support codex resume <id>, but it leaves no equivalent liveness signal (its rollout JSONL carries no pid/lock), so "idle" could only be guessed from mtime — unsafe on a transcript-corruption surface. codex also isn't installed in this environment and node-pty can't spawn under Node 26, so a speculative path couldn't be verified end-to-end. So it's documented as deliberately unsupported, with the unblock conditions.

While doing so I found + fixed a latent footgun: POST /api/agents/pty/start {agent:"codex", resumeSessionId} used to pass the claude-only liveness check and then silently start a fresh codex session (the resume id was dropped) — "resume X" became "new session". Now:

  • PtyAgent.start throws for resumeSessionId on a non-claude agent.
  • the endpoint returns a clear 400 (instead of the generic 503).

codex adopt-at-launch (a fresh lisa agents pty codex "<task>") is unaffected. The CLI/iOS/GUI never request codex resume, so this only tightens the direct-API path.

Docs

  • docs/PTY_AGENTS.md: new "Why codex resume-adopt isn't supported (yet)" section.
  • docs/IOS_COMPANION_PLAN.md §4: records the investigation + explicit refusal.

Verification

npm run typecheck && npm run build && npm test804 pass, 1 skip (the real-node-pty round-trip, which can't spawn under Node 26). The refusal is unit-tested in src/agents/pty.test.ts.

🤖 Generated with Claude Code

… downgrading

Resume-adopt (claude --resume under a PTY) is claude-only because the
liveness guard that prevents resuming a *live* session — and corrupting its
transcript via a second writer — relies on claude's pid-file
(~/.claude/sessions/<pid>.json + kill -0). Codex has no equivalent: its
rollout JSONL carries no pid/lock, so "idle" could only be guessed from
mtime, which isn't safe. The codex CLI *does* support `codex resume <id>`;
the blocker is the missing liveness signal, not the capability.

Previously POST /api/agents/pty/start {agent:"codex", resumeSessionId}
passed the claude-only liveness check (the id isn't in the claude set), then
PtyAgent.start dropped the resume args (gate was kind==="claude-code") and
spawned a *fresh* codex session — so "resume X" silently became "new
session". Now it's refused honestly:
- PtyAgent.start throws for resumeSessionId on a non-claude agent.
- POST /api/agents/pty/start returns 400 (clearer than the generic 503).
codex adopt-at-launch (a fresh `lisa agents pty codex "<task>"`) is unaffected.

Docs: PTY_AGENTS.md gains "Why codex resume-adopt isn't supported (yet)"
(with unblock conditions); IOS_COMPANION_PLAN.md §4 records the investigation
and the explicit refusal.

Verified: npm run typecheck && npm run build && npm test -> 804 pass, 1 skip
(the real-node-pty round-trip, which can't spawn under Node 26).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@oratis oratis merged commit aaf9b73 into main Jun 19, 2026
1 check passed
@oratis oratis deleted the fix/codex-resume-adopt-refusal branch June 19, 2026 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant