outfitter-dispatch 0.2.1__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/.gitignore +2 -0
  2. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/AGENTS.md +9 -2
  3. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/PKG-INFO +41 -11
  4. outfitter_dispatch-0.7.0/README.md +103 -0
  5. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/justfile +9 -0
  6. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/plugins/dispatch/README.md +13 -4
  7. outfitter_dispatch-0.7.0/plugins/dispatch/skills/dispatch/SKILL.md +452 -0
  8. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/plugins/dispatch/skills/dm/SKILL.md +16 -14
  9. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/pyproject.toml +2 -1
  10. outfitter_dispatch-0.7.0/scripts/check_package_contents.py +49 -0
  11. outfitter_dispatch-0.7.0/scripts/check_pypi_smoke.py +163 -0
  12. outfitter_dispatch-0.7.0/scripts/run_scenario.py +355 -0
  13. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/client/client.py +90 -5
  14. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/client/models.py +117 -3
  15. outfitter_dispatch-0.7.0/src/outfitter/dispatch/config.py +112 -0
  16. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/context.py +47 -3
  17. outfitter_dispatch-0.7.0/src/outfitter/dispatch/contracts/derive_cli.py +650 -0
  18. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/derive_mcp.py +15 -9
  19. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/errors.py +9 -1
  20. outfitter_dispatch-0.7.0/src/outfitter/dispatch/contracts/schema.py +26 -0
  21. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/handlers.py +1712 -0
  22. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/history.py +281 -0
  23. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/launch.py +325 -0
  24. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/model_registry.py +177 -0
  25. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/models.py +837 -0
  26. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/core/new_config.py +61 -1
  27. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/ops.py +756 -0
  28. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/packet.py +172 -0
  29. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/core/queue.py +18 -4
  30. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/core/reactor.py +4 -8
  31. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/selectors.py +113 -0
  32. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/staging.py +238 -0
  33. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/sync.py +263 -0
  34. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/core/triggers.py +7 -6
  35. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/turn_settings.py +86 -0
  36. outfitter_dispatch-0.7.0/src/outfitter/dispatch/core/workspace.py +554 -0
  37. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/daemon/host.py +8 -1
  38. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/daemon/supervisor.py +16 -8
  39. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/doctor.py +41 -5
  40. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/registry/models.py +98 -0
  41. outfitter_dispatch-0.7.0/src/outfitter/dispatch/registry/refs.py +29 -0
  42. outfitter_dispatch-0.7.0/src/outfitter/dispatch/registry/store.py +1135 -0
  43. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/surfaces/cli.py +154 -4
  44. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/surfaces/mcp.py +3 -0
  45. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/client/test_client.py +122 -0
  46. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/client/test_events.py +8 -0
  47. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/client/test_models.py +128 -6
  48. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/core/test_examples.py +6 -0
  49. outfitter_dispatch-0.7.0/tests/core/test_handlers.py +1914 -0
  50. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/core/test_new_config.py +40 -0
  51. outfitter_dispatch-0.7.0/tests/core/test_packet.py +219 -0
  52. outfitter_dispatch-0.7.0/tests/core/test_selectors.py +81 -0
  53. outfitter_dispatch-0.7.0/tests/core/test_staging.py +147 -0
  54. outfitter_dispatch-0.7.0/tests/core/test_sync.py +128 -0
  55. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/core/test_triggers.py +18 -0
  56. outfitter_dispatch-0.7.0/tests/core/test_workspace.py +391 -0
  57. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/daemon/test_control.py +1 -1
  58. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/daemon/test_supervisor.py +15 -7
  59. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/fakes.py +129 -7
  60. outfitter_dispatch-0.7.0/tests/fixtures/README.md +21 -0
  61. outfitter_dispatch-0.7.0/tests/fixtures/__init__.py +45 -0
  62. outfitter_dispatch-0.7.0/tests/fixtures/app_server/config_read/current.json +9 -0
  63. outfitter_dispatch-0.7.0/tests/fixtures/app_server/events/turn_failure_unsupported_model.jsonl +4 -0
  64. outfitter_dispatch-0.7.0/tests/fixtures/app_server/model_list/current.json +69 -0
  65. outfitter_dispatch-0.7.0/tests/fixtures/app_server/model_list/legacy_additional_speed_tiers.json +18 -0
  66. outfitter_dispatch-0.7.0/tests/fixtures/app_server/thread_list/basic.json +26 -0
  67. outfitter_dispatch-0.7.0/tests/fixtures/app_server/thread_read/with_turns.json +31 -0
  68. outfitter_dispatch-0.7.0/tests/fixtures/cli_smoke/README.md +10 -0
  69. outfitter_dispatch-0.7.0/tests/fixtures/registry/builders.py +95 -0
  70. outfitter_dispatch-0.7.0/tests/fixtures/test_corpus.py +115 -0
  71. outfitter_dispatch-0.7.0/tests/fixtures/transcripts/long_history_top_and_tail.jsonl +6 -0
  72. outfitter_dispatch-0.7.0/tests/fixtures/transcripts/malformed_lines.jsonl +6 -0
  73. outfitter_dispatch-0.7.0/tests/fixtures/transcripts/minimal.jsonl +3 -0
  74. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/integration/test_app_server.py +30 -1
  75. outfitter_dispatch-0.7.0/tests/registry/test_store.py +578 -0
  76. outfitter_dispatch-0.7.0/tests/scenarios/README.md +25 -0
  77. outfitter_dispatch-0.7.0/tests/scenarios/basic_coordination.toml +21 -0
  78. outfitter_dispatch-0.7.0/tests/surfaces/test_derive_cli.py +656 -0
  79. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/surfaces/test_derive_mcp.py +25 -8
  80. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/surfaces/test_mcp_routing.py +51 -11
  81. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/surfaces/test_parity.py +123 -19
  82. outfitter_dispatch-0.7.0/tests/test_config.py +35 -0
  83. outfitter_dispatch-0.7.0/tests/test_doctor.py +294 -0
  84. outfitter_dispatch-0.7.0/tests/test_scenarios.py +26 -0
  85. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/uv.lock +1 -1
  86. outfitter_dispatch-0.2.1/README.md +0 -73
  87. outfitter_dispatch-0.2.1/plugins/dispatch/skills/dispatch/SKILL.md +0 -252
  88. outfitter_dispatch-0.2.1/src/outfitter/dispatch/config.py +0 -34
  89. outfitter_dispatch-0.2.1/src/outfitter/dispatch/contracts/derive_cli.py +0 -388
  90. outfitter_dispatch-0.2.1/src/outfitter/dispatch/core/handlers.py +0 -641
  91. outfitter_dispatch-0.2.1/src/outfitter/dispatch/core/models.py +0 -331
  92. outfitter_dispatch-0.2.1/src/outfitter/dispatch/core/ops.py +0 -403
  93. outfitter_dispatch-0.2.1/src/outfitter/dispatch/registry/store.py +0 -392
  94. outfitter_dispatch-0.2.1/tests/core/test_handlers.py +0 -662
  95. outfitter_dispatch-0.2.1/tests/registry/test_store.py +0 -89
  96. outfitter_dispatch-0.2.1/tests/surfaces/test_derive_cli.py +0 -234
  97. outfitter_dispatch-0.2.1/tests/test_doctor.py +0 -112
  98. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/plugins/dispatch/.codex-plugin/plugin.json +0 -0
  99. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/plugins/dispatch/.mcp.json +0 -0
  100. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/plugins/dispatch/assets/dispatch.svg +0 -0
  101. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/plugins/dispatch/skills/README.md +0 -0
  102. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/__init__.py +0 -0
  103. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/cli.py +0 -0
  104. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/client/__init__.py +0 -0
  105. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/client/errors.py +0 -0
  106. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/client/events.py +0 -0
  107. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/client/router.py +0 -0
  108. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/client/transport.py +0 -0
  109. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/__init__.py +0 -0
  110. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/examples.py +0 -0
  111. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/execute.py +0 -0
  112. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/op.py +0 -0
  113. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/contracts/registry.py +0 -0
  114. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/core/__init__.py +0 -0
  115. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/core/scheduler.py +0 -0
  116. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/core/trigger_handlers.py +0 -0
  117. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/daemon/__init__.py +0 -0
  118. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/daemon/__main__.py +0 -0
  119. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/daemon/control.py +0 -0
  120. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/daemon/lifecycle.py +0 -0
  121. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/registry/__init__.py +0 -0
  122. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/surfaces/__init__.py +0 -0
  123. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/src/outfitter/dispatch/version.py +0 -0
  124. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/__init__.py +0 -0
  125. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/client/__init__.py +0 -0
  126. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/client/conftest.py +0 -0
  127. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/client/test_router.py +0 -0
  128. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/client/test_transport.py +0 -0
  129. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/conftest.py +0 -0
  130. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/contracts/__init__.py +0 -0
  131. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/contracts/test_contracts.py +0 -0
  132. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/core/__init__.py +0 -0
  133. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/core/test_trigger_handlers.py +0 -0
  134. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/daemon/__init__.py +0 -0
  135. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/daemon/test_lifecycle.py +0 -0
  136. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/integration/__init__.py +0 -0
  137. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/integration/_drive.py +0 -0
  138. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/integration/conftest.py +0 -0
  139. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/integration/test_daemon_e2e.py +0 -0
  140. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/integration/test_lifecycle_e2e.py +0 -0
  141. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/registry/__init__.py +0 -0
  142. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/registry/test_triggers_store.py +0 -0
  143. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/surfaces/__init__.py +0 -0
  144. {outfitter_dispatch-0.2.1 → outfitter_dispatch-0.7.0}/tests/test_smoke.py +0 -0
