Developers/The envelope
Protocol spec

The envelope

The Vibe Commerce Protocol (VCP) is one protocol with four action namespaces. All of it rides on a single typed message: the universal envelope. Every buyer search, merchant offer, platform certificate, and world-state write is the same shape on the wire — only the inner action changes.

Centering everything on one envelope is what keeps a transaction intelligible as a single evidence chain. A buyer mandate, a merchant offer, a match certificate, and a state diff are different objects, but they travel through the same envelope and share the same session, idempotency, permission, and audit semantics.

Shape

This is the wire form materialized by src/protocol/envelope.py. A buyer-side discovery search, opening a session:

commerce.search.json
{
  "protocol": "vcp",
  "version": "1.0",
  "msg_id": "msg_001",
  "ts": "2026-05-15T12:00:00Z",
  "from": "buyer:discovery",
  "to": "platform:aggregator",
  "session_id": "sess_abc",
  "in_reply_to": null,
  "idempotency_key": "idem_001",
  "signature": null,
  "action": {
    "kind": "commerce.search",
    "payload": {
      "query": "refurbished iphone 13 128gb",
      "constraints": { "delivery_days": 3 }
    }
  }
}

And a merchant proposing a committed offer in reply — the same envelope, a different action, money as integer minor units (unit_price: 42900 is $429.00):

commerce.propose_offer.json
{
  "protocol": "vcp",
  "version": "1.0",
  "msg_id": "msg_042",
  "ts": "2026-05-15T12:03:11Z",
  "from": "merchant:pricing",
  "to": "buyer:negotiation",
  "session_id": "sess_abc",
  "in_reply_to": "msg_041",
  "idempotency_key": "idem_offer_7c1",
  "signature": null,
  "action": {
    "kind": "commerce.propose_offer",
    "payload": {
      "offer_id": "off_88",
      "merchant_id": "m_acme",
      "sku_id": "sku_iphone13_128",
      "qty": 1,
      "unit_price": 42900,
      "fulfillment": { "method": "courier", "eta_days": 2 },
      "claims": ["battery_health_88pct", "grade_a_refurb"],
      "expires_at": "2026-05-15T12:33:11Z",
      "idempotency_key": "idem_offer_7c1"
    }
  }
}

Fields

Every envelope carries the same top-level fields. The shape is wire-stable: fields can be added, never removed or renamed.

  • protocol — always "vcp". Lets a future bus carry non-VCP control-plane traffic without ambiguity.
  • version — semver-style MAJOR.MINOR. Wire-additive only.
  • msg_id — UUID v4, globally unique. The audit-log primary key.
  • ts — RFC 3339 / ISO 8601 timestamp with timezone. Used for ordering; signed-envelope scenarios also use it for a freshness window.
  • from — the sender address, shaped <side>[:<role>] (e.g. buyer:discovery, merchant:pricing, platform:psp). The side prefixis what the router's allow-table keys against; the role after the colon scopes it further.
  • to — same <side>[:<role>] shape. Special value world addresses the world tables; * is reserved.
  • session_id — one per buyer-side journey (intent → mandate → cart → settle → fulfillment → optional return). Negotiation rounds nest inside one session via in_reply_to chains.
  • in_reply_to — the msg_id of the envelope this responds to, or null for a session-opening message.
  • idempotency_key — REQUIRED on every state-changing action. De-duped on (from, idempotency_key); ≤255 chars, UUID v4 recommended, ≥24h retention.
  • signature — reserved. null unless the scenario opts into signed envelopes; when populated, an AP2-style ECDSA signature used for hostile scenarios.
  • action.kind — a namespaced action name of the form <namespace>.<verb> (e.g. commerce.search). The router splits on the first . to recover the namespace.
  • action.payload — a JSON object whose schema is determined by action.kind. Payloads reference the protocol's shared commerce objects rather than inventing ad-hoc shapes.

Money

Money is integer minor units everywhere — $3.00 is 300, never 3.0. There is no floating point anywhere money appears: unit_price, budget, floor_price, and ledger deltas are all integers. This convention is inherited from ACP and is non-negotiable; a float in a money field is a malformed payload.

Audit & replay

Every envelope the runtime accepts is appended to a JSONL audit log before it is dispatched. Each audit entry is one envelope plus a runtime metadata block (route_decision, partition_check, payload_check, applied_state_diff_id).

  • Replay is byte-exact given (audit_log, world_seed).
  • The contract that makes replay work is canonical JSON: the serializer in envelope.py uses sorted keys (sort_keys=True) and a fixed float repr, so the same envelope always serializes to the same bytes.
  • A signed envelope appends its signature to the audit entry; replay verifies it against the pinned key set for that scenario.

Idempotency

The runtime de-dupes on (from, idempotency_key) for any action whose manifest declares it a state mutation. A second send with the same key does not re-run the action — it returns the cached TransactionStateDiff (an HTTP-style 200 carrying Idempotent-Replayed: true). The same key with a different body is a conflict (422); an in-flight collision is a 409.

Source of truth
The protocol is the only source of truth, and the audit log is the replayable artifact. Disputes, reputation, and evaluation point to protocol evidence on the wire — not to transcript impressions of what an agent "meant".
Status
The envelope, its field rules, and the audit/replay contract above are the design of record. The runtime that signs, routes, and replays these envelopes is in private beta.