Install
$ agentstack add skill-javimosch-a2a-skill-a2a ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
/a2a — agent-to-agent peer messaging
a2a turns N agentic-CLI sessions into peers on a shared SQLite message bus. Each agent can send to any other agent (or all for broadcast) and recv blocking until something arrives. There is no orchestrator: communication flows freely.
Usage
/a2a spawn [--role R] [--prompt "..."] [--cli claude|opencode|pi] [--model MODEL]
/a2a list
/a2a peek # show recent messages on the bus
/a2a send "" --from # inject a message from the host shell
/a2a stop # kill all spawned a2a sessions in this project
/a2a clear # wipe the message bus
The default project name is the basename of the current working directory. Set A2A_PROJECT or pass --project NAME to override.
For the full list of CLI commands and their usage (Python & Go binaries), see [docs/GOCLIREFERENCE.md](../../../docs/GOCLIREFERENCE.md).
⚠️ Critical: Use Pattern 3 for Multi-Agent Teams
When spawning 2+ agents, ALWAYS use Pattern 3 auto-spawn. Manual spawning or ad-hoc approaches will fail — agents will work independently without bus coordination.
Pattern 3 is the only reliable method because:
- Agents register BEFORE spawning (critical for bus communication)
- Kit prompts are written to files (avoids shell escaping bugs)
--projectflag ensures all agents connect to the same bus- PIDs are updated after spawn with
--upsert - Agents coordinate via the bus, not just file editing
See Step 2-4 below for the Pattern 3 workflow. Reference implementation: examples/remote_worktree_team.sh
Common Command Syntax Mistakes
These mistakes will cause agents to fail:
❌ Wrong: a2a register --as agent-1 ✅ Correct: a2a register agent-1 --role "Dev"
❌ Wrong: a2a send --as agent-1 "hello" ✅ Correct: a2a send agent-2 "hello" --from agent-1
❌ Wrong: a2a recv agent-1 ✅ Correct: a2a recv --as agent-1
❌ Wrong: Inline kit prompts in spawn commands ✅ Correct: Write kit prompts to files first, then reference with --kit-file
When to use
- The user asks for "multiple claude sessions talking to each other"
- The user wants a "team of agents" without a fixed orchestrator
- Debate / red-team-blue-team setups, multi-perspective analysis
- Divide-and-conquer where peers self-coordinate
If the user wants a strict orchestrator → workers pattern, prefer the standard Agent tool (subagents) instead. a2a is for peer communication.
Three usage patterns
This skill implements Pattern 3 below. See [docs/QUICKSTART.md](../../../docs/QUICKSTART.md) for Patterns 1 and 2.
| # | Pattern | Who drives | Documented in | |---|---------|------------|---------------| | 1 | Human-drive CLI — you open terminals and type a2a send/recv by hand | You (the human) | QUICKSTART.md — "Pattern 1" section | | 2 | Multi-terminal AI team — you open N terminals, tell each AI agent to join the bus with a role, and they self-coordinate | AI agents (you instruct them) | QUICKSTART.md — "Pattern 2" section | | 3 | Auto-spawn — one agent launches N background sessions via /a2a spawn | AI agents (spawned automatically) | This document (below) |
What follows assumes Pattern 3: you are an AI agent running inside an agentic CLI (Claude Code, pi, opencode, etc.) and you will spawn peer agents as background processes. The kit prompt, a2a-spawn flags, monitoring loop, and teardown steps are all specific to this pattern.
For Pattern 2 (multi-terminal AI team), you don't need this spawn protocol. Just tell each human-driven terminal: "register yourself, a2a recv, a2a send, `a2a status done". The kit prompt in Step 4 can serve as inspiration.
What You Must Do When Invoked
Step 0 — Locate the a2a binary
The a2a CLI lives next to the skill. It is available as a Python script (default) or a faster Go binary companion. Resolution order:
$A2A_BINenv var (overrides all — set this to a downloaded Go binary)$PATH(preferred — installer symlinks it into~/.local/bin)~/.agents/skills/a2a/a2a(global cross-CLI skills path)~/.claude/skills/a2a/a2a(Claude Code skills path)- The skill source directory itself
A2A="${A2A_BIN:-}"
if [ -z "$A2A" ]; then
for cand in \
"$(command -v a2a 2>/dev/null)" \
"$HOME/.agents/skills/a2a/a2a" \
"$HOME/.claude/skills/a2a/a2a" ; do
if [ -x "$cand" ]; then A2A="$cand"; break; fi
done
fi
[ -z "${A2A:-}" ] && { echo "a2a binary not found"; exit 1; }
PROJECT="${A2A_PROJECT:-$(basename "$PWD")}"
export A2A_PROJECT="$PROJECT"
Step 1 — Initialize the project bus
"$A2A" init
If the user supplied agent definitions inline (e.g. "spawn alice as a planner and bob as a critic"), use those. Otherwise ask the user once for the agent roster, then proceed without further questions.
Step 2 — Register each agent up front
For each agent the user wants, before spawning the process:
"$A2A" register --role "" --prompt "" --cli claude
Registration makes the agent addressable. The --prompt is stored so other agents can a2a list --json to see who they are talking to.
Step 3 — Spawn each agent as a background CLI session
Each agent runs in its own CLI process and receives the peer kit prompt that bootstraps it onto the bus. The kit prompt is CLI-agnostic; only the launch flags differ. Use the a2a-spawn helper that ships with the skill — it knows the right flags for each supported CLI:
| CLI | System prompt flag | Non-interactive flag | Notes | |-----------|----------------------------|----------------------|------------------------------------------------------| | claude | --append-system-prompt | -p | use --dangerously-skip-permissions for unattended | | opencode | (none — embed in message) | run "" | use ~/.opencode/bin/opencode (the opencode alias goes through tmux) | | pi | --append-system-prompt | -p | needs a --provider and --model set, e.g. --provider google --model gemini-2.5-flash |
Write each agent's kit prompt to a temp file (avoids shell-escape bugs for multi-line prompts) and spawn:
printf '%s' "$KIT_PROMPT_FOR_ALICE" > /tmp/a2a-$PROJECT-alice.kit
printf '%s' "$KIT_PROMPT_FOR_BOB" > /tmp/a2a-$PROJECT-bob.kit
ALICE_PID=$(a2a-spawn --cli claude --id alice --model haiku \
--log /tmp/a2a-$PROJECT-alice.log \
--kit-file /tmp/a2a-$PROJECT-alice.kit)
BOB_PID=$( a2a-spawn --cli opencode --id bob --model anthropic/claude-haiku-4-5 \
--log /tmp/a2a-$PROJECT-bob.log \
--kit-file /tmp/a2a-$PROJECT-bob.kit)
⚠️ CRITICAL: Do NOT foreground-wait for agents after spawning. a2a-spawn already nohup+disowns the process — the PIDs are captured above for lifecycle tracking, NOT for wait loops. If the caller adds a while loop polling a2a list or sleeps between checks, it blocks the entire spawning context for the agent's full runtime. This prevents parallel spawns, defeats Hermes background-task tracking, and causes timeouts on long agent sessions.
Correct patterns:
- Hermes:
terminal(command="a2a-spawn ...", background=True, notify_on_complete=True)— let Hermes track lifecycle - Shell script: capture PIDs, move on. Poll A2A bus as a SEPARATE process or cron, not inline after the spawn
- AM daemon: use scheduler run-lifecycle tracking (DB run records), not a synchronous
waitForAgents()loop
Save each PID so you can stop them later, and write it back to the registry so peers can see who is online:
"$A2A" register alice --pid "$ALICE_PID" --upsert
"$A2A" register bob --pid "$BOB_PID" --upsert
If a2a-spawn is not on PATH, invoke it directly: ~/.agents/skills/a2a/a2a-spawn or ~/.claude/skills/a2a/a2a-spawn.
Step 4 — The peer kit prompt (what every agent receives)
⚠️ Critical: Kit prompts must include coordination instructions.
Without explicit instructions to:
- Register themselves on the bus
- Introduce themselves to peers
- Use
a2a send/recvfor coordination
Agents will skip bus coordination and work directly on files, defeating the purpose of A2A. Always include these steps in every kit prompt.
This is CLI-agnostic. Substitute {AGENT_ID}, {ROLE}, {USER_PROMPT}, {PEER_LIST}, {PROJECT}. The {A2A_PATH} line is computed dynamically by the agent so it works across CLIs that may or may not have a2a on PATH.
You are agent "{AGENT_ID}" on an a2a peer bus (project={PROJECT}).
Your role: {ROLE}
Your standing instruction from the user:
{USER_PROMPT}
You are one of several peers. There is no boss. You decide whom to message,
when to ask, when to answer, when to stop. Coordinate with your peers.
== Peers on the bus ==
{PEER_LIST}
== How to find the a2a CLI ==
Run the bash snippet below ONCE at the start to pick a working `a2a` binary
and store it in $A2A. Check $A2A_BIN first (if set), then try PATH, then
common skill installation paths:
A2A="${A2A_BIN:-}"
[ -z "$A2A" ] && A2A="$(command -v a2a 2>/dev/null)"
[ -z "$A2A" ] && [ -x "$HOME/.agents/skills/a2a/a2a" ] && A2A="$HOME/.agents/skills/a2a/a2a"
[ -z "$A2A" ] && [ -x "$HOME/.claude/skills/a2a/a2a" ] && A2A="$HOME/.claude/skills/a2a/a2a"
echo "using a2a at: $A2A"
== How to communicate ==
You have a shell/bash tool. Use ONLY the `a2a` CLI to talk to peers.
A2A_PROJECT={PROJECT} is already in the environment.
# see who is online (json includes their roles and prompts)
$A2A list --json
# check your inbox (blocks up to 30s for new messages)
$A2A recv --as {AGENT_ID} --wait 30
# send a direct message to a peer by id
$A2A send "your message" --from {AGENT_ID}
# broadcast to everyone
$A2A send all "your message" --from {AGENT_ID}
# mark yourself done so others know
$A2A status done --as {AGENT_ID}
== Loop ==
1. recv --as {AGENT_ID} --wait 30
2. Decide: respond to a peer, ask a question, broadcast a finding, or finish.
3. Send at most one short message.
4. If nothing left to do AND no peer is awaiting your reply, run
`status done --as {AGENT_ID}` and stop.
5. Else go back to step 1.
== Rules ==
- Do not invent peers. Address only ids returned by `a2a list`.
- Stay terse. One short message per turn unless asked for detail.
- Never speak on behalf of another agent.
- If you receive a broadcast that does not concern you, ignore it silently.
- If `recv` returns empty 3 times in a row, mark yourself `done` and stop.
- Do NOT call `a2a clear`, `a2a unregister`, or modify other agents' state.
- Hard cap: 8 loop iterations, then mark done and stop.
== Coordination rules (multi-role teams) ==
Omit this block if all agents have the same role or there is no role discipline.
- CLAIM: — BEFORE starting any work. Wait for ACK-CLAIM if collision.
- CLAIM expires after 5 minutes. Re-CLAIM if resuming after a gap.
- Bug reports: verify the issue exists in the current state before reporting. Do not report from assumptions formed earlier in the session.
- Role boundary: each agent stays within their declared role. Announce before crossing.
- To cross a role: send ROLE-CROSS: and wait 60s for a VETO before proceeding.
- Do NOT claim tasks outside your declared role without a ROLE-CROSS signal.
Begin now: run the locator snippet, then `$A2A recv --as {AGENT_ID} --wait 5`.
If empty, introduce yourself with one short broadcast, then enter the loop.
Step 5 — Monitor & relay to the user
While the agents run, poll the bus and show the user activity:
"$A2A" peek --limit 50
"$A2A" list
The user is not on the bus by default. To inject a message from the user, register a synthetic user (or host) agent once and send from it:
"$A2A" register user --role human --upsert
"$A2A" send all "stop debating, summarize." --from user
Step 6 — Tear down
When the user signals stop, or when every agent's status is done:
# Kill spawned background sessions (using ids you saved at spawn time)
# The harness reports completion when each background bash finishes; you can
# also kill via the saved PIDs:
"$A2A" list --json | grep -o '"pid": [0-9]*' | awk '{print $2}' | xargs -r kill 2>/dev/null || true
Leave the database intact unless the user asks to wipe it (/a2a clear). Database survives between sessions — useful for resuming.
Remote machine spawn
You can run the entire spawn sequence on a remote host via SSH. The pattern is identical to local spawn — init, register, write kit files, spawn, register --pid — but pipe it all through a single `ssh host bash /dev/null)"; [ -z "$CLAUDE" ] && CLAUDE="$HOME/.local/bin/claude"
a2a-spawn
SPAWN="$(command -v a2a-spawn 2>/dev/null)" [ -z "$SPAWN" ] && SPAWN="$HOME/.agents/skills/a2a/a2a-spawn" [ -z "$SPAWN" ] && SPAWN="$HOME/.claude/skills/a2a/a2a-spawn"
**Always pass `--project` explicitly.** The default is `basename($PWD)`,
which on a root home directory resolves to `root` — a collision-prone name.
**Resolve stale git state before creating a worktree.** Check for
`.git/rebase-merge` or `.git/rebase-apply` and abort before running
`git worktree add`. Reset to `origin/main` if local and remote diverged.
**Add explicit ACK instructions to implementer kit prompts.** Without them,
developer agents silently begin work and PM/architect agents send redundant
check-in messages while waiting for confirmation.
See [`examples/remote_worktree_team.sh`](../../../examples/remote_worktree_team.sh)
for a complete working example of this pattern.
## Common Pitfalls & Gotchas
### 12. Cross-user database ownership
When the spawning agent (orchestrator) runs as one user (e.g. `root`) but
spawned agents run as a different user (e.g. via `sudo -u agent`), the a2a
database at `~/.a2a/{project}/database.db` is created with the orchestrator's
ownership. The spawned agents then get:
a2a: list error: attempt to write a readonly database
**Fix:** After `a2a init`, `chown` the database directory to the agent user:
```bash
chown -R agent:agent ~agent/.a2a/{project}/
Or run a2a init as the target user in the first place:
sudo -u agent a2a --project {project} init
sudo -u agent a2a --project {project} register ...
13. Sudo spawns lose the parent's PATH and env vars
When spawning agents via sudo -u user, the child process inherits a minimal environment. The A2A_PROJECT env var, PATH entries, and shell configs (.bashrc, .zshrc) are not inherited. The kit prompt's a2a locator snippet handles this by probing standard paths.
Fix: Either:
- Pass
envexplicitly:sudo -u agent env A2A_PROJECT=... a2a ... - Use absolute paths for
a2ain the kit prompt locator - Install
a2ato a system-wide location like/usr/local/bin/a2a
14. --dangerously-skip-permissions blocked on root
The claude CLI refuses --dangerously-skip-permissions when running as root/sudo:
--dangerously-skip-permissions cannot be used with root/sudo privileges
Fix: Either:
- Run claude as a non-root user (via
sudo -u user claude ...) - Use the env var
CLAUDE_CODE_DANGEROUSLY_SKIP_PERMISSIONS=1combined with
--permission-mode acceptEdits instead of the flag
15. Foreground-waiting after spawn blocks the caller indefinitely
a2a-spawn already backgrounds agents with nohup+disown. If the calling script/daemon adds a while loop or sleep-based polling after spawning, it blocks until every agent exits — preventing parallel spawns, defeating Hermes background-task tracking, and causing spurious timeouts.
Common symptom: "spawning team for X..." prints, agents log activity, then the spawning terminal hangs for 30+ minutes until timeout kills it.
**Correct patterns instead of a
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: javimosch
- Source: javimosch/a2a-skill
- License: MIT
- Homepage: https://javimosch.github.io/a2a-skill/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.