outfitter-dispatch 0.2.0__tar.gz → 0.5.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 (109) hide show
  1. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/AGENTS.md +4 -2
  2. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/PKG-INFO +31 -11
  3. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/README.md +30 -10
  4. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/justfile +1 -0
  5. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/plugins/dispatch/README.md +10 -4
  6. outfitter_dispatch-0.5.0/plugins/dispatch/skills/dispatch/SKILL.md +345 -0
  7. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/plugins/dispatch/skills/dm/SKILL.md +16 -14
  8. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/pyproject.toml +1 -1
  9. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/client/client.py +95 -7
  10. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/client/models.py +117 -3
  11. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/client/transport.py +12 -1
  12. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/context.py +44 -2
  13. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/derive_cli.py +212 -77
  14. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/derive_mcp.py +13 -9
  15. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/errors.py +1 -1
  16. outfitter_dispatch-0.5.0/src/outfitter/dispatch/contracts/schema.py +26 -0
  17. outfitter_dispatch-0.5.0/src/outfitter/dispatch/core/handlers.py +1412 -0
  18. outfitter_dispatch-0.5.0/src/outfitter/dispatch/core/model_registry.py +177 -0
  19. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/models.py +249 -30
  20. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/ops.py +185 -25
  21. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/reactor.py +4 -8
  22. outfitter_dispatch-0.5.0/src/outfitter/dispatch/core/selectors.py +113 -0
  23. outfitter_dispatch-0.5.0/src/outfitter/dispatch/core/sync.py +263 -0
  24. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/triggers.py +7 -6
  25. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/daemon/supervisor.py +16 -8
  26. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/doctor.py +40 -5
  27. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/registry/models.py +75 -0
  28. outfitter_dispatch-0.5.0/src/outfitter/dispatch/registry/refs.py +29 -0
  29. outfitter_dispatch-0.5.0/src/outfitter/dispatch/registry/store.py +991 -0
  30. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/surfaces/cli.py +154 -4
  31. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/surfaces/mcp.py +3 -0
  32. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/client/test_client.py +160 -1
  33. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/client/test_events.py +8 -0
  34. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/client/test_models.py +137 -6
  35. outfitter_dispatch-0.5.0/tests/client/test_transport.py +63 -0
  36. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/core/test_examples.py +4 -0
  37. outfitter_dispatch-0.5.0/tests/core/test_handlers.py +1244 -0
  38. outfitter_dispatch-0.5.0/tests/core/test_selectors.py +81 -0
  39. outfitter_dispatch-0.5.0/tests/core/test_sync.py +128 -0
  40. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/core/test_triggers.py +18 -0
  41. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/daemon/test_control.py +1 -1
  42. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/daemon/test_supervisor.py +15 -7
  43. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/fakes.py +124 -6
  44. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/integration/test_app_server.py +30 -1
  45. outfitter_dispatch-0.5.0/tests/registry/test_store.py +445 -0
  46. outfitter_dispatch-0.5.0/tests/surfaces/test_derive_cli.py +407 -0
  47. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/surfaces/test_derive_mcp.py +25 -8
  48. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/surfaces/test_mcp_routing.py +51 -11
  49. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/surfaces/test_parity.py +108 -19
  50. outfitter_dispatch-0.5.0/tests/test_doctor.py +294 -0
  51. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/uv.lock +1 -1
  52. outfitter_dispatch-0.2.0/plugins/dispatch/skills/dispatch/SKILL.md +0 -250
  53. outfitter_dispatch-0.2.0/src/outfitter/dispatch/core/handlers.py +0 -631
  54. outfitter_dispatch-0.2.0/src/outfitter/dispatch/registry/store.py +0 -392
  55. outfitter_dispatch-0.2.0/tests/core/test_handlers.py +0 -641
  56. outfitter_dispatch-0.2.0/tests/registry/test_store.py +0 -89
  57. outfitter_dispatch-0.2.0/tests/surfaces/test_derive_cli.py +0 -214
  58. outfitter_dispatch-0.2.0/tests/test_doctor.py +0 -112
  59. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/.gitignore +0 -0
  60. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/plugins/dispatch/.codex-plugin/plugin.json +0 -0
  61. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/plugins/dispatch/.mcp.json +0 -0
  62. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/plugins/dispatch/assets/dispatch.svg +0 -0
  63. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/plugins/dispatch/skills/README.md +0 -0
  64. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/__init__.py +0 -0
  65. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/cli.py +0 -0
  66. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/client/__init__.py +0 -0
  67. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/client/errors.py +0 -0
  68. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/client/events.py +0 -0
  69. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/client/router.py +0 -0
  70. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/config.py +0 -0
  71. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/__init__.py +0 -0
  72. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/examples.py +0 -0
  73. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/execute.py +0 -0
  74. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/op.py +0 -0
  75. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/contracts/registry.py +0 -0
  76. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/__init__.py +0 -0
  77. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/new_config.py +0 -0
  78. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/queue.py +0 -0
  79. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/scheduler.py +0 -0
  80. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/core/trigger_handlers.py +0 -0
  81. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/daemon/__init__.py +0 -0
  82. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/daemon/__main__.py +0 -0
  83. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/daemon/control.py +0 -0
  84. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/daemon/host.py +0 -0
  85. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/daemon/lifecycle.py +0 -0
  86. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/registry/__init__.py +0 -0
  87. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/surfaces/__init__.py +0 -0
  88. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/src/outfitter/dispatch/version.py +0 -0
  89. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/__init__.py +0 -0
  90. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/client/__init__.py +0 -0
  91. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/client/conftest.py +0 -0
  92. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/client/test_router.py +0 -0
  93. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/conftest.py +0 -0
  94. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/contracts/__init__.py +0 -0
  95. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/contracts/test_contracts.py +0 -0
  96. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/core/__init__.py +0 -0
  97. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/core/test_new_config.py +0 -0
  98. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/core/test_trigger_handlers.py +0 -0
  99. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/daemon/__init__.py +0 -0
  100. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/daemon/test_lifecycle.py +0 -0
  101. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/integration/__init__.py +0 -0
  102. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/integration/_drive.py +0 -0
  103. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/integration/conftest.py +0 -0
  104. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/integration/test_daemon_e2e.py +0 -0
  105. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/integration/test_lifecycle_e2e.py +0 -0
  106. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/registry/__init__.py +0 -0
  107. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/registry/test_triggers_store.py +0 -0
  108. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/surfaces/__init__.py +0 -0
  109. {outfitter_dispatch-0.2.0 → outfitter_dispatch-0.5.0}/tests/test_smoke.py +0 -0