@@ -27,3 +27,5 @@ dist/
27
27
  # Local Claude settings (per-machine; e.g. bg-isolation opt-out for Graphite stacking)
28
28
  .claude/settings.local.json
29
29
  .claude/worktrees/
30
+ # Staged launch sessions (runtime artifacts, local only).
31
+ .agents/sessions/
@@ -14,6 +14,7 @@ just test # pytest
14
14
  just lint # ruff check
15
15
  just fmt # ruff format
16
16
  just typecheck # mypy --strict
17
+ just scenario -- tests/scenarios/basic_coordination.toml
17
18
  just run -- ... # run the dispatch CLI in-tree
18
19
  uv run dispatch --help
19
20
  uv run dispatchd --help
@@ -33,6 +34,8 @@ dispatch owns one `codex app-server` subprocess (stdio JSONL, shared `~/.codex`)
33
34
  - `docs/usage/` — operator docs for the CLI, MCP, triggers, and plugin setup.
34
35
  - `.agents/plans/v0/` — phased plan (`PLAN.md`) + references (`REFS.md`); tracked.
35
36
  - `spikes/` — App Server probe scripts; seed of the integration suite.
37
+ - `tests/fixtures/` — small named App Server, JSONL, CLI-smoke, and registry fixtures.
38
+ - `tests/scenarios/` — live agent workflow fixtures run intentionally with `just scenario`.
36
39
  - `.agents/notes/` — working notes, session recaps, learnings; **gitignored, local only**.
