claude-tempo 0.2.5-beta.1 → 0.3.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/README.md CHANGED
@@ -1,82 +1,18 @@
1
1
  # claude-tempo
2
2
 
3
- MCP server for multi-session Claude Code coordination via [Temporal](https://temporal.io).
3
+ Multi-session [Claude Code](https://claude.ai/code) coordination via [Temporal](https://temporal.io).
4
4
 
5
5
  Multiple Claude Code sessions discover each other, exchange messages in real time, and coordinate work — across machines, not just localhost.
6
6
 
7
- Inspired by [claude-peers](https://github.com/louislva/claude-peers-mcp) and seeing how it interacted with Claude Code's experimental channel capability. claude-tempo takes the concept further with Temporal as the coordination backbone adding durable state, cross-machine messaging, structured orchestration, and automatic stale session cleanup.
7
+ Each Claude Code session registers as a **player** in Temporal. Players discover each other with `ensemble`, exchange messages with `cue`, and coordinate work across machines, not just localhost. An optional **conductor** orchestrates the group and connects to external interfaces like Discord, Telegram, or a dashboard.
8
8
 
9
- ## How it works
10
-
11
- **claude-tempo** uses Temporal workflows as the coordination layer:
12
-
13
- - Each Claude Code session registers as a **player** (a Temporal workflow)
14
- - Players belong to an **ensemble** — a named group of sessions that can see and message each other
15
- - Players discover each other via `ensemble`, message via `cue`, and spawn new sessions via `recruit`
16
- - Players can interact directly (peer-to-peer) — no central hub required
17
- - An optional **conductor** player acts as an orchestration hub for the ensemble, connected to external interfaces like Discord or Telegram
18
-
19
- ### Ensembles
20
-
21
- An **ensemble** is an isolated group of players identified by name (e.g., `frontend`, `backend`, `default`). Players in one ensemble cannot see or message players in another — they are completely independent.
22
-
23
- Each ensemble can have:
24
- - Any number of **players** working on tasks
25
- - One optional **conductor** coordinating work and connected to external interfaces
26
-
27
- By default, all sessions join the `default` ensemble. Pass an ensemble name when starting a session to create or join a different one:
9
+ ## Installation
28
10
 
29
11
  ```bash
30
- claude-tempo conduct frontend # conduct the "frontend" ensemble
31
- claude-tempo start backend # join the "backend" ensemble
32
- claude-tempo conduct # conduct the "default" ensemble
33
- ```
34
-
35
- This lets you run separate groups of sessions for different projects or concerns without interference.
36
-
37
- ```mermaid
38
- graph TD
39
- You["You (Discord / Telegram / CLI / Claude Code)"]
40
- You -->|signal / query| Conductor
41
-
42
- subgraph Temporal["Temporal Server"]
43
- Conductor["Conductor Workflow"]
44
- PA["Player A Workflow"]
45
- PB["Player B Workflow"]
46
- PC["Player C Workflow"]
47
- Conductor -->|cue| PA
48
- Conductor -->|cue| PB
49
- Conductor -->|cue| PC
50
- end
51
-
52
- subgraph Host1["Host 1"]
53
- S1["Claude Session A"]
54
- S2["Claude Session B"]
55
- end
56
-
57
- subgraph Host2["Host 2"]
58
- S3["Claude Session C"]
59
- end
60
-
61
- PA -.-> S1
62
- PB -.-> S2
63
- PC -.-> S3
12
+ npm install -g claude-tempo
64
13
  ```
65
14
 
66
- ## Tools
67
-
68
- | Tool | Description |
69
- |------|-------------|
70
- | `ensemble` | Discover active sessions in your ensemble. Scope: `machine`, `repo`, `all`. |
71
- | `cue` | Send a message to any session by player name. Instant via Temporal signal. |
72
- | `set_name` | Set a human-readable name for this session. Used by other players to message you. |
73
- | `set_part` | Describe what you're working on. Visible to others via `ensemble`. |
74
- | `listen` | Manual fallback for checking pending messages. |
75
- | `recruit` | Start a named Claude Code session in a directory. Opens a new terminal window automatically. |
76
- | `report` | Send updates to the conductor (surfaces to Discord/Telegram). No-op if no conductor. |
77
- | `terminate` | Terminate a player session by name. Use to clean up orphaned sessions. |
78
-
79
- ## Prerequisites
15
+ ### Prerequisites
80
16
 
81
17
  - [Node.js](https://nodejs.org/) 18+
82
18
  - [Temporal CLI](https://docs.temporal.io/cli) (for local dev server)
@@ -84,25 +20,22 @@ graph TD
84
20
 
85
21
  ## Quick start
86
22
 
87
- The fastest way to get going — one command handles everything:
23
+ One command handles everything:
88
24
 
89
25
  ```bash
90
- # Install
91
- npm install -g claude-tempo
92
-
93
- # Go to your project and run `up`
94
26
  cd your-project
95
27
  claude-tempo up
96
28
  ```
97
29
 
98
- `claude-tempo up` will:
99
- 1. Check that the Temporal CLI is installed
100
- 2. Start the Temporal dev server if it's not already running (data persists in `~/.claude-tempo/`)
101
- 3. Register the required search attributes automatically
102
- 4. Create `.mcp.json` in your project if it doesn't exist
30
+ This will:
31
+
32
+ 1. Check that Temporal CLI is installed
33
+ 2. Start the Temporal dev server (data persists in `~/.claude-tempo/`)
34
+ 3. Register required search attributes
35
+ 4. Create `.mcp.json` in your project
103
36
  5. Launch a conductor session in a new terminal window
104
37
 
105
- After `up` completes, you're ready to add players:
38
+ Then add players:
106
39
 
107
40
  ```bash
108
41
  claude-tempo start # open a player session
@@ -113,10 +46,10 @@ Or ask the conductor to `recruit` players for you from inside Claude Code.
113
46
 
114
47
  ### Manual setup
115
48
 
116
- If you prefer more control, you can run each step individually:
49
+ For more control, run each step individually:
117
50
 
118
51
  ```bash
119
- # Start Temporal dev server (keep this running)
52
+ # Start Temporal dev server (keep running)
120
53
  claude-tempo server
121
54
 
122
55
  # In your project directory, create .mcp.json
@@ -133,9 +66,26 @@ claude-tempo conduct
133
66
  claude-tempo start
134
67
  ```
135
68
 
136
- ## CLI
69
+ ## Core concepts
137
70
 
138
- The `claude-tempo` CLI handles setup, session management, and diagnostics.
71
+ - **Player** A Claude Code session registered as a Temporal workflow
72
+ - **Conductor** — An optional orchestration hub connected to external interfaces (one per ensemble)
73
+ - **Ensemble** — A named group of players that can see and message each other, isolated from other ensembles
74
+ - **Cue** — A message sent to a player by name via Temporal signal
75
+
76
+ Players in one ensemble cannot see or message players in another. By default, sessions join the `default` ensemble:
77
+
78
+ ```bash
79
+ claude-tempo conduct frontend # conduct the "frontend" ensemble
80
+ claude-tempo start backend # join the "backend" ensemble
81
+ claude-tempo conduct # conduct the "default" ensemble
82
+ ```
83
+
84
+ ## CLI reference
85
+
86
+ ```
87
+ claude-tempo <command> [options]
88
+ ```
139
89
 
140
90
  ### Commands
141
91
 
@@ -147,40 +97,42 @@ The `claude-tempo` CLI handles setup, session management, and diagnostics.
147
97
  | `conduct [ensemble]` | Start a conductor session (one per ensemble) |
148
98
  | `start [ensemble]` | Start a player session |
149
99
  | `status [ensemble]` | Show active sessions and Temporal health |
100
+ | `config` | Configure Temporal connection settings (interactive or `set`/`show`) |
150
101
  | `init` | Create `.mcp.json` config in the current directory |
151
- | `preflight` | Run environment checks only |
102
+ | `preflight` | Run environment checks |
152
103
  | `help` | Show usage info |
153
104
 
154
- ### Options
105
+ ### Global options
155
106
 
156
107
  ```
157
- --temporal-address <addr> Temporal server address (default: localhost:7233)
158
- -n, --name <name> Set the player name for the session (start/conduct/up)
159
- --skip-preflight Skip preflight checks (start/conduct)
160
- --background, -d Run Temporal in background (server only)
161
- --dir <path> Target directory for init (default: cwd)
108
+ --temporal-address <addr> Temporal server address (default: localhost:7233)
109
+ --temporal-namespace <ns> Temporal namespace (default: default)
110
+ --temporal-api-key <key> Temporal Cloud API key
111
+ --temporal-tls-cert <path> mTLS client certificate path
112
+ --temporal-tls-key <path> mTLS client key path
113
+ -n, --name <name> Set the player name (start/conduct/up)
114
+ --skip-preflight Skip preflight checks (start/conduct)
115
+ -d, --dir <path> Target directory (default: cwd)
116
+ --background Run Temporal in background (server only)
162
117
  ```
163
118
 
164
- ### `up` — first-time setup
119
+ ### `claude-tempo up`
165
120
 
166
- `claude-tempo up` is the recommended way to get started. It handles everything in order:
121
+ The recommended way to get started:
167
122
 
168
123
  ```
169
124
  $ claude-tempo up myband
170
125
 
171
126
  claude-tempo setup
172
- pass temporal CLI installed
173
- ... Starting Temporal dev server...
174
- pass Temporal started (pid 12345, data in ~/.claude-tempo/)
175
- ok Registered search attribute: ClaudeTempoHostname
176
- ok Registered search attribute: ClaudeTempoGitRoot
177
- ok Registered search attribute: ClaudeTempoEnsemble
178
- ok Registered search attribute: ClaudeTempoPlayerId
179
- pass .mcp.json created
127
+ temporal CLI installed
128
+ Starting Temporal dev server...
129
+ Temporal started (pid 12345, data in ~/.claude-tempo/)
130
+ Registered search attributes
131
+ .mcp.json created
180
132
 
181
133
  Launching conductor in ensemble myband...
182
134
 
183
- ok You're all set!
135
+ You're all set!
184
136
  Conductor launched (pid 12346)
185
137
  Ensemble: myband
186
138
 
@@ -190,40 +142,20 @@ ok You're all set!
190
142
  Or ask the conductor to recruit players for you
191
143
  ```
192
144
 
193
- ### `server` — Temporal management
145
+ ### `claude-tempo server`
194
146
 
195
- `claude-tempo server` starts the Temporal dev server with automatic search attribute registration:
147
+ Starts the Temporal dev server with automatic search attribute registration:
196
148
 
197
149
  ```bash
198
150
  claude-tempo server # foreground (Ctrl+C to stop)
199
151
  claude-tempo server --background # daemonize
200
- claude-tempo server -d # shorthand
201
152
  ```
202
153
 
203
- - Stores data in `~/.claude-tempo/temporal-data.db` (persists across restarts)
204
- - Registers all required search attributes automatically
205
- - If Temporal is already running, just registers attributes and exits
154
+ Data persists in `~/.claude-tempo/temporal-data.db`. If Temporal is already running, registers attributes and exits.
206
155
 
207
- ### `init` — MCP configuration
156
+ ### `claude-tempo status`
208
157
 
209
- `claude-tempo init` creates a `.mcp.json` in the current directory (or merges into an existing one):
210
-
211
- ```json
212
- {
213
- "mcpServers": {
214
- "claude-tempo": {
215
- "command": "npx",
216
- "args": ["claude-tempo-server"]
217
- }
218
- }
219
- }
220
- ```
221
-
222
- Uses `npx` to resolve the server binary, so it works regardless of PATH configuration.
223
-
224
- ### `status` — ensemble overview
225
-
226
- `claude-tempo status` shows all active sessions:
158
+ Shows all active sessions:
227
159
 
228
160
  ```
229
161
  Ensemble: myband
@@ -242,42 +174,63 @@ Ensemble: myband
242
174
  /Users/me/projects/app feat/ui my-machine.local
243
175
  ```
244
176
 
245
- ### `preflight` — environment checks
177
+ ### `claude-tempo preflight`
178
+
179
+ Verifies your environment: Node.js >= 18, Temporal reachable, `claude` on PATH, `claude-tempo-server` on PATH, `.mcp.json` configured.
180
+
181
+ ### `claude-tempo init`
182
+
183
+ Creates `.mcp.json` in the current directory (or merges into an existing one):
184
+
185
+ ```json
186
+ {
187
+ "mcpServers": {
188
+ "claude-tempo": {
189
+ "command": "npx",
190
+ "args": ["claude-tempo-server"]
191
+ }
192
+ }
193
+ }
194
+ ```
195
+
196
+ ## MCP tools
246
197
 
247
- `claude-tempo preflight` verifies your environment:
198
+ These tools are available inside Claude Code sessions connected to claude-tempo:
248
199
 
249
- - Node.js >= 18
250
- - Temporal server reachable
251
- - `claude` binary on PATH
252
- - `claude-tempo-server` binary on PATH
253
- - `.mcp.json` configured in the current directory
200
+ | Tool | Description |
201
+ |------|-------------|
202
+ | `ensemble` | Discover active sessions. Scope: `machine`, `repo`, or `all`. |
203
+ | `cue` | Send a message to a player by name. Delivered instantly via Temporal signal. |
204
+ | `set_name` | Set a human-readable name for this session. |
205
+ | `set_part` | Describe what you're working on. Visible to others via `ensemble`. |
206
+ | `listen` | Manually check for pending messages. |
207
+ | `recruit` | Spawn a new Claude Code session in a directory. Opens a new terminal window. |
208
+ | `report` | Send updates to the conductor. No-op if no conductor exists. |
209
+ | `terminate` | Terminate a player session by name. |
254
210
 
255
- ## Starting a conductor
211
+ ## Conductors
256
212
 
257
- A **conductor** is an optional special player that acts as an orchestration hub for the ensemble. Use a conductor when you want:
213
+ A **conductor** is an optional special player that acts as an orchestration hub. Use one when you want:
258
214
 
259
215
  - A single session coordinating work across multiple players
260
216
  - External access to the ensemble via Discord, Telegram, or any Temporal client
261
217
  - A central point for players to `report` progress, blockers, and questions
262
218
 
263
- Without a conductor, players still work fine — they discover each other via `ensemble` and communicate directly via `cue`. The conductor is a hub, not a gatekeeper.
264
-
265
- There is one conductor per ensemble. Start one with:
219
+ Without a conductor, players work fine peer-to-peer — they discover each other via `ensemble` and communicate via `cue`.
266
220
 
267
221
  ```bash
268
- claude-tempo conduct # conductor in "default" ensemble
269
- claude-tempo conduct my-project # conductor in "my-project" ensemble
222
+ claude-tempo conduct # default ensemble
223
+ claude-tempo conduct my-project # named ensemble
270
224
  ```
271
225
 
272
226
  ### External access
273
227
 
274
- The conductor's Temporal workflow exposes a signal/query API that anyone can use — no Claude Code session needed:
228
+ The conductor's Temporal workflow exposes a signal/query API:
275
229
 
276
230
  ```typescript
277
231
  import { Client } from '@temporalio/client';
278
232
 
279
233
  const client = new Client();
280
- // Conductor workflow ID: claude-session-{ensemble}-conductor
281
234
  const conductor = client.workflow.getHandle('claude-session-default-conductor');
282
235
 
283
236
  // Send a command
@@ -286,11 +239,11 @@ await conductor.signal('command', {
286
239
  source: 'cli',
287
240
  });
288
241
 
289
- // Check history of commands and reports
242
+ // Check history
290
243
  const history = await conductor.query('history');
291
244
  ```
292
245
 
293
- You can also connect external channel plugins (e.g., Discord):
246
+ Connect external channel plugins (e.g., Discord):
294
247
 
295
248
  ```bash
296
249
  CLAUDE_TEMPO_CONDUCTOR=true claude \
@@ -298,170 +251,200 @@ CLAUDE_TEMPO_CONDUCTOR=true claude \
298
251
  --dangerously-skip-permissions --dangerously-load-development-channels server:claude-tempo
299
252
  ```
300
253
 
301
- ## Starting players
254
+ ## Players
302
255
 
303
- The recommended way to build an ensemble is to use the CLI to start sessions. Each session opens in a new terminal window with the full shell environment preserved.
256
+ ### Starting players
304
257
 
305
258
  ```bash
306
259
  # Terminal 1 — conductor
307
260
  claude-tempo conduct my-project
308
261
 
309
- # Terminal 2 — frontend player
262
+ # Terminal 2 — frontend
310
263
  claude-tempo start my-project -n frontend
311
264
 
312
- # Terminal 3 — backend player
265
+ # Terminal 3 — backend
313
266
  claude-tempo start my-project -n backend
314
267
  ```
315
268
 
316
- Or let the conductor `recruit` players directly — this spawns new terminal windows automatically.
269
+ Or let the conductor `recruit` players — this spawns new terminal windows automatically.
317
270
 
318
- Once sessions are running, try:
271
+ Inside a session, try:
319
272
  - "Show me the ensemble" — discovers other sessions
320
- - "Set your name to 'frontend'" — gives your session a human-readable name
321
- - "Cue frontend: what are you working on?" — sends a message by name
273
+ - "Set your name to 'frontend'" — human-readable name
274
+ - "Cue frontend: what are you working on?" — sends a message
322
275
 
323
- ### Terminal support
276
+ ### Session naming
324
277
 
325
- The `recruit` tool and CLI automatically detect and open sessions in your terminal:
278
+ Sessions start with a random 8-character hex ID. Set a name at launch with `-n` or use `set_name` inside a session.
326
279
 
327
- | Terminal | macOS | Linux | Windows |
328
- |----------|-------|-------|---------|
329
- | Ghostty | `initial input` via AppleScript | | |
330
- | iTerm2 | `write text` via AppleScript | — | — |
331
- | Terminal.app | `.command` file | | |
332
- | gnome-terminal | — | `--` flag | — |
333
- | konsole / xterm | — | `-e` flag | — |
334
- | cmd.exe / PowerShell | — | — | `start` command |
280
+ - Names are stored as Temporal search attributes (`ClaudeTempoPlayerId`)
281
+ - Other players use names to send messages via `cue`
282
+ - `recruit` automatically tells new sessions to set their name
283
+ - Names must be unique within an ensemble
284
+ - Names must contain only letters, numbers, hyphens, and underscores
335
285
 
336
- All macOS terminals use approaches that preserve the user's full shell environment (fish, zsh, bash) including node version managers (fnm, nvm).
286
+ ### Terminal support
337
287
 
338
- ### Session naming
288
+ `recruit` and the CLI detect your terminal automatically:
339
289
 
340
- Sessions start with a random 8-character hex ID. You can set a name at launch with `-n` or use `set_name` inside a session:
290
+ | Terminal | macOS | Linux | Windows |
291
+ |----------|-------|-------|---------|
292
+ | Ghostty | ✓ | — | — |
293
+ | iTerm2 | ✓ | — | — |
294
+ | Terminal.app | ✓ | — | — |
295
+ | gnome-terminal | — | ✓ | — |
296
+ | konsole / xterm | — | ✓ | — |
297
+ | cmd.exe / PowerShell | — | — | ✓ |
341
298
 
342
- - Names are stored as Temporal search attributes (`ClaudeTempoPlayerId`) and updated in-place no workflow restart needed
343
- - Other players use the name to send messages via `cue` and discover sessions via `ensemble`
344
- - `recruit` automatically tells the new session to set its name
345
- - Names must be unique within an ensemble — `set_name` rejects duplicates
346
- - Names must contain only letters, numbers, hyphens, and underscores
299
+ macOS terminals preserve the full shell environment (fish, zsh, bash) including node version managers (fnm, nvm).
347
300
 
348
301
  ## Configuration
349
302
 
350
- | Environment Variable | Default | Description |
351
- |---------------------|---------|-------------|
352
- | `TEMPORAL_ADDRESS` | `localhost:7233` | Temporal server address |
353
- | `TEMPORAL_NAMESPACE` | `default` | Temporal namespace |
354
- | `CLAUDE_TEMPO_TASK_QUEUE` | `claude-tempo` | Task queue name |
355
- | `CLAUDE_TEMPO_ENSEMBLE` | `default` | Ensemble name (isolates groups of players) |
356
- | `CLAUDE_TEMPO_CONDUCTOR` | `false` | Set to `true` to enable conductor mode |
357
- | `CLAUDE_TEMPO_PLAYER_NAME` | *(random hex)* | Set a player name on startup (used by `-n` flag) |
303
+ Run `claude-tempo config` to save Temporal connection settings so you don't need flags or env vars every time:
358
304
 
359
- ## Development
305
+ ```
306
+ $ claude-tempo config
307
+
308
+ ? Temporal address (localhost:7233): my-ns.tmprl.cloud:7233
309
+ ? Temporal namespace (default): my-ns.abc123
310
+ ? Auth method: (None / API key / mTLS)
311
+ ? API key: ****
312
+ Saved to ~/.claude-tempo/config.json
313
+ ✓ Connected successfully
314
+ ```
315
+
316
+ Settings are stored in `~/.claude-tempo/config.json`. You can also set values non-interactively:
360
317
 
361
318
  ```bash
362
- # Clone and install
363
- git clone https://github.com/vinceblank/claude-tempo.git
364
- cd claude-tempo && npm install
319
+ claude-tempo config set temporalAddress my-ns.tmprl.cloud:7233
320
+ claude-tempo config set temporalNamespace my-ns.abc123
321
+ claude-tempo config set temporalApiKey tcl_...
322
+ claude-tempo config show
323
+ ```
365
324
 
366
- # Build (compiles TypeScript and pre-bundles workflow code)
367
- npm run build
325
+ ### Resolution order
368
326
 
369
- # Run MCP server in development
370
- npx ts-node src/server.ts
327
+ Settings are resolved in this order (first match wins):
371
328
 
372
- # Link CLI for local testing
373
- npm link
374
- ```
329
+ 1. CLI flags (`--temporal-address`, `--temporal-namespace`, etc.)
330
+ 2. Environment variables (`TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, etc.)
331
+ 3. claude-tempo config file (`~/.claude-tempo/config.json`)
332
+ 4. Temporal CLI config (`~/.config/temporalio/temporal.yaml`) — if you've already configured the Temporal CLI, claude-tempo reads it automatically
333
+ 5. Defaults (`localhost:7233`, `default` namespace)
375
334
 
376
- > **Important**: Run `npm run build` after changing workflow code (`src/workflows/`). The build pre-bundles workflows into `workflow-bundle.js` so all workers use identical code.
335
+ ### Temporal Cloud
377
336
 
378
- ## Why Temporal?
337
+ For Temporal Cloud, run `claude-tempo config` and provide your cloud address, namespace, and API key. Or set them as environment variables in CI:
379
338
 
380
- - **Cross-machine**: Any session that can reach the Temporal server can join the ensemble
381
- - **Instant signaling**: Temporal signals deliver messages between sessions with no broker polling
382
- - **Durable history**: Full audit trail of every message in Temporal's event history
383
- - **No custom infrastructure**: No broker daemon, no database — just Temporal
384
- - **Extensible**: The conductor's signal/query contract is a public API anyone can build on
339
+ ```bash
340
+ export TEMPORAL_ADDRESS=my-ns.abc123.tmprl.cloud:7233
341
+ export TEMPORAL_NAMESPACE=my-ns.abc123
342
+ export TEMPORAL_API_KEY=tcl_...
343
+ ```
385
344
 
386
- ## Stale session cleanup
345
+ ## Environment variables
387
346
 
388
- When a Claude Code session crashes or is closed without graceful shutdown, its Temporal workflow detects the problem automatically:
347
+ | Variable | Default | Description |
348
+ |----------|---------|-------------|
349
+ | `TEMPORAL_ADDRESS` | `localhost:7233` | Temporal server address |
350
+ | `TEMPORAL_NAMESPACE` | `default` | Temporal namespace |
351
+ | `TEMPORAL_API_KEY` | *(none)* | Temporal Cloud API key |
352
+ | `TEMPORAL_TLS_CERT_PATH` | *(none)* | mTLS client certificate path |
353
+ | `TEMPORAL_TLS_KEY_PATH` | *(none)* | mTLS client key path |
354
+ | `CLAUDE_TEMPO_TASK_QUEUE` | `claude-tempo` | Task queue name |
355
+ | `CLAUDE_TEMPO_ENSEMBLE` | `default` | Ensemble name |
356
+ | `CLAUDE_TEMPO_CONDUCTOR` | `false` | Enable conductor mode |
357
+ | `CLAUDE_TEMPO_PLAYER_NAME` | *(random hex)* | Player name on startup |
389
358
 
390
- - If a message is sent to a dead session and remains undelivered for **3 minutes**, the workflow self-completes
391
- - Before exiting, it notifies the conductor with the undelivered message content so work can be reassigned
392
- - Idle sessions with no pending messages remain running (they aren't hurting anyone) until the 24-hour execution timeout
359
+ ## Stale session cleanup
393
360
 
394
- This means you don't need to manually clean up crashed sessions just `cue` the dead player and the system handles the rest.
361
+ When a session crashes or closes without graceful shutdown, Temporal detects it automatically:
395
362
 
396
- ## Known limitations
363
+ - If a message to a dead session remains undelivered for **3 minutes**, the workflow self-completes
364
+ - Before exiting, it notifies the conductor with the undelivered message so work can be reassigned
365
+ - Idle sessions with no pending messages remain running until the 24-hour timeout
397
366
 
398
- - **`recruit` requires manual acknowledgment**: Recruited Claude Code sessions use `--dangerously-load-development-channels` to enable channel-based message delivery. Claude Code shows an interactive confirmation prompt that must be manually acknowledged (press Enter) in the spawned terminal window. This will be resolved once claude-tempo is published as an approved channel plugin. Copilot bridge sessions do not have this limitation.
367
+ No manual cleanup needed `cue` a dead player and the system handles the rest.
399
368
 
400
369
  ## Copilot CLI integration (experimental)
401
370
 
402
- > **Warning:** Copilot bridge support is **experimental** and subject to breaking changes. Copilot bridge sessions are headless — they have no interactive terminal. A Claude conductor (or custom Temporal client) is required to send them work via `cue`. Do not rely on this feature for production workflows.
371
+ > **Warning:** Copilot bridge support is experimental and subject to breaking changes.
403
372
 
404
- GitHub Copilot CLI sessions can join an ensemble via the **Copilot bridge**. The bridge uses the [Copilot SDK](https://github.com/github/copilot-sdk) to spawn a Copilot session with claude-tempo as an MCP server, and injects incoming messages as prompts.
373
+ GitHub Copilot CLI sessions can join an ensemble via the Copilot bridge. Bridge sessions are headless they require a Claude conductor or custom Temporal client to receive work via `cue`.
405
374
 
406
- ### Setup
375
+ <details>
376
+ <summary>Setup and usage</summary>
407
377
 
408
- The Copilot SDK is an optional dependency — install it only if you want Copilot support:
378
+ ### Prerequisites
409
379
 
410
380
  ```bash
411
- npm install @github/copilot-sdk
381
+ npm install @github/copilot-sdk # optional dependency (~243MB)
412
382
  ```
413
383
 
414
- You also need:
415
- - [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli) installed and authenticated
416
- - An active GitHub Copilot subscription
384
+ Also requires [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli) installed, authenticated, with an active subscription. Node 20+ required for Copilot features.
417
385
 
418
386
  ### Starting a Copilot player
419
387
 
420
- The easiest way to add a Copilot player is via the `recruit` tool from any active session in the ensemble. The `agent` parameter accepts `"claude"` (default) or `"copilot"`:
388
+ The easiest way is via `recruit` from any active session:
421
389
 
422
390
  > "Recruit a copilot session named 'copilot-dev' in /repos/my-project with agent copilot"
423
391
 
424
- This spawns a headless bridge process, registers it as a Temporal workflow, and sets the player name automatically.
425
-
426
- <details>
427
- <summary>Advanced: running the bridge directly</summary>
428
-
429
- You can also start the bridge manually with environment variables:
392
+ Or start the bridge directly:
430
393
 
431
394
  ```bash
432
- # Linux/macOS
433
395
  CLAUDE_TEMPO_ENSEMBLE=default COPILOT_BRIDGE_NAME=copilot-dev npx ts-node src/copilot-bridge.ts
434
-
435
- # Windows PowerShell
436
- $env:TEMPORAL_ADDRESS="localhost:7233"; $env:CLAUDE_TEMPO_ENSEMBLE="default"; $env:COPILOT_BRIDGE_NAME="copilot-dev"; npx ts-node src/copilot-bridge.ts
437
396
  ```
438
397
 
439
- </details>
440
-
441
398
  ### How it works
442
399
 
443
- 1. The bridge spawns a Copilot CLI session via the SDK with claude-tempo configured as an MCP server
444
- 2. The MCP server registers the session as a Temporal workflow (same as Claude Code players)
445
- 3. An initial prompt is sent to trigger MCP server initialization (the SDK lazily starts MCP servers)
446
- 4. The bridge polls the workflow for pending messages every 2 seconds
447
- 5. When messages arrive, they're injected as prompts via `session.sendAndWait()`
448
- 6. The Copilot session can use all claude-tempo tools (`ensemble`, `cue`, `report`, etc.)
400
+ 1. Bridge spawns a Copilot CLI session via the SDK with claude-tempo as MCP server
401
+ 2. MCP server registers the session as a Temporal workflow
402
+ 3. Bridge polls for pending messages every 2 seconds
403
+ 4. Messages are injected as prompts via `session.sendAndWait()`
404
+ 5. The Copilot session can use all claude-tempo tools
449
405
 
450
- ### Environment variables
406
+ ### Copilot environment variables
451
407
 
452
408
  | Variable | Default | Description |
453
409
  |----------|---------|-------------|
454
- | `COPILOT_BRIDGE_NAME` | *(none)* | Player name (calls `set_name` automatically) |
455
- | `COPILOT_BRIDGE_MODEL` | *(Copilot default)* | Model override for the Copilot session |
410
+ | `COPILOT_BRIDGE_NAME` | *(none)* | Player name |
411
+ | `COPILOT_BRIDGE_MODEL` | *(Copilot default)* | Model override |
456
412
  | `GITHUB_TOKEN` | *(logged-in user)* | GitHub auth token |
457
413
 
458
414
  ### Limitations
459
415
 
460
- - **No interactive access**Copilot bridge sessions run in the background. Unlike Claude Code sessions where you can chat directly, bridge sessions only respond to cues from other players. To send messages to a bridge session, use `cue` from another player or signal the workflow directly via the Temporal CLI.
461
- - **Polling latency** the bridge polls for messages every 2 seconds, unlike Claude Code sessions which receive instant channel notifications. This adds slight latency to message delivery and orchestration.
462
- - **Copilot sessions must be spawned via the bridge** to participate (not standalone Copilot CLI).
463
- - **The `@github/copilot-sdk` adds ~243MB** to node_modules when installed.
464
- - **Node 20+ required for Copilot features** — the `@github/copilot-sdk` requires Node.js 20 or later. The rest of claude-tempo works on Node 18+.
416
+ - No interactive access — bridge sessions only respond to cues
417
+ - 2-second polling latency (vs instant for Claude Code sessions)
418
+ - Must be spawned via the bridge to participate
419
+ - `@github/copilot-sdk` adds ~243MB to node_modules
420
+ - Node 20+ required (rest of claude-tempo works on Node 18+)
421
+
422
+ </details>
423
+
424
+ ## Development
425
+
426
+ ```bash
427
+ git clone https://github.com/vinceblank/claude-tempo.git
428
+ cd claude-tempo && npm install
429
+
430
+ npm run build # compile TypeScript + pre-bundle workflows
431
+ npm test # run tests
432
+ npm link # link CLI for local testing
433
+ ```
434
+
435
+ > **Important**: Run `npm run build` after changing workflow code (`src/workflows/`). The build pre-bundles workflows into `workflow-bundle.js` so all workers use identical code.
436
+
437
+ ## Why Temporal?
438
+
439
+ - **Cross-machine** — Any session that can reach the Temporal server can join
440
+ - **Instant signaling** — Temporal signals deliver messages with no polling
441
+ - **Durable history** — Full audit trail in Temporal's event history
442
+ - **No custom infrastructure** — No broker, no database — just Temporal
443
+ - **Extensible** — The conductor's signal/query contract is a public API
444
+
445
+ ## Known limitations
446
+
447
+ - **`recruit` requires manual acknowledgment** — Recruited sessions use `--dangerously-load-development-channels`. Claude Code shows a confirmation prompt that must be manually acknowledged in the spawned terminal. This will be resolved once claude-tempo is published as an approved channel plugin. Copilot bridge sessions do not have this limitation.
465
448
 
466
449
  ## License
467
450