Skip to main content

Agent Mesh

V2 only — invite-only edition. This is part of AI Partner V2 and is not in the open-source V1 you self-host from the Quick Start. V2 is available now, by invite. See V1 vs V2.

Overview

Agent Mesh operates in two directions:

  • Outbound (orchestrator mode) — AI Partner discovers external agents on the internet, delegates tasks to them with cryptographically scoped authority, classifies their behavior in real time, and maintains an immutable audit trail.
  • Inbound (orchestratee mode) — AI Partner accepts tasks delegated by external A2A orchestrators, including another AI Partner instance. Toggled independently via a sub-setting.

Both directions are disabled by default. Enable them in Settings → Agent Mesh.


How it works

Outbound — AI Partner as orchestrator

AI Partner (orchestrator)

├─ discovers external agent via /.well-known/agent.json
├─ mints a scoped Ed25519 JWT (5 min TTL)
├─ plants a canary tripwire token alongside it
├─ delegates the task (stream / push / poll)
├─ classifies agent behavior in real time
└─ revokes all authority the moment anything looks wrong

Inbound — AI Partner as orchestratee

External orchestrator (e.g. another AI Partner instance)

├─ reads /.well-known/agent.json → sees url=/api/a2a, streaming=true
├─ sends POST /api/a2a { method: "message/stream", goal: "..." }
│ X-API-Key: <consumer key from Admin Console → Agent Access>

AI Partner (orchestratee)
├─ validates API key → resolves the calling consumer's service account
├─ creates inbound_task record owned by that consumer (taskId returned)
├─ runs the goal AS the consumer —
│ isolated workspace, metered usage, per-consumer concurrency cap
├─ streams TaskStatusUpdateEvent / TaskArtifactUpdateEvent back via SSE
└─ updates inbound_tasks with status + result on completion

Protocol model

Protocol detection (at registration)

When you register an agent URL, AI Partner runs a two-step probe:

  1. A2A probeGET {url}/.well-known/agent.json. If a valid AgentCard is returned, protocol is a2a.
  2. REST fallback probePOST {url}/tasks. If it responds, protocol is rest_fallback.
  3. Otherwise — protocol is unknown (observe-only, no tokens issued, no canary planted).

Delivery mode (at delegation time)

For a2a agents, the delivery mode is chosen from the registered AgentCard:

ModeConditionMechanism
streamcapabilities.streaming = trueAgent streams TaskStatusUpdateEvent / TaskArtifactUpdateEvent back via SSE. Relayed to frontend via Socket.IO.
pushcapabilities.pushNotifications = trueAgent POSTs a notification to our callback URL. We then call tasks/get.
pollneitherWe poll tasks/get every 5 seconds until terminal state.

rest_fallback agents always use poll.


Security model

SSRF Guard

