claude-tempo 0.24.0 → 0.25.0-beta.2

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 (80) hide show
  1. package/CLAUDE.md +48 -150
  2. package/README.md +2 -2
  3. package/dist/activities/outbox.d.ts +37 -24
  4. package/dist/activities/outbox.js +201 -77
  5. package/dist/adapters/base.d.ts +150 -0
  6. package/dist/adapters/base.js +341 -0
  7. package/dist/adapters/claude-code/adapter.d.ts +78 -0
  8. package/dist/adapters/claude-code/adapter.js +171 -0
  9. package/dist/adapters/claude-code/index.d.ts +15 -0
  10. package/dist/adapters/claude-code/index.js +20 -0
  11. package/dist/adapters/copilot/adapter.d.ts +100 -0
  12. package/dist/adapters/copilot/adapter.js +730 -0
  13. package/dist/adapters/copilot/index.d.ts +15 -0
  14. package/dist/adapters/copilot/index.js +20 -0
  15. package/dist/adapters/index.d.ts +24 -0
  16. package/dist/adapters/index.js +35 -0
  17. package/dist/adapters/sdk/base.d.ts +95 -0
  18. package/dist/adapters/sdk/base.js +134 -0
  19. package/dist/cli/commands.d.ts +34 -2
  20. package/dist/cli/commands.js +466 -99
  21. package/dist/cli.js +126 -9
  22. package/dist/client/index.js +52 -4
  23. package/dist/client/interface.d.ts +31 -3
  24. package/dist/config.d.ts +95 -0
  25. package/dist/config.js +101 -1
  26. package/dist/daemon.d.ts +52 -1
  27. package/dist/daemon.js +302 -8
  28. package/dist/reconcile/orphans.d.ts +72 -0
  29. package/dist/reconcile/orphans.js +72 -0
  30. package/dist/server.js +44 -23
  31. package/dist/spawn.d.ts +8 -0
  32. package/dist/spawn.js +10 -3
  33. package/dist/tools/attachment-info.d.ts +4 -0
  34. package/dist/tools/attachment-info.js +48 -0
  35. package/dist/tools/destroy.d.ts +4 -0
  36. package/dist/tools/destroy.js +45 -0
  37. package/dist/tools/{stop.d.ts → detach.d.ts} +1 -1
  38. package/dist/tools/detach.js +45 -0
  39. package/dist/tools/{encore.d.ts → migrate.d.ts} +1 -1
  40. package/dist/tools/migrate.js +60 -0
  41. package/dist/tools/restart.d.ts +31 -0
  42. package/dist/tools/restart.js +123 -0
  43. package/dist/tui/App.js +16 -18
  44. package/dist/tui/commands.d.ts +19 -0
  45. package/dist/tui/commands.js +188 -44
  46. package/dist/tui/components/ChatView.d.ts +13 -1
  47. package/dist/tui/components/ChatView.js +24 -2
  48. package/dist/tui/components/PlayerDetailView.d.ts +10 -1
  49. package/dist/tui/components/PlayerDetailView.js +19 -4
  50. package/dist/tui/index.js +6 -1
  51. package/dist/tui/store.d.ts +5 -2
  52. package/dist/tui/store.js +8 -3
  53. package/dist/tui/utils/format.d.ts +9 -0
  54. package/dist/tui/utils/format.js +15 -0
  55. package/dist/types.d.ts +208 -7
  56. package/dist/utils/validation.d.ts +4 -2
  57. package/dist/utils/validation.js +5 -3
  58. package/dist/worker.js +4 -1
  59. package/dist/workflows/session.js +677 -129
  60. package/dist/workflows/signals.d.ts +108 -6
  61. package/dist/workflows/signals.js +76 -4
  62. package/examples/agents/tempo-composer.md +2 -0
  63. package/examples/agents/tempo-conductor.md +32 -7
  64. package/examples/agents/tempo-critic.md +1 -0
  65. package/examples/agents/tempo-improv.md +17 -0
  66. package/examples/agents/tempo-liner.md +17 -0
  67. package/examples/agents/tempo-roadie.md +4 -1
  68. package/examples/agents/tempo-soloist.md +16 -0
  69. package/examples/agents/tempo-tuner.md +17 -0
  70. package/package.json +9 -4
  71. package/packaging/launchd/com.claude.tempo.plist +46 -0
  72. package/packaging/systemd/claude-tempo.service +32 -0
  73. package/packaging/windows/install-task.ps1 +71 -0
  74. package/workflow-bundle.js +754 -134
  75. package/dist/channel.d.ts +0 -3
  76. package/dist/channel.js +0 -48
  77. package/dist/copilot-bridge.d.ts +0 -22
  78. package/dist/copilot-bridge.js +0 -509
  79. package/dist/tools/encore.js +0 -56
  80. package/dist/tools/stop.js +0 -58
