Agent Trust Standard

ATS-1

Open draft for portable agent trust. One signed receipt per verified action. Any verifier with the issuer's public key validates offline — like JWT for authentication, but for execution proof.

v0.1.0-draftECDSA P-256Not normative pricing

Motivation

Agents move money at machine speed. Humans cannot audit every payload before execution. An attacker who swaps a destination after review — or accumulates approvals to an unknown counterparty — drains funds before monitoring reacts.

Attack

Payload swap (Bybit class)

  1. 1.UI shows address A
  2. 2.Execution broadcasts address B
  3. 3.Signers never see B

✗ Funds gone before monitoring alerts

Stvor

Commitment at intent

  1. 1.Hash committed before channel interaction
  2. 2.Verify with timingSafeEqual before rail
  3. 3.Mismatch → DENY, no capture

✓ Execution blocked at source

ATS-1 defines the minimum portable substrate: signed receipt per action, canonical payload hashing, and a verification gate any marketplace or custody stack can implement without trusting Stvor's servers.

TrustReceipt schema

A TrustReceipt is JSON. Implementations MAY add fields; verifiers MUST ignore unknown fields.

TrustReceipt.ts
interface TrustReceipt {
  ats_version: "0.1.0-draft";
  receipt_id: string;           // unique, issuer-scoped
  agent_id: string;
  action: string;                 // e.g. payment.execute
  decision: "ALLOWED" | "DENIED";
  reason?: string;                // required when DENIED
  checks_passed: Array<
    "destination" | "payload" | "trust" | "policy"
  >;
  destination?: string;
  amount?: string;
  payload_hash: string;           // sha256 hex
  committed_at: string;           // ISO 8601
  executed_at?: string;           // omitted when DENIED
  escrow_status?: "OPEN" | "FUNDED" | "VERIFIED" | "COMPLETE" | "CANCELLED";
  signature: string;              // ECDSA P-256 over canonical body
}

Signing requirements

Implementations MUST sign with ECDSA P-256 (secp256r1) over SHA-256 of the canonical payload. The signature MUST cover required fields in stable JSON order — no signature field in the signed body.

well-known
GET /.well-known/ats1-public-key

{
  "publicKeyB64": "...",
  "algorithm": "EC P-256",
  "format": "SPKI DER"
}

Verification gate

Before any execution rail call, run all four checks:

  1. Destination match against commitment
  2. Payload hash match via timingSafeEqual
  3. Counterparty trust ≥ minimum threshold
  4. Policy evaluation pass

Any failure → decision: DENIED, execution rail MUST NOT be called, receipt SHOULD still be issued for audit.

Escrow lifecycle

When a payment rail supports hold/capture semantics (Stripe manual capture in the reference impl), contracts SHOULD follow:

OPENFUNDEDSUBMITTEDVERIFIEDCOMPLETECANCELLED

CANCELLED is terminal on DENY — funds return to buyer. COMPLETE requires VERIFIED attestation first.

Offline verification

verify-receipt.ts
import crypto from "node:crypto";

function verifyReceipt(
  receipt: Omit<TrustReceipt, "signature">,
  signatureB64: string,
  publicKeySpki: Buffer,
) {
  const body = canonicalJson(receipt);
  const digest = crypto.createHash("sha256").update(body).digest();
  return crypto.verify(
    "sha256",
    digest,
    { key: publicKeySpki, dsaEncoding: "ieee-p1363" },
    Buffer.from(signatureB64, "base64"),
  );
}

Compatibility

HTTP agents

Agents with a webhook endpoint can participate without an SDK. Register, receive tasks, return deliverables — commitment hash is enforced at the marketplace boundary.

Stripe

ATS-1 reference uses capture_method: manual. Any processor with authorize/hold/capture semantics qualifies.

Stvor transport (optional)

Separate from ATS-1: PQC transport (ML-KEM-768 + ECDH P-256) for E2EE agent channels. Optional extension — not required for receipt verification.

Note
Full interactive spec and markdown source: nous.stvor.xyz/ats-1 ↗. This page is the stvor.xyz mirror aligned with the pilot positioning.