Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .agents/plans/stations-providers/GOAL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Current execution objective

Make the shared Dispatch foundation reviewable and advance the first bounded code slice ahead of Hermes: complete DIS-78's project, native issue dependencies, portable Linear handoff and repository contract; then implement and verify DIS-70's operation-bound schema check in a separate draft PR.
Continue from the reviewed DIS-78/DIS-70 stack through the shared provider foundation, evidence-backed Hermes research and the smallest complete native Hermes integration. Implement the remaining shared identity, routing, reservation and observation contracts; prove two coherent Hermes turns and advance recovery, Desktop continuity, independent startup and operator documentation as far as the supported runtime permits.

The broader project is tracked by the [plan](PLAN.md). This current wave does not complete DIS-79–83, enable Hermes execution, build network infrastructure, merge, release or replace installed runtimes.
The [plan](PLAN.md) records the dependency graph. Matt authorized direct Hermes interaction on September 12 using the local `default` profile. Use dedicated synthetic conversations for live proof and isolated automated/fault tests. #Dispatch owns shared source and Git coordination; Hermes is a research collaborator. Network infrastructure, merges, releases, public deployments and installed-runtime replacement retain their separate authority boundaries.

Completion evidence: read-back-verified Linear resources, reviewed documentation, meaningful compatibility tests, full repository checks, scoped draft PRs and an updated handoff that accurately names remaining prerequisites and the next base to consume. Do not mark the Hermes integration gate ready until its separate dependencies are fulfilled.
Completion evidence includes verified migration and Codex compatibility, meaningful provider-routing and receipt tests, native Hermes session/run/history proof, full repository checks, independent review, scoped draft PRs, and read-back-verified Linear status and portable handoff. Do not claim support, durability or Desktop coexistence without the corresponding evidence. Record any concrete upstream limit and the exact remaining work.
16 changes: 12 additions & 4 deletions .agents/plans/stations-providers/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The [Linear project](https://linear.app/outfitter/project/dispatch-stations-and-

## Current assignment

#Dispatch coordinates the shared foundation ahead of the Hermes agent. The current bounded wave completes the project/issue/document setup, repository architecture reconciliation in DIS-78, and the operation-bound compatibility fix in DIS-70. It does not claim to finish every prerequisite for Hermes integration. The portable handoff must continue to show the remaining blockers until their implementation evidence exists.
#Dispatch coordinates implementation through the shared foundation and the Hermes integration. On September 12, Matt expanded the assignment beyond DIS-78/DIS-70 to proceed as far as the evidence supports, including direct Hermes interaction on the local `default` profile. Use dedicated synthetic conversations for live proof; automated tests and destructive fault simulations remain isolated. The portable handoff must show remaining blockers until their implementation evidence exists.

Use the dedicated foundation worktree and preserve other worktree owners. One branch owns each shared registry/admission change. Existing Claude and provider-history projects keep their provider-specific scope. DIS-50 consumes the shared foundation rather than implementing another migration. DIS-24 retains its existing parent and anchors network design.

Expand All @@ -19,7 +19,7 @@ Use the dedicated foundation worktree and preserve other worktree owners. One br
| [DIS-81](https://linear.app/outfitter/issue/DIS-81) | Minimum immutable prepared-request/reservation seam on Codex | DIS-80 |
| [DIS-82](https://linear.app/outfitter/issue/DIS-82) | Minimum shared observation/receipt seam on Codex | DIS-80 |
| [DIS-83](https://linear.app/outfitter/issue/DIS-83) | Independent provider startup/recovery | DIS-80, DIS-82 |
| [DIS-84](https://linear.app/outfitter/issue/DIS-84) | Isolated native Hermes API contract proof | Can start independently; findings inform the shared design |
| [DIS-84](https://linear.app/outfitter/issue/DIS-84) | Native Hermes API proof on the authorized default profile | Can start independently; findings inform the shared design |
| [DIS-85](https://linear.app/outfitter/issue/DIS-85) | Hermes adapter and two coherent local turns | DIS-70, DIS-79, DIS-80, DIS-81, DIS-82, DIS-84 |
| [DIS-86](https://linear.app/outfitter/issue/DIS-86) | Hermes ambiguity/replay/attention recovery | DIS-85 |
| [DIS-87](https://linear.app/outfitter/issue/DIS-87) | Desktop A → Dispatch B → Desktop C coexistence | DIS-86 |
Expand All @@ -35,7 +35,7 @@ This is a dependency graph, not a requirement to work through every row serially

DIS-81/82 extract the minimum request/evidence contract with actual Codex callers and preserve current guarantees. Hermes native creation, replay windows, crash recovery and attention are exercised in DIS-85/86; Claude-specific hook/generation/resolution proof remains in DIS-50/51/52. The first adapter must not wait for a generic recovery framework or a full network read model.

Matt is the native Linear assignee for the active foundation and initial Hermes issues. #Dispatch is the execution owner for DIS-70/78–83; the Hermes Desktop agent is the intended execution owner for DIS-84 onward. No Hermes app user is available in Linear, so this plan and the handoff carry that worker distinction without triggering a different agent integration.
Matt is the native Linear assignee for the active foundation and initial Hermes issues. #Dispatch owns execution and source-control coordination through DIS-88, with bounded research, implementation and review workers. A dedicated Hermes Desktop conversation on the local default profile provides independent native-runtime research. Keep one source owner for each shared migration and one live writer per synthetic Hermes session.

## Current wave gates

Expand All @@ -55,6 +55,14 @@ Keep the change within the control protocol and CLI/MCP transport projection. De

Verify matching/mismatching/malformed hashes, unknown checked method, changed daemon between preflight and execution, zero handler calls on rejection, CLI/MCP error parity and existing compatibility behavior. Run the smallest relevant suites, then `just check`; request local review after green checks. Keep the PR draft and record hosted CI for its exact head.

### 3. DIS-79–88: complete the foundation and native Hermes path

Implement and review the binding migration before enabling provider routing. Extract the minimum prepared-request and observation seams with real Codex callers, then consume the verified Hermes contract in a small native API adapter. Keep independent startup as a focused slice and prove it before claiming Hermes-only availability.

In parallel with shared code, inspect the installed Hermes contract and use the authorized local default profile for synthetic live checks. Record version, profile, session/run IDs, replay scope and canonical history evidence. Alternate Desktop and API writers only after the preceding turn is demonstrably idle. An acceptance response or a closed event stream alone never proves execution.

After two coherent Dispatch turns, exercise replay/conflict, lost acknowledgment, unavailable runtime and attention boundaries, using isolated services for destructive fault simulations. Verify Desktop continuity and operator diagnostics, then run a fresh full-stack review. Continue through correctable findings; stop only at a concrete capability or authority boundary and preserve a precise pickup record.

## Hermes pickup contract

The [Linear handoff](https://linear.app/outfitter/document/hermes-agent-handoff-prerequisites-workflow-and-pickup-gates-5dd9c614285a) is the portable entry point. It must work without another agent's gitignored files.
Expand All @@ -71,7 +79,7 @@ A completed document, a passing transport probe or a green unrelated revision do

## Verification and authority

Use repository tasks and `uv`; new behavior follows TDD. Full gates include lint, format, strict types, unit/examples tests and package contents. Live integration/scenarios are separate opt-in isolated proofs with temporary Dispatch/provider homes and synthetic state. Documentation-only changes do not need a new live provider turn.
Use repository tasks and `uv`; new behavior follows TDD. Full gates include lint, format, strict types, unit/examples tests and package contents. Automated integration/scenarios use temporary Dispatch/provider homes and synthetic state. Matt separately authorized live interaction on Hermes's local default profile for this task; use dedicated synthetic sessions and retain their evidence. Documentation-only changes do not need a new live provider turn.

Each phase is a Graphite branch. A local reviewer must score at least 4/5 with no open P0/P1/P2 before the next phase. Record commands, revision, review and unresolved limits in [RETRO.md](RETRO.md). Keep source-control mutations with the coordinator. PRs remain draft until the applicable current-head checks and readiness authorization are satisfied. Merge, publication, installed-runtime changes and public deployment are separate actions.

Expand Down
15 changes: 15 additions & 0 deletions .agents/plans/stations-providers/RETRO.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,18 @@ DIS-70 adds protocol version 2's reserved checked-execution envelope and receivi
- Fresh targeted implementation review passed at 5/5 with no findings. The reviewer independently reran the 158-test daemon/surface/contract suite, a 49-test focused suite, scoped Ruff, strict mypy on changed source files and diff checks. No provider model call, registry migration, installed-runtime replacement, merge or release was performed.

DIS-79–82 remain unimplemented. DIS-84's isolated native Hermes API investigation may start; DIS-85 adapter integration remains blocked on real foundation and API proof. The Linear handoff must retain that distinction when PR evidence is added.

## September 12, 2026 — provider and binding identity

Matt expanded the assignment through the shared foundation and native Hermes implementation, including direct default-profile research. DIS-79 extends the reviewed `904386c` stack with schema v24. It scopes native sessions, history, topology, events, normalized receipts, runtime state and server requests by provider and binding, while preserving Dispatch lane keys and refs. Default Codex keeps `provider_thread_id == id`; other bindings remain non-executable in this migration slice.

### Verification and review

- Added collision and no-fallback regressions, an exact populated v23 schema fixture, deterministic failed-migration rollback, and transaction recovery tests.
- Migration preserves child foreign keys, durable local row IDs and SQLite sequence high-water marks, including previously deleted rows. An independent probe with the prior sequence at 42 confirmed the next ID is 43 and `PRAGMA foreign_key_check` is clean.
- Review found and resolved provider leaks in read/recovery paths, native server-request lookup collisions, transaction cleanup on identity conflict, default-Codex identity reassignment, sequence reuse, and stale public identity documentation. The full client routing extraction remains DIS-80.
- Final implementer and independent reviewer `just check` runs passed Ruff lint/format, strict mypy, 1,115 tests / 17 live tests deselected, wheel/sdist build and package-content validation. `git diff --check` passed.
- Fresh targeted review passed at 5/5 with zero open P0/P1/P2. The reviewed source/doc diff fingerprint was `2dea8b8df01191053a93212f6c512f1faaba3ee0b2aa4293c68aecef56ca8861`; this ledger entry adds the resulting evidence.
- The migration was tested only on isolated state. It was not run on the installed Dispatch registry. No installed runtime replacement, merge, release or deployment was performed.

DIS-80 may begin from this reviewed slice. The separately researched Hermes transport remains subject to DIS-81/82 reservation/observation and adapter integration gates; its successful native probes do not bypass them.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Observed-only sessions require stable binding-scoped observation identity withou
This proposal extends [ADR-0019](0019-dispatch-local-refs-and-flat-thread-cli.md) to additional providers while preserving its full Codex ID escape hatch:

- Existing and newly created threads in the default Codex binding retain their full native Codex ID as `lanes.id`. Existing refs and child foreign keys remain unchanged. Other providers allocate opaque Dispatch keys in a namespace disjoint from Codex IDs; they never derive refs with Codex-specific hashing.
- In local managed-thread outputs, `id` remains the stable Dispatch key and the existing `lane` compatibility field, wherever present, remains its alias. `ref` and `handle` retain their current meanings. Add `provider`, `binding_id`, and `provider_thread_id` as local identity metadata; do not introduce another `lane_key` output alias or rename existing fields. Native thread continuation may change `provider_thread_id` with positive evidence while `id`, `lane`, and `ref` stay stable.
- In local managed-thread outputs, `id` remains the stable Dispatch key and the existing `lane` compatibility field, wherever present, remains its alias. `ref` and `handle` retain their current meanings. Add `provider`, `binding_id`, and `provider_thread_id` as local identity metadata; do not introduce another `lane_key` output alias or rename existing fields. For other bindings with opaque Dispatch keys, native thread continuation may change `provider_thread_id` with positive evidence while `id`, `lane`, and `ref` stay stable. The default Codex binding preserves `provider_thread_id == id`; reassignment is unsupported.
- Existing managed ref, exact Dispatch key, handle and title resolution keeps its precedence. The full native Codex ID remains accepted, including unmanaged read paths, against the designated default Codex binding. Enabling Hermes does not redirect that fallback or make it ambiguous. Unsupported operations still fail at the authority/capability boundary.
- The first additional-provider slice selects managed threads by existing refs, Dispatch keys or labels. It does not accept a bare Hermes/Claude native ID or invent colon-qualified selector syntax. Native lookup within another binding requires a future explicit binding-scoped authored contract. Additional Codex execution bindings remain disabled until that contract is defined; storage collision tests cover them without implying public execution support.
- A network target's `thread_id` is the managed Dispatch key. Binding IDs and native IDs remain local metadata by default and are not remote authority tokens. Endpoint addresses, credentials and filesystem paths are never encoded into these identifiers.
Expand Down Expand Up @@ -110,7 +110,7 @@ Keep raw history, provider events, absolute paths, credentials and full tool out

### Independent progress and compatibility

The Hermes native API probe can proceed in an isolated profile while the shared contract is reviewed. Its findings constrain supported adapter semantics. Local Hermes integration depends on the complete identity, routing, reservation, evidence and compatibility gates, not on building a cloud gateway or finishing Claude's UI transport.
The Hermes native API probe can proceed while the shared contract is reviewed. Its findings constrain supported adapter semantics. For this implementation Matt authorized dedicated synthetic conversations on the local default profile; automated tests and destructive fault simulations remain isolated. Local Hermes integration depends on the complete identity, routing, reservation, evidence and compatibility gates, not on building a cloud gateway or finishing Claude's UI transport.

[DIS-70](https://linear.app/outfitter/issue/DIS-70) is the first bounded code slice: validate the expected op schema at the receiving execution boundary. A separate preflight connection cannot protect against daemon replacement. An old receiver must reject a checked request it does not understand instead of silently ignoring a new field. Intentional legacy read compatibility needs separate proof; provider-bearing operations never fall back to unchecked execution.

Expand Down
38 changes: 33 additions & 5 deletions docs/usage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,30 @@ Common recovery paths:
operations. In shared mode, verify the configured Unix socket exists and its daemon is
ready; Dispatch will not replace it with a private server.

### Provider identity migration (schemas 24-25)

Schema 24 adds a runtime binding namespace to managed threads and normalized
provider history, topology, receipts, runtime state and server requests. Schema
25 names a managed thread's native conversation identity `provider_thread_id`.
Existing Codex thread IDs, refs and dependent records remain unchanged.
Managed-thread output adds `provider`, `binding_id` and `provider_thread_id`;
`id` and the existing `lane` alias still identify the same stable Dispatch
thread. Native thread IDs are interpreted inside their binding, so identical IDs
in different profiles cannot share evidence.

Use the backed-up `dispatch registry migrate` workflow above before starting the
new binary against an existing registry. The migration rebuilds affected tables
transactionally and verifies foreign keys. Binaries supporting only schema 23
refuse to open the upgraded database. Rolling back the executable therefore also
requires restoring the pre-migration backup with the daemon stopped; it does not
preserve work recorded after that snapshot. Keep the upgraded database for
recovery rather than replacing it without a copy.

This migration provides storage identity. It does not itself enable another
execution provider or grant additional write authority. Existing full Codex IDs
remain valid selectors; another provider's bare native session ID is not a new
public selector syntax.

## Release Publishing

`project.version` in `pyproject.toml` is the release trigger. Maintainers bump
Expand Down Expand Up @@ -316,9 +340,11 @@ uv run dispatch send <dispatch-ref> "Review the README for missing usage steps."
```

Every managed thread gets a dispatch-local `ref`, for example `0k7M4a`. Use refs
for day-to-day commands. The full Codex thread id is still the canonical global
identity and is accepted everywhere. Titles and `@handles` are mutable labels;
they are convenient, but not stable identity.
for day-to-day commands. Its `id` is the stable Dispatch identity. For the
default Codex binding, that remains the full native Codex thread ID; existing
full-ID selectors retain their behavior. Other bindings keep native identity
in `provider_thread_id`. Titles and `@handles` are mutable labels; they are
convenient, but not stable identity.

Example `.dispatch/config.toml`:

Expand Down Expand Up @@ -1340,8 +1366,10 @@ to fork history through that completed turn, inclusive.
The thread-read tool's `roster`, `discover`, and `show` ops expose the same
parent/ancestor/root filters and bounded topology fields as the CLI. Reading or
discovering topology does not create a lane or grant write authority.
Structured MCP outputs that identify a managed thread include the dispatch `ref`, full
Codex id, title/handle, managed/source/status, and cwd when available.
Structured MCP outputs that identify a managed thread include its Dispatch `ref`
and stable `id`, provider/binding/native-session metadata, title/handle,
managed/source/status, and cwd when available. In the default Codex binding,
the stable `id` remains the full native Codex thread ID.

The workspace Codex plugin at [`plugins/dispatch/`](../../plugins/dispatch/) exposes that
MCP server through [`plugins/dispatch/.mcp.json`](../../plugins/dispatch/.mcp.json). The
Expand Down
Loading