agent-tempo 1.7.0-beta.1 → 1.7.0-beta.11

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 (161) hide show
  1. package/CLAUDE.md +24 -18
  2. package/README.md +11 -2
  3. package/dashboard/dist/assets/{index-jmYe6rmS.js → index-BbR7zIdK.js} +2 -2
  4. package/dashboard/dist/assets/index-BbR7zIdK.js.map +1 -0
  5. package/dashboard/dist/index.html +1 -1
  6. package/dashboard/package.json +1 -1
  7. package/dist/activities/maestro.d.ts +46 -1
  8. package/dist/activities/maestro.js +69 -20
  9. package/dist/activities/outbox.d.ts +14 -10
  10. package/dist/activities/outbox.js +66 -23
  11. package/dist/activities/resolve.d.ts +36 -0
  12. package/dist/activities/resolve.js +119 -4
  13. package/dist/activities/schedule-fire.js +5 -2
  14. package/dist/adapters/base.d.ts +2 -0
  15. package/dist/adapters/base.js +9 -0
  16. package/dist/adapters/claude-api/adapter.js +26 -4
  17. package/dist/adapters/claude-code/adapter.js +15 -9
  18. package/dist/adapters/claude-code-headless/adapter.js +22 -4
  19. package/dist/adapters/copilot/adapter.js +58 -8
  20. package/dist/adapters/opencode/adapter.js +26 -6
  21. package/dist/adapters/pi/adapter.js +0 -6
  22. package/dist/adapters/sdk/base.d.ts +60 -0
  23. package/dist/adapters/sdk/base.js +83 -0
  24. package/dist/adapters/sdk/doorbell-client.d.ts +106 -0
  25. package/dist/adapters/sdk/doorbell-client.js +261 -0
  26. package/dist/adapters/sdk/idle-backoff.d.ts +71 -0
  27. package/dist/adapters/sdk/idle-backoff.js +136 -0
  28. package/dist/cli/command-center-command.d.ts +28 -0
  29. package/dist/cli/command-center-command.js +139 -0
  30. package/dist/cli/commands.d.ts +28 -0
  31. package/dist/cli/commands.js +93 -19
  32. package/dist/cli/config-command.js +14 -0
  33. package/dist/cli/daemon-command.js +41 -5
  34. package/dist/cli/daemon.d.ts +245 -5
  35. package/dist/cli/daemon.js +505 -44
  36. package/dist/cli/ensure-infra.d.ts +9 -1
  37. package/dist/cli/ensure-infra.js +16 -4
  38. package/dist/cli/help-text.js +4 -1
  39. package/dist/cli/mcp.d.ts +26 -2
  40. package/dist/cli/mcp.js +33 -4
  41. package/dist/cli/sa-preflight.d.ts +27 -1
  42. package/dist/cli/sa-preflight.js +29 -5
  43. package/dist/cli/startup.js +8 -2
  44. package/dist/cli/upgrade-to-2-command.d.ts +10 -0
  45. package/dist/cli/upgrade-to-2-command.js +159 -0
  46. package/dist/cli.js +58 -5
  47. package/dist/client/core.d.ts +6 -0
  48. package/dist/client/core.js +122 -34
  49. package/dist/client/interface.d.ts +26 -1
  50. package/dist/config.d.ts +100 -8
  51. package/dist/config.js +116 -9
  52. package/dist/daemon.d.ts +78 -7
  53. package/dist/daemon.js +313 -41
  54. package/dist/ensemble/saver.d.ts +10 -0
  55. package/dist/ensemble/saver.js +18 -6
  56. package/dist/http/aggregate.d.ts +115 -1
  57. package/dist/http/aggregate.js +218 -13
  58. package/dist/http/auth.d.ts +1 -1
  59. package/dist/http/auth.js +2 -2
  60. package/dist/http/coat-check.d.ts +36 -0
  61. package/dist/http/coat-check.js +110 -0
  62. package/dist/http/deliverability.d.ts +68 -0
  63. package/dist/http/deliverability.js +78 -0
  64. package/dist/http/doorbell-routes.d.ts +32 -0
  65. package/dist/http/doorbell-routes.js +72 -0
  66. package/dist/http/doorbell.d.ts +45 -0
  67. package/dist/http/doorbell.js +162 -0
  68. package/dist/http/event-types.d.ts +16 -1
  69. package/dist/http/event-types.js +1 -0
  70. package/dist/http/inner-loop-routes.d.ts +9 -12
  71. package/dist/http/inner-loop-routes.js +4 -20
  72. package/dist/http/qa.d.ts +28 -0
  73. package/dist/http/qa.js +95 -0
  74. package/dist/http/server.d.ts +7 -10
  75. package/dist/http/server.js +103 -49
  76. package/dist/http/snapshot.d.ts +28 -5
  77. package/dist/http/snapshot.js +16 -6
  78. package/dist/http/writes.js +24 -2
  79. package/dist/pi/cue-pump.d.ts +184 -11
  80. package/dist/pi/cue-pump.js +230 -18
  81. package/dist/pi/extension.d.ts +4 -10
  82. package/dist/pi/extension.js +48 -89
  83. package/dist/pi/headless.d.ts +11 -17
  84. package/dist/pi/headless.js +63 -32
  85. package/dist/pi/inner-loop-client.d.ts +0 -9
  86. package/dist/pi/inner-loop-client.js +1 -16
  87. package/dist/pi/inner-loop-publisher.d.ts +1 -27
  88. package/dist/pi/install.d.ts +47 -0
  89. package/dist/pi/install.js +78 -5
  90. package/dist/pi/mission-control/actions.d.ts +116 -9
  91. package/dist/pi/mission-control/actions.js +220 -21
  92. package/dist/pi/mission-control/board.d.ts +103 -0
  93. package/dist/pi/mission-control/board.js +103 -2
  94. package/dist/pi/mission-control/extension.d.ts +150 -5
  95. package/dist/pi/mission-control/extension.js +544 -36
  96. package/dist/pi/mission-control/inner-tail.d.ts +7 -1
  97. package/dist/pi/mission-control/inner-tail.js +10 -2
  98. package/dist/pi/mission-control/pi-ui.d.ts +53 -0
  99. package/dist/pi/mission-control/render.d.ts +13 -0
  100. package/dist/pi/mission-control/render.js +117 -13
  101. package/dist/pi/pi-types.d.ts +4 -3
  102. package/dist/pi/workflow-client.d.ts +29 -0
  103. package/dist/pi/workflow-client.js +87 -3
  104. package/dist/reconcile/orphans.js +8 -9
  105. package/dist/server-tools.js +5 -1
  106. package/dist/server.js +11 -1
  107. package/dist/spawn.d.ts +91 -7
  108. package/dist/spawn.js +59 -7
  109. package/dist/tools/broadcast.js +15 -1
  110. package/dist/tools/cue.js +40 -11
  111. package/dist/tools/ensemble.js +11 -2
  112. package/dist/tools/recruit.js +5 -55
  113. package/dist/tools/respond.d.ts +4 -0
  114. package/dist/tools/respond.js +45 -0
  115. package/dist/tools/who-am-i.d.ts +3 -2
  116. package/dist/tools/who-am-i.js +9 -2
  117. package/dist/tui/index.js +3 -0
  118. package/dist/types.d.ts +67 -9
  119. package/dist/upgrade/phase-engine.d.ts +160 -0
  120. package/dist/upgrade/phase-engine.js +555 -0
  121. package/dist/upgrade/snapshot-v1.d.ts +214 -0
  122. package/dist/upgrade/snapshot-v1.js +165 -0
  123. package/dist/utils/action-counters.d.ts +75 -0
  124. package/dist/utils/action-counters.js +279 -0
  125. package/dist/utils/format-hosts.js +7 -0
  126. package/dist/utils/hosts.js +5 -0
  127. package/dist/utils/sdk-probe.d.ts +12 -0
  128. package/dist/utils/sdk-probe.js +28 -0
  129. package/dist/utils/search-attributes.d.ts +76 -4
  130. package/dist/utils/search-attributes.js +89 -4
  131. package/dist/utils/suspension.d.ts +99 -0
  132. package/dist/utils/suspension.js +128 -0
  133. package/dist/utils/validation.d.ts +12 -0
  134. package/dist/utils/validation.js +14 -1
  135. package/dist/utils/visibility-deadline.js +5 -0
  136. package/dist/worker.d.ts +16 -2
  137. package/dist/worker.js +25 -4
  138. package/dist/workflows/maestro-signals.d.ts +25 -1
  139. package/dist/workflows/maestro-signals.js +15 -1
  140. package/dist/workflows/maestro.d.ts +10 -0
  141. package/dist/workflows/maestro.js +204 -21
  142. package/dist/workflows/scheduler.js +17 -2
  143. package/dist/workflows/session.js +251 -17
  144. package/dist/workflows/signals.d.ts +8 -0
  145. package/dist/workflows/signals.js +3 -2
  146. package/examples/agents/tempo-conductor.md +12 -0
  147. package/package.json +4 -4
  148. package/workflow-bundle.js +687 -45
  149. package/dashboard/dist/assets/index-jmYe6rmS.js.map +0 -1
  150. package/dist/http/gate-audit.d.ts +0 -12
  151. package/dist/http/gate-audit.js +0 -95
  152. package/dist/http/gate-registry.d.ts +0 -167
  153. package/dist/http/gate-registry.js +0 -163
  154. package/dist/http/gate-routes.d.ts +0 -48
  155. package/dist/http/gate-routes.js +0 -102
  156. package/dist/pi/gate-client.d.ts +0 -54
  157. package/dist/pi/gate-client.js +0 -136
  158. package/dist/pi/reset-pump.d.ts +0 -85
  159. package/dist/pi/reset-pump.js +0 -135
  160. package/dist/pi/tool-capability.d.ts +0 -60
  161. package/dist/pi/tool-capability.js +0 -156
