Skip to content

Latest commit

 

History

History
196 lines (157 loc) · 9.88 KB

File metadata and controls

196 lines (157 loc) · 9.88 KB

ASPL — Protocol Specification v0.1

ASPL (Agent Supply Protocol Layer) is a trust and supply-chain layer for agent capabilities. It sits above MCP (agent↔tool) and A2A (agent↔agent): it lets an agent find, verify, trust, and receive capabilities with cryptographic provenance.

This document defines the wire protocol so that any implementation — in any language — can interoperate. An implementation is conformant if it passes the conformance suite in conformance/ (python -m conformance.aspl_conformance <url>).

  • Version string: aspl/0.1
  • Transport: HTTP/1.1, JSON bodies (Content-Type: application/json).
  • Signatures: Ed25519. Keys are lowercase hex. A namespaced key is written ed25519:<hex>.
  • Hashes: sha256:<first-32-hex-chars-of-sha256> over the JSON-canonical form of the value (json.dumps(value, sort_keys=True, separators=(',',':'))).
  • IDs: ag_<hex> (agents), cap_<hex> (capabilities), txn_<hex> (transactions). Opaque to clients.

1. Roles

  • Node — a server implementing this spec. Holds an Ed25519 node identity and signs capabilities and deliveries.
  • Agent — a client. Receives an Ed25519 keypair + API key at registration.
  • Capability — a unit of value: template | block | tool | config | knowledge.

2. Registration (anti-sybil)

Registration is gated by proof-of-work to raise the cost of mass sybil creation.

  1. GET /v1/pow/challenge{challenge_id, prefix, difficulty, algorithm:"sha256", ttl_seconds}
  2. Client finds nonce such that sha256(prefix + nonce) has ≥ difficulty leading zero bits.
  3. POST /v1/register {name, environment?, pow_challenge_id, pow_nonce}{agent_id, api_key, public_key, passport}.

The passport is a JSON document the node signs over "{agent_id}:{public_key}:{created}" with the node key; it carries shop_signature and shop_public_key.

A challenge is single-use and expires after ttl_seconds. Difficulty is node-configurable; PoW is a speed-bump, not a strong barrier (see README).

3. Authentication

All mutating endpoints require X-API-Key: <api_key>. The node stores only a SHA-256 hash of the key. Missing/invalid key → 401.

4. Capabilities

4.1 Publish

POST /v1/publish (auth) with {type, intent, intent_tags?, description, requires?, provides?, content, safety_level?, version?, source_protocol?, source_ref?}.

The node MUST:

  • compute content_hash over content;
  • run a security scan over content (§7). If the scan returns safe=false (a CRITICAL finding), reject with 422 and the findings;
  • set safety_level to the stricter of the declared level and the scan result;
  • co-sign: shop_signature = sign("{content_hash}:{publisher_id}").

4.2 Discover (need)

POST /v1/need {intent, type_filter?, min_trust?, max_results?, environment?, include_imported?}{matches, query_intent, total_found}.

Ranking MUST combine an intent-match score and trust: combined = 0.7*intent + 0.3*trust. min_trust MUST filter on the capability's trust score (not on combined). The trust score used for ranking/gating is the stored score after read-time freshness decay (§5): a capability not exercised for a long time ranks lower. If environment is supplied, each match SHOULD carry env_compatible (§6). Revoked capabilities MUST NOT appear.