package/CLAUDE.md CHANGED
@@ -26,7 +26,11 @@ src/
26
26
  │ ├── mcp.ts # MCP server registration helpers (init, global vs project)
27
27
  │ ├── output.ts # Shared CLI output formatting helpers
28
28
  │ └── preflight.ts # Environment preflight checks
29
- ├── copilot-bridge.ts # Copilot SDK bridge for Copilot CLI players
29
+ ├── adapters/
30
+ │ ├── index.ts # Adapter registry bootstrap + barrel exports
31
+ │ ├── base.ts # BaseAttachment + SdkAttachment base classes (lifecycle skeleton)
32
+ │ ├── claude-code/ # InteractiveAttachment — Claude Code CLI adapter
33
+ │ └── copilot/ # CopilotSdkAttachment — Copilot bridge adapter
30
34
  ├── client/
31
35
  │ ├── interface.ts # TempoClient TypeScript interface and related types
32
36
  │ └── index.ts # TempoClient factory implementation and barrel re-exports
@@ -34,179 +38,77 @@ src/
34
38
  ├── connection.ts # Temporal connection factory (shared by server + CLI)
35
39
  ├── spawn.ts # Cross-platform process spawning helpers
36
40
  ├── workflows/
37
- │ ├── index.ts # Workflow exports (re-exports for worker bundle)
38
41
  │ ├── session.ts # claude-session workflow
39
42
  │ ├── scheduler.ts # durable scheduler workflow (one per ensemble)
40
- │ ├── maestro.ts # Maestro workflows — per-ensemble hub (one per ensemble) and global hub (one instance spanning all ensembles)
41
- │ ├── maestro-signals.ts # Maestro signal/query/update type definitions
42
- ├── scheduler-signals.ts # Scheduler signal/query type definitions
43
- │ └── signals.ts # Session signal/query type definitions
43
+ │ ├── maestro.ts # Maestro workflows — per-ensemble hub and global hub
44
+ │ ├── maestro-signals.ts / scheduler-signals.ts / signals.ts # Signal/query/update type defs
45
+ └── index.ts # Workflow re-exports for worker bundle
44
46
  ├── activities/
45
- │ ├── outbox.ts # Outbox delivery activities (cue, report, stop, recruit, encore)
46
- │ ├── maestro.ts # Maestro activities (refreshEnsembleState, relayCommandToConductor, fetchConductorHistory, fetchEnsembleChat)
47
+ │ ├── outbox.ts # Outbox delivery activities (cue, report, recruit, release, spawn)
48
+ │ ├── maestro.ts # Maestro activities
47
49
  │ ├── resolve.ts # Session resolver shared by outbox + schedule-fire activities
48
- │ └── schedule-fire.ts # Schedule fire activity
50
+ │ └── schedule-fire.ts
51
+ ├── reconcile/
52
+ │ └── orphans.ts # Shared orphan-query helper (daemon reconcile-on-boot + CLI restore)
49
53
  ├── ensemble/
50
- │ ├── schema.ts # Lineup type definitions
51
- │ ├── loader.ts # Load and validate YAML lineups
52
- │ ├── saver.ts # Save live ensemble state to YAML
54
+ │ ├── schema.ts / loader.ts / saver.ts # Lineup type definitions, load, save
53
55
  │ └── agent-types.ts # Agent type discovery, resolution, and lineup resolution