37
40
  - `skills/` — first-party Codex skills for operating dispatch (`dispatch`) and dispatch-backed direct messages (`dm`).
38
41
  - `plugins/dispatch/` — workspace-local Codex plugin bundle exposing the skills and MCP server.
@@ -43,12 +46,14 @@ Read `docs/development/design.md` and `.agents/plans/v0/PLAN.md` before implemen
43
46
 
44
47
  Use the project language consistently:
45
48
 
46
- - **lane** — a managed Codex thread (own or attached). Not "thread", "agent", or "unit" in user-facing text.
49
+ - **lane** — internal term for a managed Codex thread (own or attached) with registry state.
50
+ - **thread** — user-facing Codex conversation/session. Public CLI/help/docs should prefer "thread" unless the managed-lane authority distinction matters.
51
+ - **ref** — dispatch-local short stable selector for a managed lane. Full Codex thread ids are always accepted; titles and `@handles` are mutable labels.
47
52
  - **op** — one authored operation (input/output/intent/examples/handler). The contract unit. Not "command" or "tool" (those are surface projections of an op).
48
53
  - **surface** — a derived rendering of the op registry: CLI, MCP, remote. Surfaces are projected, never hand-written per-op.
49
54
  - **trigger** — an automated when→action→lane binding (time or event). Not "rule" (collides with agent rules), "automation", or "job".
