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.
- package/CLAUDE.md +48 -150
- package/README.md +2 -2
- package/dist/activities/outbox.d.ts +37 -24
- package/dist/activities/outbox.js +201 -77
- package/dist/adapters/base.d.ts +150 -0
- package/dist/adapters/base.js +341 -0
- package/dist/adapters/claude-code/adapter.d.ts +78 -0
- package/dist/adapters/claude-code/adapter.js +171 -0
- package/dist/adapters/claude-code/index.d.ts +15 -0
- package/dist/adapters/claude-code/index.js +20 -0
- package/dist/adapters/copilot/adapter.d.ts +100 -0
- package/dist/adapters/copilot/adapter.js +730 -0
- package/dist/adapters/copilot/index.d.ts +15 -0
- package/dist/adapters/copilot/index.js +20 -0
- package/dist/adapters/index.d.ts +24 -0
- package/dist/adapters/index.js +35 -0
- package/dist/adapters/sdk/base.d.ts +95 -0
- package/dist/adapters/sdk/base.js +134 -0
- package/dist/cli/commands.d.ts +34 -2
- package/dist/cli/commands.js +466 -99
- package/dist/cli.js +126 -9
- package/dist/client/index.js +52 -4
- package/dist/client/interface.d.ts +31 -3
- package/dist/config.d.ts +95 -0
- package/dist/config.js +101 -1
- package/dist/daemon.d.ts +52 -1
- package/dist/daemon.js +302 -8
- package/dist/reconcile/orphans.d.ts +72 -0
- package/dist/reconcile/orphans.js +72 -0
- package/dist/server.js +44 -23
- package/dist/spawn.d.ts +8 -0
- package/dist/spawn.js +10 -3
- package/dist/tools/attachment-info.d.ts +4 -0
- package/dist/tools/attachment-info.js +48 -0
- package/dist/tools/destroy.d.ts +4 -0
- package/dist/tools/destroy.js +45 -0
- package/dist/tools/{stop.d.ts → detach.d.ts} +1 -1
- package/dist/tools/detach.js +45 -0
- package/dist/tools/{encore.d.ts → migrate.d.ts} +1 -1
- package/dist/tools/migrate.js +60 -0
- package/dist/tools/restart.d.ts +31 -0
- package/dist/tools/restart.js +123 -0
- package/dist/tui/App.js +16 -18
- package/dist/tui/commands.d.ts +19 -0
- package/dist/tui/commands.js +188 -44
- package/dist/tui/components/ChatView.d.ts +13 -1
- package/dist/tui/components/ChatView.js +24 -2
- package/dist/tui/components/PlayerDetailView.d.ts +10 -1
- package/dist/tui/components/PlayerDetailView.js +19 -4
- package/dist/tui/index.js +6 -1
- package/dist/tui/store.d.ts +5 -2
- package/dist/tui/store.js +8 -3
- package/dist/tui/utils/format.d.ts +9 -0
- package/dist/tui/utils/format.js +15 -0
- package/dist/types.d.ts +208 -7
- package/dist/utils/validation.d.ts +4 -2
- package/dist/utils/validation.js +5 -3
- package/dist/worker.js +4 -1
- package/dist/workflows/session.js +677 -129
- package/dist/workflows/signals.d.ts +108 -6
- package/dist/workflows/signals.js +76 -4
- package/examples/agents/tempo-composer.md +2 -0
- package/examples/agents/tempo-conductor.md +32 -7
- package/examples/agents/tempo-critic.md +1 -0
- package/examples/agents/tempo-improv.md +17 -0
- package/examples/agents/tempo-liner.md +17 -0
- package/examples/agents/tempo-roadie.md +4 -1
- package/examples/agents/tempo-soloist.md +16 -0
- package/examples/agents/tempo-tuner.md +17 -0
- package/package.json +9 -4
- package/packaging/launchd/com.claude.tempo.plist +46 -0
- package/packaging/systemd/claude-tempo.service +32 -0
- package/packaging/windows/install-task.ps1 +71 -0
- package/workflow-bundle.js +754 -134
- package/dist/channel.d.ts +0 -3
- package/dist/channel.js +0 -48
- package/dist/copilot-bridge.d.ts +0 -22
- package/dist/copilot-bridge.js +0 -509
- package/dist/tools/encore.js +0 -56
- 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
|
-
├──
|
|
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
|
|
41
|
-
│ ├── maestro-signals.ts
|
|
42
|
-
│
|
|
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,
|
|
46
|
-
│ ├── maestro.ts # Maestro activities
|
|
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
|
|
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
|
|
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
|
|
56
|
-
│ ├──
|
|
57
|
-
│ ├──
|
|
58
|
-
│ ├──
|
|
59
|
-
│ ├──
|
|
60
|
-
│ ├──
|
|
61
|
-
│ ├──
|
|
62
|
-
│ ├──
|
|
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
|
-
│ ├──
|
|
87
|
-
│ ├──
|
|
88
|
-
│ ├──
|
|
89
|
-
│
|
|
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
|
|
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
|
-
> **
|
|
151
|
-
>
|
|
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
|
-
|
|
154
|
-
|
|
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
|
-
- **
|
|
165
|
-
- **
|
|
166
|
-
- **
|
|
167
|
-
- **
|
|
168
|
-
- **
|
|
169
|
-
- **
|
|
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
|
-
**
|
|
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
|
-
|
|
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/
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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.
|