@@ -43,12 +43,14 @@ Read `docs/development/design.md` and `.agents/plans/v0/PLAN.md` before implemen
43
43
 
44
44
  Use the project language consistently:
45
45
 
46
- - **lane** — a managed Codex thread (own or attached). Not "thread", "agent", or "unit" in user-facing text.
46
+ - **lane** — internal term for a managed Codex thread (own or attached) with registry state.
47
+ - **thread** — user-facing Codex conversation/session. Public CLI/help/docs should prefer "thread" unless the managed-lane authority distinction matters.
48
+ - **ref** — dispatch-local short stable selector for a managed lane. Full Codex thread ids are always accepted; titles and `@handles` are mutable labels.
47
49
  - **op** — one authored operation (input/output/intent/examples/handler). The contract unit. Not "command" or "tool" (those are surface projections of an op).
48
50
  - **surface** — a derived rendering of the op registry: CLI, MCP, remote. Surfaces are projected, never hand-written per-op.
49
51
  - **trigger** — an automated when→action→lane binding (time or event). Not "rule" (collides with agent rules), "automation", or "job".
50
52
  - **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.
53
+ - **register/registry** — the durable store of lanes, refs, sync state, and triggers.
52
54
 
53
55
  ## Core rules (summary; full detail in `.claude/rules/`)