50
55
  - **daemon** (`dispatchd`) — the long-lived host owning the app-server and core; the CLI is a thin client to it.
51
- - **register/registry** — the durable store of lanes and triggers.
56
+ - **register/registry** — the durable store of lanes, refs, sync state, and triggers.
52
57
 
53
58
  ## Core rules (summary; full detail in `.claude/rules/`)
54
59
 
@@ -62,6 +67,8 @@ Use the project language consistently:
62
67
  - **App Server access only via `client/`.** Never spawn or speak to `codex app-server` outside the client layer. See [client rules](.claude/rules/client.md).
63
68
  - **Async core, sync CLI.** The daemon is asyncio end-to-end; the CLI is a thin sync client over the control socket. No blocking calls in the loop (use `aiosqlite`, asyncio subprocess, `run_in_executor`). See [python-conventions](.claude/rules/python-conventions.md).
64
69
  - **Never touch the user's live state in tests.** Integration tests use a real ephemeral app-server with an isolated `CODEX_HOME` and `ephemeral:true` lanes.
70
+ - **Fixtures should be exercised.** Add checked-in cases under `tests/fixtures/` only when a test loads them; prefer Python builders over binary SQLite fixtures.
71
+ - **Live scenarios are opt-in.** Scenario fixtures start real isolated Dispatch/Codex daemons and make model calls; keep them small, synthetic, low-effort, and outside `just check`.
65
72
 
66
73
  ## Source control
67
74
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: outfitter-dispatch
3
- Version: 0.2.1
3
+ Version: 0.7.0
4
4
  Summary: Local control plane for orchestrating Codex agent lanes over the Codex App Server.
5
5
  Project-URL: Homepage, https://github.com/outfitter-dev/dispatch
6
6
  Project-URL: Repository, https://github.com/outfitter-dev/dispatch
@@ -32,6 +32,8 @@ uv tool install outfitter-dispatch
32
32
  dispatch --help
33
33
  dispatchd --help
34
34
  dispatch doctor
35
+ dispatch up --json
36
+ dispatch down --json
35
37
  ```
36
38
 
37
39
  From a source checkout:
@@ -40,34 +42,62 @@ From a source checkout:
40
42
  uv sync
41
43
  uv run dispatch --help
42
44
  uv run dispatch doctor --no-app-server
43
- uv run dispatch up
45
+ uv run dispatch models --no-refresh
46
+ uv run dispatch up --json
44
47
  uv run dispatch daemon status
45
48
  ```
46
49
 
47
- Open an owned lane, send it work, and inspect the daemon:
50
+ Create an owned managed thread, send it work, and inspect the daemon:
48
51
 
49
52
  ```bash
50
53
  uv run dispatch new \
51
54
  --name docs \
52
55
  --cwd /path/to/dispatch \
56
+ --goal "Finish the docs review." \
53
57
  --text "Please summarize the current stack state."
54
- uv run dispatch lane tail "@[dispatch] docs" --limit 20
55
- uv run dispatch goal set "@[dispatch] docs" "Finish the docs review."
58
+ uv run dispatch list
59
+ uv run dispatch get <dispatch-ref>
60
+ uv run dispatch tail <dispatch-ref> --limit 20
56
61
  uv run dispatch daemon log --limit 10
57
- uv run dispatch down
62
+ uv run dispatch down --json
58
63
  ```