54
- ├── tools/
55
- │ ├── ensemble.ts # Discover active sessions
56
- │ ├── cue.ts # Send message to peer (via outbox)
57
- │ ├── set-name.ts # Set session name
58
- │ ├── set-part.ts # Update own summary
59
- │ ├── who-am-i.ts # Query own identity, role, and session details
60
- │ ├── agent-types.ts # Discover available player types (agent definitions)
61
- │ ├── resolve.ts # Search-attribute session lookup
62
- │ ├── listen.ts # Manual message check
63
- │ ├── recruit.ts # Spawn new session (via outbox), supports `type` param
64
- │ ├── report.ts # Report to conductor (via outbox)
65
- │ ├── stop.ts # Stop a session (via outbox)
66
- │ ├── broadcast.ts # Send message to all active players (via outbox fan-out)
67
- │ ├── encore.ts # Revive a stale session (via outbox)
68
- │ ├── recall.ts # Read own message history (received + sent)
69
- │ ├── load-lineup.ts # Load an ensemble lineup, recruit players
70
- │ ├── save-lineup.ts # Save current ensemble state as a lineup
71
- │ ├── schedule.ts # Create one-shot or recurring schedules
72
- │ ├── unschedule.ts # Cancel a named schedule
73
- │ ├── schedules.ts # List active schedules
74
- │ ├── quality-gate.ts # Define quality gates for tasks (conductor only)
75
- │ ├── evaluate-gate.ts # Mark gate criteria as passed/failed (conductor only)
76
- │ ├── gates.ts # List quality gates and their status (conductor only)
77
- │ ├── worktree.ts # Manage git worktrees for player isolation (conductor only)
78
- │ ├── stage.ts # Define a stage — fan-out/fan-in tracking for parallel tasks (conductor only)
79
- │ ├── stages.ts # List stages and their status (conductor only)
80
- │ ├── cancel-stage.ts # Cancel an active stage (conductor only)
81
- │ ├── release.ts # Release held players (unlock outbox + deliver deferred messages)
82
- │ ├── pause-ensemble.ts # Pause all sessions and the scheduler ensemble-wide
83
- │ ├── resume-ensemble.ts # Resume a paused ensemble
56
+ ├── tools/ # One file per MCP tool — see docs/tools.md for full reference
57
+ │ ├── ensemble.ts / cue.ts / recruit.ts / report.ts / broadcast.ts / recall.ts / listen.ts
58
+ │ ├── restart.ts / detach.ts / destroy.ts / migrate.ts / attachment-info.ts
59
+ │ ├── schedule.ts / unschedule.ts / schedules.ts
60
+ │ ├── quality-gate.ts / evaluate-gate.ts / gates.ts
61
+ │ ├── worktree.ts / stage.ts / stages.ts / cancel-stage.ts
62
+ │ ├── load-lineup.ts / save-lineup.ts / agent-types.ts / resolve.ts
63
+ │ ├── set-name.ts / set-part.ts / who-am-i.ts / release.ts
64
+ │ ├── pause-ensemble.ts / resume-ensemble.ts
84
65
  │ └── helpers.ts # Zod/MCP tool registration wrapper
85
66
  ├── tui/
86
- │ ├── index.ts # TUI entry point connects to Temporal and renders the Ink app
87
- │ ├── App.tsx # Root TUI component — chat-focused shell with slash commands
88
- │ ├── store.ts # TUI state reducer (phase, players, messages, schedules, static history)
89
- ├── client.ts # Thin re-export shim re-exports createTempoClient from src/client/ for backward compatibility
90
- │ ├── commands.ts # Slash command parser and registry (/player, /broadcast, /status, etc.)
91
- │ ├── ink-loader.ts # Dynamic ESM loader for Ink (avoids CJS/ESM conflicts)
92
- │ ├── ink-context.tsx # React context for injected Ink primitives
93
- │ ├── components/
94
- │ │ ├── Splash.tsx # Splash/connecting screen component
95
- │ │ ├── TitleBar.tsx # Pinned title bar showing ensemble/player context
96
- │ │ ├── PromptArea.tsx # Pinned input area with ❯ prompt, inline hints, and divider
97
- │ │ ├── MainView.tsx # Main ensemble view (players, messages, schedules)
98
- │ │ ├── ChatView.tsx # Per-player chat view (entered via /cue <player>)
99
- │ │ ├── ErrorView.tsx # Connection failure screen with troubleshooting checks (zero Yoga nodes)
100
- │ │ ├── StatusBar.tsx # Persistent status bar (player counts, schedule count, connection health)
101
- │ │ ├── CommandPalette.tsx # Autocomplete dropdown for slash commands and parameters
102
- │ │ ├── Picker.tsx # Full-screen interactive picker (players, ensembles)
103
- │ │ ├── PlayerDetailView.tsx # Player metadata + scrollable message history (zero Yoga nodes)
104
- │ │ ├── StatusOverlay.tsx # Dismissible overlay showing ensemble player cards (/status)
105
- │ │ ├── CommandOverlay.tsx # Generic dismissible overlay for data-display commands (/gates, /stages, /recall, /search)
106
- │ │ ├── ScheduleOverlay.tsx # Dismissible overlay showing active schedules with timing details (/schedule)
107
- │ │ ├── ConversationStream.tsx # Live message area merging server conversation + optimistic echo
108
- │ │ ├── CreateEnsembleWizard.tsx # Step-by-step wizard for creating new ensembles (name → workDir → lineup → confirm)
109
- │ │ ├── ScheduleWizard.tsx # Step-by-step wizard for /schedule create
110
- │ │ └── RecruitWizard.tsx # Step-by-step wizard for /recruit
111
- │ └── utils/
112
- │ ├── format.ts # Display formatting helpers
113
- │ ├── platform.ts # Terminal size detection helpers
114
- │ ├── theme.ts # THEME constants (colors, borders, icons)
115
- │ ├── fullscreen.ts # Fullscreen/alternate-screen helpers
116
- │ └── history.ts # Persistent command history (~/.claude-tempo/tui-history.json)
67
+ │ ├── App.tsx / store.ts / commands.ts # TUI root, state, slash commands
68
+ │ ├── client.ts # Backward-compat shim src/client/
69
+ │ ├── components/ # Ink components see docs/tui.md for inventory
70
+ └── utils/ # format, platform, theme, fullscreen, history
117
71
  ├── utils/