54
56
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: outfitter-dispatch
3
- Version: 0.2.0
3
+ Version: 0.5.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,52 @@ 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
+ Use owned managed threads for turn-writing work. Existing desktop Codex threads can be attached as
66
+ managed threads, but ADR-0005 still blocks turn-writing and history-mutating commands such
67
+ as `send`, `stop`, `goal set`, and `goal clear` on attached lanes. Every managed
68
+ thread has a dispatch-local `ref`; full Codex thread UUIDs remain accepted everywhere.
69
+ Titles and `@handles` are mutable convenience labels, not stable identity. Metadata
70
+ lifecycle actions (`rename`, `archive`, `restore`) can target managed refs or raw
71
+ unmanaged Codex thread ids, and `search` can span both. Attach is metadata-only by
72
+ default; use `dispatch sync <selector>` when you want dispatch to refresh its local
73
+ indexed view of an attached thread.
74
+
75
+ `new` reports whether the first message was accepted by the App Server, not whether
76
+ assistant work completed. Use `get` to inspect the latest turn state and persisted
77
+ App Server errors, or `watch` for a bounded live event sample. Slash commands in
78
+ `--text` are plain text; use `--goal` when creating a native App Server goal.
79
+ Use `dispatch models` before pinning model or service-tier presets; Dispatch
80
+ resolves aliases such as `fast` from the live App Server model catalog and keeps
81
+ omitted model/tier values on Codex defaults.
64
82
 
65
83
  For the operator guide, CLI/MCP examples, triggers, and plugin setup, start at
66
84
  [`docs/usage/README.md`](docs/usage/README.md).
67
85
 
68
86
  Start troubleshooting with `dispatch doctor`. It checks PATH visibility, the Codex CLI
69
87
  and auth footprint, daemon socket/pidfile state, registry schema/integrity, packaged
70
- skills/plugin assets, and a low-risk Codex App Server initialize smoke.
88
+ skills/plugin assets, and a low-risk Codex App Server initialize smoke. If doctor reports
89
+ an old registry schema, stop the daemon and run `dispatch registry migrate` before
90
+ starting it again.
71
91
 
72
92
  ## Agent And Plugin Support
73
93
 
@@ -12,6 +12,8 @@ uv tool install outfitter-dispatch
12
12
  dispatch --help
13
13
  dispatchd --help
14
14
  dispatch doctor
15
+ dispatch up --json
16
+ dispatch down --json
15
17
  ```
16
18
 
17
19
  From a source checkout:
@@ -20,34 +22,52 @@ From a source checkout:
20
22
  uv sync
21
23
  uv run dispatch --help
22
24
  uv run dispatch doctor --no-app-server
23
- uv run dispatch up
25
+ uv run dispatch models --no-refresh
26
+ uv run dispatch up --json
24
27
  uv run dispatch daemon status
25
28
  ```
26
29
 
27
- Open an owned lane, send it work, and inspect the daemon:
30
+ Create an owned managed thread, send it work, and inspect the daemon:
28
31
 
29
32
  ```bash
30
33
  uv run dispatch new \
31
34
  --name docs \
32
35
  --cwd /path/to/dispatch \
36
+ --goal "Finish the docs review." \
33
37
  --text "Please summarize the current stack state."
34
- uv run dispatch lane tail "@[dispatch] docs" --limit 20
35
- uv run dispatch goal set "@[dispatch] docs" "Finish the docs review."
38
+ uv run dispatch list
39
+ uv run dispatch get <dispatch-ref>
40
+ uv run dispatch tail <dispatch-ref> --limit 20
36
41
  uv run dispatch daemon log --limit 10
37
- uv run dispatch down
42
+ uv run dispatch down --json
38
43
  ```
39
44
 
40
- Use owned lanes for writes. Existing desktop Codex threads can be attached, but v0 treats
41
- attached lanes as observe-only: mutating commands such as `send`, `stop`, `lane archive`,
42
- `goal set`, `goal clear`, `lane fork`, `lane rollback`, and `lane compact` are blocked by
43
- ADR-0005.
45
+ Use owned managed threads for turn-writing work. Existing desktop Codex threads can be attached as
46
+ managed threads, but ADR-0005 still blocks turn-writing and history-mutating commands such
47
+ as `send`, `stop`, `goal set`, and `goal clear` on attached lanes. Every managed
48
+ thread has a dispatch-local `ref`; full Codex thread UUIDs remain accepted everywhere.
49
+ Titles and `@handles` are mutable convenience labels, not stable identity. Metadata
50
+ lifecycle actions (`rename`, `archive`, `restore`) can target managed refs or raw
51
+ unmanaged Codex thread ids, and `search` can span both. Attach is metadata-only by
52
+ default; use `dispatch sync <selector>` when you want dispatch to refresh its local
53
+ indexed view of an attached thread.
54
+
55
+ `new` reports whether the first message was accepted by the App Server, not whether
56
+ assistant work completed. Use `get` to inspect the latest turn state and persisted
57
+ App Server errors, or `watch` for a bounded live event sample. Slash commands in
58
+ `--text` are plain text; use `--goal` when creating a native App Server goal.
59
+ Use `dispatch models` before pinning model or service-tier presets; Dispatch
60
+ resolves aliases such as `fast` from the live App Server model catalog and keeps
61
+ omitted model/tier values on Codex defaults.
44
62
 