59
64
 
60
- Use owned lanes for writes. Existing desktop Codex threads can be attached, but v0 treats
61
- attached lanes as observe-only: mutating commands such as `send`, `stop`, `lane archive`,
62
- `goal set`, `goal clear`, `lane fork`, `lane rollback`, and `lane compact` are blocked by
63
- ADR-0005.
65
+ For durable or parallel launches, point `new` at a launch packet directory and
66
+ preview it without side effects: `dispatch new --name lane-a --cwd /repo --packet
67
+ ./packet --dry-run --json`, then `--stage all` to write durable session files under
68
+ `.agents/sessions/<ref>/`. See [`docs/usage/README.md`](docs/usage/README.md) for
69
+ packet layout, file/stdin inputs, and staging.
70
+
71
+ Use owned managed threads for turn-writing work. Existing desktop Codex threads can be attached as
72
+ managed threads, but ADR-0005 blocks turn-writing and history-mutating commands such
73
+ as `send`, `stop`, `goal set`, and `goal clear` on attached lanes by default. A
74
+ local operator can explicitly opt in with `[policy] allow_attached_writes = true`
75
+ in `~/.dispatch/config.toml`; `list --json` and `get --json` expose
76
+ `writable`, `capabilities`, and `write_locked_reason` so scripts can tell which
77
+ lanes can receive writes. Every managed thread has a dispatch-local `ref`; full
78
+ Codex thread UUIDs remain accepted everywhere.
79
+ Titles and `@handles` are mutable convenience labels, not stable identity. Metadata
80
+ lifecycle actions (`rename`, `archive`, `restore`) can target managed refs or raw
81
+ unmanaged Codex thread ids, and `search` can span both. Attach is metadata-only by
82
+ default; use `dispatch sync <selector>` when you want dispatch to refresh its local
83
+ indexed view of an attached thread.
84
+
85
+ `new` reports whether the first message was accepted by the App Server, not whether
86
+ assistant work completed. Use `get` to inspect the latest turn state and persisted
87
+ App Server errors, or `watch` for a bounded live event sample. Slash commands in
88
+ `--text` are plain text; use `--goal` when creating a native App Server goal.
89
+ Use `dispatch models` before pinning model or service-tier presets; Dispatch
90
+ resolves aliases such as `fast` from the live App Server model catalog and keeps
91
+ omitted model/tier values on Codex defaults.
64
92
 
65
93
  For the operator guide, CLI/MCP examples, triggers, and plugin setup, start at
66
94
  [`docs/usage/README.md`](docs/usage/README.md).
67
95
 
68
96
  Start troubleshooting with `dispatch doctor`. It checks PATH visibility, the Codex CLI
69
97
  and auth footprint, daemon socket/pidfile state, registry schema/integrity, packaged
70
- skills/plugin assets, and a low-risk Codex App Server initialize smoke.
98
+ skills/plugin assets, and a low-risk Codex App Server initialize smoke. If doctor reports
99
+ an old registry schema, stop the daemon and run `dispatch registry migrate` before
100
+ starting it again.
71
101
 
72
102
  ## Agent And Plugin Support
73
103
 
