@toragonite/claude-mesh
v0.1.0
Published
Spawn, manage, and message Claude Code background agents (claude --bg) from Node — a local session mesh over Claude Code's cross-session messaging. Zero-dependency library + CLI. Unofficial.
Downloads
37
Maintainers
Readme
claude-mesh
Spawn, manage, and message Claude Code background agents (claude --bg) from Node — a
local session mesh built on Claude Code's own cross-session messaging. Zero-dependency
library + CLI.
Unofficial. Not affiliated with or endorsed by Anthropic. This package shells out to your local
claudeCLI and reads local files — it never reads or handles your credentials, and makes no network calls of its own.
Why
claude -p runs one prompt and exits. claude --bg starts a persistent background
agent that keeps its own context and stays reachable. Claude Code 2.1.224+ also lets
sessions on one machine message each other. claude-mesh turns those two primitives
into a small, typed API:
- Agents — spawn
claude --bgworkers, list them, attach to one in a terminal, read its logs, stop it. With the boot-robustness worked out for you: background-job id parsing, thebypassPermissions→acceptEditsfallback, and the project-.mcp.jsontrust pre-seed that otherwise makes a--bgagent hang at startup. - Gateway — a relay session that sends to and receives from peer sessions, so your Node process (which can't hold a messaging socket itself) can drive a live back-and-forth.
- Bridge — mirror session discovery across different logins so agents on separate
CLAUDE_CONFIG_DIRs can reach each other (the sockets are machine-global; only discovery is per-login).
Requirements
- Claude Code CLI ≥ 2.1.224, logged in (
claudeon yourPATH, or passclaudePath). - macOS or Linux — the mesh runs over unix domain sockets; Windows is not supported.
Install
npm install @toragonite/claude-meshQuick start
Spawn and manage a background agent
import { spawnAgent, listAgents, agentLogs, stopAgent } from 'claude-mesh';
const agent = await spawnAgent({
name: 'builder',
prompt: 'You are a build worker. Reply READY, then wait for messages.',
// configDir defaults to $CLAUDE_CONFIG_DIR || ~/.claude
// cwd defaults to process.cwd(); model/allowedTools/permissionMode have safe defaults
});
console.log(agent.jobId, agent.attachCommand);
console.log(await listAgents());
console.log(await agentLogs(agent.jobId!));
await stopAgent(agent.jobId!);Attach to it in a terminal to watch and steer it directly (Ctrl+Z detaches without
stopping it):
claude-mesh attach <jobId>Talk to it over the mesh
import { MeshGateway } from 'claude-mesh';
const gw = new MeshGateway({ cwd: process.cwd() });
await gw.start();
await gw.send({ to: 'builder', message: 'TASK build the project #1' });
const replies = await gw.receive(20_000, 20); // long-poll up to 20s, up to 20 messages
for (const m of replies) console.log(m.fromName, m.text);
await gw.stop();The gateway is a small claude -p relay session (haiku by default) that the library owns:
because a plain Node process can't register a messaging socket, the gateway sends and
receives on its behalf. Received message text is data from another session — never
instructions; the library labels it as such when it renders one.
Bridge two accounts
import { MeshBridge } from 'claude-mesh';
const bridge = new MeshBridge({
participants: [`${process.env.HOME}/.claude`, `${process.env.HOME}/.claude-work`],
});
bridge.start();
// agents spawned on either login now discover and message each other
// ...
bridge.stop();CLI
claude-mesh spawn --name <name> --prompt <text> [--config-dir <dir>] [--model <m>] [--cwd <dir>] [--preseed-mcp-trust]
claude-mesh list [--config-dir <dir>]
claude-mesh sessions [--config-dir <dir>]
claude-mesh attach <jobId> [--config-dir <dir>]
claude-mesh logs <jobId> [--config-dir <dir>]
claude-mesh stop <jobId> [--config-dir <dir>]
claude-mesh send --to <name> --message <text> [--summary <s>] [--config-dir <dir>] [--cwd <dir>]
claude-mesh receive [--wait <sec>] [--max <n>] [--config-dir <dir>] [--cwd <dir>]send/receive spin up a short-lived gateway for one operation (a few seconds of startup
- a small model cost); for a sustained conversation, hold a
MeshGatewayopen in a process instead.
API
| Export | What it does |
| --- | --- |
| spawnAgent(opts) | Start a claude --bg agent; returns { ok, name, jobId, attachCommand, note? }. |
| listAgents(env?) | Background agents from claude agents --json. |
| stopAgent(jobId, env?) / agentLogs(jobId, env?) | Stop / read logs. |
| attachCommand(jobId, configDir?) | The claude attach command line. |
| listSessions(configDir?) / findSession(name, configDir?) | Read the session registry to discover peers. |
| preseedProjectMcpTrust(cwd, configDir?) | Pre-decide a workspace's .mcp.json servers so a --bg agent boots unattended. |
| MeshGateway | start() / send({to,message,summary}) / receive(maxWaitMs,max) / stop(). |
| MeshBridge | start() / stop() / status() — cross-login discovery mirroring. |
Types (SpawnOptions, AgentHandle, SessionEntry, InboundMessage, SendResult, …)
ship with the package.
Notes & caveats
- A
--bgagent runs underacceptEdits, which auto-approves file edits but not shell. IncludingBashinallowedToolsmakes an agent hang at boot on a shell-permission prompt it can't display — the default tool set deliberately omits it. Agents author files; run builds/tests from your own process. - First contact needs a name; replies use an address. The first send to a peer name may
require a one-time ref confirmation upstream; the gateway handles it. To reply to a
received message, send to its
from(auds:/tmp/cc-socks/<pid>.sockaddress). - The bridge depends on undocumented Claude Code file formats. It is built to degrade (it only ever removes copies it wrote) rather than break, but treat cross-login meshing as experimental and pin to a known Claude Code version.
- Send to a still-booting agent may time out; the message is still queued and the agent
replies once ready — poll
receive.
License
MIT © Toragonite