package/CLAUDE.md CHANGED
@@ -21,10 +21,12 @@ src/
21
21
  ├── daemon.ts # Daemon entry point — runs Temporal workers as a detached background process
22
22
  ├── cli/
23
23
  │ ├── commands.ts # CLI command implementations (up, start, conduct, status, stop, …)
24
+ │ ├── command-center-command.ts # command-center subcommand — crash-proof; launches Pi mission-control board; sets AGENT_TEMPO_MISSION_CONTROL=1 (#729)
24
25
  │ ├── config-command.ts # config subcommand (interactive + set/show) — crash-proof for show/set
25
26
  │ ├── daemon.ts # Daemon management utilities (start, stop, status, heartbeat, isDaemonRunning)
26
27
  │ ├── daemon-command.ts # daemon subcommand handler — crash-proof, no Temporal deps
27
28
  │ ├── dashboard-command.ts # dashboard subcommand — crash-proof; opens the web dashboard, optionally minting a QR-code pairing token (#340)
29
+ │ ├── ensure-infra.ts # shared infra bootstrap (`ensureInfra()`) — brings up Temporal, SAs, daemon; shared by `up` and the Pi extension `/ensemble-up` (#700 P1)
28
30
  │ ├── dev-banner.ts # [DEV MODE] banner formatter (ADR 0014 §5.4) — gate 4 production-safety line
