agentbridge — General-Purpose Agent Interconnect over A2A¶
agentbridge is the layer of SHADI that bridges agents over the
A2A protocol — via a pluggable A2A transport (SLIMRPC or
standard gRPC), DID identity, DIR discovery, and shadi_mas for autonomous
multi-round coordination — so they can exchange context, delegate tasks to
each other, and coordinate autonomously toward a shared goal. Nothing in that
mechanism is specific to any one kind of agent: any agent that speaks A2A, or
the simpler agentbridge subprocess protocol (GenericStdioAdapter), can be
bridged this way.
Today's built-in adapters happen to target CLI coding tools — Claude Code,
GitHub Copilot CLI, OpenAI Codex CLI, Cursor Agent — because interconnecting
coding assistants was the motivating use case this was first built for, and
they remain the flagship, most-exercised example throughout this page and the
demos. The CliAdapter trait, the A2A/SLIM transport, and the coordination
runtime underneath them don't know or care that they're wrapping coding
tools; a bridge for any other class of agent looks the same.
Motivation¶
The concrete problem that motivated agentbridge: every major coding assistant operates in isolation. When a developer switches tools (e.g., from Claude Code to Copilot), all conversation history, open files, and accumulated context is lost. There was no standard way to:
- Hand off an in-progress session from one tool to another,
- Ask one agent to generate a specific artifact for another agent's task, or
- Have multiple agents propose solutions and converge on the best one without human mediation.
agentbridge solves this using the existing SHADI infrastructure: A2A for task
delegation, SLIMRPC or gRPC for transport, DIR for discovery, and shadi_mas
for autonomous multi-round coordination — the same general-purpose stack that
would bridge any other kind of agent, applied here to coding tools first.
Quick start¶
The self-contained demo needs no infrastructure — it runs all scenarios against an in-process SLIM node:
# Run the self-contained demo (all scenarios, no infrastructure required)
cargo run -p agentbridge_demo
# Run the 4-agent coordination scenario
cargo run -p agentbridge_demo -- --scenario coordination
# Run the context handoff scenario
cargo run -p agentbridge_demo -- --scenario handoff
# Run the CliAdapter → ToolAdapter bridge scenario
cargo run -p agentbridge_demo -- --scenario bridge
See examples/agentbridge_demo/README.md for the in-process scenarios, and scripts/agentbridge_shell*.sh or the DID agent-group demo for a live SLIM run.
Architecture¶
Deployment topology¶
register and coordinate run on separate hosts (or separate terminals on the
same machine). Unicast A2A can use a SLIM node (--slim-endpoint) or
official A2A unicast (--a2a-listen / --a2a-binding / delegate --a2a-url) without one.
handoff and coordinate stay on SLIM in this slice. Identity is always
the application DID on the message, not the URL. Address a peer by that DID;
look up the current gRPC URL or SLIM name when it moves.
flowchart LR
subgraph reg["agentbridge register (one per agent)"]
direction TB
tool["CLI tool\ngeneric-stdio | claude-code | copilot | codex | cursor-agent | goose | opencode"]
ca["CliAdapter\nexecute_prompt(prompt) → text"]
srv["A2A server\nAgentBridgeRequestHandler\nInMemoryTaskStore"]
tool -- "stdin / stdout" --> ca --> srv
end
slim{{"SLIM node\nagntcy/shadi/<tool>-a2a\nmTLS · DID auth"}}
subgraph coord["agentbridge coordinate"]
direction TB
mas["MasRuntime<DevelopmentEngine>\nproposal → vote → finalize"]
sta["SlimToolAdapter\n(one per --agents spec)"]
laa["LiveA2ATaskAdapter\nSLIMRPC dispatch"]
mas --> sta --> laa
end
srv <-- "A2A tasks (text/plain)" --> slim
slim <-- "A2A tasks (text/plain)" --> laa
register --tool accepts generic-stdio or a bundled profile id
(claude-code, copilot, codex, cursor-agent, goose, opencode).
After a listener starts, agentbridge list --local shows it (name, DID,
slim://… and/or http://…) from the lease file under $SHADI_TMP_DIR.
goose and opencode keep their own provider config (~/.config/goose,
~/.config/opencode). Agentbridge does not set a base URL or API key.
When GOOSE_PROVIDER / GOOSE_MODEL are set in the host environment,
the goose listener passes them as goose run --provider / --model.
Host GOOSE_*, OPENAI_*, *_API_KEY, and api_key_env names from
the operator's Goose provider files are copied onto that process.
Extra flags: GOOSE_ARGS / OPENCODE_ARGS.
Outbound A2A text is wrapped in a DID-proof envelope. Unsigned inbound parks
as AUTH_REQUIRED (re-prove / ask / deny); a forged DID is rejected.
Coordination loop¶
coordinate --pattern development (default) is CONVERGE for a code
class: every agent proposes a code artifact, then every agent votes on
the best one. Finalization fires as soon as endorsements reach the
quorum — triggered by applying the last proposal of the epoch.
The same two group phases cover any class. --assembly asks the team to
model the problem first. --pattern preference|cascade|resource runs
CONVERGE on a paper engine. See ASSEMBLY and CONVERGE.
sequenceDiagram
participant MAS as DevelopmentEngine
participant CO as coordinator
participant A as copilot (SLIM)
participant B as codex (SLIM)
rect rgb(240,248,255)
note right of CO: epoch 0 — proposal phase
CO->>A: proposal prompt (goal, epoch 0)
A-->>CO: code artifact
CO->>B: proposal prompt (goal, epoch 0)
B-->>CO: code artifact
CO->>MAS: apply ExternalBytes(copilot_code)
CO->>MAS: apply ExternalBytes(codex_code)
end
rect rgb(240,255,240)
note right of CO: epoch 0 — vote phase
CO->>A: vote prompt (goal + both proposals)
A-->>CO: endorses copilot
CO->>B: vote prompt (goal + both proposals)
B-->>CO: endorses copilot
CO->>MAS: apply ToolResult{copilot, accepted:true}
CO->>MAS: apply ExternalBytes(codex_vote_artifact)
note over MAS: quorum met on last apply
MAS-->>CO: Finalized — winner: copilot (2/2 votes)
end
CO->>CO: write artifact → output.rs
A2A task flow inside a registered adapter¶
How one incoming task travels from the SLIM node down to the wrapped CLI tool and back:
sequenceDiagram
participant CO as coordinator
participant SL as SLIM node
participant SV as AgentBridgeRequestHandler
participant EX as AgentBridgeExecutor
participant AD as CliAdapter
CO->>SL: SendMessage(DID-proof envelope)
SL->>SV: SLIMRPC frame
SV->>SV: unwrap DID-proof (unsigned → AUTH_REQUIRED, forged → Rejected)
SV->>EX: execute(context)
EX->>EX: strip "body:\n" envelope header
EX->>AD: execute_prompt(prompt)
AD->>AD: invoke CLI tool (subprocess / API)
AD-->>EX: response text
EX-->>SV: StatusUpdate(Working)
EX-->>SV: Task{Completed, message: response_text}
SV-->>SL: stream response
SL-->>CO: Task{Completed}
Use from a harness¶
Coding harnesses (Claude Code, Cursor, Copilot, Codex) should call the
agentbridge CLI, not speak SLIMRPC themselves. Install the skill pack
by copying skills/agentbridge/
to the host skills directory (folder name must be agentbridge):
| Host | Destination |
|---|---|
| Claude Code | ~/.claude/skills/agentbridge/ or .claude/skills/agentbridge/ |
| Cursor | .cursor/skills/agentbridge/ |
| GitHub Copilot | ~/.copilot/skills/agentbridge/ |
| Codex / others | that host’s skills directory, same folder name |
The skill only documents existing flags: list --local, delegate,
handoff --from slim:… --to slim:…. Source
demo-env.sh so DID auth is set. A fifth CLI on the
register side is a JSON profile under crates/agentbridge/profiles/,
not a new Rust adapter.
ASSEMBLY / CONVERGE hops load skills/assembly
and skills/converge
the same way. Do not paste those files into --text. See
ASSEMBLY and CONVERGE.
Three interaction models¶
1. Context handoff¶
Export a session snapshot from one tool and import it into another. The
ContextPacket carries conversation history, open files, git diff, and any
generated artifacts.
agentbridge handoff --from claude-code --to copilot
SHADI_AGENT_ID=claude-code agentbridge handoff \
--from slim:claude-code --to slim:copilot --slim-endpoint 127.0.0.1:47591
--from / --to accept the same specs as coordinate (claude-code,
copilot, codex, cursor-agent, goose, opencode,
generic-stdio:<cmd>, slim:<id>).
A bare subprocess command still opens GenericStdio. --save /
--from-file persist the packet.
Bare tool names open a local CliAdapter (snapshot_context /
inject_context). slim:<id> is A2A: LiveA2ATaskAdapter proves as
SHADI_AGENT_ID and SendMessages to agntcy/shadi/<id>-a2a. When
SHADI_AGENT_ID matches --from slim:<id>, the source is that agent
acting as an A2A client — snapshot stays local so the process does not
call its own listener; only the destination inject is an A2A task.
The round-robin Rust demo does not call handoff
from avatar. After a coding turn the register listener reads NEXT
<peer> and dispatches that inject itself (AGENTBRIDGE_A2A_FORWARD=1).
The snapshot is an LLM summary of the source session this cycle, not a
true session export (except the self-slim: case, which is a short local
note).
- Source →
ContextPacket(local snapshot, or A2A summary ifavatarreads a remoteslim:peer) - Optional
--saveof the packet - Destination →
inject_context(local) or A2A inject prompt (slim:)
2. Task delegation¶
One tool commissions a specific subtask to another and retrieves the artifact.
agentbridge delegate --to codex "write unit tests for src/parser.rs"
Implemented via LiveA2ATaskAdapter::dispatch() from shadi_mas. The result
is an A2A artifact containing the generated code.
3. Autonomous multi-round coordination¶
agentbridge coordinate \
--goal "implement a JSON parser" \
--agents claude-code,copilot,codex,cursor-agent \
--quorum 3
MasRuntime<DevelopmentEngine>is instantiated with all four adapters.- Each agent invokes its CLI tool via
ToolAdapter::call()→ code proposal. - Proposals are published to a SLIM group session.
- Agents vote via
SemanticPayload::ToolResult { accepted: true }. - When
accepted_votes ≥ quorum→EventOutcome::Finalized→ loop exits. - The winning artifact is written to disk. Human approval is optional.
Asking a channel's owner¶
A channel's owner is a human DID, and the owner's SHADI decides who may join (agntcy/shadi#420). An agent asks it over A2A:
agentbridge request-invite --owner agntcy/shadi/avatar \
--channel agntcy/shadi/review-room \
--invitee-name agntcy/shadi/copilot --invitee-did did:key:z6Mk...
The request is a SHADI-CHANNEL-REQUEST/1 body, signed with the agent's DID
like any task, and goes to the owner's <owner>-owner service. The owner's
standing rules (agentbridge::owner) decide it:
{
"default": "ask",
"ask_timeout_seconds": 300,
"grant_seconds": 3600,
"rules": [
{ "channel": "*", "requested_by": "did:key:z6MkMyAgent", "decision": "allow" },
{ "channel": "agntcy/shadi/review-room", "invitee": "did:key:z6MkStranger", "decision": "block" }
]
}
The first rule that matches decides. If none matches, default decides.
allowsigns aSLIM-CHANNEL-GRANT/1, and the owner invites the invitee.blockrefuses the request.askholds the request for the owner. An ask nobody answers is denied when it times out.
A rule can also match requested_by_human: the human named by the binding a
sender attaches, if it attaches one. A channel manager also asks the owner
about removals; a rule decides those only if it says "action": "delete", and
a rule without an action decides only additions. Every decision is appended to the owner's
audit log. The agent gets a one-line reply: granted: ..., pending: ... or
refused: ....
A2A server — how register exposes an adapter¶
When agentbridge register is called with --slim-endpoint and/or
--a2a-listen, it starts a full A2A server that makes the local adapter
reachable to peers on that binding. Both paths share
AgentBridgeRequestHandler and the same DID-proof admission.
--a2a-listen host:port plus --a2a-binding grpc|jsonrpc|http+json serves
one official A2A binding (default grpc → lf.a2a.v1.A2aService). The DID
is the portable name (aliases: tool name, SLIM channel
agntcy/shadi/<name>-a2a). The locator is the local SLIM node
(slim://host:port) and/or a unicast {binding, url}, looked up from the
lease or DIR. Loopback (127.0.0.1, ::1) may be plaintext HTTP. Any other
bind, including 0.0.0.0, requires TLS 1.3 from A2A_TLS_CERT /
A2A_TLS_KEY (or $SHADI_TMP_DIR/shadi-a2a-tls/{server.crt,server.key}).
Do not reuse SLIM_TLS_*. Verify operator-supplied certificates with
openssl x509 -text -noout -in <cert> before use (expiration, RSA ≥ 2048 or
P-256+, SHA-2 signatures; self-signed only for lab). https:// gRPC
client TLS is not wired (a2aproject/a2a-rs#162); JSON-RPC and HTTP+JSON
clients use reqwest and can speak HTTPS.
SLIM address¶
Each adapter registers under the hierarchical name:
agntcy/shadi/<tool>-a2a
For example, --tool copilot listens as agntcy/shadi/copilot-a2a. The
coordinate command reaches it with --agents slim:copilot.
Request handler stack¶
SlimRpcHandler (shadi_a2a) ← SLIMRPC frames
GrpcHandler (a2a-grpc) ← official A2A gRPC (tonic)
jsonrpc_router / rest_router ← official JSON-RPC / HTTP+JSON (axum)
└─ AgentBridgeRequestHandler ← full A2A protocol surface
├─ DefaultRequestHandler ← routes send/get/list/cancel/subscribe/push
│ └─ AgentBridgeExecutor ← executes the task against the CliAdapter
└─ InMemoryTaskStore ← stores task state for get/list operations
AgentBridgeRequestHandler implements all A2A request methods and delegates
to DefaultRequestHandler for everything except get_extended_agent_card,
which returns a static AgentCard describing the adapter:
| Field | Value |
|---|---|
capabilities.streaming |
true |
capabilities.push_notifications |
false |
default_input_modes |
["text/plain"] |
default_output_modes |
["text/plain"] |
Task execution flow¶
See the A2A task flow sequence diagram
above. The executor streams two events: a Working status update followed by a
Completed task carrying the adapter's response text as a text/plain part.
Task history (the original prompt message) is included in the completed task.
Tracing¶
Each task a listener receives runs in a shadi.a2a.receive span, and each task
sent by delegate, handoff, coordinate or a NEXT handoff runs in a
shadi.a2a.send span; a NEXT send shows up inside the receive span that
caused it. Both carry a2a.task_id, peer.did and a2a.outcome. A receive
ends completed, rejected, auth_required or withheld; a send records the
peer's reply state, or error when it never got one. The peer can choose the
task, context and message ids, so a receive span also records a local
evaluation_id, which every refusal quotes back to the sender. Admission and
egress policy decisions are events on the span, the egress ones with their own
evaluation_id. A send carries its W3C traceparent in the message metadata,
so the receive span joins the sender's trace. Nothing signs that value: it only
links traces. Prompts and replies are recorded only when
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true, as the GenAI
conventions' gen_ai.input.messages and gen_ai.output.messages, and only once
they have passed admission and the egress policy. Telemetry
covers exporting them.
TLS certificate resolution¶
Without a bearer token (below), the listener needs a client-side mTLS certificate to authenticate with the SLIM node. Resolution order:
- Explicit env vars —
SLIM_TLS_CERT+SLIM_TLS_KEY+SLIM_TLS_CA - Agent-specific fallback —
.tmp/shadi-slim-mtls/client-<agent_id>.crt/.key - Generic fallback —
.tmp/shadi-slim-mtls/client.crt/.key
SLIM_TLS_CA defaults to .tmp/shadi-slim-mtls/ca.crt. Generate the
certificate bundle once with tools/generate_slim_mtls_certs.sh.
A remote node that authenticates the connection with a bearer token instead
takes SLIM_AUTH_TOKEN_FILE: a file holding only the token, such as the one
slimctl login writes. The token goes on every connection and is re-read when
the file changes. With a token the fallbacks above aren't used: no client
certificate is sent unless SLIM_TLS_CERT and SLIM_TLS_KEY are set, and the
node's certificate is checked against the system roots unless SLIM_TLS_CA is
set.
Lifecycle¶
register --slim-endpoint 127.0.0.1:47357
│
├─ service.connect() connect to SLIM node (TLS 1.3)
├─ shadi_identity::require_did_auth_from_env()
│ + shadi_identity::create_app() authenticate with this agent's DID
├─ app.subscribe() subscribe to agntcy/shadi/<tool>-a2a
├─ srv.serve() start the A2A/SLIMRPC event loop
│
│ [agentbridge] ready — listening on agntcy/shadi/<tool>-a2a
│
├─ … handles tasks until Ctrl-C …
│
└─ app.unsubscribe() deregister from the SLIM topic
service.disconnect() close the SLIM connection
service.shutdown() clean up
Wiring to coordinate¶
The coordinate command uses slim:<agent-id> specs to reach registered
adapters. It constructs a LiveA2ATaskAdapter per spec, which speaks the
same SLIMRPC protocol to the listening server:
coordinate --agents slim:copilot,slim:codex
│
├─ LiveA2ATaskAdapter { peer: agntcy/shadi/copilot-a2a }
└─ LiveA2ATaskAdapter { peer: agntcy/shadi/codex-a2a }
│
└─ SlimToolAdapter::call() → dispatch() → receives Task(Completed)
The A2A traffic is printed with ┌─ A2A ─→ / ┌─ A2A ←─ banners showing
the agent ID, coordination phase, epoch, and elapsed milliseconds.
Security model¶
agentbridge executes real coding tools on your machine and reaches them over a shared SLIM bus, so two trust boundaries matter.
The register listener is a remote-execution surface¶
A registered adapter forwards every incoming A2A task straight to the local CLI
tool (execute_prompt → subprocess). Some adapters run their tool with elevated
permissions — for example, the Copilot profile invokes copilot --allow-all-tools
so it can act non-interactively.
Any peer able to reach the listener can drive local code execution
Any peer able to reach agntcy/shadi/<tool>-a2a on the SLIM node can drive
local code execution through the wrapped CLI tool.
Controls:
- Enforced:
register --slim-endpointrefuses to start unless the process is running under a SHADI sandbox with network blocked by default (shadi_sandbox::sandbox_enforced, which checks that the kernel refuses outbound connections rather than trusting environment variables). Seatbelt (macOS), Landlock (Linux), and AppContainer + Job Objects (Windows) sandboxes are all kernel-enforced and inherited by child processes, so wrappingagentbridge registerinshadictl—shadictl --net-block --net-allow <slim-endpoint> --read <mtls-cert-dir> -- agentbridge register ...— is enough to confine whatever CLI tool the adapter spawns to run a task: it can reach only the listed ports. Give the CLI its own API endpoint as--net-allow api.example.com:443, which without--watch-policyopens port 443 to any host, or add--watch-policyto enforce host names (Network allow-lists). agentbridge has no sandboxing code of its own; it leans entirely on the same enforcementshadictlalready provides. The--readgrant needs the SLIM mTLS client certificate directory so the listener itself can still connect. On macOS,--allow /tmpand--read /tmpemit both/tmpand/private/tmp(Seatbelt matches the kernel-resolved path). Resolving a cert directory withpwd -Premains valid. - The listener prints a warning on start-up naming the tool that will execute incoming tasks.
- Only expose the listener to trusted SLIM peers (
SLIM_MEMBER_DIDSdecides who may send a task; the sandbox decides what it can do once it runs). - Keep the SLIM node on loopback (
127.0.0.1) for local demos; only bind a routable address when the peer set is trusted and authenticated.
DID authentication¶
SLIM apps authenticate with a per-agent DID, not a shared secret. Set
SHADI_SLIM_AUTH=did and SLIM_HUMAN_SEED (the human root key every agent's
DID is derived from), plus SLIM_MEMBER_DIDS — the allow-list of DIDs
permitted to participate. shadi_identity::require_did_auth_from_env enforces
this: it errors out if SHADI_SLIM_AUTH isn't did, so register,
delegate, and coordinate cannot silently fall back to a shared secret.
See the Secure Agent Group Demo for a full worked example, including how DID admission is verified against the allow-list.
Transport authentication¶
SLIMRPC peer-to-peer A2A authenticates to the SLIM node with mutual TLS, or
with a bearer token from SLIM_AUTH_TOKEN_FILE. The listener resolves a client certificate from SLIM_TLS_CERT / SLIM_TLS_KEY /
SLIM_TLS_CA, an agent-specific fallback, or a generic fallback (see
TLS certificate resolution). Generate the bundle
with tools/generate_slim_mtls_certs.sh and keep the CA private to the peers you
trust. gRPC listeners use a separate A2A_TLS_* pair and must not reuse those
SLIM files.
Multi-agent coordination layer (shadi_mas)¶
agentbridge coordinate is a driver for SHADI MAS. That
crate owns epochs, engines, and ASSEMBLY / CONVERGE. This page only
covers how AgentBridge feeds it.
coordinate builds a roster, optionally runs ASSEMBLY, then constructs
MasRuntime<E> for the class and turns tool replies into
SemanticEvents. --pattern development (default) uses
DevelopmentEngine. --pattern preference|cascade|resource uses the
scalar paper driver. --assembly infers the class first. See
ASSEMBLY and CONVERGE.
LiveA2ATaskAdapter (in shadi_mas::experiments) is the live task
dispatch used by delegate, handoff --from/--to slim:…, and
coordinate over SLIM or official A2A unicast. CliToolAdapter is
AgentBridge’s ToolAdapter over a local CLI profile.
DevelopmentEngine¶
DevelopmentEngine is the CONVERGE engine for a shared code artifact.
agentbridge coordinate --pattern development (default) stays here.
ASSEMBLY, other classes, skills, and halt rules are in
ASSEMBLY and CONVERGE.
| Event | Payload | Effect |
|---|---|---|
| Code proposal | ExternalBytes(code) |
Stored keyed by source agent |
| Endorsement vote | ToolResult { accepted: true, tool_name: agent_id } |
Votes tallied per artifact |
| Other payloads | any | Accepted silently (applied) |
| Finalization | — | Artifact with most votes wins; epoch advances |
| Max rounds exceeded | — | Force-finalizes with current best artifact |
Epoch discipline prevents duplicate, stale, and future-epoch events from corrupting the state machine.
Goal analysis: what was asked for vs. what is built
Original goal¶
"Write a new application to interconnect Claude CLI, Copilot CLI, Codex CLI or other similar applications to exchange context or messages, artifacts etc. Use the A2A protocol, SLIM/shadi for transport, and DIR to discover each other. Make agents coordinate with a goal and work in autonomy until the work is achieved."
What is implemented¶
| Requirement | Status | Detail |
|---|---|---|
| Architecture design | ✅ | Full A2A + SLIM + DIR stack documented |
| Coordination backbone | ✅ | shadi_mas migrated + DevelopmentEngine added |
CliAdapter trait |
✅ | Unified interface for any coding tool |
ContextPacket |
✅ | Portable session snapshot with JSON serde |
| Generic subprocess adapter | ✅ | GenericStdioAdapter — newline-delimited JSON protocol |
| Register profiles | ✅ | ProfileAdapter + crates/agentbridge/profiles/*.json (no per-CLI Rust) |
CliToolAdapter bridge |
✅ | Any CliAdapter → shadi_mas::ToolAdapter |
| DIR registration | ✅ | Real AgentCard (skills + SLIM endpoint) published to DIR's integration/a2a OASF module, DID carried in authors |
| DIR-driven group discovery | ✅ | MemberSource (skill search / DID lookup / explicit list) resolves SLIM group trust sets from Directory — see the Agent Directory Discovery Demo |
agentbridge library |
✅ | crates/agentbridge |
| CLI binary | ✅ | agentbridge register \| list \| handoff \| delegate \| coordinate |
| Live A2A transport | ✅ | LiveA2ATaskAdapter wired into register, delegate, handoff --from/--to slim:…, and coordinate |
| Quorum-vote finalization | ✅ | DevelopmentEngine — autonomous, no human required |
| SLIM group relay | ✅ | shadictl slim a2a-collaborate (SLIMRPC Collaborate RPC via shadi_a2a::A2AGroupChannel) — see SLIM and A2A |
| DID-identified secure groups | ✅ | Moderator-invited channels admitted against a per-agent DID allow-list — see the Secure Agent Group Demo |
| Application-layer DID proof | ✅ | Send/recv bound to did:key; forged DID rejected; AUTH_REQUIRED re-prove/ask/deny |
Native handoff specs |
✅ | Same --from/--to as coordinate, including cursor-agent and slim:<id> |
register --tool cursor-agent |
✅ | Same sandbox + DID listener as the other tools |
list --local |
✅ | Live listeners from on-host register leases |
| Two-line token-passing coding | ✅ | Round-robin Rust Demo — avatar delegate + capped apply + agent-as-A2A-client NEXT until cargo test (sample run). Same fifo outcome over official A2A unicast without a SLIM node: A2A unicast (sample run). |
What remains¶
| Requirement | Detail |
|---|---|
shadi_memory ContextPacket persistence |
SqlCipherStore wire-up in crates/shadi_memory/ |
Does the existing middleware help?¶
Yes — substantially. Every component of the target architecture existed or was extended from existing SHADI infrastructure:
- A2A:
shadi_a2a::A2AChannel/A2AChannelBuilderprovide identity-verified A2A over SLIMRPC or gRPC.LiveA2ATaskAdapterinshadi_masis a ready-made task dispatcher. - SLIM:
agent_transport_slim::NativeSlimSessionandLiveSlimMessagingAdapterprovide group and point-to-point messaging. TheLiveSlimGroupSenderhandles multi-agent broadcast with receipt acknowledgements. - DIR:
shadictl dirsubcommand already integrates withagntcy/dir. OASF records are the natural format for adapter agent cards. - shadi_mas: The
DevelopmentEnginerequired a newPatternKindand engine implementation, but the runtime, epoch discipline, adapter traits, and test infrastructure were already in place. - shadi_memory:
SqlCipherStoreprovides encryptedContextPacketpersistence with no additional code.
The middleware was designed for exactly this use case. The agentbridge application is an adapter layer on top of an existing, tested coordination stack.
File map
crates/
agentbridge/ ← library
src/
adapter.rs ← CliAdapter trait + CliToolAdapter
context.rs ← ContextPacket, CodeContext, ArtifactPayload
dir_registry.rs ← AgentCard → OASF module wrapping + dirctl integration
local_registry.rs ← on-host leases for `agentbridge list --local`
member_source.rs ← MemberSource (skill/DID/explicit list) group-discovery trait
adapters/
generic_stdio.rs ← subprocess JSON protocol adapter
profile.rs ← ProfileAdapter (JSON under profiles/)
agentbridge_cli/ ← binary (agentbridge)
src/
main.rs
commands/
register.rs ← register + SLIM A2A listener
list.rs
handoff.rs
delegate.rs ← single-shot A2A dispatch
coordinate.rs ← MasRuntime driver (ASSEMBLY / CONVERGE)
shadi_mas/ ← coordination runtime (SHADI MAS)
examples/
agentbridge_demo/ ← self-contained demo (no infrastructure needed)
Next steps¶
- Read SHADI MAS for the coordination runtime, then ASSEMBLY and CONVERGE for the group protocol.
- Try the Secure Agent Group Demo for a full multi-agent, DID-identified walkthrough.
- Try the Round-robin Rust Demo for a multi-turn loop where each agent may write at most two lines and chooses the next A2A peer.
- Try the Agent Directory Discovery Demo to form and grow a group by discovering members in DIR instead of naming them by hand.
- Review the transport layer in SLIM and A2A.
- See sandboxing guidance for running bridged tools in Sandbox and Policies.