claude-code-controller 0.3.0 → 0.5.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 CHANGED
@@ -18,8 +18,7 @@
18
18
 
19
19
  <br />
20
20
 
21
- > Control real Claude Code instances through a **REST API**, a **TypeScript SDK**, or a **Web Dashboard**.
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
- ## Why this instead of the Agent SDK?
29
+ ## Quick Start
31
30
 
32
- 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.
31
+ ```bash
32
+ npm install claude-code-controller
33
+ ```
33
34
 
34
- That means:
35
+ > **Prerequisite:** [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) v2.1.34+
35
36
 
36
- - **Uses your Claude Code subscription** — No separate API key. No usage-based billing surprise. If you have a Max plan, your agents run on it.
37
- - **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.
38
- - **Full tool access** Bash, Read, Write, Edit, Glob, Grep, WebSearch, Task sub-agents... everything Claude Code can do, your agents can do.
39
- - **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.
40
- - **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.
37
+ <br />
38
+
39
+ ### One-linerask 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
- ## What you can do
67
+ ### Multi-agent session parallel teams
68
+
69
+ ```typescript
70
+ const session = await claude.session({ model: "sonnet" });
49
71
 
50
- **Spawn multiple agents on the same codebase**, each with a different role. One reviews security, another writes tests, another refactors — all in parallel, all through a simple API.
72
+ const reviewer = await session.agent("reviewer", { model: "opus" });
73
+ const coder = await session.agent("coder");
51
74
 
52
- ```bash
53
- # Spawn an agent via the REST API
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
- # Give it work
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
- **Build automation on top of Claude Code.** A webhook that triggers a code fix when CI fails. A Slack bot that assigns tasks to agents. A cron job that runs nightly code reviews. If you can make an HTTP call, you can control Claude Code.
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
- **Monitor and control agents from a web dashboard.** See what each agent is doing, approve or reject their plans, grant tool permissions, kill runaway agents — all in real-time from your browser.
83
+ <br />
67
84
 
68
- **Manage work with tasks.** Create tasks, assign them to agents, track progress, define dependencies between tasks. Agents pick up their assignments and report back when done.
85
+ ### Auto-cleanup with `await using`
69
86
 
70
87
  ```typescript
71
- const taskId = await ctrl.createTask({
72
- subject: "Add input validation to all API routes",
73
- description: "Use zod schemas for request body validation in src/routes/",
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
- ## Features
100
+ ## Why this instead of the Agent SDK?
86
101
 
87
- - **REST API** Control everything over HTTP. Spawn agents, send messages, manage tasks. Works from any language, any platform.
88
- - **TypeScript SDK** — Full programmatic control with type safety and an event-driven architecture.
89
- - **Web Dashboard** — Real-time monitoring, agent management, and interactive approvals from your browser.
90
- - **Multi-Agent** — Run multiple agents in parallel, each with their own role, model, and permissions.
91
- - **Task Management** — Create tasks, assign them, track status, define blocking dependencies.
92
- - **Plan & Permission Approval** — Agents ask before acting. You approve or reject programmatically or from the UI.
93
- - **Any Provider** — Point agents at any Anthropic-compatible endpoint. Per-agent environment and API key overrides.
94
- - **Your Subscription** — Runs on your existing Claude Code plan. No separate API costs.
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
- ## Install
103
-
104
- ```bash
105
- npm install claude-code-controller
106
- ```
118
+ ## Features
107
119
 
108
- > **Prerequisite:** [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) v2.1.34+
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
- ## Quick Start — 30 seconds to your first agent
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
- import { ClaudeCodeController } from "claude-code-controller";
150
+ // Full access (default)
151
+ const agent = await claude.agent({ permissions: "full" });
120
152
 
121
- const ctrl = new ClaudeCodeController({ teamName: "my-project" });
122
- await ctrl.init();
153
+ // Read-only explorer
154
+ const agent = await claude.agent({ permissions: "plan" });
123
155
 
124
- const agent = await ctrl.spawnAgent({
125
- name: "coder",
126
- model: "sonnet",
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
- await new Promise((r) => setTimeout(r, 10_000));
162
+ // Auto-approve everything (YOLO mode)
163
+ const agent = await claude.agent({
164
+ permissions: "ask",
165
+ autoApprove: true,
166
+ });
167
+ ```
130
168
 
131
- const answer = await agent.ask(
132
- "Read package.json and tell me the project name. Reply using SendMessage.",
133
- { timeout: 60_000 }
134
- );
135
- console.log(answer);
169
+ <br />
170
+
171
+ ### Inline callbacks
172
+
173
+ Handle permission and plan requests with simple callbacks:
136
174
 
137
- await ctrl.shutdown();
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
- The API lets you control Claude Code agents from **any language, any platform** — just HTTP.
220
+ Control Claude Code agents from **any language, any platform** — just HTTP.
221
+
222
+ <br />
149
223
 
150
- Start a server in a few lines:
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(); // lazy mode — init via POST /session/init
157
- serve({ port: 3000, fetch: app.fetch.bind(app) });
229
+ const app = createApi();
230
+ Bun.serve({ port: 3000, fetch: app.fetch });
158
231
  ```
159
232
 
160
- Or attach to an existing controller:
161
-
162
- ```typescript
163
- import { ClaudeCodeController } from "claude-code-controller";
164
- import { createApi } from "claude-code-controller/api";
233
+ <br />
165
234
 
166
- const ctrl = new ClaudeCodeController({ teamName: "my-team" });
167
- await ctrl.init();
235
+ ### One-liner over HTTP
168
236
 