29
31
  │ ├── dev-mode-bootstrap.ts # pre-import side-effect: promotes top-level `--dev` flag to `CLAUDE_TEMPO_DEV_MODE=1` before any other module loads
30
32
  │ ├── dev-verbs.ts # dev-mode scriptable CLI verbs (#432) — shell-scriptable wrappers over MCP tools for E2E validation; stripped from production surface
@@ -35,10 +37,12 @@ src/
35
37
  │ ├── output.ts # Shared CLI output formatting helpers
36
38
  │ ├── preflight.ts # Environment preflight checks
37
39
  │ ├── removed-verbs.ts # lookup table for the 10 CLI verbs removed in #288 — dispatches migration hints before loading Temporal surface
40
+ │ ├── resolve-ensemble.ts # canonical ensemble-name resolver — `--ensemble` flag > positional > env > 'default' (#685)
38
41
  │ ├── sa-preflight.ts # search-attribute preflight — REQUIRED_SEARCH_ATTRIBUTES list (single source of truth), registerSearchAttribute, verifySearchAttributes, assertSearchAttributesOrExit
39
42
  │ ├── scenarios-command.ts # scenarios subcommand (dev mode only) — list/show shipped YAML scenario library (ADR 0014 §4.8)
40
43
  │ ├── startup.ts # auto-provisioning bootstrap state machine (#289) — six-step idempotent sequence used by bare `agent-tempo` invocation
41
- └── upgrade-command.ts # upgrade subcommand — crash-proof; dynamic-imports Temporal only for active-session warning
44
+ ├── upgrade-command.ts # upgrade subcommand — crash-proof; dynamic-imports Temporal only for active-session warning
45
+ │ └── upgrade-to-2-command.ts # upgrade-to-2 cutover verb (#785) — crash-proof; dynamic-imports the phase-engine + Temporal inside try/catch; --yes/--dry-run/--force-drain
42
46
  ├── adapters/
43
47
  │ ├── README.md # Adapter contract documentation
44
48
  │ ├── index.ts # Adapter registry bootstrap + barrel exports (mock registered iff isDevMode())
@@ -50,7 +54,7 @@ src/
50
54
  │ ├── opencode/ # OpenCodeAttachment — headless multi-provider adapter via SST OpenCode subprocess (#449)
51
55
  │ ├── pi/ # Headless Pi adapter — descriptor + spawn entry (Phase 3a). No BaseAttachment; the Pi extension singleton owns lifecycle (claim/heartbeat/tools/cue pump). `adapter.ts` is the process entry; `index.ts` is the registry descriptor.
52
56
  │ ├── mock/ # MockAttachment — dev-mode-only SDK adapter (ADR 0014 PR-2). prepack strips dist/adapters/mock from npm tarball.
53
- │ └── sdk/ # SDK-style adapter base (used by Copilot bridge and opencode)
57
+ │ └── sdk/ # SDK-style adapter base (used by Copilot bridge and opencode). Key files: `idle-backoff.ts` (T0.2 IdleBackoff helper — base 2s, cap 30s/60s, reset-on-delivery), `doorbell-client.ts` (T1.1 DoorbellClient + WakeableSleep — reconnecting SSE consumer for `/doorbell`; ding→reset()+wake(); connected ceiling 60s; disconnected falls back to 30s T0.2 floor)
54
58
  ├── client/
55
59
  │ ├── interface.ts # TempoClient TypeScript interface and related types
56
60
  │ └── index.ts # TempoClient factory implementation and barrel re-exports
@@ -82,15 +86,17 @@ src/
82
86
  │ ├── inner-loop.ts # InnerLoopRegistry + InnerSubscription — daemon-local fine-tail sink (3c MD-F); drop-oldest bounded queue (256) + `compacted{dropped,sinceTs}` marker; NOT on Temporal/bus, ephemeral no-replay
83
87
  │ ├── ingest-registry.ts # IngestTokenRegistry — per-player ingest token (mint-on-pi-spawn / revoke-on-destroy / revokeAll-on-shutdown); timing-safe validation; cross-player-spoof guard
84
88
  │ ├── inner-loop-routes.ts # 3 inner-loop HTTP routes: POST /inner/ingest + GET /inner/presence (INGRESS, loopback + X-Ingest-Token, uniform 403); GET /inner (EGRESS operator SSE, requireTier(3))
