zahadun

zahadun

Enables Claude Code and OpenCode agents to delegate tasks to peer machines over a self-hosted A2A mesh, using mTLS identity and executing via local CLIs or scripts.

Category
Visit Server

README

zahadun

A self-hosted mesh of full-peer AI agents — Claude Code and OpenCode talking across your machines over A2A, with real mTLS identity and no API keys.

Every machine is an equal peer: it can ask (an MCP bridge inside Claude Code / OpenCode) and answer (an A2A server executing tasks with the local claude CLI, OpenCode, or plain scripts). There is no controller node, no cloud relay, and no per-token billing — the Claude track runs on your existing subscription via claude -p.

you, on machine A                                machine B
┌───────────────────────┐                        ┌───────────────────────┐
│ Claude Code / OpenCode│   A2A JSON-RPC         │ reverse proxy :8443   │
│   │ MCP bridge        │ ──────────────────────▶│   mTLS, CN → identity │
│   ▼                   │   over WireGuard mesh  │   ▼                   │
│ "@bob audit the SEO   │   (NetBird/Tailscale)  │ A2A server :9990      │
│  of example.com"      │                        │   ├─ script           │
│                       │◀── task id, then ──────│   ├─ claude -p        │
│ zahadun_task(id)      │    artifacts           │   └─ opencode         │
└───────────────────────┘                        └───────────────────────┘

Why this exists

Multi-machine agent collaboration is a frequently requested capability. The pieces all exist — A2A↔MCP bridges, WireGuard meshes, workload identity (SPIFFE), agent memory servers — but as separate, mostly cloud- or Kubernetes-shaped projects. zahadun is the whole thing in ~1,500 lines of Python with two dependencies (httpx, mcp), sized for one operator and a handful of machines.

What's different here

  • Subscription, not API keys. The Claude executor is the CLI in -p mode. If you pay for Claude Code, your mesh costs nothing extra.
  • One conversation, two machines. The A2A contextId is the Claude session UUID on every machine in a task's path. claude --resume <id> on either end shows that machine's half of the same conversation.
  • Deterministic @peer addressing. A UserPromptSubmit hook parses mentions before the model sees the prompt. Routing is code, not an LLM decision: unknown peer → hard block with the roster; unreachable peer → the prompt never reaches the local model (you can't mistake a local answer for the peer's).
  • Conflict-free mesh memory, no database. Shared memory is a git-synced directory of markdown files named <peer>-<timestamp>.md. A peer only ever creates its own files, so replication can't conflict — git pull --rebase never meets a merge.
  • Real identity, home-lab sized. mTLS everywhere; each machine's cert is signed by your own root CA (an OpenBao PKI mount works well — see docs/CA-RUNBOOK.md). CSR authenticity is attested with an SSH signature (ssh-keygen -Y) from the operator's personal key. Client-only machines get clientAuth-only certs: even a stolen key can't impersonate a server.
  • Honest cards. A peer's AgentCard lists only skills that work today. A planned skill is a promise the caller can't distinguish from a working one — they just get FAILED.

Architecture in five decisions

  1. The router is a human. Pure A2A: addressing means choosing a peer. No broadcasts, no capability matching. You say @bob, code delivers to bob.
  2. Tracks are pure end-to-end. A task submitted from Claude Code executes in Claude on the target; OpenCode-to-OpenCode likewise. Mixing tracks would orphan the session history that makes --resume work.
  3. The bridge has no model. The MCP server is an HTTP client plus a file layer. All intelligence lives in the tool that loaded it or on the target peer. It detects its own track from the MCP handshake's clientInfo.
  4. The risky part is code; the convenient part is the model. Delivery and addressing: hook, deterministic. Result pickup, catalogs, memory: MCP tools, model-driven.
  5. Peer input is untrusted. The Claude executor runs headless with no tools by default (permission prompts auto-deny). You grant tools per skill, explicitly, in skills.json. Loops are cut by an X-Zahadun-Trace header; caller identity comes from the client cert's CN via the proxy — never from the request body.

Quick start

See INSTALL.md. The short version, per machine:

# module
python3 -m venv /opt/zahadun-a2a/venv
/opt/zahadun-a2a/venv/bin/pip install zahadun-a2a   # or from a checkout

# client side (every machine): MCP bridge + @peer hook
claude mcp add zahadun --scope user -- /opt/zahadun-a2a/venv/bin/python -m zahadun_a2a.mcp
# + hook in ~/.claude/settings.json, + block in opencode.json  → INSTALL.md

# server side (machines that answer): systemd unit + reverse proxy with mTLS
# examples/ has units and nginx/Apache/Caddy configs

Everything runs as a regular user. No dedicated system account, no root services — the Claude executor needs the user's ~/.claude anyway.

MCP tools exposed to your agent

tool purpose
zahadun_peers() who is in the mesh, what they can do (live AgentCards)
zahadun_ask(peer, task, …) delegate; returns a task id
zahadun_task(id) poll result / status
zahadun_models() live model catalog of the local OpenCode engine
zahadun_memory_search/read/write/topics shared mesh memory

Status

Working: the full client+server loop, three executors (script / claude -p --session-id / OpenCode prompt_async with a model-fallback ladder), task persistence across restarts, audit log, loop detection.

Not yet: SSE streaming (cards honestly say streaming: false), input-required pauses (skills marked as needing human confirmation are refused, not hung), per-caller rate limits.

Security model

Read SECURITY.md before exposing anything. Summary: designed for a single operator's machines on a private WireGuard mesh; peers are semi-trusted (authenticated, but their task content is not); it is not a multi-tenant system and was never designed as one.

A note on language

The project was built for a Polish-speaking mesh: code comments, error messages and some config keys (drabina = model ladder, wykonawca = executor, potwierdzenie_czlowieka = human confirmation) are Polish. The docs you're reading, the wire protocol (A2A v1.0) and the MCP tool names are English. Translating internals is on the table if anyone actually needs it — open an issue.

License

Apache-2.0.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured