claude-tempo 0.9.0 → 0.10.0
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 +15 -1
- package/README.md +81 -18
- package/dist/activities/outbox.d.ts +5 -0
- package/dist/activities/outbox.js +19 -3
- package/dist/cli/commands.d.ts +6 -1
- package/dist/cli/commands.js +202 -40
- package/dist/cli.js +9 -3
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/ensemble/agent-types.d.ts +23 -0
- package/dist/ensemble/agent-types.js +125 -0
- package/dist/ensemble/loader.d.ts +3 -3
- package/dist/ensemble/loader.js +20 -14
- package/dist/ensemble/saver.d.ts +6 -6
- package/dist/ensemble/saver.js +14 -12
- package/dist/ensemble/schema.d.ts +7 -1
- package/dist/ensemble/schema.js +1 -1
- package/dist/server.js +27 -4
- package/dist/tools/agent-types.d.ts +2 -0
- package/dist/tools/agent-types.js +18 -0
- package/dist/tools/ensemble.js +5 -1
- package/dist/tools/load-ensemble.js +22 -4
- package/dist/tools/load-lineup.d.ts +5 -0
- package/dist/tools/load-lineup.js +303 -0
- package/dist/tools/recruit.js +31 -1
- package/dist/tools/save-lineup.d.ts +4 -0
- package/dist/tools/save-lineup.js +43 -0
- package/dist/tools/who-am-i.d.ts +3 -0
- package/dist/tools/who-am-i.js +24 -0
- package/dist/types.d.ts +21 -0
- package/dist/workflows/session.js +11 -0
- package/dist/workflows/signals.d.ts +2 -0
- package/examples/agents/tempo-composer.md +44 -0
- package/examples/agents/tempo-conductor.md +52 -0
- package/examples/agents/tempo-critic.md +45 -0
- package/examples/agents/tempo-improv.md +47 -0
- package/examples/agents/tempo-liner.md +48 -0
- package/examples/agents/tempo-roadie.md +48 -0
- package/examples/agents/tempo-soloist.md +45 -0
- package/examples/agents/tempo-tuner.md +49 -0
- package/examples/ensembles/tempo-big-band.yaml +146 -0
- package/examples/ensembles/tempo-dev-team.yaml +58 -0
- package/examples/ensembles/tempo-jam-session.yaml +41 -0
- package/examples/ensembles/tempo-review-squad.yaml +32 -0
- package/package.json +2 -1
- package/workflow-bundle.js +12 -1
package/CLAUDE.md
CHANGED
|
@@ -24,16 +24,28 @@ src/
|
|
|
24
24
|
├── activities/
|
|
25
25
|
│ ├── outbox.ts # Outbox delivery activities (cue, report, stop, recruit)
|
|
26
26
|
│ └── schedule-fire.ts # Schedule fire activity
|
|
27
|
+
├── ensemble/
|
|
28
|
+
│ ├── schema.ts # Lineup type definitions
|
|
29
|
+
│ ├── loader.ts # Load and validate YAML lineups
|
|
30
|
+
│ ├── saver.ts # Save live ensemble state to YAML
|
|
31
|
+
│ └── agent-types.ts # Agent type discovery, resolution, and lineup resolution
|
|
27
32
|
├── tools/
|
|
28
33
|
│ ├── ensemble.ts # Discover active sessions
|
|
29
34
|
│ ├── cue.ts # Send message to peer (via outbox)
|
|
30
35
|
│ ├── set-name.ts # Set session name
|
|
31
36
|
│ ├── set-part.ts # Update own summary
|
|
37
|
+
│ ├── who-am-i.ts # Query own identity, role, and session details
|
|
38
|
+
│ ├── agent-types.ts # Discover available player types (agent definitions)
|
|
32
39
|
│ ├── resolve.ts # Search-attribute session lookup
|
|
33
40
|
│ ├── listen.ts # Manual message check
|
|
34
|
-
│ ├── recruit.ts # Spawn new session (via outbox)
|
|
41
|
+
│ ├── recruit.ts # Spawn new session (via outbox), supports `type` param
|
|
35
42
|
│ ├── report.ts # Report to conductor (via outbox)
|
|
36
43
|
│ ├── stop.ts # Stop a session (via outbox)
|
|
44
|
+
│ ├── load-lineup.ts # Load an ensemble lineup, recruit players
|
|
45
|
+
│ ├── save-lineup.ts # Save current ensemble state as a lineup
|
|
46
|
+
│ ├── schedule.ts # Create one-shot or recurring schedules
|
|
47
|
+
│ ├── unschedule.ts # Cancel a named schedule
|
|
48
|
+
│ ├── schedules.ts # List active schedules
|
|
37
49
|
│ └── helpers.ts # Zod/MCP tool registration wrapper
|
|
38
50
|
├── types.ts # Shared type definitions
|
|
39
51
|
├── channel.ts # Claude channel notification helper
|
|
@@ -79,6 +91,8 @@ npm test
|
|
|
79
91
|
- **Session status**: Each session has a status (`pending` → `active` → `stale`) tracked via `ClaudeTempoStatus` search attribute. Pre-created workflows start as `pending`, transition to `active` when the process connects, and become `stale` if messages go undelivered for 3+ minutes.
|
|
80
92
|
- **Outbox**: Outbound requests (cue, report, stop, recruit) go through the session's own workflow outbox instead of directly signaling other workflows. The workflow's dispatch loop processes entries via activities, decoupling tools from cross-workflow signaling.
|
|
81
93
|
- **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.
|
|
94
|
+
- **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.
|
|
95
|
+
- **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).
|
|
82
96
|
|
|
83
97
|
## Dashboard
|
|
84
98
|
|
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ claude-tempo <command> [options]
|
|
|
98
98
|
|
|
99
99
|
| Command | Description |
|
|
100
100
|
|---------|-------------|
|
|
101
|
-
| `up [ensemble]` | First-time setup: start Temporal, configure MCP, launch conductor. Use `--
|
|
101
|
+
| `up [ensemble]` | First-time setup: start Temporal, configure MCP, launch conductor. Use `--lineup` to load a lineup. |
|
|
102
102
|
| `down` | Stop Temporal, terminate sessions, remove MCP config |
|
|
103
103
|
| `server` | Start the Temporal dev server and register search attributes |
|
|
104
104
|
| `conduct [ensemble]` | Start a conductor session (one per ensemble). Use `--resume` or `--replace` if one exists. |
|
|
@@ -108,7 +108,8 @@ claude-tempo <command> [options]
|
|
|
108
108
|
| `stop [ensemble]` | Stop sessions (`-n <name>` for one, `--all` for everything) |
|
|
109
109
|
| `init` | Register claude-tempo MCP server globally (`--project` for per-directory) |
|
|
110
110
|
| `preflight` | Run environment checks |
|
|
111
|
-
| `ensemble <sub>` | Manage saved
|
|
111
|
+
| `ensemble <sub>` | Manage saved lineups (`save`, `list`, `show`) |
|
|
112
|
+
| `agent-types <sub>` | Manage player types (`list`, `show <name>`, `init`) |
|
|
112
113
|
| `help` | Show usage info |
|
|
113
114
|
|
|
114
115
|
### Global options
|
|
@@ -123,7 +124,7 @@ claude-tempo <command> [options]
|
|
|
123
124
|
--skip-preflight Skip preflight checks (start/conduct)
|
|
124
125
|
-d, --dir <path> Target directory (default: cwd)
|
|
125
126
|
--background Run Temporal in background (server only)
|
|
126
|
-
--
|
|
127
|
+
--lineup <name|file> Load an ensemble lineup by name or file path (up only)
|
|
127
128
|
--resume Resume an existing conductor session (conduct only)
|
|
128
129
|
--replace Stop existing conductor and start fresh (conduct only)
|
|
129
130
|
```
|
|
@@ -221,8 +222,10 @@ These tools are available inside Claude Code sessions connected to claude-tempo:
|
|
|
221
222
|
| `schedule` | Create a one-shot or recurring schedule to cue a player. |
|
|
222
223
|
| `unschedule` | Cancel a named schedule. |
|
|
223
224
|
| `schedules` | List all active schedules. |
|
|
224
|
-
| `
|
|
225
|
-
| `
|
|
225
|
+
| `who_am_i` | Get your identity, role, player type, and session details. |
|
|
226
|
+
| `agent_types` | List available player types with name, description, and source. |
|
|
227
|
+
| `save_lineup` | Save the current ensemble as a YAML lineup (conductor only). |
|
|
228
|
+
| `load_lineup` | Load a lineup to recruit players and create schedules. |
|
|
226
229
|
|
|
227
230
|
## Scheduling
|
|
228
231
|
|
|
@@ -255,11 +258,11 @@ Schedules support one-shot delays, fixed times, and recurring intervals with opt
|
|
|
255
258
|
- `claude-tempo status` shows active schedules alongside sessions
|
|
256
259
|
- A single durable scheduler workflow per ensemble manages all schedules using Temporal timers
|
|
257
260
|
|
|
258
|
-
## Ensemble
|
|
261
|
+
## Ensemble Lineups
|
|
259
262
|
|
|
260
|
-
Define reusable ensemble configurations as YAML files. A
|
|
263
|
+
Define reusable ensemble configurations as YAML files. A lineup specifies which players to recruit, what instructions to give them, what schedules to create, and optionally which custom agent files to use.
|
|
261
264
|
|
|
262
|
-
### Example
|
|
265
|
+
### Example lineup
|
|
263
266
|
|
|
264
267
|
```yaml
|
|
265
268
|
name: my-project
|
|
@@ -287,29 +290,29 @@ schedules:
|
|
|
287
290
|
delay: 10m
|
|
288
291
|
```
|
|
289
292
|
|
|
290
|
-
### Three ways to use
|
|
293
|
+
### Three ways to use lineups
|
|
291
294
|
|
|
292
|
-
1. **From the CLI** — load a
|
|
295
|
+
1. **From the CLI** — load a lineup when starting an ensemble:
|
|
293
296
|
|
|
294
297
|
```bash
|
|
295
|
-
claude-tempo up --
|
|
298
|
+
claude-tempo up --lineup my-lineup.yaml
|
|
296
299
|
```
|
|
297
300
|
|
|
298
|
-
2. **From inside a session** — use the `
|
|
301
|
+
2. **From inside a session** — use the `load_lineup` tool:
|
|
299
302
|
|
|
300
|
-
*"Load the
|
|
303
|
+
*"Load the lineup from ~/.claude-tempo/ensembles/my-project.yaml"*
|
|
301
304
|
|
|
302
|
-
3. **Save the current state** — snapshot a running ensemble as a
|
|
305
|
+
3. **Save the current state** — snapshot a running ensemble as a lineup (conductor only):
|
|
303
306
|
|
|
304
|
-
*"Save this ensemble as a
|
|
307
|
+
*"Save this ensemble as a lineup called my-project"*
|
|
305
308
|
|
|
306
309
|
### Natural language examples
|
|
307
310
|
|
|
308
311
|
Tell your session things like:
|
|
309
312
|
|
|
310
|
-
- *"Load the my-project
|
|
311
|
-
- *"Save this ensemble as a
|
|
312
|
-
- *"Load the
|
|
313
|
+
- *"Load the my-project lineup"*
|
|
314
|
+
- *"Save this ensemble as a lineup"*
|
|
315
|
+
- *"Load the lineup from /repos/configs/team.yaml"*
|
|
313
316
|
|
|
314
317
|
### Fan-out schedules
|
|
315
318
|
|
|
@@ -329,6 +332,66 @@ players:
|
|
|
329
332
|
instructions: "Review the latest PR for security issues"
|
|
330
333
|
```
|
|
331
334
|
|
|
335
|
+
## Player Types
|
|
336
|
+
|
|
337
|
+
Player types are reusable agent definitions in Claude Code's standard subagent format — `.md` files with YAML frontmatter specifying name, description, and optional model. They let you define specialized roles once and reuse them across lineups.
|
|
338
|
+
|
|
339
|
+
### How player types work
|
|
340
|
+
|
|
341
|
+
Reference a type by name in a lineup's `type` field:
|
|
342
|
+
|
|
343
|
+
```yaml
|
|
344
|
+
players:
|
|
345
|
+
- name: arch
|
|
346
|
+
type: tempo-composer
|
|
347
|
+
- name: eng
|
|
348
|
+
type: tempo-soloist
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
When a player is recruited with a type, the agent definition is resolved and passed to the session. Players know their type via the `who_am_i` tool.
|
|
352
|
+
|
|
353
|
+
### Three-tier lookup
|
|
354
|
+
|
|
355
|
+
Player types are resolved in order (first match wins):
|
|
356
|
+
|
|
357
|
+
1. **Project** — `.claude/agents/` in the project directory
|
|
358
|
+
2. **User** — `~/.claude/agents/` in the user's home directory
|
|
359
|
+
3. **Shipped** — `examples/agents/` bundled with claude-tempo
|
|
360
|
+
|
|
361
|
+
Project and user types are resolved natively by Claude Code via `--agent <name>`. Shipped types fall back to `--system-prompt <path>`.
|
|
362
|
+
|
|
363
|
+
### Shipped player types
|
|
364
|
+
|
|
365
|
+
| Type | Description |
|
|
366
|
+
|------|-------------|
|
|
367
|
+
| `tempo-conductor` | Orchestrates the ensemble — breaks down tasks, delegates to players, tracks progress |
|
|
368
|
+
| `tempo-composer` | Software architect — designs system structure, defines interfaces, makes technology decisions |
|
|
369
|
+
| `tempo-soloist` | Senior engineer — implements features, fixes bugs, writes tests, delivers working code |
|
|
370
|
+
| `tempo-tuner` | QA engineer — designs test strategies, finds bugs, validates edge cases |
|
|
371
|
+
| `tempo-critic` | Code reviewer — evaluates changes for correctness, security, performance, maintainability |
|
|
372
|
+
| `tempo-roadie` | DevOps engineer — manages CI/CD, deployments, infrastructure, environment configuration |
|
|
373
|
+
| `tempo-improv` | Researcher and explorer — investigates unknowns, runs spikes, evaluates options |
|
|
374
|
+
| `tempo-liner` | Documentation specialist — owns README, CHANGELOG, CLAUDE.md, and PR descriptions |
|
|
375
|
+
|
|
376
|
+
### Shipped lineups
|
|
377
|
+
|
|
378
|
+
| Lineup | Description |
|
|
379
|
+
|--------|-------------|
|
|
380
|
+
| `tempo-big-band` | Full-lifecycle ensemble with all 8 player types — design, implement, test, review, and ship |
|
|
381
|
+
| `tempo-dev-team` | Feature development — conductor, composer, two soloists, and a tuner |
|
|
382
|
+
| `tempo-review-squad` | Three critics with different focus areas for thorough parallel code review |
|
|
383
|
+
| `tempo-jam-session` | Exploratory ensemble for spikes, research, and problems where the path is unclear |
|
|
384
|
+
|
|
385
|
+
### Discovery
|
|
386
|
+
|
|
387
|
+
Use the `agent_types` MCP tool inside a session or the CLI:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
claude-tempo agent-types list # show available types
|
|
391
|
+
claude-tempo agent-types show <name> # print full definition
|
|
392
|
+
claude-tempo agent-types init # copy shipped examples to ~/.claude/agents/
|
|
393
|
+
```
|
|
394
|
+
|
|
332
395
|
## Conductors
|
|
333
396
|
|
|
334
397
|
A **conductor** is an optional special player that acts as an orchestration hub. Use one when you want:
|
|
@@ -28,6 +28,8 @@ export interface StartRecruitedSessionInput {
|
|
|
28
28
|
agent: AgentType;
|
|
29
29
|
systemPrompt?: string;
|
|
30
30
|
taskQueue: string;
|
|
31
|
+
agentDefinition?: string;
|
|
32
|
+
agentDefinitionDescription?: string;
|
|
31
33
|
}
|
|
32
34
|
export interface SpawnProcessInput {
|
|
33
35
|
targetName: string;
|
|
@@ -41,6 +43,9 @@ export interface SpawnProcessInput {
|
|
|
41
43
|
temporalApiKey?: string;
|
|
42
44
|
temporalTlsCertPath?: string;
|
|
43
45
|
temporalTlsKeyPath?: string;
|
|
46
|
+
agentDefinition?: string;
|
|
47
|
+
agentDefinitionPath?: string;
|
|
48
|
+
nativeResolvable?: boolean;
|
|
44
49
|
}
|
|
45
50
|
export interface OutboxActivityResult {
|
|
46
51
|
success: boolean;
|
|
@@ -104,7 +104,7 @@ function createOutboxActivities(client, config) {
|
|
|
104
104
|
return { success: true };
|
|
105
105
|
},
|
|
106
106
|
async startRecruitedSession(input) {
|
|
107
|
-
const { ensemble, targetName, workDir, isConductor, initialMessage, fromPlayerId, agent, systemPrompt, taskQueue } = input;
|
|
107
|
+
const { ensemble, targetName, workDir, isConductor, initialMessage, fromPlayerId, agent, systemPrompt, taskQueue, agentDefinition, agentDefinitionDescription } = input;
|
|
108
108
|
try {
|
|
109
109
|
const workflowId = isConductor
|
|
110
110
|
? (0, config_1.conductorWorkflowId)(ensemble)
|
|
@@ -121,6 +121,9 @@ function createOutboxActivities(client, config) {
|
|
|
121
121
|
isConductor,
|
|
122
122
|
agentType: agent,
|
|
123
123
|
status: 'pending',
|
|
124
|
+
...(agentDefinition ? { playerType: agentDefinition } : {}),
|
|
125
|
+
...(agentDefinitionDescription ? { playerTypeDescription: agentDefinitionDescription } : {}),
|
|
126
|
+
recruitedBy: fromPlayerId,
|
|
124
127
|
},
|
|
125
128
|
autoSummary: `Session in ${require('path').basename(workDir)}`,
|
|
126
129
|
disableStaleDetection: true,
|
|
@@ -154,7 +157,7 @@ function createOutboxActivities(client, config) {
|
|
|
154
157
|
}
|
|
155
158
|
},
|
|
156
159
|
async spawnProcess(input) {
|
|
157
|
-
const { targetName, workDir, isConductor, agent, systemPrompt, ensemble, temporalAddress, temporalNamespace, temporalApiKey, temporalTlsCertPath, temporalTlsKeyPath } = input;
|
|
160
|
+
const { targetName, workDir, isConductor, agent, systemPrompt, ensemble, temporalAddress, temporalNamespace, temporalApiKey, temporalTlsCertPath, temporalTlsKeyPath, agentDefinition, agentDefinitionPath, nativeResolvable } = input;
|
|
158
161
|
try {
|
|
159
162
|
if (agent === 'copilot') {
|
|
160
163
|
const { pid } = (0, spawn_1.spawnCopilotBridge)({
|
|
@@ -171,11 +174,22 @@ function createOutboxActivities(client, config) {
|
|
|
171
174
|
log(`Spawned copilot-bridge (pid ${pid}) in ${workDir} as "${targetName}"`);
|
|
172
175
|
}
|
|
173
176
|
else {
|
|
177
|
+
// Resolve agent flags: --agent (native) > --system-prompt (shipped/legacy)
|
|
178
|
+
let agentFlags = [];
|
|
179
|
+
if (agentDefinition && nativeResolvable) {
|
|
180
|
+
agentFlags = ['--agent', agentDefinition];
|
|
181
|
+
}
|
|
182
|
+
else if (agentDefinitionPath) {
|
|
183
|
+
agentFlags = ['--system-prompt', agentDefinitionPath];
|
|
184
|
+
}
|
|
185
|
+
else if (systemPrompt) {
|
|
186
|
+
agentFlags = ['--system-prompt', systemPrompt];
|
|
187
|
+
}
|
|
174
188
|
const spawnArgs = [
|
|
175
189
|
'--dangerously-skip-permissions',
|
|
176
190
|
'--dangerously-load-development-channels', 'server:claude-tempo',
|
|
177
191
|
'-n', targetName,
|
|
178
|
-
...
|
|
192
|
+
...agentFlags,
|
|
179
193
|
];
|
|
180
194
|
const envVars = {
|
|
181
195
|
[config_2.ENV.ENSEMBLE]: ensemble,
|
|
@@ -184,6 +198,8 @@ function createOutboxActivities(client, config) {
|
|
|
184
198
|
[config_2.ENV.TEMPORAL_ADDRESS]: temporalAddress,
|
|
185
199
|
[config_2.ENV.TEMPORAL_NAMESPACE]: temporalNamespace,
|
|
186
200
|
};
|
|
201
|
+
if (agentDefinition)
|
|
202
|
+
envVars[config_2.ENV.PLAYER_TYPE] = agentDefinition;
|
|
187
203
|
if (temporalApiKey)
|
|
188
204
|
envVars[config_2.ENV.TEMPORAL_API_KEY] = temporalApiKey;
|
|
189
205
|
if (temporalTlsCertPath)
|
package/dist/cli/commands.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare function server(opts: ServerOpts): Promise<void>;
|
|
|
27
27
|
interface UpOpts extends CliOverrides {
|
|
28
28
|
ensemble: string;
|
|
29
29
|
name?: string;
|
|
30
|
-
|
|
30
|
+
lineup?: string;
|
|
31
31
|
agent: AgentType;
|
|
32
32
|
}
|
|
33
33
|
export declare function up(opts: UpOpts): Promise<void>;
|
|
@@ -45,6 +45,11 @@ interface StopOpts extends CliOverrides {
|
|
|
45
45
|
all?: boolean;
|
|
46
46
|
}
|
|
47
47
|
export declare function stop(opts: StopOpts): Promise<void>;
|
|
48
|
+
interface AgentTypesCommandOpts {
|
|
49
|
+
subcommand?: string;
|
|
50
|
+
name?: string;
|
|
51
|
+
}
|
|
52
|
+
export declare function agentTypesCommand(opts: AgentTypesCommandOpts): Promise<void>;
|
|
48
53
|
interface EnsembleCommandOpts extends CliOverrides {
|
|
49
54
|
subcommand?: string;
|
|
50
55
|
name?: string;
|