Every URL is validated before any network call. Blocked ranges:

  • Loopback: localhost, 127.0.0.0/8, ::1
  • Private: 10.0.0.0/8, 172.16–31.x, 192.168.0.0/16
  • Link-local / metadata: 169.254.0.0/16, 100.64.0.0/10
  • Non-HTTP schemes (file://, ftp://, etc.)

The guard runs at three explicit points: registration, task dispatch, and the delegate_to_external_agent executor tool.

Scoped JWT tokens

Each delegation gets a fresh Ed25519-signed JWT:

  • Lifetime: 5 minutes
  • Scope: array of permitted actions (e.g. ["task:read", "task:write"])
  • Stored: jti in external_tokens table
  • Verified via: active_tokens view (revoked_at IS NULL AND expires_at > NOW())
  • Revoked immediately: on delegation revoke, canary trip, or HOSTILE classification

AI Partner's public key is available at GET /.well-known/jwks.json so external agents can verify tokens you issue.

Canary tokens

A hidden "tripwire" credential is planted alongside every real token for a2a and rest_fallback agents. If any inbound request ever presents this canary:

  1. canary_triggered event written to the audit ledger
  2. Agent immediately forced to HOSTILE
  3. All active tokens for the agent revoked
  4. Forensic snapshot written to data/forensics/{agentId}-{timestamp}.json
  5. Socket.IO agent:hostile alert sent to the Triage tab

Canary tokens are never minted for unknown protocol agents (no comms channel to plant through).

Callback verification (push mode)

Inbound callbacks are verified by verifyCallbackPoI middleware:

  1. Authorization header = valid JWT in active_tokens view
  2. X-Poi-Signature = valid Ed25519 signature over the raw request body
  3. correlationId in body matches an active delegation
  4. X-Timestamp header: reject if |now − timestamp| > 30 seconds
  5. X-Nonce header: reject if seen within the last 60 seconds (in-memory LRU)

Any failure → HTTP 401 + callback_rejected event in audit ledger.


Classification

Classification is fully deterministic — rules run in priority order and the first match wins. The LLM is called only to generate the human-readable reasoning string, never to determine the class.

RuleTriggerClassConfidence
1 (highest)Canary token presentedHOSTILE100
2PoI absent or signature invalidROGUE90
3Correlation ID absent on callbackROGUE80
4JSON-RPC response malformedCONFUSED70
5a0 out-of-scope skills observedFRIENDLY85
5b1–2 minor out-of-scope skillsCONFUSED65
5c3+ or any sensitive capabilityROGUE80

Trust classes: UNCLASSIFIEDFRIENDLYCONFUSEDROGUEHOSTILE

You can manually override any classification in the Triage tab.


The five tabs

Registry

Register external agents by pasting a URL. AI Partner probes the agent automatically and displays:

  • Protocol badgea2a (green), rest_fallback (blue), or unknown (gray)
  • Trust class badge — color-coded from UNCLASSIFIED to HOSTILE
  • Online/offline indicator — based on consecutive failure tracking (circuit breaker at 5 failures)

Delegate

Compose a task for any registered agent:

  • Select target agent
  • Enter a goal
  • Add optional constraints
  • Set a timeout

Returns a delegationId for tracking.

Delegations

Live view of all delegations. For each:

  • Status badge (pendingrunningcompleted / failed / revoked)
  • Delivery mode indicator (stream / push / poll)
  • Result preview (truncated at 300 chars)
  • Respond inline form when status is input_required
  • Revoke button for active delegations

Updates arrive in real time via Socket.IO delegation:update events.

Triage

Agents grouped by trust class (HOSTILE first). For each:

  • Fired rules that led to the classification
  • Manual override buttons (FRIENDLY / CONFUSED / ROGUE / HOSTILE)
  • Forensic snapshot link for HOSTILE agents
  • Real-time alert banner on agent:hostile Socket.IO event

Audit Ledger

Immutable, append-only audit trail. Features:

  • 50-row pagination
  • Filter by correlation_id or event_type
  • Expandable payload viewer
  • CSV exportaudit-{correlationId}.csv download
    (PoI column is SHA-256 hash only, not raw blob; formula-injection cells sanitized)

AI Partner's own A2A identity

AI Partner publishes its own AgentCard so other A2A-compatible orchestrators can discover it:

GET /.well-known/agent.json — AgentCard for AI Partner
GET /.well-known/jwks.json — Ed25519 public key in JWK format

These endpoints are served before any authentication middleware so they're reachable without credentials.


Using Agent Mesh from goal execution

The delegate_to_external_agent tool is available inside any goal:

Tool: delegate_to_external_agent
Args:
agentId: <id from the registry>
goal: "Fetch the latest pricing from Acme Corp's agent and return a JSON summary"
constraints: ["return_json", "no_pii"]
timeout_ms: 30000

The executor validates the agent URL against the SSRF guard before dispatch, then monitors the delegation until completion and returns the result to the goal context.


Forensic snapshots

When an agent is classified HOSTILE (by canary trip or manual override), a JSON snapshot is written to {appDataDir}/forensics/:

{
"agentId": "...",
"agentCard": { ... },
"trustClass": "HOSTILE",
"classificationReason": "Canary token presented at 2026-05-24T09:15:00Z",
"auditRows": [ ... ],
"observedSkills": [ ... ],
"recentRequests": [ ... ]
}

Download via:

GET /api/external-agents/forensics/:filename

The filename is validated against a strict [\w-]+\.json regex to prevent path traversal.


Data model

Five tables are added to the SQLite database:

TablePurpose
external_agentsRegistered agents — protocol, AgentCard, trust class, circuit breaker
external_delegationsActive and historical task delegations — status, delivery mode, result
external_agent_auditImmutable append-only event ledger — never deleted
external_tokensJWT jti registry + canary tokens — verified via active_tokens view
inbound_tasksTasks received from external orchestrators — goal, execution_id, status, result

Enabling Agent Mesh (outbound)

  1. Open Settings in the sidebar
  2. Find the Agent Mesh toggle card
  3. Switch the main toggle on — AI Partner verifies the backend subsystem is ready
  4. The Agent Mesh sidebar item appears

To disable: toggle off — the sidebar item disappears and no new delegations can be issued. Existing audit records are preserved.


Enabling inbound tasks

Within the Agent Mesh settings card there is an Inbound sub-section:

  1. Enable the main Agent Mesh toggle first (or enable inbound independently)
  2. Turn on Accept inbound tasks
  3. The AgentCard at GET /.well-known/agent.json immediately updates:
    • url/api/a2a
    • capabilities.streamingtrue
    • securityX-API-Key header

External orchestrators that re-read the AgentCard will automatically switch to streaming delivery mode.


Two-instance AI Partner collaboration

The primary use case for inbound A2A is two AI Partner instances working in tandem — Instance A coordinates, Instance B specialises.

Setup

Instance B (executor) — configure first:

  1. Admin Console → Agent Access → toggle Inbound Agent API ON (and Outbound Agent Mesh if B will also delegate). Also available via PATCH /api/admin/agent-access.
  2. Admin Console → Agent AccessNew Consumer (e.g. instance-a) — creates a service account and mints its API key in one step. Copy the aip_… key immediately; it is shown only once. Each external caller gets its own consumer: isolated workspace, metered usage, instantly-revocable key.
  3. Note Instance B's base URL, e.g. http://instance-b:3000

Full consumer model, limits, billing statements, and error codes: see the Agent API guide.

Instance A (coordinator):

  1. Agent Mesh → Registry → Register http://instance-b:3000
    • AI Partner probes /.well-known/agent.json
    • Sees url=/api/a2a, streaming: true → protocol a2a, delivery mode stream
  2. Agent Mesh → Delegate:
    • Agent: Instance B
    • Goal: "Summarise all files in /workspace/reports"
    • → sends POST /api/a2a { method: "message/stream" } with X-API-Key: instance-a-key
  3. Agent Mesh → Delegations:
    • Live streaming status as Instance B executes the goal
    • Result appears when complete
    • Instance B is classified by AgentClassifier (rule 5: skills diff)

Wire format (what Instance A sends)

POST /api/a2a
X-API-Key: instance-a-key

{
"jsonrpc": "2.0",
"id": "rpc-uuid",
"method": "message/stream",
"params": {
"message": {
"role": "user",
"parts": [{ "text": "Summarise all files in /workspace/reports" }]
},
"metadata": { "correlationId": "corr-uuid" }
}
}

SSE events streamed back

data: {"type":"TaskStatusUpdateEvent","taskId":"...","status":{"state":"running"}}

data: {"type":"TaskStatusUpdateEvent","taskId":"...","status":{"state":"running","message":"Iter 2: Reading files..."}}

data: {"type":"TaskArtifactUpdateEvent","taskId":"...","artifact":{"parts":[{"text":"Here is the summary..."}]}}

data: {"type":"TaskStatusUpdateEvent","taskId":"...","status":{"state":"completed"}}