118
- │ ├── validation.ts # Shared validation constants (name/message/path limits, encore defaults) and helpers
119
- │ ├── worktree.ts # Git worktree create/remove helpers (cross-platform)
120
- │ ├── safe-path.ts # Path safety utilities
121
- │ └── duration.ts # Duration parsing helpers
72
+ │ ├── validation.ts / worktree.ts / safe-path.ts / duration.ts
122
73
  ├── types.ts # Shared type definitions
123
- ├── channel.ts # Claude channel notification helper
124
74
  ├── git-info.ts # Git repository detection helper
125
75
  └── config.ts # Env var handling
126
76
  ```
127
77
 
78
+ See [docs/tui-performance.md](docs/tui-performance.md) for Ink/React performance notes when
79
+ touching `src/tui/`.
80
+
128
81
  ## Development
129
82
 
130
83
  ```bash
131
- # Install dependencies
132
84
  npm install
133
-
134
- # Start Temporal dev server (separate terminal)
135
- temporal server start-dev
136
-
137
- # Start the daemon (runs Temporal workers in background)
138
- claude-tempo daemon start
139
-
140
- # Run in development
141
- npx ts-node src/server.ts
142
-
143
- # Build (compiles TS and pre-bundles workflow code)
144
- npm run build
145
-
146
- # Test
85
+ npm run build # compiles TS + pre-bundles workflow code into workflow-bundle.js
147
86
  npm test