45
63
  For the operator guide, CLI/MCP examples, triggers, and plugin setup, start at
46
64
  [`docs/usage/README.md`](docs/usage/README.md).
47
65
 
48
66
  Start troubleshooting with `dispatch doctor`. It checks PATH visibility, the Codex CLI
49
67
  and auth footprint, daemon socket/pidfile state, registry schema/integrity, packaged
50
- skills/plugin assets, and a low-risk Codex App Server initialize smoke.
68
+ skills/plugin assets, and a low-risk Codex App Server initialize smoke. If doctor reports
69
+ an old registry schema, stop the daemon and run `dispatch registry migrate` before
70
+ starting it again.
51
71
 
52
72
  ## Agent And Plugin Support
53
73
 
@@ -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
 
@@ -8,16 +8,22 @@ 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.
16
+ Use `dispatch models` or the MCP daemon-read `models` op before pinning explicit
17
+ model/service-tier presets.
13
18
 
14
19
  Run `dispatch doctor` after installing or upgrading dispatch. It verifies the CLI
15
20
  entrypoints, Codex CLI/auth footprint, daemon socket/pidfile state, registry
16
21
  schema/integrity, packaged skills/plugin assets, and a low-risk App Server
17
22
  initialize smoke. Use `dispatch doctor --no-app-server` when you only want local
18
- install checks.
23
+ install checks. If doctor reports an old registry schema, run `dispatch down`,
24
+ `dispatch registry migrate`, then `dispatch up`.
19
25
 
20
- Run `dispatch up` before MCP tool calls that need the daemon. `dispatch mcp`
26
+ Run `dispatch up --json` before MCP tool calls that need the daemon. `dispatch mcp`
21
27
  serves the derived tools over stdio; the daemon remains the executor.
22
28
 
23
29
  `skills` is a symlink to the repo-root [`../../skills`](../../skills) tree so the plugin