85
- │ ├── gate-registry.ts # GateRegistry (3d MD-G) per-player armed-gate + pending-request store; 45s lazy auto-allow (R3 locked); arm/disarm/decide/getResolution; injected auditSink + publishToInner callback
86
- │ ├── gate-routes.ts # Gate HTTP routes: POST /gate-arm + /gate-disarm + /gate/:requestId (OPERATOR, Tier 3); GET /gate/:requestId/resolution (SOURCE, loopback + X-Ingest-Token); uniform 403 no-leak
87
- │ ├── gate-audit.ts # createGateAuditSink — append-only JSONL at ~/.agent-tempo/gate-audit/<ensemble>/<workflowId>.jsonl; sync write (R5 durable-before-return); whitelisted path segments; swallows I/O errors
89
+ │ ├── doorbell.ts # DoorbellRegistry in-process Map<"{ensemble}:{playerId}", Set<waiter>>; ring-with-no-listener drops on floor; level-triggered coalescing; never throws (T1.1 PR-1, #776)
90
+ │ ├── doorbell-routes.ts # GET /doorbell/:ensemble/:playerId SSE route — content-free ding events; loopback + X-Ingest-Token auth (same ingress model as inner-loop); NO event IDs / Last-Event-ID / replay by design; :ka keepalive every 15s (T1.1 PR-1, #776)
88
91
  │ ├── auth.ts # 3e MD-E RBAC: two-token model (readToken T1 / adminToken T1+T2+T3 env-var-only); loadRbacTokens; requireTier(tier, input) → TierGuardResult; tierForToken; loadReadToken (env>config>legacy httpToken>auto-gen); loadAdminToken (env-only); TLS/legacy startup warnings in startHttpServer
89
92
  │ ├── cors.ts / responses.ts / event-id.ts / port-file.ts / index.ts
90
93
  ├── reconcile/
91
94
  │ └── orphans.ts # Shared orphan-query helper (daemon reconcile-on-boot + CLI restore)
95
+ ├── upgrade/ # 1.x→2.0 cutover (#785)
96
+ │ ├── snapshot-v1.ts # VERSIONED upgrade-snapshot-v1.json schema + atomic persistence — the cross-release interface #786 imports (Temporal-free)
97
+ │ └── phase-engine.ts # 6-phase resumable cutover engine (preflight→pause→drain→snapshot→destroy→done); snapshot strictly precedes destroy
92
98
  ├── ensemble/
93
- │ ├── schema.ts / loader.ts / saver.ts # Lineup type definitions, load, save
99
+ │ ├── schema.ts / loader.ts / saver.ts # Lineup type definitions, load, save (saver exports buildLineupFromCluster — shared by save_lineup + #785 snapshot)
94
100
  │ └── agent-types.ts # Agent type discovery, resolution, and lineup resolution
95
101
  ├── tools/ # One file per MCP tool — see docs/tools.md for full reference
96
102
  │ ├── ensemble.ts / cue.ts / recruit.ts / report.ts / broadcast.ts / recall.ts / listen.ts
@@ -104,24 +110,22 @@ src/
104
110
  │ ├── hosts.ts / set-ensemble-description.ts
105
111
  │ ├── save-state.ts / fetch-state.ts / clear-state.ts
106
112
  │ ├── coat-check-put.ts / coat-check-get.ts / coat-check-list.ts / coat-check-evict.ts
113
+ │ ├── respond.ts
107
114
  │ └── descriptor.ts # Transport-neutral tool descriptor (TempoToolDescriptor) + renderToMcp; per-tool `build*Tool` factories live in each tool file (MD-B, Phase 1)
108
115
  ├── pi/ # Pi-native integration — a Pi session as a first-class player over the Temporal core
109
116
  │ ├── extension.ts # `export default function(pi)` — interactive runtime entry. Holds the MODULE-SCOPE singleton `Map<workflowId, PiPlayerRuntime>` that survives Pi's per-switch instance rebuild (rebind, not re-claim); full tool surface via renderToPi; Option-C reason-discriminated teardown
110
- │ ├── phase-driver.ts / workflow-client.ts / cue-pump.ts # Pi-event→attachment-phase machine, thin client-side WorkflowClient (lease/heartbeat 90/30, handle getter), cue pump (D10 steer/followUp)
117
+ │ ├── phase-driver.ts / workflow-client.ts / cue-pump.ts # Pi-event→attachment-phase machine, thin client-side WorkflowClient (lease/heartbeat 90/30, handle getter), cue pump (D10 steer/followUp; IdleBackoff loop 1s base→30s disconnected/60s connected ceiling + ding wake via DoorbellClient; pendingIntake combined query T0.3; S3 merge, D14 clean-wipe + /tempo-reset operator notice)
111
118
  │ ├── lazy-proxy.ts # D11 createLazyProxy — Client/WorkflowHandle proxy resolving the live module-scope target per call (survives instance rebuild)
112
119
  │ ├── headless.ts # Headless Pi runtime (Phase 3a) — boots Pi's createAgentSession with inline extension; `noExtensions: true` closes S2 exec-tool bypass; SIGTERM/SIGINT shutdown → reliable detach + dispose
113
120
  │ ├── render-tools.ts # renderToPi — registers the shared tool descriptors on Pi's ExtensionAPI (TypeBox params via the converter)
114
121
  │ ├── zod-to-typebox.ts # zod→TypeBox tool-schema converter (fail-loud on unsupported constructs; Phase 1 / D1)
115
122
  │ ├── inner-loop-publisher.ts # InnerLoopPublisher (3c MD-F) — single Pi-source observer; Tier-1 coarse via heartbeat piggyback (currentTool + context pressure), Tier-2 fine presence-gated; source coalescing (100ms/2KB) + 2KB truncation
