
Research
/Security News
OpenAPI React Query Codegen Compromised in Mini Shai-Hulud npm Supply Chain Attack
Ten malicious OpenAPI React Query Codegen versions were published to npm in the Mini Shai-Hulud attack, all with valid provenance.
a2acalling
Advanced tools
Agent-to-Agent calling with OpenClaw support. "I'll have my people call your people!"
Your AI agent can now call other AI agents — across instances, with scoped permissions, strategic summaries, and owner notifications. Think of it as a comms stream system for agents to communicate via text as effeciently as possible.
trace_id, error_code, and hintsa2a create --name "My Agent" --owner "Your Name" --permissions friends
# Output:
# 🤝 Your Name is inviting you to connect agents!
# Your agent can reach My Agent for: chat, web, files
# a2a://your-host.com/fed_abc123xyz
# Add them as a contact
a2a add "a2a://their-host.com/fed_xyz789" "Alice's Agent"
# Make a call
a2a call "Alice's Agent" "Hey! Want to collaborate on the a2a protocol?"
# Or call directly
a2a call "a2a://their-host.com/fed_xyz789" "Hello!"
A2A Callbook is also available as a native macOS app that wraps the dashboard in a proper macOS window with native integrations.
Features:
a2a:// URLs open in the app)Auto-installed on macOS when you run npm install -g a2acalling. The app is placed in ~/Applications/.
Manual install: Download the .dmg from GitHub Releases.
Build from source:
# Requires Rust: https://rustup.rs
cargo install tauri-cli --version "^2"
cd native/macos/src-tauri
cargo tauri build --target universal-apple-darwin
To open the app via CLI: a2a gui (prefers native app; use --browser to force browser).
# Global CLI
npm install -g a2acalling
# As a library
npm install a2acalling
# Stop pm2 server (name: a2a) and remove local config/DB (prompts unless --force)
a2a uninstall
# Keep config/DB for reinstall
a2a uninstall --keep-config --force
# Remove the global package
npm uninstall -g a2acalling
# Auto setup (detects OpenClaw gateway/runtime or configures standalone mode)
npx a2acalling setup
# Or clone and install
git clone https://github.com/onthegonow/a2a_calling.git
cd a2a_calling
npm install
node scripts/install-openclaw.js setup
Setup behavior:
/a2a and A2A API at /api/a2a/* (proxied to A2A backend)./dashboard.Before the first a2a call, the owner must complete onboarding (install location, permission tiers, and server ingress verification). Run:
/a2a quickstart
CLI equivalents:
# Local machine (local-only invites)
a2a quickstart --port 3001
# Server / public hostname (recommended: terminate at 443 via reverse proxy)
a2a quickstart --hostname YOUR_DOMAIN:443 --port 3001
| Tier | What They Can Access |
|---|---|
public | Conversation only |
friends | Most read-only tools (calendar/email/search) |
family | Full tool access (careful!) |
Customize tiers in ~/.config/openclaw/a2a-config.json:
{
"tiers": {
"friends": {
"topics": ["chat", "web", "files", "calendar"],
"allowed_tools": ["Bash(readonly)", "Read", "Grep", "Glob", "WebSearch", "WebFetch"],
"disclosure": "minimal"
}
}
}
# Add a contact
a2a add "a2a://host/token" "Alice"
# View contact details (shows trust level from YOUR token to them)
a2a show "Alice"
# Ping to check availability
a2a ping "Alice"
# Link a token you created FOR them
a2a link "Alice" tok_abc123
# List all contacts
a2a contacts
# Remove a contact
a2a rm "Alice"
Every call generates an owner-context summary that tracks the exchange:
{
"exchange": {
"weGot": ["learned about their developer tools project"],
"weGave": ["shared our A2A work"],
"balance": "even",
"fair": true
},
"mutualValue": {
"found": true,
"opportunities": ["potential integration partnership"],
"alignment": "connects to owner's interest in agent collaboration"
},
"trust": {
"assessment": "appropriate",
"recommendation": "maintain",
"pattern": "genuine partner, collaborative tone"
}
}
Summaries are private — never shared with the caller.
a2a create [options] # Create an invite token
--name, -n <name> # Token/contact name
--owner, -o <name> # Your name (for invite)
--tier, -t <tier> # public|friends|family
--topics <list> # Custom topic list
--expires, -e <duration> # 1h|1d|7d|30d|never (default: never)
--max-calls <n> # Limit total calls (default: unlimited)
--notify <level> # all|summary|none
a2a list # List your tokens
a2a revoke <id> # Revoke a token
a2a quickstart # Deterministic onboarding
a2a call <target> <message> # Call an agent
--timeout <seconds> # Response timeout (default: 60)
--context <text> # Add context for the call
a2a ping <target> # Check if agent is available
a2a server [options] # Start A2A server
--port, -p <port> # Port (default: 3001)
a2a setup # Auto setup via installer (gateway-aware dashboard)
Dashboard paths:
http://<host>:<port>/dashboardhttp://<gateway>/a2aIf the owner wants to manage A2A from a different machine (ex: their MacBook), you can pair a browser session using a one-time install link:
http://127.0.0.1:<port>/dashboard/Settings -> Remote CallbookCreate Install Link (24h) and copy the URLNotes:
Settings -> Remote Callbook.~/.config/openclaw/a2a-callbook.db (or $A2A_CONFIG_DIR/a2a-callbook.db).All runtime logs are persisted in SQLite and also emitted to stdout:
~/.config/openclaw/a2a-logs.db (or $A2A_CONFIG_DIR/a2a-logs.db)trace_id, conversation_id, token_id, error_code, status_code, hintDashboard/API log routes:
GET /api/a2a/dashboard/logsGET /api/a2a/dashboard/logs/trace/:traceIdGET /api/a2a/dashboard/logs/statsGET /api/a2a/dashboard/debug/call?trace_id=<id> (or conversation_id=<id>)Useful filters for /api/a2a/dashboard/logs:
trace_id, conversation_id, token_iderror_code, status_codecomponent, event, level, search, from, to, limitExample:
curl "http://localhost:3001/api/a2a/dashboard/logs?trace_id=trace_abc123&error_code=TOKEN_INVALID_OR_EXPIRED"
Every /api/a2a/invoke and /api/a2a/end response now returns:
trace_id (generated when caller does not send one)request_id (generated when caller does not send one)To inspect one call, use the dashboard debug endpoint:
curl -H "x-admin-token: $A2A_ADMIN_TOKEN" \
"http://localhost:3001/api/a2a/dashboard/debug/call?trace_id=<trace_id>"
For each call you get:
summary (event count, first/last seen, duration, and IDs involved)errors and error_codes for fast triagelogs (ordered timeline events from that trace)Tokens use the a2a:// URI scheme:
a2a://<hostname>[:port]/<token>
| Method | Path | Description |
|---|---|---|
GET | /api/a2a/status | Check A2A support |
GET | /api/a2a/ping | Health check with auth |
POST | /api/a2a/invoke | Call the agent |
POST | /api/a2a/end | End a conversation and return summary data |
{
"message": "Hello!",
"caller": { "name": "Agent Name", "owner": "Owner Name" },
"conversation_id": "optional-for-continuation",
"timeout_seconds": 60
}
{
"success": true,
"conversation_id": "conv_123",
"response": "Agent's response",
"can_continue": true,
"tokens_remaining": null
}
{
"conversation_id": "conv_123"
}
{
"success": true,
"conversation_id": "conv_123",
"status": "concluded",
"summary": "Optional call summary"
}
const { A2AClient } = require('a2acalling');
const client = new A2AClient({
caller: { name: 'My Agent', owner: 'My Name' }
});
// Call via invite URL
const response = await client.call(
'a2a://their-host.com/fed_token123',
'Can you help me with something?'
);
// Continue the conversation
const followUp = await client.call(
'a2a://their-host.com/fed_token123',
'Thanks! One more question...',
{ conversationId: response.conversation_id }
);
// Explicitly end the call when done
const ended = await client.end(
'a2a://their-host.com/fed_token123',
response.conversation_id
);
const { createRoutes, TokenStore } = require('a2acalling');
const express = require('express');
const app = express();
app.use(express.json());
app.use('/api/a2a', createRoutes({
tokenStore: new TokenStore(),
async handleMessage(message, context) {
// context.permissions, context.caller, context.conversationId
return {
text: await yourAgent.respond(message, context),
canContinue: true
};
},
async notifyOwner({ caller, message }) {
await notify(`🤝 ${caller.name} called your agent`);
}
}));
app.listen(3001);
a2a revoke| Variable | Description |
|---|---|
A2A_HOSTNAME | Hostname for invite URLs (required for internet-facing invites) |
A2A_PORT | Server port (default: 3001) |
A2A_CONFIG_DIR | Config directory (default: ~/.config/openclaw) |
A2A_WORKSPACE | Workspace root for context files like USER.md (default: current directory) |
A2A_RUNTIME | Runtime mode: auto (default), openclaw, or claude |
A2A_AGENT_NAME | Override local agent display name |
A2A_OWNER_NAME | Override owner display name |
A2A_COLLAB_MODE | Conversation style: adaptive (default) or deep_dive |
A2A_ADMIN_TOKEN | Protect dashboard/conversation admin routes for non-local access |
A2A_LOG_LEVEL | Minimum persisted/stdout log level: trace, debug, info, warn, error (default: info) |
A2A_LOG_STACKS | Include stack traces in log DB error payloads (true by default outside production) |
A2A is cooperative AND adversarial. Each agent maximizes value for their owner — but the best outcomes are mutual wins.
Your agent should:
MIT — go build something cool.
I'll have my people call your people. 🤝
FAQs
Agent-to-agent calling for OpenClaw - A2A agent communication
We found that a2acalling demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Ten malicious OpenAPI React Query Codegen versions were published to npm in the Mini Shai-Hulud attack, all with valid provenance.

Security News
Socket joins more than 100 technology, cybersecurity, and financial organizations calling for a global surge in cyber defense.

Product
Enterprise security teams can now detect malware, credential theft, suspicious network activity, and risky updates across Microsoft Edge extensions.