@@ -0,0 +1,103 @@
1
+ # dispatch
2
+
3
+ Local control plane for orchestrating Codex agent lanes over the Codex App Server.
4
+ One authored contract per operation, projected to CLI + MCP (+ remote later) with no drift.
5
+
6
+ ## Quick Start
7
+
8
+ Install the CLI from PyPI:
9
+
10
+ ```bash
11
+ uv tool install outfitter-dispatch
12
+ dispatch --help
13
+ dispatchd --help
14
+ dispatch doctor
15
+ dispatch up --json
16
+ dispatch down --json
17
+ ```
18
+
19
+ From a source checkout:
20
+
21
+ ```bash
22
+ uv sync
23
+ uv run dispatch --help
24
+ uv run dispatch doctor --no-app-server
25
+ uv run dispatch models --no-refresh
26
+ uv run dispatch up --json
27
+ uv run dispatch daemon status
28
+ ```
29
+
30
+ Create an owned managed thread, send it work, and inspect the daemon:
31
+
32
+ ```bash
33
+ uv run dispatch new \
34
+ --name docs \
35
+ --cwd /path/to/dispatch \
36
+ --goal "Finish the docs review." \
37
+ --text "Please summarize the current stack state."
38
+ uv run dispatch list
39
+ uv run dispatch get <dispatch-ref>
40
+ uv run dispatch tail <dispatch-ref> --limit 20
41
+ uv run dispatch daemon log --limit 10
42
+ uv run dispatch down --json
43
+ ```
44
+
45
+ For durable or parallel launches, point `new` at a launch packet directory and
46
+ preview it without side effects: `dispatch new --name lane-a --cwd /repo --packet
47
+ ./packet --dry-run --json`, then `--stage all` to write durable session files under
48
+ `.agents/sessions/<ref>/`. See [`docs/usage/README.md`](docs/usage/README.md) for
49
+ packet layout, file/stdin inputs, and staging.
50
+
51
+ Use owned managed threads for turn-writing work. Existing desktop Codex threads can be attached as
52
+ managed threads, but ADR-0005 blocks turn-writing and history-mutating commands such
53
+ as `send`, `stop`, `goal set`, and `goal clear` on attached lanes by default. A
54
+ local operator can explicitly opt in with `[policy] allow_attached_writes = true`
55
+ in `~/.dispatch/config.toml`; `list --json` and `get --json` expose
56
+ `writable`, `capabilities`, and `write_locked_reason` so scripts can tell which
57
+ lanes can receive writes. Every managed thread has a dispatch-local `ref`; full
58
+ Codex thread UUIDs remain accepted everywhere.
59
+ Titles and `@handles` are mutable convenience labels, not stable identity. Metadata
60
+ lifecycle actions (`rename`, `archive`, `restore`) can target managed refs or raw
61
+ unmanaged Codex thread ids, and `search` can span both. Attach is metadata-only by
62
+ default; use `dispatch sync <selector>` when you want dispatch to refresh its local
63
+ indexed view of an attached thread.
64
+
65
+ `new` reports whether the first message was accepted by the App Server, not whether
66
+ assistant work completed. Use `get` to inspect the latest turn state and persisted
67
+ App Server errors, or `watch` for a bounded live event sample. Slash commands in
68
+ `--text` are plain text; use `--goal` when creating a native App Server goal.
69
+ Use `dispatch models` before pinning model or service-tier presets; Dispatch
70
+ resolves aliases such as `fast` from the live App Server model catalog and keeps
71
+ omitted model/tier values on Codex defaults.
72
+
73
+ For the operator guide, CLI/MCP examples, triggers, and plugin setup, start at
74
+ [`docs/usage/README.md`](docs/usage/README.md).
75
+
76
+ Start troubleshooting with `dispatch doctor`. It checks PATH visibility, the Codex CLI
77
+ and auth footprint, daemon socket/pidfile state, registry schema/integrity, packaged
78
+ skills/plugin assets, and a low-risk Codex App Server initialize smoke. If doctor reports
79
+ an old registry schema, stop the daemon and run `dispatch registry migrate` before
80
+ starting it again.
81
+
82
+ ## Agent And Plugin Support
83
+
84
+ This repo ships first-party skills in [`skills/`](skills/):
85
+
86
+ - [`skills/dispatch/SKILL.md`](skills/dispatch/SKILL.md) teaches agents how to operate
87
+ dispatch safely.
88
+ - [`skills/dm/SKILL.md`](skills/dm/SKILL.md) is the dispatch-backed "dispatch message"
89
+ workflow for short inter-lane messages.
90
+
91
+ The workspace-local Codex plugin bundle lives at [`plugins/dispatch/`](plugins/dispatch/),
92
+ with a marketplace entry in [`.agents/plugins/marketplace.json`](.agents/plugins/marketplace.json).
93
+ Restart Codex if the plugin does not appear immediately.
94
+
95
+ ## Project Docs
96
+
97
+ - [`docs/development/design.md`](docs/development/design.md) - architecture and design notes.
98
+ - [`docs/adrs/`](docs/adrs/) - accepted architecture decisions.
99
+ - [`docs/research/`](docs/research/) - verified Codex App Server findings.
100
+ - [`.agents/plans/v0/RETRO.md`](.agents/plans/v0/RETRO.md) - v0 execution ledger and
101
+ verification record.
102
+
103
+ For contributors, [`AGENTS.md`](AGENTS.md) is the canonical fieldguide.
@@ -6,6 +6,7 @@ check:
6
6
  uv run ruff format --check .