@@ -0,0 +1,345 @@
1
+ ---
2
+ name: dispatch
3
+ description: Use when operating dispatch, creating or attaching Codex lanes, sending/steering/context-injecting/stopping through dispatch, managing triggers, checking daemon status/logs, or configuring the dispatch MCP/plugin surface. Not for changing dispatch source code; use AGENTS.md for implementation work.
4
+ metadata:
5
+ short-description: Operate the dispatch control plane
6
+ ---
7
+
8
+ # dispatch
9
+
10
+ Use `$dispatch` to operate the local dispatch control plane. dispatch owns one
11
+ `codex app-server` through a daemon and exposes one authored op registry through
12
+ CLI and MCP surfaces.
13
+
14
+ For source changes, read the repo-root `AGENTS.md` instead. This skill is for
15
+ using the tool.
16
+
17
+ ## Command Surface
18
+
19
+ When you are in this repo, prefer the in-tree command:
20
+
21
+ ```bash
22
+ uv run dispatch --help
23
+ ```
24
+
25
+ The current canonical operator grammar is:
26
+
27
+ - health: `doctor`
28
+ - daemon process: `up`, `down`
29
+ - daemon reads: `daemon status`, `daemon log`
30
+ - registry recovery: `registry migrate`
31
+ - model catalog: `models`
32
+ - thread lifecycle/read/search: `new`, `attach`, `list`, `list --unmanaged`,
33
+ `get`, `sync`, `tail`, `watch`, `search`
34
+ - thread actions: `rename`, `archive`, `restore`
35
+ - message verbs: `send`, `stop`
36
+ - goals: `goal status`, `goal set`, `goal clear`
37
+ - triggers: `trigger add`, `trigger list`, `trigger rm`, `trigger pause`,
38
+ `trigger resume`
39
+ - schemas/MCP: `schema <command>`, `mcp`
40
+
41
+ Successful CLI output is JSON-shaped. Use `--json` in scripts when you want the
42
+ machine-output contract to be explicit.
43
+
44
+ ## Start Or Inspect The Daemon
45
+
46
+ ```bash
47
+ uv run dispatch doctor --no-app-server
48
+ uv run dispatch up --json
49
+ uv run dispatch daemon status
50
+ uv run dispatch daemon log --limit 10
51
+ ```
52
+
53
+ Use `uv run dispatch doctor` before relying on live thread operations in a new or
54
+ untrusted environment. It checks PATH visibility, Codex CLI/auth footprint,
55
+ daemon socket/pidfile state, registry schema/integrity, packaged skills/plugin
56
+ assets, and a low-risk Codex App Server initialize smoke. Use `--no-app-server`
57
+ when you only need local install/runtime diagnostics.
58
+
59
+ If doctor reports an old registry schema, run `uv run dispatch down`, then
60
+ `uv run dispatch registry migrate`, then `uv run dispatch up --json`.
61
+
62
+ Stop only when it is clearly your daemon/session to stop:
63
+
64
+ ```bash
65
+ uv run dispatch down
66
+ ```
67
+
68
+ Runtime state defaults to `~/.dispatch`. Use `DISPATCH_HOME` for isolation when
69
+ testing. Do not point tests at the user's live `~/.codex`; the repo integration
70
+ suite uses an isolated `CODEX_HOME`.
71
+
72
+ ## Thread Selectors And Lane Rules
73
+
74
+ Every managed thread has a stored dispatch-local `ref`. Prefer refs for command
75
+ arguments. The full Codex thread id is always accepted. Titles and `@handles`
76
+ are mutable convenience labels; use them only when a unique human label is more
77
+ useful than a ref.
78
+
79
+ Owned lanes are created by dispatch and are writable. Prefer `new` for a
80
+ configured managed thread; it applies `.dispatch/config.toml`, presets, name
81
+ prefixes, and can send an initial turn:
82
+
83
+ ```bash
84
+ uv run dispatch new --name my-lane --cwd /path/to/project --text "Do the bounded thing."
85
+ uv run dispatch new --name my-lane --goal "Loop until green." --text "Start with tests."
86
+ uv run dispatch new --name my-lane --preset reviewer --no-send
87
+ ```
88
+
89
+ Use `--goal` for a native App Server goal before the initial turn. Do not put
90
+ `/goal ...` in `--text`; dispatch treats slash commands as plain text and rejects
91
+ that shape so agents do not create a thread that only looks goal-driven.
92
+
93
+ `new` returns `message_accepted`, not proof of assistant completion. After launch,
94
+ use `get` to check `latest_turn`, `tail` for persisted history, or `watch` for a
95
+ bounded live sample.
96
+
97
+ Before choosing explicit `--model`, `--model-provider`, or `--service-tier`
98
+ values, ask dispatch for the live catalog:
99
+
100
+ ```bash
101
+ uv run dispatch models
102
+ uv run dispatch models --no-refresh
103
+ uv run dispatch schema models
104
+ ```
105
+
106
+ Omit model/tier values when Codex defaults are acceptable. If a preset uses a
107
+ user-facing tier such as `fast`, Dispatch resolves it through `model/list`
108
+ service tiers before starting the thread. Do not guess current model ids from
109
+ memory; use the catalog output and its `aliases` field.
110
+
111
+ Attached lanes are existing desktop Codex threads registered by raw thread id:
112
+
113
+ ```bash
114
+ uv run dispatch attach <codex-thread-id>
115
+ uv run dispatch attach <codex-thread-id> --sync
116
+ ```
117
+
118
+ Attached lanes are managed by dispatch but are not turn-writable in v0. Do not
119
+ try turn-writing or history-mutating commands such as `send`, `stop`,
120
+ `goal set`, `goal clear`, `lane fork`, `lane rollback`, or `lane compact` on
121
+ attached lanes. Explicit metadata/lifecycle commands (`rename`, `archive`,
122
+ `restore`) are allowed because they do not start turns or mutate turn history.
123
+ ADR-0005 and ADR-0018 keep this boundary locked because desktop Codex and
124
+ dispatch run separate app-server processes and there is no cross-process write
125
+ interlock.
126
+
127
+ Attach is compact by default: it verifies the thread with
128
+ `thread/read(includeTurns:false)`, registers metadata, and does not resume turn
129
+ history. Use `--sync` or `sync` when you want dispatch to refresh its local
130
+ indexed view.
131
+
132
+ ```bash
133
+ uv run dispatch sync <dispatch-ref-or-thread-id>
134
+ uv run dispatch sync <dispatch-ref-or-thread-id> --full
135
+ ```
136
+
137
+ Sync indexes source identity, sync state, latest event time, latest turn id, and
138
+ bounded top+tail JSONL facts when Codex exposes a rollout path. It does not copy
139
+ the full transcript by default and it does not grant write authority to attached
140
+ lanes.
141
+
142
+ ## Discover Sessions
143
+
144
+ `list` shows threads dispatch already manages. `list --unmanaged` lists
145
+ persisted Codex sessions that are not registered in dispatch. It uses App Server
146
+ `thread/list` in state-db-only mode, asking for active sessions sorted by recent
147
+ updates. It is read-only and does not resume or register anything:
148
+
149
+ ```bash
150
+ uv run dispatch list
151
+ uv run dispatch list --unmanaged --limit 20
152
+ ```
153
+
154
+ Use a discovered session `id` with `attach <id>`.
155
+
156
+ ## Search And Thread Actions
157
+
158
+ Use top-level actions when you want to work with either managed threads or raw
159
+ unmanaged Codex thread ids:
160
+
161
+ ```bash
162
+ uv run dispatch rename @my-lane my-lane-final
163
+ uv run dispatch archive <codex-thread-id>
164
+ uv run dispatch restore @my-lane
165
+ ```
166
+
167
+ `restore` only unarchives; it does not resume or start a turn.
168
+
169
+ Use `search` before attaching when you need to find the right existing thread:
170
+
171
+ ```bash
172
+ uv run dispatch search "schema drift"
173
+ uv run dispatch search "schema drift" --managed
174
+ uv run dispatch search "schema drift" --unmanaged
175
+ uv run dispatch search "schema drift" --thread <dispatch-ref>
176
+ uv run dispatch search "schema drift" --repo .
177
+ uv run dispatch search "schema drift" --dir /path/to/project
178
+ uv run dispatch search "schema drift" --since 2026-06-01 --until 2026-06-05
179
+ ```
180
+
181
+ Broad search uses experimental App Server `thread/search` plus dispatch-side
182
+ filters. Lane-focused search reads one thread transcript and scans locally.
183
+ Sync is separate: `sync` refreshes dispatch's local index for a managed
184
+ lane, but it does not attach unmanaged sessions or grant write authority.
185
+
186
+ ## Message Verbs
187
+
188
+ `send` is the primary way to put work or context into a lane:
189
+
190
+ ```bash
191
+ uv run dispatch send @my-lane "Do the bounded thing."
192
+ uv run dispatch send @my-lane "Focus on docs first." --steer
193
+ uv run dispatch send @my-lane "Stop and do this instead." --interject
194
+ uv run dispatch send @my-lane "Context: use lane publicly, thread internally." --context
195
+ uv run dispatch send @my-lane "After this finishes, summarize risks." --mode queue
196
+ uv run dispatch send @my-lane "Can you check this?" --intro
197
+ ```
198
+
199
+ The mode flags and `--mode send|steer|queue|interject|context` are mutually
200
+ exclusive. `--queue` stores the message durably and starts one queued turn when
201
+ the lane is idle.
202
+
203
+ Use `--intro` when you are sending from one managed Codex thread to another and
204
+ want the recipient to know how to reply through dispatch. It derives the sender
205
+ from `CODEX_THREAD_ID`, so the current thread must already be managed.
206
+
207
+ Use `stop` to cancel the active turn without replacement text:
208
+
209
+ ```bash
210
+ uv run dispatch stop <dispatch-ref>
211
+ ```
212
+
213
+ Destroy-intent commands prompt by default. In scripts, use explicit confirmation:
214
+
215
+ ```bash
216
+ uv run dispatch archive <dispatch-ref> --yes --json
217
+ uv run dispatch trigger rm <trigger-id> --yes --json
218
+ ```
219
+
220
+ For short inter-lane chat, use the companion `$dm` skill, which is backed by
221
+ `dispatch send`.
222
+
223
+ ## History, Watch, And Goals
224
+
225
+ Use `get` for compact managed-thread metadata:
226
+
227
+ ```bash
228
+ uv run dispatch get <dispatch-ref>
229
+ ```
230
+
231
+ Check `latest_turn` when a message was accepted but no assistant work is visible.
232
+ It records the latest observed turn id, status, and App Server error text/time for
233
+ failed turns.
234
+
235
+ Use `tail` for persisted turn history:
236
+
237
+ ```bash
238
+ uv run dispatch tail <dispatch-ref> --limit 50
239
+ ```
240
+
241
+ `tail` uses App Server `includeTurns`, which is not available for ephemeral
242
+ threads.
243
+
244
+ Use `watch` for a bounded live event sample. It returns raw App
245
+ Server method/params until a limit or timeout, and it is not an infinite tail:
246
+
247
+ ```bash
248
+ uv run dispatch watch <dispatch-ref> --limit 20 --timeout 10
249
+ ```
250
+
251
+ Use native goals on owned lanes when a worker has a durable objective:
252
+
253
+ ```bash
254
+ uv run dispatch goal set @my-lane "Loop until checks are green."
255
+ uv run dispatch goal status <dispatch-ref>
256
+ uv run dispatch goal clear <dispatch-ref>
257
+ ```
258
+
259
+ Goals require non-ephemeral App Server threads.
260
+
261
+ `tail --follow` is not canonical; use `watch`.
262
+
263
+ ## Markdown Thread Links
264
+
265
+ Use readable handles plus Codex thread URIs in human-facing text. Compose a
266
+ Markdown link whose label is the handle and whose destination is the Codex URI:
267
+
268
+ ```markdown
269
+ label: @Target
270
+ destination: codex://threads/<codex-thread-id>
271
+ ```
272
+
273
+ Use raw thread ids for `attach`. Use refs or full thread ids for dispatch
274
+ thread arguments.
275
+
276
+ ## Triggers
277
+
278
+ A trigger binds `when -> action -> lane`.
279
+
280
+ ```bash
281
+ uv run dispatch trigger add \
282
+ --name pulse \
283
+ --lane <dispatch-ref> \
284
+ --when interval \
285
+ --seconds 1800 \
286
+ --action send \
287
+ --text "Check in briefly."
288
+ ```
289
+
290
+ Use `--idle-only`, `--min-interval`, and `--dedupe` to reduce noisy automation.
291
+ Remember that dedupe state is process-local and resets when the daemon restarts.
292
+
293
+ ```bash
294
+ uv run dispatch trigger list
295
+ uv run dispatch trigger pause <trigger-id>
296
+ uv run dispatch trigger resume <trigger-id>
297
+ uv run dispatch trigger rm <trigger-id>
298
+ ```
299
+
300
+ ## Schemas
301
+
302
+ Use `schema` for derived input/output schemas:
303
+
304
+ ```bash
305
+ uv run dispatch schema send
306
+ uv run dispatch schema "list --unmanaged"
307
+ uv run dispatch schema models
308
+ uv run dispatch schema "goal set"
309
+ ```
310
+
311
+ Prefer `schema` for `jq`/automation field discovery. It is derived from the same
312
+ op registry as CLI and MCP, including composed spellings like `list --unmanaged`.
313
+
314
+ ## MCP And Plugin
315
+
316
+ The MCP server is:
317
+
318
+ ```bash
319
+ uv run dispatch mcp
320
+ ```
321
+
322
+ The MCP surface is grouped for agent ergonomics, not one tool per CLI
323
+ subcommand. Tools are grouped by workflow and safety boundary, and each call
324
+ selects an `op` inside the tool. In this repo, the workspace-local Codex plugin
325
+ lives at `plugins/dispatch`. It exposes these skills and the same MCP registry.
326
+ Use the daemon-read MCP tool's `models` op before setting explicit model or
327
+ service-tier arguments.
328
+ If the plugin does not appear immediately, restart Codex for the workspace.
329
+ Installed PyPI packages also include read-only copies of these skills and the
330
+ plugin bundle under `outfitter.dispatch.assets`; use the repo copies for editing.
331
+
332
+ ## Guardrails
333
+
334
+ - Do not mutate source files, Git, PRs, Graphite, or tracker state as part of
335
+ ordinary dispatch operation.
336
+ - Do not install launchd autostart unless the user explicitly asks.
337
+ - Start troubleshooting with `dispatch doctor`; use its recovery hints rather
338
+ than guessing about stale sockets, PATH, auth, or registry shape.
339
+ - If doctor reports an old registry, stop the daemon and run
340
+ `dispatch registry migrate` before starting it again.
341
+ - Do not describe `tail --follow` as canonical or streaming forever. Use `watch`
342
+ for bounded live samples until dispatch grows a subscription-capable control socket.
343
+ - Do not treat `rollback` as file undo.
344
+ - If a request becomes long-running owned work, use a proper delegated lane or
345
+ goal workflow rather than a casual message.
@@ -21,7 +21,7 @@ Use dispatch first:
21
21
 
