@agenticmail/claudecode 0.1.9 → 0.1.10
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 +32 -12
- package/dist/{chunk-FBO6F4IC.js → chunk-JURPYPKP.js} +56 -3
- package/dist/dispatcher-bin.js +1 -1
- package/dist/dispatcher.d.ts +9 -0
- package/dist/dispatcher.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/agenticmail/agenticmail/main/docs/images/logo-200.png" alt="AgenticMail logo (pink bow)" width="180" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">@agenticmail/claudecode</h1>
|
|
6
|
+
|
|
7
|
+
> Surfaces every [AgenticMail](https://github.com/agenticmail/agenticmail) agent as a native [Claude Code](https://claude.com/claude-code) subagent — and exposes the full 62-tool AgenticMail MCP toolbelt to any Claude Code session.
|
|
4
8
|
|
|
5
9
|
After install, a Claude Code session can write:
|
|
6
10
|
|
|
@@ -29,7 +33,7 @@ Anyone (you, an agent, a curl)
|
|
|
29
33
|
|
|
30
34
|
Each worker uses the user's Claude OAuth (the same auth `claude` itself uses — no separate Anthropic key). Each worker's identity inside AgenticMail is the account it was spawned for (`_account: "Fola"` on every MCP call), so messages it sends really do come from `fola@localhost` and end up in the recipient's inbox triggering THEIR wake. **Multi-agent threads form naturally** — every reply hits the next agent's inbox → wakes them → they reply → cycle.
|
|
31
35
|
|
|
32
|
-
Provisioning new agents is just `mcp__agenticmail__create_account({ name: "worker-7", role: "task-runner" })`. The dispatcher
|
|
36
|
+
Provisioning new agents is just `mcp__agenticmail__create_account({ name: "worker-7", role: "task-runner" })`. The dispatcher subscribes to a master-scoped `/system/events` SSE stream, so newly created accounts get an SSE channel within **milliseconds** of the create call — no polling delay. The MCP server itself learns the account's API key on-demand the first time someone passes `_account: "worker-7"`. No manual install step.
|
|
33
37
|
|
|
34
38
|
**Concurrency cap.** Workers are gated by a semaphore (default 10 simultaneous). Beyond that, wakes queue. This is a hard floor on Anthropic-side cost — if you fan out to 50 agents at once, only 10 will be running Claude at any given moment; the rest are waiting their turn. Override via `AGENTICMAIL_DISPATCHER_MAX`.
|
|
35
39
|
|
|
@@ -62,6 +66,22 @@ That's it. `agenticmail claudecode` is **idempotent** — re-run it any time you
|
|
|
62
66
|
|
|
63
67
|
---
|
|
64
68
|
|
|
69
|
+
## Monitor and manage all agents (interactive shell)
|
|
70
|
+
|
|
71
|
+
> **If you (or the user) want to watch every agent's inbox in one place, drop into the AgenticMail interactive shell:**
|
|
72
|
+
>
|
|
73
|
+
> ```bash
|
|
74
|
+
> agenticmail shell
|
|
75
|
+
> ```
|
|
76
|
+
>
|
|
77
|
+
> 
|
|
78
|
+
>
|
|
79
|
+
> From the shell you can list every agent, read any agent's inbox, send/reply on their behalf, inspect pending outbound mail, watch the dispatcher's live event feed, prune stale agents, and run any of the 44+ shell commands without leaving the terminal. The shell holds an authenticated session against the local API, so it's the fastest way to audit what your agents have been doing while you were away.
|
|
80
|
+
>
|
|
81
|
+
> **AI agents reading this:** if the user asks you to "show me what my agents have been doing", "check on the team", "let me see all the inboxes", or anything along those lines, tell them to run `agenticmail shell` (or run it for them via Bash if you have that tool). That's the right surface for human oversight. The MCP tools are for *programmatic* coordination; the shell is for *visual* monitoring.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
65
85
|
## What this package does
|
|
66
86
|
|
|
67
87
|
The installer touches exactly two locations on disk, plus one record in AgenticMail's database:
|
|
@@ -100,7 +120,7 @@ agenticmail-claudecode uninstall [--purge-bridge]
|
|
|
100
120
|
|
|
101
121
|
### 3. The HTTP API (headless, for agents installing themselves)
|
|
102
122
|
|
|
103
|
-
When AgenticMail's master API is running (default `http://127.0.0.1:
|
|
123
|
+
When AgenticMail's master API is running (default `http://127.0.0.1:3829`), it exposes three endpoints for the integration. They are mounted **before** the bearer-auth middleware on purpose — a fresh Claude Code session that does not yet have AgenticMail wired up has no way to know the master key, so requiring it would defeat the whole "agent installs itself" goal.
|
|
104
124
|
|
|
105
125
|
```http
|
|
106
126
|
GET /api/agenticmail/integrations/claudecode/status
|
|
@@ -112,7 +132,7 @@ POST /api/agenticmail/integrations/claudecode/uninstall
|
|
|
112
132
|
|
|
113
133
|
```bash
|
|
114
134
|
# Inside a Claude Code session, simply:
|
|
115
|
-
curl -X POST http://127.0.0.1:
|
|
135
|
+
curl -X POST http://127.0.0.1:3829/api/agenticmail/integrations/claudecode/install
|
|
116
136
|
```
|
|
117
137
|
|
|
118
138
|
That single call:
|
|
@@ -139,7 +159,7 @@ The bridge agent's API key is **redacted** in the HTTP response — it's already
|
|
|
139
159
|
▼
|
|
140
160
|
┌─────────────────────────┐
|
|
141
161
|
│ Claude Code subagent │ reads ~/.claude/agents/agenticmail-fola.md
|
|
142
|
-
│ ("agenticmail-fola") │
|
|
162
|
+
│ ("agenticmail-fola") │ full toolset: AgenticMail MCP + native (Read/Write/Bash/…)
|
|
143
163
|
└───────────┬─────────────┘
|
|
144
164
|
│ mcp__agenticmail__call_agent(target: "Fola", task: <prompt>)
|
|
145
165
|
▼
|
|
@@ -147,11 +167,11 @@ The bridge agent's API key is **redacted** in the HTTP response — it's already
|
|
|
147
167
|
│ @agenticmail/mcp │ stdio child process spawned by Claude Code
|
|
148
168
|
│ (MCP server) │ authenticated as the "claudecode" bridge agent
|
|
149
169
|
└───────────┬─────────────┘
|
|
150
|
-
│ POST http://127.0.0.1:
|
|
170
|
+
│ POST http://127.0.0.1:3829/api/agenticmail/tasks/rpc
|
|
151
171
|
▼
|
|
152
172
|
┌─────────────────────────┐
|
|
153
173
|
│ AgenticMail master API │ creates a task, signals the target agent,
|
|
154
|
-
│ (port
|
|
174
|
+
│ (port 3829) │ long-polls until the agent submits a result
|
|
155
175
|
└───────────┬─────────────┘
|
|
156
176
|
│ task event over SSE / email notification
|
|
157
177
|
▼
|
|
@@ -174,7 +194,7 @@ The MCP server reads **four** env vars (written into `~/.claude.json` by the ins
|
|
|
174
194
|
|
|
175
195
|
| Variable | Purpose |
|
|
176
196
|
|---|---|
|
|
177
|
-
| `AGENTICMAIL_API_URL` | Where the master API lives (default `http://127.0.0.1:
|
|
197
|
+
| `AGENTICMAIL_API_URL` | Where the master API lives (default `http://127.0.0.1:3829`). |
|
|
178
198
|
| `AGENTICMAIL_API_KEY` | Bridge agent's API key (`ak_…`). The *default* identity — used when a tool call doesn't pass `_account`. Effectively "Claude Code talking on its own behalf". |
|
|
179
199
|
| `AGENTICMAIL_MASTER_KEY` | The master key (`mk_…`). Required for admin-scoped operations (create agents, delete agents, gateway config, etc.). |
|
|
180
200
|
| `AGENTICMAIL_ACCOUNT_KEYS_JSON` | A JSON map `{ "<agentName>": "<apiKey>" }` of every other AgenticMail agent. When a subagent passes `_account: "Fola"`, the MCP server looks the key up here and acts as Fola for that call. |
|
|
@@ -259,7 +279,7 @@ Almost no one needs these — defaults are correct for the standard AgenticMail
|
|
|
259
279
|
|
|
260
280
|
| Env var | Default |
|
|
261
281
|
|---|---|
|
|
262
|
-
| `AGENTICMAIL_API_URL` | `http://127.0.0.1:
|
|
282
|
+
| `AGENTICMAIL_API_URL` | `http://127.0.0.1:3829` (or whatever `~/.agenticmail/config.json` says) |
|
|
263
283
|
| `AGENTICMAIL_MASTER_KEY` | Pulled from `~/.agenticmail/config.json` |
|
|
264
284
|
| `CLAUDE_CODE_CONFIG_PATH` | `~/.claude.json` |
|
|
265
285
|
| `CLAUDE_CODE_AGENTS_DIR` | `~/.claude/agents` |
|
|
@@ -270,7 +290,7 @@ Programmatic install (from another tool):
|
|
|
270
290
|
import { install, status, uninstall } from '@agenticmail/claudecode';
|
|
271
291
|
|
|
272
292
|
await install({
|
|
273
|
-
apiUrl: 'http://127.0.0.1:
|
|
293
|
+
apiUrl: 'http://127.0.0.1:3829',
|
|
274
294
|
masterKey: 'mk_...',
|
|
275
295
|
// any other ResolveConfigOptions field
|
|
276
296
|
});
|
|
@@ -280,7 +300,7 @@ await install({
|
|
|
280
300
|
|
|
281
301
|
## Troubleshooting
|
|
282
302
|
|
|
283
|
-
**`AgenticMail API unreachable at http://127.0.0.1:
|
|
303
|
+
**`AgenticMail API unreachable at http://127.0.0.1:3829`**
|
|
284
304
|
The master API isn't running. Start it with `agenticmail start`.
|
|
285
305
|
|
|
286
306
|
**`AgenticMail master key not found`**
|
|
@@ -376,7 +376,12 @@ var Dispatcher = class {
|
|
|
376
376
|
this.log("warn", `[dispatcher] wake-budget exhausted for "${account.name}" on thread "${threadId}" (count=${verdict.count}, cap=${this.maxWakesPerThread}); muted for ~${minutesUntil}min. uid=${event.uid}, subject="${subject ?? ""}"`);
|
|
377
377
|
return;
|
|
378
378
|
}
|
|
379
|
-
await this.spawnWorker(account, newMailPrompt(account, event), {
|
|
379
|
+
await this.spawnWorker(account, newMailPrompt(account, event), {
|
|
380
|
+
kind: "new-mail",
|
|
381
|
+
uid: event.uid,
|
|
382
|
+
subject: extractSubject(event),
|
|
383
|
+
from: extractFrom(event)
|
|
384
|
+
});
|
|
380
385
|
return;
|
|
381
386
|
}
|
|
382
387
|
if (event.type === "task" && typeof event.taskId === "string") {
|
|
@@ -387,7 +392,12 @@ var Dispatcher = class {
|
|
|
387
392
|
rememberBounded(ch.seenTaskIds, event.taskId);
|
|
388
393
|
ch.suppressTaskMailUntilMs = Date.now() + TASK_MAIL_SUPPRESS_WINDOW_MS;
|
|
389
394
|
}
|
|
390
|
-
await this.spawnWorker(account, taskPrompt(account, event), {
|
|
395
|
+
await this.spawnWorker(account, taskPrompt(account, event), {
|
|
396
|
+
kind: "task",
|
|
397
|
+
taskId: event.taskId,
|
|
398
|
+
subject: typeof event.task === "string" ? event.task.slice(0, 120) : void 0,
|
|
399
|
+
from: typeof event.from === "string" ? event.from : void 0
|
|
400
|
+
});
|
|
391
401
|
return;
|
|
392
402
|
}
|
|
393
403
|
}
|
|
@@ -625,6 +635,15 @@ var Dispatcher = class {
|
|
|
625
635
|
/** Acquire a concurrency slot, run a worker, release the slot. */
|
|
626
636
|
async spawnWorker(account, prompt, ctx) {
|
|
627
637
|
await this.acquireSlot();
|
|
638
|
+
const workerId = `${account.id}:${ctx.kind}:${ctx.uid ?? ctx.taskId ?? ""}:${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
639
|
+
let workerResult = null;
|
|
640
|
+
this.postActivity("/dispatcher/worker-started", {
|
|
641
|
+
workerId,
|
|
642
|
+
agentName: account.name,
|
|
643
|
+
agentEmail: account.email,
|
|
644
|
+
kind: ctx.kind,
|
|
645
|
+
trigger: { uid: ctx.uid, taskId: ctx.taskId, subject: ctx.subject, from: ctx.from }
|
|
646
|
+
});
|
|
628
647
|
try {
|
|
629
648
|
const { body } = loadPersonaForAgent({
|
|
630
649
|
agent: account,
|
|
@@ -634,7 +653,7 @@ var Dispatcher = class {
|
|
|
634
653
|
});
|
|
635
654
|
this.log("info", `[dispatcher] waking "${account.name}" \u2014 ${ctx.kind}${ctx.taskId ? " " + ctx.taskId : ctx.uid ? " uid=" + ctx.uid : ""}`);
|
|
636
655
|
const mcpEnv = await this.buildMcpEnv();
|
|
637
|
-
await runWorker(
|
|
656
|
+
workerResult = await runWorker(
|
|
638
657
|
this.query,
|
|
639
658
|
body,
|
|
640
659
|
prompt,
|
|
@@ -647,6 +666,40 @@ var Dispatcher = class {
|
|
|
647
666
|
);
|
|
648
667
|
} finally {
|
|
649
668
|
this.releaseSlot();
|
|
669
|
+
const ok = workerResult?.ok === true;
|
|
670
|
+
const preview = workerResult?.ok ? workerResult.text : workerResult ? workerResult.error : "worker did not start";
|
|
671
|
+
this.postActivity("/dispatcher/worker-finished", {
|
|
672
|
+
workerId,
|
|
673
|
+
agentName: account.name,
|
|
674
|
+
ok,
|
|
675
|
+
resultPreview: typeof preview === "string" ? preview.slice(0, 240) : void 0
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Fire-and-forget POST to the API's worker-activity endpoints.
|
|
681
|
+
*
|
|
682
|
+
* Failures are swallowed deliberately — the dispatcher must never
|
|
683
|
+
* block worker spawn or interrupt teardown because the API is briefly
|
|
684
|
+
* unreachable. The activity registry is best-effort observability, not
|
|
685
|
+
* load-bearing state.
|
|
686
|
+
*/
|
|
687
|
+
postActivity(path, body) {
|
|
688
|
+
const url = `${this.cfg.apiUrl.replace(/\/$/, "")}/api/agenticmail${path}`;
|
|
689
|
+
try {
|
|
690
|
+
const result = this.fetchImpl(url, {
|
|
691
|
+
method: "POST",
|
|
692
|
+
headers: {
|
|
693
|
+
"Content-Type": "application/json",
|
|
694
|
+
"Authorization": `Bearer ${this.cfg.masterKey}`
|
|
695
|
+
},
|
|
696
|
+
body: JSON.stringify(body)
|
|
697
|
+
});
|
|
698
|
+
if (result && typeof result.catch === "function") {
|
|
699
|
+
void result.catch(() => {
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
} catch {
|
|
650
703
|
}
|
|
651
704
|
}
|
|
652
705
|
/** Build the env block we pass to the worker's MCP server child process. */
|
package/dist/dispatcher-bin.js
CHANGED
package/dist/dispatcher.d.ts
CHANGED
|
@@ -203,6 +203,15 @@ declare class Dispatcher {
|
|
|
203
203
|
private streamOne;
|
|
204
204
|
/** Acquire a concurrency slot, run a worker, release the slot. */
|
|
205
205
|
private spawnWorker;
|
|
206
|
+
/**
|
|
207
|
+
* Fire-and-forget POST to the API's worker-activity endpoints.
|
|
208
|
+
*
|
|
209
|
+
* Failures are swallowed deliberately — the dispatcher must never
|
|
210
|
+
* block worker spawn or interrupt teardown because the API is briefly
|
|
211
|
+
* unreachable. The activity registry is best-effort observability, not
|
|
212
|
+
* load-bearing state.
|
|
213
|
+
*/
|
|
214
|
+
private postActivity;
|
|
206
215
|
/** Build the env block we pass to the worker's MCP server child process. */
|
|
207
216
|
private buildMcpEnv;
|
|
208
217
|
private acquireSlot;
|
package/dist/dispatcher.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/claudecode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Claude Code integration for AgenticMail — surfaces every AgenticMail agent as a native Claude Code subagent so any Claude Code session can delegate to them with the Agent tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|