148
87
  ```
149
88
 
150
- > **Important**: Always run `npm run build` after changing workflow code (`src/workflows/`).
151
- > The build pre-bundles workflows into `workflow-bundle.js` so all workers use identical code.
89
+ > **Always run `npm run build` after changing workflow code (`src/workflows/`).** The build
90
+ > pre-bundles workflows into `workflow-bundle.js` so all workers use identical code.
152
91
 
153
- > **Daemon workers**: Temporal workers are no longer run in-process by sessions. The daemon
154
- > (`src/daemon.ts`) runs as a detached background process and owns all worker duties. Sessions are
155
- > pure MCP clients. The daemon is auto-started by any claude-tempo command if not already running.
92
+ See [docs/development.md](docs/development.md) for full setup (Temporal dev server command,
93
+ daemon worker notes, `npx ts-node` dev runner).
156
94
 
157
95
  ## Key Concepts
158
96
 
97
+ > **Architecture overview**: See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the three-layer workflow/adapter/process model and ensemble coordination layer.
98
+
159
99
  - **Player**: A Claude Code session registered as a Temporal workflow
160
100
  - **Conductor**: A special player that acts as orchestration hub, connected to external interfaces (one per ensemble)
161
101
  - **Ensemble**: The set of all active players, namespaced by `CLAUDE_TEMPO_ENSEMBLE`
162
102
  - **Cue**: A message sent to a player by name via Temporal signal
163
103
  - **Part**: A player's description of what it's working on
164
- - **Recruit**: Spawning a new Claude Code session as a player. The workflow is pre-created with the initial message before the process spawns, ensuring reliable delivery.
165
- - **set_name**: Players start with a random hex ID; `set_name` updates the `ClaudeTempoPlayerId` search attribute to a human-readable name
166
- - **Session status**: Each session has a status (`pending` `active` `stale` | `blocked`) tracked via `ClaudeTempoStatus` search attribute. Pre-created workflows start as `pending`, transition to `active` when the process connects, and become `stale` if messages go undelivered for 3+ minutes. Sessions become `blocked` when they are alive (delivering messages) but have produced no response to a `responseRequested: true` message for 5+ minutes — they may be stuck or spinning. Informational messages (broadcasts, schedule-fires, heartbeats, system notifications) set `responseRequested: false` and do not trigger blocked detection. Blocked status auto-recovers to `active` on next outbound.
167
- - **Outbox**: Outbound requests (cue, report, stop, recruit, encore) go through the session's own workflow outbox instead of directly signaling other workflows. The workflow's dispatch loop processes entries via activities, decoupling tools from cross-workflow signaling.
168
- - **Encore**: Revives a `stale` player session by restarting the Claude process and reconnecting to the existing Temporal workflow, with recent message context restored. Cannot encore `active`, `pending`, or `terminated` sessions use `cue`, wait, or `recruit` respectively.
169
- - **Broadcast**: Fan-out variant of `cue` sends a message to all active players in the ensemble in a single call. Optionally filtered by player type. Skips the sender, pending sessions, and (by default) stale sessions.
170
- - **Recall**: Queries a session's own message history from the Temporal workflow. Shows received messages by default; pass `includeSent: true` to also see sent messages. Supports `limit`, `since`, and `from` filters.
171
- - **Per-host task queues**: Each host runs a `claude-tempo-{hostname}` activity worker for local-only operations (e.g., `spawnProcess`). This enables cross-machine recruiting — the `recruit` tool accepts an optional `host` parameter to route the spawn to a remote machine's task queue.
172
- - **Player types**: Reusable agent definitions in Claude Code's standard subagent format (`.md` files with YAML frontmatter). Ensemble lineups can reference types by name via a `type` field on players. Three-tier lookup: project `.claude/agents/` → user `~/.claude/agents/` → shipped `examples/agents/`. Players know their type via workflow metadata and the `who_am_i` tool. Agent type frontmatter may include an `allowedTools` array to restrict which MCP/CLI tools the spawned session can use (e.g., `allowedTools: [Read, Glob, Grep]`). When present, the type's `allowedTools` overrides any lineup-level setting and is passed to the Claude Code session via `--allowedTools`.
173
- - **Agent type discovery**: The `agent_types` MCP tool and `claude-tempo agent-types` CLI command let conductors discover available player types. Shipped examples (tempo-conductor, tempo-composer, tempo-soloist, tempo-tuner, tempo-critic, tempo-roadie, tempo-improv, tempo-liner) work out of the box. Ensemble lineups: tempo-big-band (full lifecycle), tempo-dev-team (feature work), tempo-review-squad (parallel review), tempo-jam-session (exploration).
174
- - **Schedule**: A one-shot or recurring message delivery configured via the `schedule` tool. Backed by a durable `claudeSchedulerWorkflow` — survives restarts. Supports delay (`delay`), fixed time (`at`), recurring interval (`every`), and cron expressions (`cron`) with optional IANA timezone (`timezone`). Cron schedules use `croner` for expression parsing and next-fire computation. Managed via `schedule`, `unschedule`, and `schedules` tools.
175
- - **Lineup**: A YAML file defining an ensemble configuration — which players to recruit, their types, working directories, and optional startup messages. Load via `load_lineup` to bootstrap a full ensemble in one step; `load_lineup` resolves the lineup by name using a three-tier lookup: saved lineups → shipped examples → file path. Save via `save_lineup` to snapshot a running ensemble's state for later reuse.
176
- - **Quality Gate**: A named checklist of criteria a conductor tracks to verify a task is complete. Created via `quality_gate` (conductor only), evaluated via `evaluate_gate`, and listed via `gates`. Each criterion has a `pending` → `passed` | `failed` status; the gate's aggregate status is derived automatically (all passed → `passed`, any failed → `failed`, else `open`). Gates are stored in the conductor workflow and survive `continueAsNew`.
177
- - **Worktree**: A git worktree provisioned by the conductor for a player, giving them an isolated checkout on a separate branch. Managed via the `worktree` tool (conductor only): `create` provisions the worktree and notifies the player, `remove` cleans up after the task, `list` shows all active worktrees. Worktree assignments are stored in the conductor workflow (`WorktreeEntry` records: player, path, branch, gitRoot, createdAt, createdBy).
178
- - **Stage**: A fan-out/fan-in tracking primitive for the conductor. Created via `stage` (conductor only), listing via `stages`, cancelled via `cancel_stage`. Each stage tracks a set of players; when a tracked player sends a `report`, their stage status updates automatically (`waiting` → `reported` or `blocked`). When all players have reported, the conductor is notified that the stage is complete. If `failurePolicy` is `'halt'` (default), a blocker from any player fails the entire stage. Stages are stored in the conductor workflow and survive `continueAsNew`.
179
- - **Hold / Release**: Controlled ensemble startup mechanism. `load_lineup(hold: true)` spawns all players with locked outboxes and a standby message ("waiting for release") instead of their real task. When ready, the conductor calls `release` (MCP tool or `claude-tempo release` CLI) to unlock outboxes and deliver the actual task messages. Use case: pre-warm a full team before kicking off a long job.
180
- - **Pause / Resume**: Ensemble-wide mid-session flow control. `pause_ensemble` locks all session outboxes and signals the scheduler to skip fires; `resume_ensemble` reverses both. `stop` outbox entries bypass the pause lock and are always dispatched. Pause state is owned by the per-ensemble Maestro (`maestroSetPaused` signal) and synced to sessions and the scheduler.
181
- - **Outbox lock**: A workflow-level flag on each session that gates outbox dispatch independently of pause. Used by the hold mechanism (`outboxLocked` query, `releaseHeld` signal) and the pause mechanism (`setPaused` signal, `paused` query). The two flags are independent — a session can be held (locked) but not paused, or paused but not locked.
182
- - **Maestro**: Two Maestro workflow variants exist. The **per-ensemble** `claudeMaestroWorkflow` (ID: `claude-maestro-{ensemble}`) monitors a single ensemble — maintains a player snapshot, ring-buffer event log (max 200 entries), an aggregated ensemble chat cache (max 500 entries, refreshed every ~10s via `fetchEnsembleChat` activity), and queues commands for relay to the conductor via `maestroSendCommand`. The ensemble chat cache merges maestro + conductor traffic and is served via the `maestroEnsembleChat` query. The **global** `claudeGlobalMaestroWorkflow` (ID: `claude-maestro-global`) spans all ensembles — aggregates players by ensemble, maintains a cross-ensemble message ring buffer (max 500 entries), and exposes on-demand player/conductor history via `maestroFetchPlayerMessages` and `maestroFetchConductorHistory` updates. Both are implemented in `src/workflows/maestro.ts` with activities in `src/activities/maestro.ts`.
183
- - **TempoClient**: The API layer for querying ensemble state (`src/client/`). The interface and types live in `interface.ts`; the factory implementation lives in `index.ts`. Provides `discoverEnsembles`, `getPlayers`, `getMessages`, `getConductorHistory`, `sendMessage`, `sendCommand`, `getEnsembleChat`, `getGates`, `getStages`, `getWorktrees`, and `terminatePlayer`. Uses Global Maestro as the primary source with graceful fallback to per-ensemble Maestro and direct workflow list queries. `src/tui/client.ts` is a thin re-export shim for backward compatibility — new consumers should import from `src/client/` directly.
184
- - **Wire protocol**: All Temporal signal, query, update, and workflow names are documented in [`docs/WIRE-PROTOCOL.md`](docs/WIRE-PROTOCOL.md). These names are stable as of v0.10 — renaming or removing any is a breaking change requiring a major version bump. **Process**: when adding signals, queries, or updates to any workflow file (`signals.ts`, `scheduler-signals.ts`, `maestro-signals.ts`), update `docs/WIRE-PROTOCOL.md` in the same commit.
185
- - **Daemon**: A standalone background process (`src/daemon.ts`) that runs all Temporal workers. Auto-started by any claude-tempo command if not already running. PID stored at `~/.claude-tempo/daemon.pid`; logs at `~/.claude-tempo/daemon.log`. Sessions are now pure MCP clients — they no longer run in-process workers. Managed via `claude-tempo daemon start|stop|status|logs`.
186
-
187
- ## TUI Key Behaviors
188
-
189
- - **Routing**: Bare text in the TUI routes to the conductor via `sendCommand`. Prefix with `@player` to message a specific player directly (e.g. `@alice can you review this?`). When no conductor is present, bare text shows an error; use `@player` to message directly.
190
- - **Schedule management**: `/schedule` is the single entry point — no standalone `/unschedule`. Subcommands: `/schedule` (show overlay), `/schedule create` (wizard), `/schedule delete <name>` (cancel).
191
- - **Interactive overlays**: `/status`, `/schedule`, `/gates`, `/stages`, `/worktree` display dismissible overlays (via `SHOW_OVERLAY`/`StatusOverlay`). `/player`, `/ensemble` open full-screen interactive pickers (`Picker`).
192
- - **Aliases removed**: `/home`, `/maestro`, `/dashboard`, `/exit`, and `/unschedule` are **not** registered commands. Using them produces a "command not found" error. Use `/back`, `/quit`, and `/schedule delete` respectively.
193
- - **`/help <command>`**: `/help` alone shows all commands; `/help recruit` (or `/help /recruit`) shows the usage and description for a specific command in an overlay.
194
- - **NO_COLOR**: Set `NO_COLOR=1` to disable all color output — respected in both the TUI theme (`src/tui/utils/theme.ts`) and CLI output helpers (`src/cli/output.ts`). Follows the https://no-color.org/ convention.
195
- - **Terminal size requirement**: The TUI requires a minimum terminal size of **80×24**. If the terminal is smaller at launch, the process exits with code 1 with an explanatory message. A soft in-app warning appears at 60×15 during resize.
196
-
197
- ## TUI Performance (Ink/React)
198
-
199
- Hard-won lessons from debugging input lag in the TUI (#58). Apply these whenever touching `src/tui/`.
200
-
201
- - **Fullscreen bypass is permanent**: When `lastOutputHeight >= stdout.rows`, Ink permanently switches to `clearTerminal + full-rewrite` on every frame — this never resets. Every component/phase must render within `height: termRows - 1` to stay in the fast `throttledLog` path (in-place line updates).
202
- - **Animation timers poison rendering**: `setInterval`-based animations (spinners, metronomes) trigger re-renders every 80–150ms. Each re-render runs the full Yoga layout + output pipeline for all nodes. Never use animation timers in components that coexist with input areas — rapid re-renders cause input lag.
203
- - **Yoga node count: keep under ~20**: Every `<Box>` creates a Yoga layout node; every keystroke recalculates all of them. 100+ nodes = laggy input. Prefer nested `<Text>` over `<Box><Text>` — nested Text creates `ink-virtual-text` with zero Yoga nodes. Pre-format content as strings with `\n` and render as a single `<Text>`.
204
- - **Uncontrolled input pattern**: Input components must not dispatch to parent state on every keystroke. Use local `useState` + `useImperativeHandle` ref for parent communication. Guard all callbacks (e.g. `onPaletteToggle`) to only fire when values actually change — otherwise you get silent parent re-renders on every keypress.
205
- - **Reducer state identity matters**: `return { ...state, field: sameValue }` creates a new object reference and triggers a re-render even when nothing changed. Always check before spreading: `if (!state.paletteVisible && state.paletteIndex === 0) return state;`
206
- - **Stale refs between renders**: When using the ref pattern for stable `useInput` callbacks, values read from `ref.current` are only updated on React render. For values that change between renders (e.g. input value), update `ref.current.value` synchronously inside the setter — not just on render. Otherwise rapid keystrokes (e.g. holding backspace) read stale values and drop inputs.
207
- - **Debugging approach**: When diagnosing Ink lag, create minimal test apps (`.mjs`) adding one factor at a time (fullscreen, Temporal, InkProvider, real components) to isolate the cause. If the minimal app is fast but the real app is slow, the component tree is the culprit — not the infrastructure.
208
- - **Cap live message counts**: ChatView and similar message lists must limit visible messages (~20). Rendering hundreds of messages in the live Yoga tree creates 1000+ React elements that slow reconciliation and output generation. Show a "↑ N earlier messages" indicator when truncated. Future: adopt Ink's `<Static>` pattern (render-once, exit Yoga tree) like Claude Code does for scroll history.
104
+ - **Outbox**: Outbound requests (cue, report, recruit, restart, detach, destroy, …) go through the session's workflow outbox instead of directly signaling other workflows. The dispatch loop processes entries via activities, decoupling tools from cross-workflow signaling.
105
+ - **Session status**: `pending active stale | blocked` (tracked via `ClaudeTempoStatus` search attribute). See [docs/concepts.md](docs/concepts.md) for full status mechanics.
106
+ - **Per-host task queues**: `host` param on `recruit`/`restart`/`migrate` routes to `claude-tempo-{hostname}` task queue. See [docs/concepts.md](docs/concepts.md) for cross-machine recruiting details.
107
+ - **Wire protocol**: All signal/query/update names are documented in [`docs/WIRE-PROTOCOL.md`](docs/WIRE-PROTOCOL.md) and are stable renaming or removing any is a breaking change. **Process**: update `docs/WIRE-PROTOCOL.md` in the same commit as any new signal, query, or update.
108
+ - **Daemon**: Standalone background process (`src/daemon.ts`) that runs all Temporal workers. Auto-started by any `claude-tempo` command. PID at `~/.claude-tempo/daemon.pid`; logs at `~/.claude-tempo/daemon.log`.
109
+ - **Player types**: Reusable agent definitions in Claude Code's subagent format (`.md` files with YAML frontmatter). Three-tier lookup: project `.claude/agents/` user `~/.claude/agents/` shipped `examples/agents/`. Discover via `agent_types` tool or `claude-tempo agent-types` CLI. Shipped types: tempo-conductor, tempo-composer, tempo-soloist, tempo-tuner, tempo-critic, tempo-roadie, tempo-improv, tempo-liner.
209
110
 
111
+ 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).
210
112
 
211
113
  ## Commit Convention
212
114
 
@@ -219,11 +121,7 @@ Examples:
219
121
 
220
122
  ## Release Process
221
123
 
222
- **Correct order never deviate:**
223
-
224
- 1. Merge the feature PR into `main` (squash merge)
225
- 2. Bump `version` in `package.json` and add a `## [x.y.z]` entry in `CHANGELOG.md` on `main`
226
- 3. Commit: `chore: bump version to vX.Y.Z`
227
- 4. Tag the bump commit: `git tag vX.Y.Z && git push origin vX.Y.Z`
124
+ > **Release rule**: Bump `package.json` + CHANGELOG before tagging. Never tag a commit that
125
+ > doesn't match the version. Tagging prematurely publishes the old version to npm.
228
126
 