4.3 Acquire → Deliver → Confirm

  • POST /v1/accept {capability_id}{transaction_id, status:"accepted"}. Accepting a revoked capability → 410.
  • GET /v1/deliver/{transaction_id} (auth, caller must own the txn) → {transaction_id, capability:{..., content_hash, shop_signature, shop_public_key}, content, integration_hint}. The node signs delivery = sign("deliver:{transaction_id}:{content_hash}"). Clients MUST verify before use: recompute content_hash from content and check it equals the advertised hash, then verify shop_signature over "deliver:{transaction_id}:{content_hash}" against shop_public_key. Delivery of a revoked capability MUST be refused with 410, even for a transaction accepted before the revocation (revocation is not bypassable by pre-accepting).
  • POST /v1/confirm {transaction_id, success, feedback?} → updates agent and capability trust (§5) and returns the new scores. A self-dealing confirmation (the confirmer is the capability's publisher) MUST NOT raise the publisher's agent trust nor the capability's trust.

5. Trust

  • Agent trust = Bayesian success rate (prior 0.5, weight 5) × activity (log, saturates ~100 txns) × inactivity decay (30-day half-life).
  • Capability trust: unused → 0.3 × publisher_trust; used → 0.7 × (success_rate × usage_factor) + 0.3 × publisher_trust + maturity_bonus. Usage and success rate MUST be computed over distinct non-publisher confirmers (each confirmer counts once; the publisher's own confirmations are excluded), so trust cannot be pumped by volume from a single identity.
  • Read-time decay: when trust is READ for ranking/gating, a 30-day half-life decay is applied based on time since the capability was last exercised.
  • Imported capabilities start at MCP 0.5, LangChain 0.4, A2A 0.3. Federated (mirrored) capabilities carry 0.5 × the origin's reported trust (§9.4).

Trust is advisory metadata; clients decide their own thresholds via min_trust.

6. Environment verification (probe)

POST /v1/probe/{capability_id} {environment?, run_smoke?}{compatible, score, reasons, smoke_ran, smoke_ok, smoke_detail}. Compatibility compares the capability's requires (runtime/os/permissions/dependencies/memory) to the agent's declared environment. The optional smoke probe executes the capability's probe/code under resource limits and is NOT a security sandbox.

7. Security scan

At publish time the node scans content for prompt injection, exfiltration, resource abuse, embedded secrets, and (for code capabilities) dangerous calls. Scanning MUST be robust to trivial evasion: unicode/homoglyph normalization, base64/hex decode-and-rescan, and AST analysis of code. Severity → risk: CRITICAL ⇒ reject; HIGH ⇒ RED; MEDIUM ⇒ YELLOW; else GREEN.

8. Revocation

  • POST /v1/revoke {capability_id, reason, severity?} (auth, publisher only) — removes the capability from discovery/delivery.
  • GET /v1/revocations/stream (auth) — Server-Sent-Events; each revocation is pushed as event: revocation with a signed data payload.
  • GET /v1/revocations — node-signed status list of all revoked capabilities for catch-up (CRL-style).

9. Adapters & federation (interop)

9.1 MCP / A2A / LangChain ingestion

  • POST /v1/ingest/mcp {server_url, tools} — import MCP tool definitions.
  • POST /v1/ingest/mcp/url {server_url} — fetch a live MCP server's tools/list (JSON-RPC 2.0) and import.
  • POST /v1/ingest/a2a <AgentCard> — import an A2A Agent Card as a passport + capabilities.
  • POST /v1/ingest/langchain {tools:[{name, description, args_schema?}]} — import LangChain tool descriptors as capabilities (initial trust 0.4).

9.4 Federation

POST /v1/federation/mirror {peer_url} (auth) — mirror a peer node's catalogue. The node MUST, before importing anything:

  • fetch the peer's signed tree head (§10) and verify its Ed25519 signature;
  • fetch the peer's signed revocation list (§8) and verify it was signed by the same key as the tree head. Each non-revoked peer capability is mirrored as a local discovery record tagged source_protocol = "aspl-federated", at 0.5 × the peer's reported trust, recording origin-node provenance (origin_node, origin_url, origin_capability_id). Peer revocations MUST be honoured.

Acquisition proxy. POST /v1/federation/acquire/{capability_id} (auth) lets a local agent acquire a mirrored capability without contacting the peer itself: the node accepts + delivers the capability AT THE ORIGIN (using credentials it registered there during mirroring), verifies the origin's delivery signature and content hash, and returns {content, origin_url, origin_capability_id, content_hash, origin_node, origin_signature_verified}. It MUST return 410 if the origin (or local mirror) has revoked the capability, and 502 if the origin's signature does not verify. SDK get() routes a federated match through this proxy transparently.

10. Transparency

  • GET /v1/audit/verify{chain_valid, entries}. Every security-relevant action is appended to a hash-chained log; verification recomputes the chain.
  • GET /v1/audit/recent?n=&event_type= → recent entries (IPs partially masked).

10.1 Verifiable transparency log (Merkle / CT-style)

A Merkle tree over the audit entries (RFC 6962 hashing: leaf SHA-256(0x00‖entry), node SHA-256(0x01‖left‖right)) gives external, O(log n) verifiability:

  • GET /v1/log/sthSigned Tree Head {tree_size, root_hash, timestamp, signature, node_public_key}, signed over the canonical {tree_size, root_hash, timestamp}.
  • GET /v1/log/proof/inclusion?leaf_index={leaf_index, tree_size, leaf_hash, audit_path, root_hash} — proves an entry is in the tree.
  • GET /v1/log/proof/consistency?first=&second={proof, first_root, second_root} — proves the size-first tree is an append-only prefix of size second (detects history rewrites).
  • GET /v1/log/leaves?start=&end= → the entries with their leaf hashes.

11. Error model

Standard HTTP status codes. Bodies are {"detail": ...} (FastAPI default) or, for scan rejections, {"error":"capability_rejected","reason":...,"findings":[...]}. 401 auth, 403 not owner, 404 missing, 410 revoked, 422 scan-rejected, 429 rate-limited, 502 upstream (MCP) fetch failure.

12. Conformance

An implementation is conformant at level 0.1 if a fresh node passes every check in conformance/aspl_conformance.py against a live instance. Run:

python -m conformance.aspl_conformance http://localhost:5010