22
22
  ```bash
23
23
  uv run dispatch doctor --no-app-server
24
- uv run dispatch lane list
24
+ uv run dispatch list
25
25
  uv run dispatch daemon status
26
26
  ```
27
27
 
@@ -29,12 +29,12 @@ If the environment is new, run `uv run dispatch doctor` once before messaging.
29
29
  Fix PATH, Codex auth, stale daemon files, registry, or plugin asset warnings
30
30
  before assuming a DM failure is about the target lane.
31
31
 
32
- The target should be an owned dispatch lane. Attached lanes are observe-only in
33
- v0, so dispatch will reject write verbs against them.
32
+ The target should be an owned dispatch lane selected by dispatch ref when possible. Attached lanes are not
33
+ turn-writable in v0, so dispatch will reject DM/send verbs against them.
34
34
 
35
- If the user wants to message an existing desktop Codex thread, attach it only
36
- for observation unless they explicitly choose a different authority model after
37
- reading ADR-0005.
35
+ If the user wants to message an existing desktop Codex thread, attach/sync it
36
+ only for observation unless they explicitly choose a different authority model
37
+ after reading ADR-0005.
38
38
 
39
39
  ## Handles And URIs
40
40
 
@@ -47,7 +47,7 @@ label: @Target
47
47
  destination: codex://threads/<target-thread-id>