229
- The release workflow triggers on `v*` tag pushes and publishes to npm. **Never tag before the version bump commit exists on main, and never tag a commit that doesn't match the version in `package.json`.** Tagging prematurely (e.g., before a feature PR merges) publishes the old version to npm and forces a patch bump to recover.
127
+ See [docs/release-process.md](docs/release-process.md) for the full 4-step sequence.
package/README.md CHANGED
@@ -240,7 +240,7 @@ The TUI provides a chat-focused shell for managing your ensemble:
240
240
  - **Slash commands** — `/recruit`, `/status`, `/schedule`, `/gates`, `/stages`, `/worktree`, `/go` (release held), `/pause`, `/resume`, and more; type `/help` for the full list
241
241
  - **Interactive overlays and wizards** — step-by-step flows for recruiting players, creating schedules, and managing ensembles
242
242
 
243
- 📖 [TUI reference → docs/dashboard.md](docs/dashboard.md)
243
+ 📖 [TUI reference → docs/tui.md](docs/tui.md)
244
244
 
245
245
  ## Copilot Integration
246
246
 
@@ -275,7 +275,7 @@ npm link # link CLI for local testing
275
275
 
276
276
  ## Contributing
277
277
 
278
- See [CLAUDE.md](CLAUDE.md) for project structure, conventions, and development setup. Pull requests welcome — run `npm test` before submitting.
278
+ See [CLAUDE.md](CLAUDE.md) for project structure, conventions, and development setup. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the three-layer session model (workflow / adapter / process). Pull requests welcome — run `npm test` before submitting.
279
279
 