7
7
  uv run mypy src tests
8
8
  uv run pytest
9
+ rm -f dist/*.whl dist/*.tar.gz
9
10
  uv build
10
11
  uv run python scripts/check_package_contents.py
11
12
 
@@ -17,6 +18,14 @@ test *args:
17
18
  test-int *args:
18
19
  uv run pytest -m integration {{args}}
19
20
 
21
+ # Smoke-test the published PyPI package from a clean temporary DISPATCH_HOME.
22
+ pypi-smoke *args:
23
+ uv run python scripts/check_pypi_smoke.py {{args}}
24
+
25
+ # Run a live agent scenario against an isolated DISPATCH_HOME/CODEX_HOME.
26
+ scenario *args:
27
+ uv run python scripts/run_scenario.py {{args}}
28
+
20
29
  # Lint with ruff.
21
30
  lint:
22
31
  uv run ruff check .
@@ -8,16 +8,25 @@ This workspace-local plugin exposes:
8
8
  `dispatch mcp`.
9
9
 
10
10
  The MCP server and skills expose the same derived operation registry as the CLI,
11
- including lane creation/messaging, bounded tails, native goals, history controls,
12
- triggers, schemas, and daemon status/log reads.
11
+ including managed-thread creation/messaging, dispatch refs, persisted `tail`,
12
+ bounded live `watch`, native goals, triggers, schemas, model catalog reads, and
13
+ daemon status/log reads.
14
+ `new --goal` creates native App Server goal state; `/goal ...` in message text is
15
+ plain text and should not be used as a goal substitute. `new` also accepts launch
16
+ packets (`--packet DIR`), file/stdin inputs (`--goal-file`/`--input-file`/
17
+ `--output-schema-file`, `-` for stdin), a mutation-free `--dry-run`, and durable
18
+ staging (`--stage all|<parts>` → `.agents/sessions/<ref>/`).
19
+ Use `dispatch models` or the MCP daemon-read `models` op before pinning explicit
20
+ model/service-tier presets.
13
21
 
14
22
  Run `dispatch doctor` after installing or upgrading dispatch. It verifies the CLI
15
23
  entrypoints, Codex CLI/auth footprint, daemon socket/pidfile state, registry
16
24
  schema/integrity, packaged skills/plugin assets, and a low-risk App Server
17
25
  initialize smoke. Use `dispatch doctor --no-app-server` when you only want local
18
- install checks.
26
+ install checks. If doctor reports an old registry schema, run `dispatch down`,
27
+ `dispatch registry migrate`, then `dispatch up`.
19
28
 
20
- Run `dispatch up` before MCP tool calls that need the daemon. `dispatch mcp`
29
+ Run `dispatch up --json` before MCP tool calls that need the daemon. `dispatch mcp`
21
30
  serves the derived tools over stdio; the daemon remains the executor.
22
31
 
23
32
  `skills` is a symlink to the repo-root [`../../skills`](../../skills) tree so the plugin