{
  "name": "AllowLatch",
  "version": "0.2.2",
  "description": "SERV Policy Copilot + spending turnstile for financial AI agents on Base (USDC). Always-on Vercel /api/gate with native x402 ($0.025). Required: createGatedAgentKit({ kind: site }). assertSpend is advisory. OpenServ optional fallback.",
  "homepage": "https://allowlatch.vercel.app",
  "repository": "https://github.com/aspekt19/AllowLatch",
  "documentation": "https://github.com/aspekt19/AllowLatch/blob/main/docs/CONNECT.md",
  "product": "https://github.com/aspekt19/AllowLatch/blob/main/docs/PRODUCT.md",
  "security": "https://github.com/aspekt19/AllowLatch/blob/main/docs/SECURITY.md",
  "protocol": {
    "openserv": {
      "agentName": "allowlatch",
      "workflowName": "AllowLatch Gate",
      "discover": "PlatformClient.payments.discoverServices() - filter name /allowlatch/i (listed as AllowLatch Gate)",
      "priceUsd": "0.025",
      "evaluatePack": "buy_evaluate_pack \u2014 each paid $0.025 x402 mints fixed credits (default 3); client cannot choose amount",
      "invoke": "x402 payWorkflow with { prompt } - no end-user API keys; users never run the host",
      "paywallUrl": "https://platform.openserv.ai/workspace/paywall/d5bd76ab6637492c8dea60fabb590b53",
      "triggerUrl": "https://api.openserv.ai/webhooks/x402/trigger/d5bd76ab6637492c8dea60fabb590b53",
      "hostInfo": "https://allowlatch.vercel.app/api/host-info",
      "failClosed": "timeout / network / malformed \u2192 DENY; check gate.isActive but still fail-closed on hang",
      "role": "optional-fallback",
      "note": "Use when site gate fails or ALLOWLATCH_PREFER_OPENSERV=1. Host keep-alive required."
    },
    "websiteGate": {
      "url": "https://allowlatch.vercel.app/api/gate",
      "actions": [
        "apply",
        "evaluate"
      ],
      "priceUsd": "0.025",
      "freeForWebsiteOrigin": true,
      "sessionSeal": "HMAC blob returned on apply/evaluate \u2014 client must send it back to survive Vercel cold starts",
      "note": "Primary always-on path. Website Origin free; agents pay $0.025 USDC x402 on Base. Required: createGatedAgentKit({ kind: site, gateUrl, sessionSeal, walletPrivateKey }). assertSpend is advisory. OpenServ is optional fallback."
    }
  },
  "agentSkill": {
    "universal": "https://github.com/aspekt19/AllowLatch/blob/main/skills/allowlatch/SKILL.md",
    "cursorMirror": "https://github.com/aspekt19/AllowLatch/blob/main/.cursor/skills/allowlatch/SKILL.md",
    "llmsTxt": "https://allowlatch.vercel.app/llms.txt"
  },
  "skills": [
    {
      "id": "draft_policy",
      "description": "SERV: draft MandatePolicy with conflicts, assumptions, questions (Multipath, prompt_guard, shadow)."
    },
    {
      "id": "revise_mandate",
      "description": "SERV: revise policy from owner feedback."
    },
    {
      "id": "apply_policy",
      "description": "Persist MandatePolicy. First apply returns ownerToken (required for later mutates)."
    },
    {
      "id": "compile_mandate",
      "description": "SERV: compile NL mandate into MandatePolicy JSON and store (requires ownerId / ownerToken)."
    },
    {
      "id": "sync_wallet_permissions",
      "description": "Optional: mirror daily USDC cap into Coinbase Spend Permissions (requires ownerToken)."
    },
    {
      "id": "evaluate_intent",
      "description": "Deterministic allow | deny | escalate. Issues single-use allow-receipt on ALLOW. No transaction."
    },
    {
      "id": "buy_evaluate_pack",
      "description": "Paid x402 call mints fixed evaluate credits for packKey (client cannot choose amount)."
    },
    {
      "id": "explain_decision",
      "description": "SERV: explain a gate result; never overrides the verdict."
    },
    {
      "id": "execute_gated_transfer",
      "description": "Re-evaluate, consume allow-receipt (jti), then AgentKit USDC transfer only on ALLOW (or escalate + humanApproved)."
    },
    {
      "id": "list_audit",
      "description": "Audit events for a policyId (ownerToken) or global (operatorToken)."
    },
    {
      "id": "reset_daily_ledger",
      "description": "Reset day/hour windows only \u2014 lifetime budget preserved. Requires ownerToken."
    }
  ],
  "invariants": [
    "Allow/deny/escalate is deterministic code - never LLM judgment",
    "Execute requires verified single-use allow-receipt (or escalate + humanApproved)",
    "Fail-closed: timeout, network error, malformed decision, or missing receipt \u2192 DENY",
    "Receipt binds chain, action digest, and calldataHash for swaps; prefer tokenAddress over symbol",
    "Tenant mutates require ownerToken (minted on first apply) or ALLOWLATCH_OPERATOR_TOKEN",
    "Lifetime budget is not reset by public APIs; reset_daily_ledger clears day/hour only",
    "End users never run npm run dev or set SERV_API_KEY \u2014 they connect via /api/gate Connect pack; agents must use createGatedAgentKit({ kind: \"site\" }); assertSpend alone is advisory",
    "AllowLatch does not custody user funds or private keys",
    "End users do not configure SERV_API_KEY or CDP - the host operator does; x402 pays the call"
  ],
  "stacks": [
    "Base",
    "USDC",
    "Coinbase AgentKit",
    "OpenServ",
    "SERV Reasoning"
  ],
  "httpGate": "npm run http:gate - POST /v1/evaluate, /v1/execute (framework-agnostic)"
}