116
- │ ├── inner-loop-client.ts # InnerLoopHttpClient — production InnerLoopRegistry impl: thin loopback-HTTP calls (publish→POST ingest, subscriberCount→cached presence GET); no-ops without AGENT_TEMPO_INGEST_TOKEN; 3d: also caches gateArmed from presence response
117
- │ ├── gate-client.ts # GateClient (3d MD-G) — Pi-subprocess poll client for operator gate resolution; awaitDecision(requestId) polls GET /gate/:id/resolution until resolved or timeout; fail-open (allow on timeout/error/auto-allow)
118
- │ ├── reset-pump.ts # ResetPump (3d D14) — polls pendingReset query every 1s; on result calls session.newSession() (clean-wipe); sends system notice; acks via ackReset signal
119
- │ ├── tool-capability.ts # classify(toolName) → ToolCapability ('exec' | 'high-blast' | 'low-risk'); EXEC_TOOLS denylist (F1 locked: bash/shell/exec/sh/powershell/pwsh/cmd/…); unknown → 'high-blast' (fail-safe)
123
+ │ ├── inner-loop-client.ts # InnerLoopHttpClient — production InnerLoopRegistry impl: thin loopback-HTTP calls (publish→POST ingest, subscriberCount→cached presence GET); no-ops without AGENT_TEMPO_INGEST_TOKEN
120
124
  │ ├── mission-control/ # 3f — observer-only Pi extension that turns one interactive Pi TUI into an ensemble mission-control board + operator controller. HTTP-driven (NOT MCP tools). Never claims attachment or registers as a player.
121
- │ │ ├── extension.ts # Controller (testable command handlers) + Pi extension lifecycle: session_start opens coarse SSE + ~200ms render tick + registers /players /tail /cue /pause /play /restart /destroy /reset /arm /gate; session_shutdown tears down SSE + widget
125
+ │ │ ├── extension.ts # Controller (testable command handlers) + Pi extension lifecycle: session_start opens coarse SSE + ~200ms render tick + registers /players /tail /cue /pause /play /restart /destroy /reset; session_shutdown tears down SSE + widget
122
126
  │ │ ├── board.ts # Pure BoardModel + reducers: applyTempoEvent (coarse /events SSE) + applyInnerFrame (selected-player inner tail); revision counter drives render throttle
123
- │ │ ├── render.ts # Pure BoardModel → string[] renderer; phase glyphs, part, currentTool, context%, selected-player tail (12 lines), inner.gate_pending/gate_resolved frames
124
- │ │ ├── actions.ts # Daemon HTTP write-surface client (T2 + T3 bearer): cue/pause/play/restart/destroy + gate arm/disarm/decide; reads AGENT_TEMPO_HTTP_ADMIN_TOKEN
127
+ │ │ ├── render.ts # Pure BoardModel → string[] renderer; phase glyphs, part, currentTool, context%, selected-player tail (12 lines)
128
+ │ │ ├── actions.ts # Daemon HTTP write-surface client (T2 + T3 bearer): cue/pause/play/restart/destroy; reads AGENT_TEMPO_HTTP_ADMIN_TOKEN
125
129
  │ │ ├── inner-tail.ts # Operator-egress /inner SSE consumer (T3 bearer): pure parseInnerSse + injectable stream pump; cross-host note: baseUrl is the preferredHost seam
126
130
  │ │ ├── pi-ui.ts # Local structural slice of Pi's ctx.ui / registerCommand / registerShortcut API (self-contained; tsc green without optional Pi dep)
127
131
  │ │ └── index.ts # Barrel — re-exports Controller, BoardModel, renderBoard, MissionControlActions, and public types
