-
Notifications
You must be signed in to change notification settings - Fork 0
Peer Tasks
The host's agent can hand a piece of work to a guest's own Claude Code. It runs on that guest's machine, in their own already-authenticated session, spending their own quota — and only after they say yes to that specific task.
This page is the compliance frame as much as the how-to. Read the two sections at the bottom before you turn it on for a team.
| switch | who holds it | without it |
|---|---|---|
claude-jam host --peer-tasks |
the host, at launch | the host's claude gets no tools at all, and /peer on is refused with the reason |
/peer on |
each guest, in their own client | that person is invisible to list_peers() and cannot be dispatched to |
| the per-task approval | that guest, every time | nothing runs |
Two switches, held by two different people, and neither one alone is enough. There is no
always on this ladder — unlike every other approval in claude-jam, the same person is asked
again for every single task.
# the host
claude-jam host --peer-tasks# the guest, in their own client
/peer on
Two MCP tools, registered from a generated file in the jam's own state dir (your
~/.claude.json, your project's .mcp.json and your global settings are never read and never
written; the registration is additive, so your own MCP servers keep working):
| tool | signature |
|---|---|
list_peers |
() → [{name, capable, busy, tasksToday}] |
dispatch_to_peer |
({peer, prompt, allowedTools?, maxTurns?, deadlineMs?, schema?}) → the answer, or the reason it did not happen |
capable is that person's own opt-in — the host cannot set it and neither can the agent. busy
means they are already running one; nothing is queued. schema gives structured output,
exactly as the built-in Agent tool does.
The whole prompt, the exact tool list, both caps and the directory it would run in:
⇄ Roy wants to run a task on YOUR machine, in YOUR Claude Code, on YOUR quota.
tools WebSearch, WebFetch, Read, Grep, Glob (read-only)
caps up to 12 turns · 3m wall clock
runs in /tmp/claude-jam-peer-8f3a91c2 — created for this task, removed after, never your repo
your own MCP servers are OFF for it, and it inherits none of your settings
the prompt, in full — this is text from another machine, read it before you answer:
│ find the current wording of the WebSocket close-code registry and quote it
[a]ccept · [d]ecline · [n]ever this session · Esc cancels it once it is running
-
d, or/peer decline— this one task. No reason needed and none is asked for. -
n, or/peer never— nothing more is offered to you for the rest of this client session. It is a one-way door: only restarting your client changes it, and no host can clear it. -
/peer off— take your machine back off the list;/peer onputs it back. -
Esc, or/peer cancel— stop a task that is already running. The process is killed and the host's agent is told you cancelled it. - Just closing your client. A task in flight ends with a reason the host's agent can act on.
A decline is a decision, not a failure. The host's agent is told "they declined it" — a different answer from a timeout, a cap-hit or a crash — precisely so that it does not retry.
- Per-task approval. No standing grant, ever.
-
Default whitelist is read-only research:
WebSearch,WebFetch,Read,Grep,Glob. Exact tool names, never rule patterns — the list has to be readable in one line by the person consenting to it. -
Bash,WriteandEditneed a second, typed gate. A task may ask for them, but one keypress will not grant them: the guest types/peer accept tools, for that one task, every time. Somebody fumbling a keystroke must not be able to hand over a shell. -
A fresh scratch directory —
$TMPDIR/claude-jam-peer-<id>, created 0700 for the task and removed when it ends, every way it can end. Never your repository, never your home. -
Your MCP servers are off for it:
--strict-mcp-configwith no MCP config at all, so nothing you have connected — a database, a ticket system, a cloud account — is reachable by a prompt that arrived over a network. -
It inherits none of your settings.
--restrictedmakes claude ignore your user, project and local settings files, refusebypassPermissions, and confine the file tools to that one directory. A machine whose own default isbypassPermissions— plenty are — does not hand that to work somebody else asked for. -
The permission mode is always passed, and is always
plan(oracceptEditswhen something that writes was granted). NeverbypassPermissions, never--dangerously-skip-permissions. A unit test and an end-to-end smoke both assert this against the argv that is actually used. -
The prompt goes in on stdin, never an argv: an argv is visible in
psto every user on your machine, and this text came off a network. - Two caps, both enforced by killing the process by its pid: a wall clock (3 minutes by default, 10 maximum) and a turn count (12 by default, 40 maximum).
-
A per-guest daily counter you can zero (
/peer reset), shown in/peersand inlist_peers(). -
An audit log both sides can read:
/peers log. Who asked, who ran it, which tools, how long, how it ended, and the head of the prompt.
maxTurns bounds how many times the model is asked, not what each of those asks costs. A
single turn can read a large file or run a long search. If you care about spend, the wall clock is
the cap that actually ends things, and your own account's usage page is the only real number.
(claude 2.1.251 has no --max-turns flag at all, so claude-jam counts the response stream itself
and terminates the process.)
Host → guest. The prompt is untrusted text that will be read by an agent on somebody else's computer. That is what the narrow whitelist, the empty scratch directory, the absent MCP servers, the ignored settings and — above all — the human reading it in full before answering are for.
Guest → host. The result is untrusted text arriving in the host agent's context. It is quoted
into the transcript behind a │ , with the [Name]: participant form neutralised so it cannot
impersonate anybody, and it is handed to the host's agent behind a banner saying what it is. It
is never executed and never auto-applied to a file.
The copy the host's agent gets is fenced rather than prefixed, because a structured (JSON)
answer has to stay readable — and until 0.22.1 a result could close that fence, putting its own
text after --- end peer output --- where the banner no longer covered it. A result line that is a
fence marker now has its leading hyphen bent, the same way a forged [Name]: has its bracket bent:
it still reads, and it is no longer the delimiter. A result's text never reaches /peers log at
all — the audit line records the prompt, the tools, the caps, the outcome and a character count,
and nothing the peer wrote.
Everything, attributed [Dana → task]: what was asked (with the tool list and the caps), that it
was accepted, each line of progress, and the answer. A task only the two parties could see would
be a private channel inside a shared session, which is the one thing claude-jam is not.
| answer | what happened |
|---|---|
declined |
they said no. A decision — do not retry it |
timeout |
the wall clock ran out and the process was killed |
cap |
the turn cap was hit and the process was killed |
cancelled |
they stopped it while it was running |
crash |
their claude exited without finishing; the reason is its own stderr |
Partial output is preserved on every one of them. A busy or offline peer is reported with its reason, never silently queued.
Claude Code subscriptions are individual. Peer tasks are built so that every single task is one person choosing, in the moment, to spend their own quota on a piece of work they were shown in full — which is ordinary individual usage of each account, on each person's own machine, with no credential shared and none pooled.
Whether a coordinated multi-account fan-out counts as ordinary individual usage is not settled. We are saying so here, out loud, rather than letting somebody discover it later. If you are planning a jam where one agent routinely dispatches to several people at once in order to get more throughput than one subscription gives, that is the question to ask before you build on it. Check the terms that apply to your accounts, and if you are a company, ask whoever owns that decision.
--peer-tasks is off by default for this reason as much as for any technical one.
Even where it is unambiguously fine, remember what a dispatch costs: somebody else's money and somebody else's attention. Ask for work that is worth interrupting a person for — research, a second opinion, something on a machine you cannot reach — not everything the agent could have done itself.
- Security-Model — the trust boundaries in the rest of claude-jam
- Hosting-a-Jam — the host's flags
- Architecture — how the daemon, the clients and the tmux session fit together