{"_id":"@ai11/openclaw-a2a","name":"@ai11/openclaw-a2a","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ai11/openclaw-a2a","version":"0.1.0","description":"OpenClaw A2A Plugin — exposes OpenClaw agents via the Agent2Agent protocol","type":"module","main":"dist/index.js","types":"dist/index.d.ts","openclaw":{"extensions":["./dist/index.js"]},"scripts":{"build":"tsc","test":"vitest run","test:watch":"vitest","clean":"rm -rf dist","prepublishOnly":"npm run build"},"dependencies":{"@a2a-js/sdk":"^0.3.10","jose":"^6.2.0","better-sqlite3":"^12.6.2"},"devDependencies":{"@types/node":"^25.3.5","typescript":"^5.7.0","vitest":"^3.0.0","@types/better-sqlite3":"^7.6.13"},"engines":{"node":">=18"},"author":{"name":"Ai11 Consulting GmbH","email":"info@ai11.at"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/Ai11-Consulting-GmbH/openclaw-a2a.git"},"homepage":"https://github.com/Ai11-Consulting-GmbH/openclaw-a2a#readme","bugs":{"url":"https://github.com/Ai11-Consulting-GmbH/openclaw-a2a/issues"},"keywords":["openclaw","a2a","agent-to-agent","plugin","ai","agent"],"gitHead":"dab9b0d7cfb176326975be625fe61eaceebd846e","_id":"@ai11/openclaw-a2a@0.1.0","_nodeVersion":"24.13.0","_npmVersion":"11.10.1","dist":{"integrity":"sha512-d1USg6Saqhr7lPxwVj+44aO3NZjhc4EZhvvDl+nf2QnhxaGtJlxoofSnaIrzmQvJKgbRSXlyspvZUpptqmPptw==","shasum":"81de1f061e94e983ee7cf84aa6fdb42621fcd89a","tarball":"https://registry.npmjs.org/@ai11/openclaw-a2a/-/openclaw-a2a-0.1.0.tgz","fileCount":60,"unpackedSize":219618,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDVzI+NvxUsozPhkBQ+p/fSeLfRGMF6S0ysKb4d4drOngIhAL3P/NGCYED2VePy3Pvr4ui+Os1iH2OWY2n6F3t04Lco"}]},"_npmUser":{"name":"ai11npm","email":"yue.sun@ai11.io"},"directories":{},"maintainers":[{"name":"ai11npm","email":"yue.sun@ai11.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/openclaw-a2a_0.1.0_1772916822099_0.3638588407365013"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-07T20:53:42.008Z","0.1.0":"2026-03-07T20:53:42.285Z","modified":"2026-03-07T20:53:42.496Z"},"maintainers":[{"name":"ai11npm","email":"yue.sun@ai11.io"}],"description":"OpenClaw A2A Plugin — exposes OpenClaw agents via the Agent2Agent protocol","homepage":"https://github.com/Ai11-Consulting-GmbH/openclaw-a2a#readme","keywords":["openclaw","a2a","agent-to-agent","plugin","ai","agent"],"repository":{"type":"git","url":"git+https://github.com/Ai11-Consulting-GmbH/openclaw-a2a.git"},"author":{"name":"Ai11 Consulting GmbH","email":"info@ai11.at"},"bugs":{"url":"https://github.com/Ai11-Consulting-GmbH/openclaw-a2a/issues"},"license":"MIT","readme":"# OpenClaw A2A Plugin\n\nExpose [OpenClaw](https://github.com/Ai11-Consulting-GmbH) agents via Google's [Agent-to-Agent (A2A) protocol](https://google.github.io/A2A/), enabling seamless interoperability with any A2A-compliant client or agent network.\n\nBuilt on the official [`@a2a-js/sdk`](https://www.npmjs.com/package/@a2a-js/sdk) as the protocol engine.\n\n## Features\n\n- **Agent Card Discovery** — `GET /.well-known/agent-card.json` serves a fully compliant A2A Agent Card\n- **JSON-RPC `message/send`** — synchronous task execution via standard A2A JSON-RPC\n- **Streaming** — SSE-based streaming responses with incremental artifact updates\n- **Skill → Agent Routing** — map A2A skills to OpenClaw agents via a configurable routing table\n- **Authentication** — static bearer tokens, JWT validation (HS256/RS256), and mTLS identity extraction\n- **Per-Skill ACLs** — fine-grained access control by subject or role per skill\n- **SQLite Persistent TaskStore** — survive Gateway restarts with WAL-mode SQLite (or use in-memory)\n- **Rate Limiting** — per-caller token bucket rate limiter with configurable RPM and burst\n- **Health Checks** — upstream `/v1/responses` reachability probes\n- **Outbound Federation** — `a2a-call-remote` and `a2a-discover` tools for calling external A2A agents\n\n## Quick Start\n\n### 1. Install\n\n```bash\nnpm install @ai11/openclaw-a2a\n```\n\n### 2. Minimal Configuration\n\nAdd the plugin to your `openclaw.json` with just the essentials:\n\n```jsonc\n{\n  \"plugins\": {\n    \"@ai11/openclaw-a2a\": {\n      \"basePath\": \"/a2a\",\n      \"gatewayBaseUrl\": \"http://127.0.0.1:3000\",\n      \"gatewayToken\": \"<your OpenClaw Gateway token>\",\n\n      \"routing\": {\n        \"defaultAgentId\": \"default-agent\"\n      },\n\n      \"auth\": {\n        \"allowedBearerTokens\": [\"<generate-a-strong-token>\"],\n        \"agentCardPublic\": true\n      },\n\n      \"agentCard\": {\n        \"name\": \"My OpenClaw Agent\",\n        \"description\": \"An AI agent powered by OpenClaw\",\n        \"version\": \"1.0.0\",\n        \"skills\": [\n          {\n            \"id\": \"general\",\n            \"name\": \"General\",\n            \"description\": \"General-purpose assistant\",\n            \"tags\": [\"general\"]\n          }\n        ]\n      }\n    }\n  }\n}\n```\n\n> **Where do I get `gatewayToken`?** This is the token configured in your OpenClaw Gateway's `openclaw.json` under the top-level `\"token\"` field. It authenticates this plugin's loopback calls to the Gateway's `/v1/responses` endpoint. If you haven't set one, add `\"token\": \"some-secret\"` to your Gateway config and use the same value here.\n\n### 3. Start the Gateway\n\n```bash\nopenclaw gateway start\n```\n\nYou're up! The agent card is at `http://localhost:3000/.well-known/agent-card.json` and A2A requests go to `POST http://localhost:3000/a2a`.\n\n## Advanced Configuration\n\nThe full config adds JWT auth, per-skill ACLs, rate limiting, persistent task storage, and multi-agent routing:\n\n```jsonc\n{\n  \"plugins\": {\n    \"@ai11/openclaw-a2a\": {\n      \"basePath\": \"/a2a\",\n      \"gatewayBaseUrl\": \"http://127.0.0.1:3000\",\n      \"gatewayToken\": \"<your OpenClaw Gateway token>\",\n\n      \"routing\": {\n        \"defaultAgentId\": \"default-agent\",\n        \"skillToAgentId\": {\n          \"code-review\": \"code-reviewer-agent\",\n          \"summarize\": \"summarizer-agent\"\n        }\n      },\n\n      \"auth\": {\n        \"allowedBearerTokens\": [\"token-abc-123\"],\n        \"agentCardPublic\": true,\n        \"jwt\": {\n          \"hsSecret\": \"your-hs256-secret\",\n          \"audience\": \"https://your-gateway.example.com\",\n          \"issuer\": \"https://auth.example.com\",\n          \"algorithms\": [\"HS256\", \"RS256\"]\n        },\n        \"acls\": {\n          \"code-review\": {\n            \"allowedSubjects\": [\"service-a\"],\n            \"allowedRoles\": [\"developer\"]\n          }\n        }\n      },\n\n      \"rateLimit\": {\n        \"requestsPerMinute\": 60,\n        \"burst\": 10\n      },\n\n      \"taskStore\": {\n        \"type\": \"sqlite\",\n        \"dbPath\": \"./data/tasks.db\",\n        \"ttlMs\": 604800000,\n        \"cleanupIntervalMs\": 3600000\n      },\n\n      \"agentCard\": {\n        \"name\": \"My OpenClaw Agent\",\n        \"description\": \"An AI agent powered by OpenClaw\",\n        \"version\": \"1.0.0\",\n        \"capabilities\": {\n          \"streaming\": true,\n          \"pushNotifications\": false,\n          \"stateTransitionHistory\": false\n        },\n        \"skills\": [\n          {\n            \"id\": \"code-review\",\n            \"name\": \"Code Review\",\n            \"description\": \"Reviews pull requests and provides feedback\",\n            \"tags\": [\"code\", \"review\"]\n          },\n          {\n            \"id\": \"summarize\",\n            \"name\": \"Summarize\",\n            \"description\": \"Summarizes documents and conversations\",\n            \"tags\": [\"text\", \"summary\"]\n          }\n        ]\n      }\n    }\n  }\n}\n```\n\n## Usage Examples\n\n### Discover the Agent Card\n\n```bash\ncurl http://localhost:3000/.well-known/agent-card.json\n```\n\n### Send a message (JSON-RPC `message/send`)\n\n```bash\ncurl -X POST http://localhost:3000/a2a \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer token-abc-123\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"id\": 1,\n    \"method\": \"message/send\",\n    \"params\": {\n      \"message\": {\n        \"kind\": \"message\",\n        \"messageId\": \"msg-001\",\n        \"role\": \"user\",\n        \"parts\": [{ \"kind\": \"text\", \"text\": \"Review this code\" }],\n        \"metadata\": { \"ai11.skillId\": \"code-review\" }\n      }\n    }\n  }'\n```\n\n### Stream a response (SSE)\n\n```bash\ncurl -X POST http://localhost:3000/a2a \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer token-abc-123\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"id\": 2,\n    \"method\": \"message/stream\",\n    \"params\": {\n      \"message\": {\n        \"kind\": \"message\",\n        \"messageId\": \"msg-002\",\n        \"role\": \"user\",\n        \"parts\": [{ \"kind\": \"text\", \"text\": \"Summarize this document\" }],\n        \"metadata\": { \"ai11.skillId\": \"summarize\" }\n      }\n    }\n  }'\n```\n\n## Security Considerations\n\n### Authentication\n\n- **Bearer tokens** are the simplest auth method. Generate strong, random tokens (e.g., `openssl rand -hex 32`). Never use placeholder values in production.\n- **JWT validation** supports HS256 and RS256. Always set `audience` and `issuer` to prevent token reuse across services.\n- **mTLS** extracts client identity from TLS certificates for high-trust environments.\n\n### Token Management\n\n- **`gatewayToken`** authenticates loopback calls from this plugin to the OpenClaw Gateway. Treat it like any internal secret — do not commit it to version control. Use environment variables or a secrets manager.\n- **`allowedBearerTokens`** should be rotated periodically. When rotating, temporarily allow both old and new tokens, then remove the old one.\n- **JWT secrets** (`hsSecret`) must be strong and unique. For RS256, use proper key management and rotate signing keys on a schedule.\n\n### Access Control (ACLs)\n\n- By default, **all authenticated callers can access all skills**. Use `auth.acls` to restrict sensitive skills to specific subjects or roles.\n- ACL subjects come from the authenticated identity (bearer token lookup, JWT `sub` claim, or mTLS CN).\n- Always apply the principle of least privilege — only grant access to the skills each caller needs.\n\n### Network Exposure\n\n- **Do not expose the Gateway directly to the public internet** without a reverse proxy (e.g., nginx, Caddy) handling TLS termination.\n- The Agent Card endpoint (`/.well-known/agent-card.json`) is public by default when `agentCardPublic: true`. Set it to `false` if your agent should not be discoverable.\n- **Rate limiting** (`rateLimit`) is per-caller and in-memory. For production deployments behind a load balancer, consider additional rate limiting at the proxy layer.\n- The loopback URL (`gatewayBaseUrl`) should always point to `127.0.0.1` or `localhost` — never expose it externally.\n\n### Task Store\n\n- SQLite task store files (`data/tasks.db`) may contain conversation content. Protect them with appropriate file permissions.\n- Set `ttlMs` to automatically purge old tasks and limit data retention.\n\n## Architecture\n\nThe plugin registers two HTTP routes on the OpenClaw Gateway:\n\n1. **`GET /.well-known/agent-card.json`** — serves the Agent Card (optionally public)\n2. **`POST {basePath}`** (prefix match, default `/a2a`) — JSON-RPC handler for A2A methods\n\nRequest flow:\n\n```\nClient → Auth middleware → Rate limiter → ACL check → a2a-js JsonRpcTransportHandler\n  → OpenClawAgentExecutor → Router.resolve(skillId) → POST /v1/responses (loopback)\n  → SSE stream parsed → EventBus artifact/status events → A2A response/stream\n```\n\nThe `OpenClawAgentExecutor` implements the `AgentExecutor` interface from `@a2a-js/sdk`. It extracts text from incoming A2A messages, resolves the target OpenClaw agent via the skill router, calls the Gateway's loopback `/v1/responses` endpoint, and streams incremental results back through the A2A protocol.\n\nFor a deep dive, see:\n- **[docs/prd.md](docs/prd.md)** — Product Requirements Document\n- **[docs/architecture.md](docs/architecture.md)** — Architecture & Design\n\n## Project Structure\n\n```\nsrc/\n├── index.ts                      # Plugin entrypoint — route registration & wiring\n├── config.ts                     # Config types, parsing, validation, AgentCard builder\n├── transport.ts                  # HTTP bridge — adapts a2a-js handlers to raw Node.js req/res\n├── router.ts                     # Skill → AgentId routing with default fallback\n├── openclaw-agent-executor.ts    # AgentExecutor — bridges A2A to OpenClaw /v1/responses\n├── auth.ts                       # Bearer token + JWT + mTLS auth, ACL authorization\n├── rate-limit.ts                 # Per-caller token bucket rate limiter\n├── sqlite-task-store.ts          # SQLite-backed TaskStore with TTL cleanup\n├── health.ts                     # Upstream health check probe\n├── *.test.ts                     # Co-located unit tests (Vitest)\ndocs/\n├── prd.md                        # Product Requirements Document\n├── architecture.md               # Architecture & design decisions\n```\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Build\nnpm run build\n\n# Run tests\nnpm test\n\n# Watch mode\nnpm run test:watch\n\n# Clean build artifacts\nnpm run clean\n```\n\n**Requirements:** Node.js ≥ 18\n\n## License\n\n[MIT](LICENSE)\n","readmeFilename":"README.md","_rev":"1-0141d489a1fd6f3950dfde0d838ddeda"}