169
- const app = createApi(ctrl); // pre-initialized mode
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-plan` | Approve or reject a plan |
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 (for dashboards & UIs)
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", "cwd": "/path/to/project"}'
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. Reply with SendMessage."}'
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
- ## TypeScript SDK
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
- // Stream events
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
- // Lifecycle
341
- agent.isRunning; // boolean
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
- ### Messaging
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
- // Wait for any agent to respond
364
- const msg = await ctrl.receiveAny({ timeout: 30_000 });
351
+ ```bash
352
+ bun run dev # backend on :3456
353
+ bun run dev:vite # frontend on :5174
365
354
  ```
366
355
 
367
- ### Task Management
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
- // Wait for completion
382
- const task = await ctrl.waitForTask(taskId, 120_000);
383
- console.log(task.status); // "completed"
358
+ ```bash
359
+ bun run build && bun run start # everything on :3456
384
360
  ```
385
361
 
386
- ### Events
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
- // Lifecycle events
407
- ctrl.on("agent:spawned", (name, pid) => console.log(`${name} started (pid: ${pid})`));
408
- ctrl.on("agent:exited", (name, code) => console.log(`${name} exited (code: ${code})`));
409
- ctrl.on("idle", (name) => console.log(`${name} is idle`));
410
- ctrl.on("task:completed", (task) => console.log(`Task done: ${task.subject}`));
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
- const ctrl = new ClaudeCodeController({ teamName: "review" });
426
- await ctrl.init();
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
- ctrl.spawnAgent({ name: "security", model: "opus" }),
430
- ctrl.spawnAgent({ name: "perf", model: "sonnet" }),
431
- ctrl.spawnAgent({ name: "style", model: "haiku" }),
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. Reply with SendMessage."),
438
- perf.ask("Review src/ for performance issues. Reply with SendMessage."),
439
- style.ask("Review src/ for code style issues. Reply with SendMessage."),
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 ctrl.shutdown();
401
+ await session.close();
447
402
  ```
448
403
 
449
404
  ### Task-Based Workflow
450
405
 
451
406
  ```typescript
452
- const ctrl = new ClaudeCodeController({ teamName: "tasks" });
453
- await ctrl.init();
407
+ import { claude, Session } from "claude-code-controller";
454
408
 
455
- const worker = await ctrl.spawnAgent({ name: "worker", model: "sonnet" });
456
- await new Promise((r) => setTimeout(r, 10_000));
409
+ const session = await claude.session({ model: "sonnet" });
410
+ const worker = await session.agent("worker");
457
411
 
458
- const taskId = await ctrl.createTask({
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 ctrl.waitForTask(taskId, 120_000);
419
+ const result = await session.controller.waitForTask(taskId, 120_000);
465
420
  console.log(`Task ${result.status}: ${result.subject}`);
466
421
 
467
- await ctrl.shutdown();
422
+ await session.close();
468
423
  ```
469
424
 
470
425
  ### Custom API Provider
471
426
 
472
427
  ```typescript
473
- const ctrl = new ClaudeCodeController({
474
- teamName: "custom",
475
- env: {
476
- ANTHROPIC_BASE_URL: "https://your-proxy.example.com/api/anthropic",
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
- // Per-agent overrides
482
- const agent = await ctrl.spawnAgent({
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
- ### Auto-Approve Everything (YOLO mode)
438
+ ### Selective Permission Control
489
439
 
490
440
  ```typescript
491
- ctrl.on("plan:approval_request", (agent, msg) => {
492
- ctrl.sendPlanApproval(agent, msg.requestId, true);
493
- });
494
-
495
- ctrl.on("permission:request", (agent, msg) => {
496
- ctrl.sendPermissionResponse(agent, msg.requestId, true);
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
- ### Selective Permission Control
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
- const SAFE_TOOLS = ["Read", "Glob", "Grep", "Task"];
504
- const NEEDS_REVIEW = ["Bash", "Write", "Edit"];
470
+ import { ClaudeCodeController } from "claude-code-controller";
505
471
 
506
- ctrl.on("permission:request", (agent, msg) => {
507
- if (SAFE_TOOLS.includes(msg.toolName)) {
508
- ctrl.sendPermissionResponse(agent, msg.requestId, true);
509
- } else if (NEEDS_REVIEW.includes(msg.toolName)) {
510
- console.log(`[REVIEW] ${agent} wants to use ${msg.toolName}: ${msg.description}`);
511
- // Implement your own review logic here
512
- ctrl.sendPermissionResponse(agent, msg.requestId, true);
513
- } else {
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
- <br />
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
- <br />
497
+ ### AgentHandle
524
498
 
525
- ## Web Dashboard
499
+ ```typescript
500
+ await agent.send("Analyze the codebase structure.");
501
+ const response = await agent.receive({ timeout: 30_000 });
526
502
 
527
- A built-in web UI for real-time agent management no code required.
503
+ const answer = await agent.ask("What framework is this project using?", {
504
+ timeout: 60_000,
505
+ });
528
506
 
529
- ```bash
530
- cd web && bun install
507
+ agent.isRunning; // boolean
508
+ agent.pid; // process ID
509
+ await agent.shutdown(); // graceful
510
+ await agent.kill(); // force
531
511
  ```
532
512
 
533
- **Development:**
513
+ ### Messaging
534
514
 
535
- ```bash
536
- bun run dev # backend on :3456
537
- bun run dev:vite # frontend on :5174
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
- **Production:**
521
+ ### Task Management
541
522
 
542
- ```bash
543
- bun run build && bun run start # everything on :3456
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
- The dashboard gives you:
534
+ ### Events
547
535
 
548
- - **Session management** — Initialize and shut down the controller
549
- - **Agent spawning** — Configure name, type, model, and environment variables
550
- - **Live message feed** — Real-time messages via WebSocket
551
- - **Approval prompts** — Interactive plan and permission approval banners
552
- - **Agent controls** — Shutdown or kill agents individually
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 (89 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