48
48
  ```
49
49
 
50
- Use the lane handle or lane id for `dispatch send`. Use the URI link in
50
+ Use the dispatch ref or full thread id for `dispatch send`. Use the URI link in
51
51
  the message body so the recipient and the human can open the thread directly.
52
52
 
53
53
  ## Message Shape
@@ -65,25 +65,27 @@ Contract: read-only, brief answer, reply in this lane unless asked otherwise.
65
65
  Then deliver it:
66
66
 
67
67
  ```bash
68
- uv run dispatch send @Target '<message>'
68
+ uv run dispatch send <target-ref> '<message>' --intro
69
69
  ```
70
70
 
71
71
  Keep DMs conversational and bounded. Prefer one ask. Include only the context
72
72
  needed for the target lane to answer without reading the sender's full
73
- transcript. Do not use `$dm` to smuggle in broad implementation work.
73
+ transcript. If the current Codex thread is not managed by dispatch, omit
74
+ `--intro` and include the sender link manually. Do not use `$dm` to smuggle in
75
+ broad implementation work.
74
76
 
75
77
  ## Harvesting
76
78
 
77
- `dispatch send` starts the target turn. Use `dispatch lane get` and `dispatch daemon log`
78
- to confirm lane state and accepted actions:
79
+ `dispatch send` starts the target turn. Use `dispatch get` and `dispatch daemon log`
80
+ to confirm thread state and accepted actions:
79
81
 
80
82
  ```bash
81
- uv run dispatch lane get @Target
83
+ uv run dispatch get <target-ref>
82
84
  uv run dispatch daemon log --limit 10
83
85
  ```
84
86
 
85
- Important v0 limitation: `dispatch lane get` is lane metadata, not a transcript
86
- reader. Use `dispatch lane tail @Target --limit 50` for persisted history when
87
+ Important v0 limitation: `dispatch get` is thread metadata, not a transcript
88
+ reader. Use `dispatch tail <target-ref> --limit 50` for persisted history when
87
89
  the lane is non-ephemeral, or open the Codex thread link. Do not pretend
88
90
  dispatch harvested text it cannot currently read.
89
91
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "outfitter-dispatch"
3
- version = "0.2.0"
3
+ version = "0.5.0"
4
4
  description = "Local control plane for orchestrating Codex agent lanes over the Codex App Server."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"