claude-code-controller 0.3.0 → 0.4.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/README.md +285 -302
- package/dist/api/index.cjs +506 -53
- package/dist/api/index.cjs.map +1 -1
- package/dist/api/index.d.cts +36 -8
- package/dist/api/index.d.ts +36 -8
- package/dist/api/index.js +506 -53
- package/dist/api/index.js.map +1 -1
- package/dist/{controller-CqCBbQYK.d.cts → claude-DectLQVR.d.cts} +237 -1
- package/dist/{controller-CqCBbQYK.d.ts → claude-DectLQVR.d.ts} +237 -1
- package/dist/index.cjs +463 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +460 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<br />
|
|
20
20
|
|
|
21
|
-
>
|
|
22
|
-
> Spawn agents, send them messages, assign tasks, approve plans — from your code or your browser.
|
|
21
|
+
> **Three lines of code.** Ask Claude a question, get an answer. Spin up persistent agents for multi-turn conversations. Orchestrate entire teams of agents working in parallel. All running **real Claude Code** — the same one you use in your terminal every day.
|
|
23
22
|
|
|
24
23
|
<br />
|
|
25
24
|
|
|
@@ -27,53 +26,69 @@
|
|
|
27
26
|
|
|
28
27
|
<br />
|
|
29
28
|
|
|
30
|
-
##
|
|
29
|
+
## Quick Start
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
```bash
|
|
32
|
+
npm install claude-code-controller
|
|
33
|
+
```
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
> **Prerequisite:** [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) v2.1.34+
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
<br />
|
|
38
|
+
|
|
39
|
+
### One-liner — ask a question, get an answer
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { claude } from "claude-code-controller";
|
|
43
|
+
|
|
44
|
+
const answer = await claude("What does this project do?", { model: "sonnet" });
|
|
45
|
+
console.log(answer);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
That's it. No initialization, no boilerplate, no `sleep()` hacks. The agent is created, responds, and cleans up automatically.
|
|
41
49
|
|
|
42
50
|
<br />
|
|
43
51
|
|
|
44
|
-
|
|
52
|
+
### Persistent agent — multi-turn conversations
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const agent = await claude.agent({ model: "sonnet", cwd: "/my/project" });
|
|
56
|
+
|
|
57
|
+
const review = await agent.ask("Review src/auth.ts for security issues");
|
|
58
|
+
const fixes = await agent.ask("Now fix the issues you found");
|
|
59
|
+
|
|
60
|
+
await agent.close();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The agent retains full context between calls. Ask follow-up questions, build on previous answers, iterate on a task — like pairing with a colleague.
|
|
45
64
|
|
|
46
65
|
<br />
|
|
47
66
|
|
|
48
|
-
|
|
67
|
+
### Multi-agent session — parallel teams
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const session = await claude.session({ model: "sonnet" });
|
|
49
71
|
|
|
50
|
-
|
|
72
|
+
const reviewer = await session.agent("reviewer", { model: "opus" });
|
|
73
|
+
const coder = await session.agent("coder");
|
|
51
74
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
curl -X POST http://localhost:3000/agents \
|
|
55
|
-
-H "Content-Type: application/json" \
|
|
56
|
-
-d '{"name": "security-reviewer", "model": "opus"}'
|
|
75
|
+
const issues = await reviewer.ask("Review src/ for security vulnerabilities");
|
|
76
|
+
await coder.ask(`Fix these issues:\n${issues}`);
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
curl -X POST http://localhost:3000/agents/security-reviewer/messages \
|
|
60
|
-
-H "Content-Type: application/json" \
|
|
61
|
-
-d '{"message": "Audit src/auth/ for vulnerabilities. Reply with SendMessage."}'
|
|
78
|
+
await session.close();
|
|
62
79
|
```
|
|
63
80
|
|
|
64
|
-
|
|
81
|
+
Each agent has its own process, its own context, its own model. They work in parallel on your codebase. One reviews, another codes, another writes tests — all at the same time.
|
|
65
82
|
|
|
66
|
-
|
|
83
|
+
<br />
|
|
67
84
|
|
|
68
|
-
|
|
85
|
+
### Auto-cleanup with `await using`
|
|
69
86
|
|
|
70
87
|
```typescript
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
})
|
|
75
|
-
await ctrl.assignTask(taskId, "coder");
|
|
76
|
-
await ctrl.waitForTask(taskId); // blocks until done
|
|
88
|
+
{
|
|
89
|
+
await using agent = await claude.agent({ model: "sonnet" });
|
|
90
|
+
const answer = await agent.ask("What is 2+2?");
|
|
91
|
+
} // agent.close() called automatically
|
|
77
92
|
```
|
|
78
93
|
|
|
79
94
|
<br />
|
|
@@ -82,16 +97,17 @@ await ctrl.waitForTask(taskId); // blocks until done
|
|
|
82
97
|
|
|
83
98
|
<br />
|
|
84
99
|
|
|
85
|
-
##
|
|
100
|
+
## Why this instead of the Agent SDK?
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- **
|
|
92
|
-
- **
|
|
93
|
-
- **
|
|
94
|
-
- **
|
|
102
|
+
This runs **real Claude Code processes**. Not a wrapper around the API. Not a simplified `-p` mode. Actual Claude Code — the same one you use in your terminal every day.
|
|
103
|
+
|
|
104
|
+
That means:
|
|
105
|
+
|
|
106
|
+
- **Uses your Claude Code subscription** — No separate API key needed. No usage-based billing surprise. If you have a Max plan, your agents run on it.
|
|
107
|
+
- **Day 0 features** — When Anthropic ships a new Claude Code feature (new tools, new models, better context handling), you get it immediately. No library update needed. No waiting for SDK support.
|
|
108
|
+
- **Full tool access** — Bash, Read, Write, Edit, Glob, Grep, WebSearch, Task sub-agents... everything Claude Code can do, your agents can do.
|
|
109
|
+
- **Real terminal environment** — Agents run in a PTY. They can install packages, run tests, use git, call APIs. They work in your actual project directory.
|
|
110
|
+
- **Battle-tested agent loop** — Claude Code's agent loop is production-hardened. You get all of that for free: retries, error handling, tool orchestration, context management.
|
|
95
111
|
|
|
96
112
|
<br />
|
|
97
113
|
|
|
@@ -99,13 +115,19 @@ await ctrl.waitForTask(taskId); // blocks until done
|
|
|
99
115
|
|
|
100
116
|
<br />
|
|
101
117
|
|
|
102
|
-
##
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
npm install claude-code-controller
|
|
106
|
-
```
|
|
118
|
+
## Features
|
|
107
119
|
|
|
108
|
-
|
|
120
|
+
- **3 lines of code** — From zero to a working agent in seconds. No boilerplate, no two-step initialization.
|
|
121
|
+
- **Multi-turn conversations** — Persistent agents that remember context across `ask()` calls.
|
|
122
|
+
- **Multi-agent sessions** — Orchestrate teams of agents working in parallel on the same codebase.
|
|
123
|
+
- **Permission control** — Four presets from full-access to ask-before-every-tool. Auto-approve, allowlists, or inline callbacks.
|
|
124
|
+
- **First-class API key support** — Pass `apiKey` and `baseUrl` directly. No env var wiring.
|
|
125
|
+
- **REST API** — Control everything over HTTP. Works from any language, any platform.
|
|
126
|
+
- **Web Dashboard** — Real-time monitoring, agent management, and interactive approvals from your browser.
|
|
127
|
+
- **Task management** — Create tasks, assign them to agents, track progress, define blocking dependencies.
|
|
128
|
+
- **`await using` support** — Automatic cleanup with `Symbol.asyncDispose`.
|
|
129
|
+
- **Any provider** — Point agents at any Anthropic-compatible endpoint. Per-agent overrides.
|
|
130
|
+
- **Your subscription** — Runs on your existing Claude Code plan. No separate API costs.
|
|
109
131
|
|
|
110
132
|
<br />
|
|
111
133
|
|
|
@@ -113,28 +135,78 @@ npm install claude-code-controller
|
|
|
113
135
|
|
|
114
136
|
<br />
|
|
115
137
|
|
|
116
|
-
##
|
|
138
|
+
## Permission Control
|
|
139
|
+
|
|
140
|
+
Every agent gets a permission preset that controls what tools it can use without asking.
|
|
141
|
+
|
|
142
|
+
| Preset | Behavior |
|
|
143
|
+
|--------|----------|
|
|
144
|
+
| `"full"` (default) | All tools, no approval needed |
|
|
145
|
+
| `"edit"` | Auto-approve read/write/bash |
|
|
146
|
+
| `"plan"` | Read-only exploration |
|
|
147
|
+
| `"ask"` | Fires events for every tool use |
|
|
117
148
|
|
|
118
149
|
```typescript
|
|
119
|
-
|
|
150
|
+
// Full access (default)
|
|
151
|
+
const agent = await claude.agent({ permissions: "full" });
|
|
120
152
|
|
|
121
|
-
|
|
122
|
-
await
|
|
153
|
+
// Read-only explorer
|
|
154
|
+
const agent = await claude.agent({ permissions: "plan" });
|
|
123
155
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
156
|
+
// Ask-mode with auto-approve for safe tools
|
|
157
|
+
const agent = await claude.agent({
|
|
158
|
+
permissions: "ask",
|
|
159
|
+
autoApprove: ["Read", "Glob", "Grep"],
|
|
127
160
|
});
|
|
128
161
|
|
|
129
|
-
|
|
162
|
+
// Auto-approve everything (YOLO mode)
|
|
163
|
+
const agent = await claude.agent({
|
|
164
|
+
permissions: "ask",
|
|
165
|
+
autoApprove: true,
|
|
166
|
+
});
|
|
167
|
+
```
|
|
130
168
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
169
|
+
<br />
|
|
170
|
+
|
|
171
|
+
### Inline callbacks
|
|
172
|
+
|
|
173
|
+
Handle permission and plan requests with simple callbacks:
|
|
136
174
|
|
|
137
|
-
|
|
175
|
+
```typescript
|
|
176
|
+
const agent = await claude.agent({
|
|
177
|
+
permissions: "ask",
|
|
178
|
+
onPermission: (req) => {
|
|
179
|
+
console.log(`Tool: ${req.toolName} — ${req.description}`);
|
|
180
|
+
req.toolName === "Bash" ? req.reject() : req.approve();
|
|
181
|
+
},
|
|
182
|
+
onPlan: (req) => {
|
|
183
|
+
console.log("Plan:", req.planContent);
|
|
184
|
+
req.approve();
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
<br />
|
|
190
|
+
|
|
191
|
+
### Event-based
|
|
192
|
+
|
|
193
|
+
Or use the event emitter pattern for more control:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const agent = await claude.agent({ permissions: "ask" });
|
|
197
|
+
|
|
198
|
+
agent.on("permission", (req) => {
|
|
199
|
+
const safe = ["Read", "Glob", "Grep"].includes(req.toolName);
|
|
200
|
+
safe ? req.approve() : req.reject();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
agent.on("plan", (req) => {
|
|
204
|
+
req.approve();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
agent.on("message", (text) => console.log(text));
|
|
208
|
+
agent.on("error", (err) => console.error(err));
|
|
209
|
+
agent.on("exit", (code) => console.log("Agent exited:", code));
|
|
138
210
|
```
|
|
139
211
|
|
|
140
212
|
<br />
|
|
@@ -145,34 +217,40 @@ await ctrl.shutdown();
|
|
|
145
217
|
|
|
146
218
|
## REST API
|
|
147
219
|
|
|
148
|
-
|
|
220
|
+
Control Claude Code agents from **any language, any platform** — just HTTP.
|
|
221
|
+
|
|
222
|
+
<br />
|
|
149
223
|
|
|
150
|
-
Start a server
|
|
224
|
+
### Start a server
|
|
151
225
|
|
|
152
226
|
```typescript
|
|
153
227
|
import { createApi } from "claude-code-controller/api";
|
|
154
|
-
import { serve } from "bun"; // or any Hono-compatible runtime
|
|
155
228
|
|
|
156
|
-
const app = createApi();
|
|
157
|
-
serve({ port: 3000, fetch: app.fetch
|
|
229
|
+
const app = createApi();
|
|
230
|
+
Bun.serve({ port: 3000, fetch: app.fetch });
|
|
158
231
|
```
|
|
159
232
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
import { ClaudeCodeController } from "claude-code-controller";
|
|
164
|
-
import { createApi } from "claude-code-controller/api";
|
|
233
|
+
<br />
|
|
165
234
|
|
|
166
|
-
|
|
167
|
-
await ctrl.init();
|
|
235
|
+
### One-liner over HTTP
|
|
168
236
|
|
|
169
|
-
|
|
237
|
+
```bash
|
|
238
|
+
curl -X POST http://localhost:3000/ask \
|
|
239
|
+
-H "Content-Type: application/json" \
|
|
240
|
+
-d '{"prompt": "What does this project do?", "model": "sonnet"}'
|
|
241
|
+
# → { "response": "This project is a..." }
|
|
170
242
|
```
|
|
171
243
|
|
|
172
244
|
<br />
|
|
173
245
|
|
|
174
246
|
### Endpoints
|
|
175
247
|
|
|
248
|
+
#### Ask (one-liner)
|
|
249
|
+
|
|
250
|
+
| Method | Endpoint | Description |
|
|
251
|
+
|--------|----------|-------------|
|
|
252
|
+
| `POST` | `/ask` | Send a prompt, get a response. Creates an ephemeral agent. |
|
|
253
|
+
|
|
176
254
|
#### Session
|
|
177
255
|
|
|
178
256
|
| Method | Endpoint | Description |
|
|
@@ -192,8 +270,7 @@ const app = createApi(ctrl); // pre-initialized mode
|
|
|
192
270
|
| `POST` | `/agents/:name/messages` | Send a message to an agent |
|
|
193
271
|
| `POST` | `/agents/:name/kill` | Force-kill an agent |
|
|
194
272
|
| `POST` | `/agents/:name/shutdown` | Request graceful shutdown |
|
|
195
|
-
| `POST` | `/agents/:name/approve
|
|
196
|
-
| `POST` | `/agents/:name/approve-permission` | Approve or deny tool use |
|
|
273
|
+
| `POST` | `/agents/:name/approve` | Approve or reject a plan or permission request |
|
|
197
274
|
|
|
198
275
|
#### Tasks
|
|
199
276
|
|
|
@@ -206,44 +283,31 @@ const app = createApi(ctrl); // pre-initialized mode
|
|
|
206
283
|
| `DELETE` | `/tasks/:id` | Delete a task |
|
|
207
284
|
| `POST` | `/tasks/:id/assign` | Assign task to an agent |
|
|
208
285
|
|
|
209
|
-
#### Actions
|
|
286
|
+
#### Actions & Broadcasting
|
|
210
287
|
|
|
211
288
|
| Method | Endpoint | Description |
|
|
212
289
|
|--------|----------|-------------|
|
|
213
290
|
| `GET` | `/actions` | All pending actions (approvals, idle agents, unassigned tasks) |
|
|
214
|
-
| `GET` | `/actions/approvals` | Pending approval requests |
|
|
215
|
-
| `GET` | `/actions/tasks` | Unassigned tasks |
|
|
216
|
-
| `GET` | `/actions/idle-agents` | Idle agents waiting for work |
|
|
217
|
-
|
|
218
|
-
#### Broadcasting
|
|
219
|
-
|
|
220
|
-
| Method | Endpoint | Description |
|
|
221
|
-
|--------|----------|-------------|
|
|
222
291
|
| `POST` | `/broadcast` | Send a message to all agents |
|
|
223
292
|
|
|
224
293
|
<br />
|
|
225
294
|
|
|
226
295
|
### API Examples
|
|
227
296
|
|
|
228
|
-
**Initialize a session:**
|
|
297
|
+
**Initialize a session with API key:**
|
|
229
298
|
|
|
230
299
|
```bash
|
|
231
300
|
curl -X POST http://localhost:3000/session/init \
|
|
232
301
|
-H "Content-Type: application/json" \
|
|
233
|
-
-d '{"teamName": "my-team", "
|
|
302
|
+
-d '{"teamName": "my-team", "apiKey": "sk-ant-...", "baseUrl": "https://api.example.com"}'
|
|
234
303
|
```
|
|
235
304
|
|
|
236
|
-
**Spawn an agent:**
|
|
305
|
+
**Spawn an agent with permissions:**
|
|
237
306
|
|
|
238
307
|
```bash
|
|
239
308
|
curl -X POST http://localhost:3000/agents \
|
|
240
309
|
-H "Content-Type: application/json" \
|
|
241
|
-
-d '{
|
|
242
|
-
"name": "reviewer",
|
|
243
|
-
"type": "general-purpose",
|
|
244
|
-
"model": "sonnet",
|
|
245
|
-
"permissions": ["Bash", "Read", "Write"]
|
|
246
|
-
}'
|
|
310
|
+
-d '{"name": "reviewer", "model": "opus", "permissions": "edit"}'
|
|
247
311
|
```
|
|
248
312
|
|
|
249
313
|
**Send a message:**
|
|
@@ -251,7 +315,7 @@ curl -X POST http://localhost:3000/agents \
|
|
|
251
315
|
```bash
|
|
252
316
|
curl -X POST http://localhost:3000/agents/reviewer/messages \
|
|
253
317
|
-H "Content-Type: application/json" \
|
|
254
|
-
-d '{"message": "Review src/auth.ts for security vulnerabilities
|
|
318
|
+
-d '{"message": "Review src/auth.ts for security vulnerabilities"}'
|
|
255
319
|
```
|
|
256
320
|
|
|
257
321
|
**Create and assign a task:**
|
|
@@ -268,148 +332,40 @@ curl -X POST http://localhost:3000/tasks/1/assign \
|
|
|
268
332
|
-d '{"agent": "reviewer"}'
|
|
269
333
|
```
|
|
270
334
|
|
|
271
|
-
**Check pending actions:**
|
|
272
|
-
|
|
273
|
-
```bash
|
|
274
|
-
curl http://localhost:3000/actions
|
|
275
|
-
# → { "pending": 2, "approvals": [...], "unassignedTasks": [...], "idleAgents": [...] }
|
|
276
|
-
```
|
|
277
|
-
|
|
278
335
|
<br />
|
|
279
336
|
|
|
280
337
|
---
|
|
281
338
|
|
|
282
339
|
<br />
|
|
283
340
|
|
|
284
|
-
##
|
|
285
|
-
|
|
286
|
-
The SDK gives you full programmatic control with type safety and an event-driven architecture.
|
|
287
|
-
|
|
288
|
-
### Controller
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
import { ClaudeCodeController } from "claude-code-controller";
|
|
292
|
-
|
|
293
|
-
const ctrl = new ClaudeCodeController({
|
|
294
|
-
teamName: "my-team", // auto-generated if omitted
|
|
295
|
-
cwd: "/path/to/project", // working directory for agents
|
|
296
|
-
claudeBinary: "claude", // path to CLI binary
|
|
297
|
-
env: { // default env vars for all agents
|
|
298
|
-
ANTHROPIC_BASE_URL: "https://your-proxy.example.com",
|
|
299
|
-
},
|
|
300
|
-
logLevel: "info", // "debug" | "info" | "warn" | "error" | "silent"
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
await ctrl.init();
|
|
304
|
-
// ... use the controller ...
|
|
305
|
-
await ctrl.shutdown();
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### Spawning Agents
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
const agent = await ctrl.spawnAgent({
|
|
312
|
-
name: "coder",
|
|
313
|
-
type: "general-purpose", // "general-purpose" | "Bash" | "Explore" | "Plan"
|
|
314
|
-
model: "sonnet", // "sonnet" | "opus" | "haiku" | full model ID
|
|
315
|
-
cwd: "/specific/directory",
|
|
316
|
-
permissions: ["Bash", "Read", "Write", "Glob", "Grep"],
|
|
317
|
-
env: { MY_VAR: "value" }, // per-agent env overrides
|
|
318
|
-
});
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### AgentHandle
|
|
322
|
-
|
|
323
|
-
Every spawned agent returns an `AgentHandle` — a convenient wrapper for interacting with it.
|
|
324
|
-
|
|
325
|
-
```typescript
|
|
326
|
-
// Send and receive
|
|
327
|
-
await agent.send("Analyze the codebase structure.");
|
|
328
|
-
const response = await agent.receive({ timeout: 30_000 });
|
|
329
|
-
|
|
330
|
-
// Or use ask() for send + receive in one call
|
|
331
|
-
const answer = await agent.ask("What framework is this project using?", {
|
|
332
|
-
timeout: 60_000,
|
|
333
|
-
});
|
|
341
|
+
## Web Dashboard
|
|
334
342
|
|
|
335
|
-
|
|
336
|
-
for await (const msg of agent.events()) {
|
|
337
|
-
console.log(`[${agent.name}]`, msg.text);
|
|
338
|
-
}
|
|
343
|
+
A built-in web UI for real-time agent management — no code required.
|
|
339
344
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
agent.pid; // process ID
|
|
343
|
-
await agent.shutdown(); // graceful
|
|
344
|
-
await agent.kill(); // force
|
|
345
|
+
```bash
|
|
346
|
+
cd web && bun install
|
|
345
347
|
```
|
|
346
348
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
```typescript
|
|
350
|
-
// Direct messaging
|
|
351
|
-
await ctrl.send("agent-name", "Your instructions here", "optional summary");
|
|
352
|
-
|
|
353
|
-
// Broadcast to all agents
|
|
354
|
-
await ctrl.broadcast("Everyone stop and report status.");
|
|
355
|
-
|
|
356
|
-
// Wait for a response
|
|
357
|
-
const messages = await ctrl.receive("agent-name", {
|
|
358
|
-
timeout: 60_000,
|
|
359
|
-
pollInterval: 500,
|
|
360
|
-
all: true, // get all unread messages
|
|
361
|
-
});
|
|
349
|
+
**Development:**
|
|
362
350
|
|
|
363
|
-
|
|
364
|
-
|
|
351
|
+
```bash
|
|
352
|
+
bun run dev # backend on :3456
|
|
353
|
+
bun run dev:vite # frontend on :5174
|
|
365
354
|
```
|
|
366
355
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
```typescript
|
|
370
|
-
// Create a task
|
|
371
|
-
const taskId = await ctrl.createTask({
|
|
372
|
-
subject: "Add input validation",
|
|
373
|
-
description: "Add zod schemas to all API endpoints in src/routes/",
|
|
374
|
-
owner: "coder", // optional — assign immediately
|
|
375
|
-
metadata: { priority: "high" },
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
// Assign later
|
|
379
|
-
await ctrl.assignTask(taskId, "coder");
|
|
356
|
+
**Production:**
|
|
380
357
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
console.log(task.status); // "completed"
|
|
358
|
+
```bash
|
|
359
|
+
bun run build && bun run start # everything on :3456
|
|
384
360
|
```
|
|
385
361
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
```typescript
|
|
389
|
-
// Agent messages
|
|
390
|
-
ctrl.on("message", (agentName, message) => {
|
|
391
|
-
console.log(`[${agentName}] ${message.text}`);
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
// Plan approval — agent wants to execute a plan
|
|
395
|
-
ctrl.on("plan:approval_request", (agentName, msg) => {
|
|
396
|
-
console.log(`${agentName} wants to execute a plan:`, msg.planContent);
|
|
397
|
-
ctrl.sendPlanApproval(agentName, msg.requestId, true);
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
// Permission request — agent wants to use a tool
|
|
401
|
-
ctrl.on("permission:request", (agentName, msg) => {
|
|
402
|
-
const safe = ["Read", "Glob", "Grep"].includes(msg.toolName);
|
|
403
|
-
ctrl.sendPermissionResponse(agentName, msg.requestId, safe);
|
|
404
|
-
});
|
|
362
|
+
The dashboard gives you:
|
|
405
363
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
ctrl.on("error", (err) => console.error("Controller error:", err));
|
|
412
|
-
```
|
|
364
|
+
- **Session management** — Initialize with API key, base URL, team name, and working directory
|
|
365
|
+
- **Agent spawning** — Configure name, type, model, and permission level from a dropdown
|
|
366
|
+
- **Live message feed** — Real-time messages via WebSocket
|
|
367
|
+
- **Approval prompts** — Interactive plan and permission approval banners
|
|
368
|
+
- **Agent controls** — Shutdown or kill agents individually
|
|
413
369
|
|
|
414
370
|
<br />
|
|
415
371
|
|
|
@@ -422,134 +378,174 @@ ctrl.on("error", (err) => console.error("Controller error:", err));
|
|
|
422
378
|
### Parallel Code Review
|
|
423
379
|
|
|
424
380
|
```typescript
|
|
425
|
-
|
|
426
|
-
|
|
381
|
+
import { claude } from "claude-code-controller";
|
|
382
|
+
|
|
383
|
+
const session = await claude.session({ model: "sonnet" });
|
|
427
384
|
|
|
428
385
|
const [security, perf, style] = await Promise.all([
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
386
|
+
session.agent("security", { model: "opus" }),
|
|
387
|
+
session.agent("perf"),
|
|
388
|
+
session.agent("style", { model: "haiku" }),
|
|
432
389
|
]);
|
|
433
390
|
|
|
434
|
-
await new Promise((r) => setTimeout(r, 12_000));
|
|
435
|
-
|
|
436
391
|
const reviews = await Promise.all([
|
|
437
|
-
security.ask("Review src/ for security vulnerabilities
|
|
438
|
-
perf.ask("Review src/ for performance issues
|
|
439
|
-
style.ask("Review src/ for code style issues
|
|
392
|
+
security.ask("Review src/ for security vulnerabilities"),
|
|
393
|
+
perf.ask("Review src/ for performance issues"),
|
|
394
|
+
style.ask("Review src/ for code style issues"),
|
|
440
395
|
]);
|
|
441
396
|
|
|
442
397
|
console.log("Security:", reviews[0]);
|
|
443
398
|
console.log("Performance:", reviews[1]);
|
|
444
399
|
console.log("Style:", reviews[2]);
|
|
445
400
|
|
|
446
|
-
await
|
|
401
|
+
await session.close();
|
|
447
402
|
```
|
|
448
403
|
|
|
449
404
|
### Task-Based Workflow
|
|
450
405
|
|
|
451
406
|
```typescript
|
|
452
|
-
|
|
453
|
-
await ctrl.init();
|
|
407
|
+
import { claude, Session } from "claude-code-controller";
|
|
454
408
|
|
|
455
|
-
const
|
|
456
|
-
|
|
409
|
+
const session = await claude.session({ model: "sonnet" });
|
|
410
|
+
const worker = await session.agent("worker");
|
|
457
411
|
|
|
458
|
-
|
|
412
|
+
// Create and assign a task via the underlying controller
|
|
413
|
+
const taskId = await session.controller.createTask({
|
|
459
414
|
subject: "Add input validation",
|
|
460
415
|
description: "Add zod validation to all API route handlers in src/routes/",
|
|
461
416
|
owner: "worker",
|
|
462
417
|
});
|
|
463
418
|
|
|
464
|
-
const result = await
|
|
419
|
+
const result = await session.controller.waitForTask(taskId, 120_000);
|
|
465
420
|
console.log(`Task ${result.status}: ${result.subject}`);
|
|
466
421
|
|
|
467
|
-
await
|
|
422
|
+
await session.close();
|
|
468
423
|
```
|
|
469
424
|
|
|
470
425
|
### Custom API Provider
|
|
471
426
|
|
|
472
427
|
```typescript
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
ANTHROPIC_AUTH_TOKEN: process.env.MY_API_KEY!,
|
|
478
|
-
},
|
|
428
|
+
const agent = await claude.agent({
|
|
429
|
+
model: "sonnet",
|
|
430
|
+
apiKey: "sk-ant-...",
|
|
431
|
+
baseUrl: "https://your-proxy.example.com/api/anthropic",
|
|
479
432
|
});
|
|
480
433
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
name: "worker",
|
|
484
|
-
env: { ANTHROPIC_AUTH_TOKEN: "different-key-for-this-agent" },
|
|
485
|
-
});
|
|
434
|
+
const answer = await agent.ask("What framework is this project using?");
|
|
435
|
+
await agent.close();
|
|
486
436
|
```
|
|
487
437
|
|
|
488
|
-
###
|
|
438
|
+
### Selective Permission Control
|
|
489
439
|
|
|
490
440
|
```typescript
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
441
|
+
const agent = await claude.agent({
|
|
442
|
+
permissions: "ask",
|
|
443
|
+
onPermission: (req) => {
|
|
444
|
+
const safe = ["Read", "Glob", "Grep", "Task"].includes(req.toolName);
|
|
445
|
+
const review = ["Bash", "Write", "Edit"].includes(req.toolName);
|
|
446
|
+
|
|
447
|
+
if (safe) {
|
|
448
|
+
req.approve();
|
|
449
|
+
} else if (review) {
|
|
450
|
+
console.log(`[REVIEW] ${req.toolName}: ${req.description}`);
|
|
451
|
+
req.approve(); // or implement your own review logic
|
|
452
|
+
} else {
|
|
453
|
+
req.reject();
|
|
454
|
+
}
|
|
455
|
+
},
|
|
497
456
|
});
|
|
498
457
|
```
|
|
499
458
|
|
|
500
|
-
|
|
459
|
+
<br />
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
<br />
|
|
464
|
+
|
|
465
|
+
## Advanced: Full Controller
|
|
466
|
+
|
|
467
|
+
The simplified API is built on top of `ClaudeCodeController` — a full-featured class that gives you direct access to the teammate protocol. Use it when you need low-level control over team configuration, inbox polling, or process management.
|
|
501
468
|
|
|
502
469
|
```typescript
|
|
503
|
-
|
|
504
|
-
const NEEDS_REVIEW = ["Bash", "Write", "Edit"];
|
|
470
|
+
import { ClaudeCodeController } from "claude-code-controller";
|
|
505
471
|
|
|
506
|
-
ctrl
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
ctrl.sendPermissionResponse(agent, msg.requestId, false);
|
|
515
|
-
}
|
|
472
|
+
const ctrl = new ClaudeCodeController({
|
|
473
|
+
teamName: "my-team",
|
|
474
|
+
cwd: "/path/to/project",
|
|
475
|
+
env: {
|
|
476
|
+
ANTHROPIC_BASE_URL: "https://your-proxy.example.com",
|
|
477
|
+
ANTHROPIC_AUTH_TOKEN: "sk-ant-...",
|
|
478
|
+
},
|
|
479
|
+
logLevel: "info",
|
|
516
480
|
});
|
|
481
|
+
|
|
482
|
+
await ctrl.init();
|
|
517
483
|
```
|
|
518
484
|
|
|
519
|
-
|
|
485
|
+
### Spawning Agents
|
|
520
486
|
|
|
521
|
-
|
|
487
|
+
```typescript
|
|
488
|
+
const agent = await ctrl.spawnAgent({
|
|
489
|
+
name: "coder",
|
|
490
|
+
type: "general-purpose",
|
|
491
|
+
model: "sonnet",
|
|
492
|
+
permissionMode: "bypassPermissions",
|
|
493
|
+
env: { MY_VAR: "value" },
|
|
494
|
+
});
|
|
495
|
+
```
|
|
522
496
|
|
|
523
|
-
|
|
497
|
+
### AgentHandle
|
|
524
498
|
|
|
525
|
-
|
|
499
|
+
```typescript
|
|
500
|
+
await agent.send("Analyze the codebase structure.");
|
|
501
|
+
const response = await agent.receive({ timeout: 30_000 });
|
|
526
502
|
|
|
527
|
-
|
|
503
|
+
const answer = await agent.ask("What framework is this project using?", {
|
|
504
|
+
timeout: 60_000,
|
|
505
|
+
});
|
|
528
506
|
|
|
529
|
-
|
|
530
|
-
|
|
507
|
+
agent.isRunning; // boolean
|
|
508
|
+
agent.pid; // process ID
|
|
509
|
+
await agent.shutdown(); // graceful
|
|
510
|
+
await agent.kill(); // force
|
|
531
511
|
```
|
|
532
512
|
|
|
533
|
-
|
|
513
|
+
### Messaging
|
|
534
514
|
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
|
|
515
|
+
```typescript
|
|
516
|
+
await ctrl.send("agent-name", "Your instructions here");
|
|
517
|
+
await ctrl.broadcast("Everyone stop and report status.");
|
|
518
|
+
const msg = await ctrl.receiveAny({ timeout: 30_000 });
|
|
538
519
|
```
|
|
539
520
|
|
|
540
|
-
|
|
521
|
+
### Task Management
|
|
541
522
|
|
|
542
|
-
```
|
|
543
|
-
|
|
523
|
+
```typescript
|
|
524
|
+
const taskId = await ctrl.createTask({
|
|
525
|
+
subject: "Add input validation",
|
|
526
|
+
description: "Add zod schemas to all API endpoints",
|
|
527
|
+
owner: "coder",
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
await ctrl.assignTask(taskId, "coder");
|
|
531
|
+
const task = await ctrl.waitForTask(taskId, 120_000);
|
|
544
532
|
```
|
|
545
533
|
|
|
546
|
-
|
|
534
|
+
### Events
|
|
547
535
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
536
|
+
```typescript
|
|
537
|
+
ctrl.on("message", (agent, msg) => console.log(`[${agent}] ${msg.text}`));
|
|
538
|
+
ctrl.on("plan:approval_request", (agent, msg) => {
|
|
539
|
+
ctrl.sendPlanApproval(agent, msg.requestId, true);
|
|
540
|
+
});
|
|
541
|
+
ctrl.on("permission:request", (agent, msg) => {
|
|
542
|
+
ctrl.sendPermissionResponse(agent, msg.requestId, true);
|
|
543
|
+
});
|
|
544
|
+
ctrl.on("agent:spawned", (name, pid) => console.log(`${name} started`));
|
|
545
|
+
ctrl.on("agent:exited", (name, code) => console.log(`${name} exited`));
|
|
546
|
+
ctrl.on("idle", (name) => console.log(`${name} is idle`));
|
|
547
|
+
ctrl.on("task:completed", (task) => console.log(`Done: ${task.subject}`));
|
|
548
|
+
```
|
|
553
549
|
|
|
554
550
|
<br />
|
|
555
551
|
|
|
@@ -603,7 +599,7 @@ ClaudeCodeController
|
|
|
603
599
|
|
|
604
600
|
```bash
|
|
605
601
|
bun install # install deps
|
|
606
|
-
bun test # run tests
|
|
602
|
+
bun test # run tests
|
|
607
603
|
bun run typecheck # type check
|
|
608
604
|
bun run build # build for distribution
|
|
609
605
|
```
|
|
@@ -614,19 +610,6 @@ bun run build # build for distribution
|
|
|
614
610
|
|
|
615
611
|
<br />
|
|
616
612
|
|
|
617
|
-
## Roadmap
|
|
618
|
-
|
|
619
|
-
- **Tmux session per agent** — Spawn each agent in its own tmux pane. Attach with `tmux attach -t <agent>` and watch it work: tool calls, file edits, reasoning — like watching someone use Claude Code interactively.
|
|
620
|
-
- **Task management in the UI** — Create, assign, and track tasks from the web dashboard.
|
|
621
|
-
- **Agent-to-agent messaging** — Let agents communicate directly with each other.
|
|
622
|
-
- **Persistent sessions** — Resume a team session after server restart.
|
|
623
|
-
|
|
624
|
-
<br />
|
|
625
|
-
|
|
626
|
-
---
|
|
627
|
-
|
|
628
|
-
<br />
|
|
629
|
-
|
|
630
613
|
## License
|
|
631
614
|
|
|
632
615
|
MIT
|