280
280
  ## Known Limitations
281
281
 
@@ -1,6 +1,6 @@
1
1
  import { Client } from '@temporalio/client';
2
2
  import { Config } from '../config';
3
- import { AgentType } from '../types';
3
+ import { AgentType, DetachReason } from '../types';
4
4
  export interface DeliverCueInput {
5
5
  ensemble: string;
6
6
  fromPlayerId: string;
@@ -40,6 +40,28 @@ export interface ReleasePlayerInput {
40
40
  ensemble: string;
41
41
  targetPlayerId: string;
42
42
  }
43
+ export interface DeliverDetachInput {
44
+ ensemble: string;
45
+ targetPlayerId: string;
46
+ reason?: DetachReason;
47
+ deadlineMs?: number;
48
+ }
49
+ export interface DeliverDestroyInput {
50
+ ensemble: string;
51
+ targetPlayerId: string;
52
+ reason?: string;
53
+ terminatedBy: string;
54
+ notifyConductor?: boolean;
55
+ }
56
+ export interface DeliverRestartInput {
57
+ ensemble: string;
58
+ targetPlayerId: string;
59
+ invokerPlayerId: string;
60
+ force?: boolean;
61
+ host?: string;
62
+ fresh?: boolean;
63
+ contextMessages?: number;
64
+ }
43
65
  export interface SpawnProcessInput {
44
66
  targetName: string;
45
67
  workDir: string;
@@ -60,28 +82,17 @@ export interface SpawnProcessInput {
60
82
  allowedTools?: string[];
61
83
  /** Custom claude binary path (from config.claudeBin). */
62
84
  claudeBin?: string;
63
- }
64
- export interface PerformEncoreInput {
65
- ensemble: string;
66
- targetPlayerId: string;
67
- fromPlayerId: string;
68
- contextMessageCount?: number;
69
- }
70
- export interface EncoreResult {
71
- workDir: string;
72
- hostname: string;
73
- isConductor: boolean;
74
- agent: AgentType;
75
- agentDefinition?: string;
76
- agentDefinitionPath?: string;
77
- nativeResolvable?: boolean;
78
- allowedTools?: string[];
79
- /** Session UUID — used for Copilot SDK sessionId and Claude Code --resume/--session-id. */
80
- sessionId?: string;
81
- temporalAddress: string;
82
- temporalNamespace: string;
83
- /** Custom claude binary path (from config.claudeBin). */
84
- claudeBin?: string;
85
+ /**
86
+ * PR-D attachment-lease handoff. When present, the workflow has already
87
+ * called `claimAttachment` and the child process should boot and invoke
88
+ * `startV2Lifecycle(workflowId, attachmentId)` to renew (rather than fresh-claim)
89
+ * the lease using the pre-assigned id. See design §8.2 step 5.
90
+ */
91
+ attachmentId?: string;
92
+ /** Pinned runId returned by `claimAttachment`; passed to the adapter for handle pinning. */
93
+ attachmentRunId?: string;
94
+ /** Resolved adapter descriptor id (e.g. 'claude-code', 'copilot'); mirrors SessionMetadata.adapterId. */
95
+ adapterId?: string;
85
96
  }
86
97
  export interface OutboxActivityResult {
87
98
  success: boolean;
@@ -97,8 +108,10 @@ export interface OutboxActivities {
97
108
  terminateSession(input: TerminateSessionInput): Promise<OutboxActivityResult>;
98
109
  startRecruitedSession(input: StartRecruitedSessionInput): Promise<RecruitResult>;
99
110
  spawnProcess(input: SpawnProcessInput): Promise<OutboxActivityResult>;
100
- performEncore(input: PerformEncoreInput): Promise<EncoreResult>;
101
111
  releasePlayer(input: ReleasePlayerInput): Promise<OutboxActivityResult>;
112
+ deliverDetach(input: DeliverDetachInput): Promise<OutboxActivityResult>;
113
+ deliverDestroy(input: DeliverDestroyInput): Promise<OutboxActivityResult>;
114
+ deliverRestart(input: DeliverRestartInput): Promise<OutboxActivityResult>;
102
115
  }
103
116
  /**
104
117
  * Create outbox delivery activities bound to a Temporal client and config.