Explicit Todo continuation: Stage A¶
- RFC status: Accepted (Stage A shipped in #4094; the historical filename is retained on purpose)
- Supersedes / closes: none
Delivery status and integration direction (2026-09-13)¶
Stage A shipped in #4094, merge 2ebd921ee989f7c696a7214ba1176d3bd5de6fb3. The historical filename does not imply that a generic memory substrate shipped. The capable manager and semantic handoff RFC includes this implementation in its M2/M3 refactor scope. That successor remains proposed; this document remains the shipped CLI compatibility and authority reference until its replacement qualifies.
Reuse rich/legacy context and the existing note validator/claim transfer boundary. Receiver acceptance of a suggestion is distinct from handoff adopt ownership mutation. Stage A's note is replaceable current Todo state, not a private immutable history. The successor maps authorized context to a recoverable brief, references current work, and supplies general assessment/result/automatic-return relations without adding a memory ledger or copying claim authority. CLI prepare/inspect/adopt remains usable during migration; frontend/Lark and automatic host continuation must be qualified separately. Same-host and registered-agent restrictions continue to apply to this adapter, not every general request. Leased execution uses the explicit transfer path below. See successor §5.13 for mappings, migration conditions and retained negative cases.
The successor §5.7 now distinguishes same-session resume, same-Agent session replacement and cross-Agent takeover. Only the last may require this adapter’s ownership mutation. Automatic brief capture, source-loss recovery, executable-session fencing and original-route result return are explicit future integration work; optional Obelisk recall supplies missing historical evidence, not a replacement transfer grant.
Language mirror: 中文版.
Status: a bounded local CLI workflow. The former general memory-substrate proposal is replaced by a cross-agent continuation workflow over the canonical Todo authority. It does not freeze a public memory schema.
Problem: switching coding agents mid-work¶
When a developer switches from one coding agent to another (e.g. Claude Code to Codex), the target agent has no context about what was done, what was tried and failed, and what comes next. The developer must re-explain the entire project state. This workflow gives the source agent a structured way to dump complete working context so the target agent can continue without re-explanation.
Stage A solves the same-machine, different registered agent scenario: an explicit handoff where the source prepares a rich continuation note and the target inspects, verifies, and adopts the Todo. It does not implement automatic context capture, agent-agnostic protocols, or zero-config onboarding. Those require a different product layer beyond this control-plane primitive.
Ownership and placement¶
The existing Todo coordination boundary owns current execution state, stable Todo IDs, revision checks and claim/lease decisions. The selected canonical File/SQLite authority supplies persistence; no new capability, provider, database, index, discovery API, recovery service or ownership protocol is introduced. The CLI is a host adapter to that TypeScript boundary.
Historical retrieval and long-term memory belong to optional providers through
existing decision_context / agent_turn_recall capability boundaries. Their
absence does not affect this workflow. Stage A neither invokes those providers
nor grants permission to index a workspace or read source-reference bodies.
First usable path¶
Prerequisites: an already explicitly promoted canonical authority and an
open, active Agent Todo claimed by a registered Agent. Lease-free adoption
retains the existing claim transaction. Hard-lease work requires the exact
current execution proof; ownership moves only through the existing atomic
task-lease transfer --transfer-claim command. This adapter never promotes a
Goal, changes its handoff mode or falls back to Markdown.
The user explicitly hands a Todo from one session to another session of a different registered agent on the same host. The source writes a revision- guarded continuation note (legacy rationale or rich context) into the existing Todo note; the target inspects current authority, verifies local artifact availability, and continues through the existing claim transaction with current-authority readback. Stop source execution before continuing in the target. Session IDs below are provenance, not authentication or a session lease. This slice does not implement automatic host launch.
Use the same registry/runtime arguments as the existing Todo CLI. Substitute an existing goal, Todo and registered agents for these example identifiers:
# Source: inspect current state, including its provider_revision.
loopx --format json handoff inspect --goal-id demo --todo-id todo_a \
--agent-id agent-a --session-id source-session --workspace .
# Copy the exact returned revision into REVISION, then explicitly replace the
# current Todo note with rich handoff context from a JSON file.
loopx handoff prepare --goal-id demo --todo-id todo_a \
--agent-id agent-a --session-id source-session --operation-id handoff-1 \
--expected-revision "$REVISION" --from-context ./handoff-context.json
# Or use the legacy compact form (rationale + source references):
loopx handoff prepare --goal-id demo --todo-id todo_a \
--agent-id agent-a --session-id source-session --operation-id handoff-1 \
--expected-revision "$REVISION" --rationale 'The narrow change preserves the existing authority boundary' \
--source-ref 'artifact:decision.md'
# Target: inspect again as the receiving agent; verify evidence and current artifact availability.
loopx handoff inspect --goal-id demo --todo-id todo_a \
--agent-id agent-b --session-id target-session --workspace . --artifact decision.md
# Target: inspect with a readable handoff digest (any registered agent, any session).
loopx --format json handoff inspect --goal-id demo --todo-id todo_a \
--agent-id agent-a --session-id target-session --workspace . --format digest
# Use the target inspect revision, then claim through the existing boundary.
# --target-agent-id specifies the receiving agent (defaults to --agent-id).
loopx handoff adopt --goal-id demo --todo-id todo_a \
--agent-id agent-b --session-id target-session --operation-id resume-1 \
--expected-revision "$REVISION" --target-agent-id agent-b --workspace . --artifact decision.md
Inspect reports the current goal/Todo/revision, decision rationale, source
pointers, local workspace/artifact availability and next action from the current
Todo. With --format digest, inspect renders a readable handoff summary that any
target agent can directly consume, including work summary, approaches tried,
next steps, files touched, key decisions, and open questions. References are
evidence pointers supplied by the source, not verified remote content. Artifact
checks prove local existence, not content integrity. Adopt preserves the Todo
ID, invokes the existing claim transaction and reads back current authority.
A same-owner claim may correctly be a no-op; it does not create a Todo or
manufacture a new lease.
Leased execution continuation¶
Prepare while the sender still owns the claim and lease. Pass the current
--task-lease-idempotency-key and --task-lease-expected-version pair to prepare.
Use actual readback versions; the example assumes source version 3.
loopx handoff prepare --goal-id demo --todo-id todo_a \
--agent-id agent-a --session-id source-session --operation-id prepare-context \
--expected-revision "$SOURCE_REVISION" --from-context ./handoff-context.json \
--task-lease-idempotency-key execution-a --task-lease-expected-version 3
loopx task-lease transfer --goal-id demo --todo-id todo_a --owner agent-a \
--idempotency-key execution-a --expected-version 3 --new-owner agent-b \
--new-idempotency-key execution-b --ttl-seconds 600 --transfer-claim
loopx handoff inspect --goal-id demo --todo-id todo_a \
--agent-id agent-b --session-id target-session --workspace . \
--task-lease-idempotency-key execution-b --task-lease-expected-version 4
loopx handoff adopt --goal-id demo --todo-id todo_a \
--agent-id agent-b --session-id target-session --operation-id accept-context \
--expected-revision "$TARGET_REVISION" --workspace . \
--task-lease-idempotency-key execution-b --task-lease-expected-version 4
Inspect remains read-only without proof, but cannot report can_adopt=true
for leased work without current execution authority. Transfer carries a note
forward only when it was valid before the authorized claim change; it updates
that note's owner-bound fingerprint in the same CAS. Changed work requirements
and previously stale notes remain stale. Arbitrary metadata edits cannot
rebind a note. An already-committed historical transfer is replayed unchanged.
Leased adopt seals a context receipt bound to Agent, session, note, revision and
lease proof. It does not transfer, acquire or renew a lease. Its adoption
result has changed=false; current_authority_verified additionally requires
fresh authority readback. The old lease-free result retains its claim field.
Historical receipts never override a released/expired lease, a different owner,
changed requirements or a Goal acceptance hold. Session IDs remain provenance,
not host authentication or grants to execute external tools.
Prepare/adopt deliver current canonical Todo state to the existing Markdown
projection. Display failure returns projection_delivery=pending with
retry_business_mutation=false; repair the local display inputs and retry the
same operation or use todo project-markdown. Inspect never writes a display.
The feature does not create frontend/Lark controls or launch a target session;
it is an explicit CLI workflow, not automatic manager-to-worker delegation.
Rich handoff context¶
The --from-context flag accepts a JSON file with structured handoff context:
{
"work_summary": "Implementing cross-agent handoff with typed transfer grant. Need to enforce note invariant.",
"approaches_tried": [
{"approach": "Unstructured note with hash only", "outcome": "failed", "reason": "Any caller can compute public facts"},
{"approach": "Typed transfer_grant without note validation", "outcome": "partial", "reason": "Still accepts arbitrary JSON"}
],
"next_steps": ["Add shared validateContinuationNote predicate", "Add regression tests"],
"files_touched": [
{"path": "todo_claim.ts", "action": "edited", "summary": "Added validateContinuationNote"},
{"path": "todo_continuation.ts", "action": "edited", "summary": "Adopt uses noteValidation.noteFacts"}
],
"key_decisions": [
{"decision": "Typed transfer_grant", "rationale": "Binds source/target/todo/revision/note"}
],
"open_questions": ["Stage B should support agent-agnostic handoff?"]
}
Fields:
- work_summary (max 2000 chars): primary description of what was done and why.
At least one of work_summary or rationale is required.
- approaches_tried (max 20): what was attempted, the outcome (success,
partial, or failed), and why.
- next_steps (max 20): what the target agent should do next.
- files_touched (max 50): files read/edited/created/deleted, with optional
summaries.
- key_decisions (max 20): decisions made and their rationale.
- open_questions (max 20): unresolved issues the target should address.
- Legacy: rationale (max 600 chars) and source_refs (max 20) are still
supported for backward compat.
Record lifecycle and failures¶
The source agent produces a note only on explicit prepare. It saves the non-reconstructable context into the existing Todo note in one revision-guarded update. It replaces that current note; it does not append a history or retain an additional store. The note's marker and execution-fact fingerprint are internal details, not a general-purpose versioned memory API.
Missing, malformed or overwritten notes permit inspection but block adoption: ask the source to prepare a current note. A changed Todo execution fact expires the note on read. Completion, archive and a different claim owner reject the flow. Source prepare replaces stale notes; there is no background expiry worker. Any provider revision change after inspect rejects a fresh adopt, even if the Todo itself did not change. Reinspect and reconsider before using a new operation.
Normal restart reads the note from the existing durable file authority. Reuse
both the operation ID and original expected revision after an uncertain write.
A failed write leaves the previous note intact; committed-but-lost responses
recover through existing receipts. Historical receipt replay never substitutes
for current open status, owner, note and revision readback. Missing artifacts
block adoption without mutation. Do not resume execution unless ok and
current_authority_verified are both true.
There is no enablement toggle: only explicit commands run this workflow. Stop
using them to disable it; replace the note with loopx todo update --note ...
if it is obsolete. Existing Todo/claim commands keep their defaults. Never put
credentials or raw private transcripts in context fields; these fields share
the existing Todo projection visibility, not a private memory ACL.
Validation and bounded next step¶
The focused test runs separate source and target Python CLI processes against a disposable real file authority, plus restart, lost acknowledgment, failed write, missing artifact, stale revision, changed owner, completed Todo, rich context, and legacy backward-compat cases. Existing claim/update suites cover default behavior and rejection of missing, stale or foreign execution proofs.
The shared continuation_note module is the single source of truth for
continuation-note validation. Both the handoff helper (todo_continuation.ts)
and the final claim authority (todo_claim.ts) use validateContinuationNote,
which enforces the typed loopx-explicit-continuation marker, bounded fields,
source session, and current todo_facts. An arbitrary JSON note with matching
hash is rejected because it lacks the typed invariant.
Cross-agent transfer is implemented through a typed transfer_grant that
binds source owner, target owner, Todo ID, exact revision, and current note facts.
Only the handoff flow (handoff prepare/inspect/adopt) can produce this grant;
regular loopx todo claim without a grant still rejects foreign-owner Todos with
claim_owner_mismatch, preserving the default claim behavior. Lease-bearing note
updates remain deferred to their owning boundaries.