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