@@ -210,15 +214,17 @@ daemon worker notes, `npx ts-node` dev runner).
210
214
  - **Claude API adapter** (`agent: 'claude-api'`, #131): Headless adapter that drives sessions via the Anthropic Messages API (`@anthropic-ai/sdk`) — no terminal, no Claude Code CLI. Requires `ANTHROPIC_API_KEY` env var and the `@anthropic-ai/sdk` optional dependency. Default model `claude-opus-4-7` (overridable via `model` recruit arg or `CLAUDE_TEMPO_API_MODEL` env). Claude-API players have access to agent-tempo MCP tools (cue, report, recall, ensemble, …) but not file-edit/shell/web tools. See `src/adapters/claude-api/`.
211
215
  - **OpenCode adapter** (`agent: 'opencode'`, #449): Headless multi-provider adapter that drives sessions via [SST OpenCode](https://opencode.ai) as a managed subprocess — supports Anthropic, OpenAI, Bedrock, Vertex, Ollama, and ~70 other providers via OpenCode's `provider/model` selector. Requires OpenCode CLI (`npm install -g opencode-ai`) and the `@opencode-ai/sdk` optional dependency. Recruit with `model: 'provider/name'` (e.g. `'anthropic/claude-opus-4-7'`). Tool bridging is MCP-native — OpenCode spawns `dist/server.js` as its own stdio MCP child. Session state is persisted server-side by OpenCode; the adapter stashes the session id on workflow metadata for reconnect across `opencode serve` restarts. See `src/adapters/opencode/`.
212
216
  - **Claude Code headless adapter** (`agent: 'claude-code-headless'`, #520): Headless adapter that drives sessions via the official `claude` CLI as a per-turn `claude -p --output-format stream-json` subprocess. The whole point: turns bill against the host's existing Claude Code subscription extra-usage credits (Pro / Max plans) rather than a Console workspace API key — the only ToS-clean way for a third-party tool to tap that pool. Requires the `claude` binary on PATH AND a logged-in Claude Code session (`claude auth login`); recruit pre-flight rejects with an actionable error otherwise. Tool surface is the union of full Claude Code built-ins (Bash / Read / Write / Edit / Glob / Grep / WebSearch / WebFetch) and the agent-tempo MCP surface — registered via inline `--mcp-config` so `claude` spawns `dist/server.js` as its own MCP child (no in-process bridge). Recruit knobs: `permissionMode` (default `'acceptEdits'`) or `dangerouslySkipPermissions: true` (mutually exclusive). Sessions resume across restart via the existing `sessionId` metadata field — the same UUID is shared with the interactive `claude-code` adapter (per-cwd JSONL is per-cwd, not per-adapter). See `src/adapters/claude-code-headless/` and `examples/ensembles/tempo-headless-jam.yaml`.
213
- - **Pi adapter** (`agent: 'pi'`, #632 / #666): Two modes. **(1) Interactive conductor** (#666): `agent-tempo up --agent pi --ensemble <name>` launches `pi` in a real terminal with the agent-tempo extension auto-loaded (`pi -e dist/pi/extension.js`); the Pi session self-bootstraps its Temporal workflow and attaches as a conductor/player — no separate recruiter step. From the TUI, `/recruit-conductor` relaunches the active ensemble's conductor — set `conductor.agent: pi` in that ensemble's lineup to make it a Pi conductor. Requires `@earendil-works/pi-coding-agent` on Node ≥ 22.19. Recommended: `ANTHROPIC_API_KEY` (without it the session falls back to Pi's own auth/default model). The `AGENT_TEMPO_*` env is auto-wired by `up`; power users can invoke the extension directly with `pi -e dist/pi/extension.js`. `--model provider/model` selector (e.g. `'github-copilot/gpt-4o'`) is a fast-follow. **(2) Headless player** (Phase 3a): `recruit` with `agent: 'pi'` — no terminal, no BaseAttachment; runs `createAgentSession` with an in-memory `SessionManager`; the module-scope singleton owns claim/heartbeat/tools/cue pump (MD-D). MD-C tool-access policy: `toolAccess: 'restricted'` (default Bash/shell/exec HARD-BLOCKED) | `'standard'` (scoped Bash) | `'full'` (unsandboxed; requires `force: true`). `noExtensions: true` closes the S2 exec-tool-bypass gap. See `src/adapters/pi/` and `src/pi/headless.ts`.
214
- - **Mission-control Pi extension** (3f): An observer-only Pi extension that turns one interactive Pi TUI into a live ensemble board + operator controller. HTTP-drives the daemon — coarse ensemble view via `/v1/events/:ensemble` SSE + fine per-player tail via `/inner` (T3); operator controls (cue/pause/play/restart/destroy + gate arm/disarm/decide) POST to the daemon write surface using `AGENT_TEMPO_HTTP_ADMIN_TOKEN`. **Never claims attachment or registers as a player** — invisible to the ensemble. ~200ms render throttle from an in-memory `BoardModel`. Requires an interactive Pi session with `ctx.hasUI`. See `src/pi/mission-control/`.
217
+ - **Pi adapter** (`agent: 'pi'`, #632 / #666): Two modes. **(1) Interactive conductor** (#666): `agent-tempo up --agent pi --ensemble <name>` launches `pi` in a real terminal with the agent-tempo extension auto-loaded (`pi -e dist/pi/extension.js`); the Pi session self-bootstraps its Temporal workflow and attaches as a conductor/player — no separate recruiter step. From the TUI, `/recruit-conductor` relaunches the active ensemble's conductor — set `conductor.agent: pi` in that ensemble's lineup to make it a Pi conductor. Requires `@earendil-works/pi-coding-agent` on Node ≥ 22.19. Recommended: `ANTHROPIC_API_KEY` (without it the session falls back to Pi's own auth/default model). The `AGENT_TEMPO_*` env is auto-wired by `up`; power users can invoke the extension directly with `pi -e dist/pi/extension.js`. The interactive `--model provider/model` selector (e.g. `'github-copilot/gpt-4o'`) remains a fast-follow. **(2) Headless player** (Phase 3a): `recruit` with `agent: 'pi'` — no terminal, no BaseAttachment; runs `createAgentSession` with an in-memory `SessionManager`; the module-scope singleton owns claim/heartbeat/tools/cue pump (MD-D). Per-player `model: 'provider/model'` on recruit (#734): built-in providers AND custom `~/.pi/agent/models.json` providers (lmstudio, ollama, vllm, …) both resolve, falling back to `AGENT_TEMPO_PI_MODEL` — enables hybrid ensembles (frontier-model conductor, local-model workers). Pi players run the full tool surface — incl. shell — with no permission layer, like the other adapters (the former `toolAccess`/`guardrailPolicy` knobs were removed). `noExtensions: true` stays: it blocks third-party disk/package extensions from loading into a recruited player (supply-chain hygiene). See `src/adapters/pi/` and `src/pi/headless.ts`.
218
+ - **Mission-control / Command-center** (3f, #700 P2): An interactive Pi TUI that is both a live ensemble board + operator controller and an LLM planner. Board side: HTTP-drives the daemon — coarse ensemble view via `/v1/events/:ensemble` SSE + fine per-player tail via `/inner` (T3); operator controls (cue/pause/play/restart/destroy) POST to the daemon write surface using `AGENT_TEMPO_HTTP_ADMIN_TOKEN`. Planner side: registers LLM tools (`ask` / `handoff` / `cue` / `recruit` / `observe_board`) via `MissionControlActions` — HTTP-backed, distinct from the player extension's `renderToPi` MCP surface. **Never claims attachment or registers as a player** — invisible to the ensemble. Launch with **`agent-tempo command-center [ensemble]`** (aliases: `cc`, `board`) — sets `AGENT_TEMPO_MISSION_CONTROL=1`. **Loopback auto-token** (#736): a local (loopback) daemon grants full trust without `AGENT_TEMPO_HTTP_ADMIN_TOKEN`; only a remote daemon requires explicit token configuration. **Role-gated and mutually exclusive** with the player extension (`resolvePiRole` discriminator: explicit `AGENT_TEMPO_PI_ROLE` → `PLAYER_NAME` present → `AGENT_TEMPO_MISSION_CONTROL` → `none`): a bare `pi` keeps both extensions dormant (plain coding session); a player session (`up --agent pi` / `recruit`) keeps the board dormant. Power users invoking `pi -e dist/pi/extension.js` directly without `PLAYER_NAME` also resolve to `none` (dormant) — set `AGENT_TEMPO_PI_ROLE=player` to force player mode. See `src/pi/mission-control/`.
219
+ - **Command-center planner** (#700 P2): An inbox-less interactive Pi session (the operator's planning seat) that routes questions to players via correlated `cue` tags (`[Q <questionId>]`). Players answer with the `respond` MCP tool, which parks the answer on the per-ensemble maestro Q&A mailbox (TTL 1h, 20-slot cap). The planner is woken by an `answer` SSE event when the answer lands (`docs/SSE-PROTOCOL.md` §6). `/handoff` cues hand active work to a conductor (a registered player with a Temporal inbox). See `docs/concepts.md` for the Q&A mechanics.
215
220
  - **Mock adapter** (`agent: 'mock'`, dev mode only): Four modes: `echo` (echoes input), `scripted` (replays YAML scenario rules), `silent` (drains messages without replying — heartbeat-stale validation), `chaos` (probabilistic fail/crash injection via seeded PRNG). Only registered when `isDevMode()` is true; stripped from the npm tarball by `prepack`. See `src/adapters/mock/`.
216
221
  - **Saveable state** (#334, ADR 0011): Per-player curated state slots — the player itself decides what context survives a restart. Three MCP tools: `save_state` (owner-only write, max 4 slots × 32 KiB), `fetch_state` (read self or peer; audit identity recorded on each entry's `savedBy`), `clear_state` (owner-only). `restart` accepts `loadFromState: true | 'someKey'` to seed the new session from a saved-state slot instead of (or, with `transcript: 'replay'`, alongside) transcript replay. Saved-state delivery uses `from: 'self-restart'` as a stable system identity. Empty-slot fallback: graceful — falls through to transcript replay with a log line. See [docs/design/334-player-saveable-state.md](docs/design/334-player-saveable-state.md).
222
+ - **`upgrade-to-2` cutover** (#785, ratified migration protocol A2 — `docs/design/v2-scoping.md` §A.3): The 1.x → 2.0 migration verb. A 2.0 worker can never replay a 1.x-recorded run, so 2.0 ships behind a clean cutover: `agent-tempo upgrade-to-2` runs a six-phase protocol — **preflight** (enumerate ensembles; refuse if any connected daemon is below the 1.7.x version floor — `hostProfile.version` on the global maestro; covers same-host-stale-daemon, #801) → **pause** (brake the work *sources* — maestro + scheduler — leaving sessions live to drain) → **drain** (poll outboxes ≤60s; `--force-drain` records stragglers instead of stopping) → **snapshot** (freeze session dispatch, then capture continuity to `~/.agent-tempo/upgrade-snapshot-v1.json`) → **destroy** (idempotent teardown: peers → scheduler+maestro → conductor) → **done**. **Load-bearing invariant: SNAPSHOT strictly precedes DESTROY** (`destroyAndFinish` takes a persisted snapshot as a required arg); a crash leaves either everything intact or a durable snapshot + partial teardown, never destruction without capture. Resumable via the snapshot's phase stamp. The snapshot captures schedules (durable intent), #334 state slots (continuity), `sessionId` (resume pointer), the non-default recruit `model` (ad-hoc claude-api/opencode/pi continuity), and undelivered cues (operator review, NOT redelivered); coat-check is dropped (TTL-transient); gates/stages/worktrees are intentionally not captured (transient coordination state; worktree continuity rides `workDir`). **`src/upgrade/snapshot-v1.ts` is the cross-release interface the 2.0-side `up --from-upgrade` (#786) imports** — it is VERSIONED and deliberately Temporal-free; additive optional fields do NOT bump the version, only removed/renamed/retyped required fields do (with a 2.0 reader migration). CLI flags: `--yes` (skip confirm), `--dry-run` (print snapshot + destroy list, exit before pausing), `--force-drain`. The verb is crash-proof (`src/cli/upgrade-to-2-command.ts` dynamic-imports the Temporal-touching engine). See `src/upgrade/` and issue #785.
217
223
  - **Coat-check** (#318, ADR 0008): Per-ensemble transient content store on Maestro state. Solves the 100 KB cue body cap — stash a large artifact with `coat_check_put` (returns a ticket id) and attach the ticket to a `cue` via `attachmentTicket`; the recipient calls `coat_check_get` to pull the full body. Four MCP tools: `coat_check_put` (any player; max 32 KiB per entry, 20 slots per ensemble, TTL 7d default), `coat_check_get` (any player; bumps fetch-audit counters), `coat_check_list` (read-only survey; headers only, content omitted), `coat_check_evict` (owner or conductor). Saturation rejects with `CoatCheckSlotsFull` (no LRU eviction). See `src/tools/coat-check-*.ts` and [docs/adr/0008-coat-check-pattern.md](docs/adr/0008-coat-check-pattern.md).
218
224
  - **Lineup examples**: Six pre-built ensemble YAML files in `examples/ensembles/` — `tempo-big-band`, `tempo-dev-team`, `tempo-review-squad`, `tempo-jam-session`, `tempo-mock-jam` (dev-mode all-mock ensemble), `tempo-headless-jam` (#520 — all-`claude-code-headless` subscription-billed ensemble). Load with `agent-tempo up --lineup <name>` or the `load_lineup` tool.
219
- - **GitHub App identity** (`agent-tempo[bot]`): When a player writes to GitHub — issue comments, PR creation/merge, commits, labels, check runs — **use `./scripts/ensemble-gh`** instead of `gh`. The wrapper mints a short-lived installation token so the action is attributed to `agent-tempo[bot]`, not to the human maintainer, making the AI authorship visible. Plain `gh` is still correct for read-only local dev (`gh pr view`, `gh repo clone`, `gh auth status`). Every bot-authored comment/PR body must include the AI attribution footer documented in [docs/github-app.md](docs/github-app.md).
225
+ - **GitHub App identity** (`agent-tempo[bot]`): When a player writes to GitHub — issue comments, PR creation/merge, commits, labels, check runs — **use `./scripts/ensemble-gh`** instead of `gh`. The wrapper mints a short-lived installation token so the action is attributed to `agent-tempo[bot]`, not to the human maintainer, making the AI authorship visible. Plain `gh` is still correct for read-only local dev (`gh pr view`, `gh repo clone`, `gh auth status`). On Windows, invoke via `bash ./scripts/ensemble-gh` — bare PowerShell silently no-ops with no error (see #741). Every bot-authored comment/PR body must include the AI attribution footer documented in [docs/github-app.md](docs/github-app.md).
220
226
 
221
- See [docs/concepts.md](docs/concepts.md) for the full glossary (Adapter, Attachment phases, Restart, Detach/Destroy, Migrate, Broadcast, Recall, Schedule, Lineup, Quality Gate, Worktree, Stage, Hold/Release, Pause/Resume, Maestro, TempoClient, and more).
227
+ See [docs/concepts.md](docs/concepts.md) for the full glossary (Adapter, Attachment phases, Restart, Detach/Destroy, Migrate, Broadcast, Recall, Schedule, Lineup, Quality Gate, Worktree, Stage, Hold/Release, Pause/Resume, Maestro, TempoClient, Command-center planner, and more).
222
228
 
223
229
  ## Commit Convention
224
230
 
package/README.md CHANGED
@@ -148,7 +148,7 @@ agent-tempo # launch TUI (auto-provisions on first run)
148
148
  agent-tempo up [ensemble] # provision infrastructure and launch conductor
149
149
  agent-tempo down [--destroy] # tear down infrastructure (--destroy also terminates workflows)
150
150
  agent-tempo status [ensemble] # list active sessions
151
- agent-tempo destroy <ensemble> # terminate all sessions in an ensemble
151
+ agent-tempo destroy [ensemble] # terminate all sessions in an ensemble (defaults to "default")
152
152
  agent-tempo restore <ensemble> # restore orphaned sessions on this host
153
153
  agent-tempo hosts # list daemons polling this Temporal namespace (--all/--json)
154
154
  agent-tempo recall <name> # read a player's message history (--limit/--offset/--preview/--json)
@@ -277,7 +277,16 @@ From the TUI, `/recruit-conductor` relaunches the active ensemble's conductor
277
277
 
278
278
  **Prerequisites:** `@earendil-works/pi-coding-agent` on Node ≥ 22.19. Recommended: `ANTHROPIC_API_KEY` (without it the session falls back to Pi's own auth/default model).
279
279
 
280
- **Headless Pi players** — recruit as a background agent slot using `agent: 'pi'` (see [docs/design/pi-hardening-h1-h2-h3.md](docs/design/pi-hardening-h1-h2-h3.md)).
280
+ **Headless Pi players** — recruit as a background agent slot using `agent: 'pi'`. Pi players run the full tool surface — including shell — without an approval layer, exactly like the other adapters. Observe them live via the mission-control board (coarse SSE + fine `/inner` tail); control via `cue`/`pause`/`restart`/`destroy`/`reset`. See [docs/concepts.md](docs/concepts.md#command-center-and-player-supervision).
281
+
282
+ **Mission-control board** — operator-only view that observes the ensemble and sends operator actions (cue, pause, restart, destroy) without joining as a player:
283
+
284
+ ```bash
285
+ agent-tempo install-pi # install Pi extensions (once per machine)
286
+ agent-tempo command-center # launch the board (aliases: cc, board)
287
+ ```
288
+
289
+ The admin token is injected automatically for loopback daemons — no manual token setup required locally (#736).
281
290
 
282
291
  📖 [Pi integration reference → docs/design/pi-hardening-h1-h2-h3.md](docs/design/pi-hardening-h1-h2-h3.md)
283
292