Clause GitHub ↗
Reference

How Clause works

Architecture

Buyer browser ──PayPal JS SDK popup──▶ PayPal Sandbox
Buyer / Seller / AI agent ──REST + SSE──▶ Clause server (Express)
MCP clients (Claude Desktop/Code) ──stdio──▶ src/mcp.js ──HTTP──▶ Clause server

Clause server
 ├─ pacts.js      state machine · spend gate · settlement · disputes · scheduler
 ├─ ai.js         Claude: compiler · arbiter · tribunal · seller agent
 ├─ jobs.js       runs AI inline, or as Render Workflows tasks
 ├─ paypal.js     Orders v2 · Authorizations · Captures · Refunds
 ├─ audit.js      SHA-256 hash chain · fingerprints
 └─ store.js      JSON file store

Pact lifecycle

Pact statusMeaning
awaiting_fundingCompiled; waiting for the buyer's PayPal approval
activeAuthorization hold placed; milestones delivered in order
completedEvery milestone settled; final capture closed the hold
cancelledRemaining hold voided and returned to the buyer

Milestone states: pending → reviewing → released (100%), settled (partial), revision_requested, escalated (buyer decides), refunded, voided.

Spend gate

Claude only recommends. Money moves automatically only when all five deterministic checks pass (spendGate() in src/pacts.js):

  1. The arbiter recommends release.
  2. Every acceptance criterion is met (a criterion the model skips counts as unverifiable).
  3. Confidence ≥ AUTO_RELEASE_MIN_CONFIDENCE (default 75%).
  4. No red flags (e.g. prompt injection, plagiarism signals).
  5. A live PayPal authorization hold exists.

Otherwise funds stay held: the buyer can approve (fully or partially), or send the milestone to the tribunal.

PayPal APIs

StepEndpoint
Create escrow order (one line item per milestone)POST /v2/checkout/orders with intent: AUTHORIZE
Place the hold after approvalPOST /v2/checkout/orders/{id}/authorize
Release a milestonePOST /v2/payments/authorizations/{id}/capture, final_capture=false until the last
Return what's leftPOST /v2/payments/authorizations/{id}/void
Extend long pactsPOST /v2/payments/authorizations/{id}/reauthorize
Appeal of released fundsPOST /v2/payments/captures/{id}/refund

Every money call sends a PayPal-Request-Id, and changes to a pact are serialized, so a retry or double click can't capture twice.

Claude roles

RoleCallNotes
Contract compilerStructured output (Zod), effort mediumMilestones, amounts, objective criteria, risks, clarifying questions
ArbiterStructured output + images, effort highPer-criterion verdict with quoted evidence; deliverable treated as untrusted
Tribunal advocatesTwo parallel calls, effort lowBuyer side and seller side; told to concede weak points
Tribunal judgeStructured output, effort highAwards a percentage based on criteria actually met
Seller agentText, effort mediumProduces the deliverable; uses arbiter feedback on revisions

Audit trail & receipts

Each pact event stores prevHash and hash = SHA-256(prevHash | canonical(event)). Money events include the PayPal ID and amount inside the hashed data. Deliverables and verdicts get their own SHA-256 fingerprints. GET /api/pacts/{id}/verify recomputes the chain and reports the first broken event; receipts re-run it when opened.

REST API

MethodPathPurpose
POST/api/pacts/draftCompile { text } into a draft (nothing saved)
POST/api/pactsCreate a pact from { draft, sellerKind }
GET/api/pacts, /api/pacts/{id}List / get pacts (with money, schedule and audit status)
GET/api/pacts/{id}/streamServer-sent events with live pact updates
POST/api/pacts/{id}/paypal/orderCreate the PayPal order; returns orderId and approveUrl
POST/api/pacts/{id}/paypal/authorizePlace the hold after approval
POST/api/pacts/{id}/milestones/{mid}/submitMultipart text, images, links; runs the arbiter and spend gate
POST/api/pacts/{id}/milestones/{mid}/agentAI seller agent does the work, then submits
POST/api/pacts/{id}/milestones/{mid}/releaseBuyer approval, { percent }
POST/api/pacts/{id}/milestones/{mid}/disputeTribunal; { claim, by: "buyer" } or { response, by: "seller" }
POST/api/pacts/{id}/cancelVoid the remaining hold
POST/api/pacts/{id}/refresh, /reauthorizeSync authorization status from PayPal / extend the hold
GET/api/pacts/{id}/verifyRecompute the audit hash chain
GET/api/pacts/{id}/receipts/{mid}Verifiable receipt for a settled milestone
GET/api/analytics/dataTables and relationships for the analytics dashboard
POST/api/ai/turnOne AG Studio agent turn executed by Claude
POST/api/maintenance/sweepCron sweep (header x-cron-secret)
GET/api/config, /api/healthClient config; health check

MCP tools

ToolWhat it does
draft_pactCompile a deal into a draft contract (nothing created)
create_pactCreate the pact and PayPal order; returns the approval URL for the human buyer
get_pact, list_pactsStatus, milestones, verdicts, money held and released
submit_deliverableSeller delivers; returns verdict and spend-gate result
release_milestoneBuyer approval (use only with explicit human approval)
open_disputeSend a milestone to the AI tribunal

Integrations

Bryntum Gantt: delivery timeline

public/timeline.js. Milestones are bars coloured by money state (held, reviewing, captured, partial, refunded), linked finish-to-start, with PayPal ledger events as time ranges. The server's scheduler adds a revision buffer whenever the arbiter requests a revision and flags milestones forecast past their deadline as at risk. Installed as @bryntum/gantt@npm:@bryntum/gantt-trial (trial watermark).

AG Studio (AG Grid): escrow analytics

public/analytics.js, src/analytics.js, src/studioAi.js. Four related tables, a dashboard generated with Studio's own add_widget/configure_widget tools, a custom LLM adapter that runs Studio's built-in agents on Claude server-side, and a custom Escrow risk analyst agent with Clause tools that delegates chart-building to Studio's lead agent. Theme mapped to Clause's design tokens. Trial mode unless AG_STUDIO_LICENSE_KEY is set.

Render: hosting, Workflows and cron

render.yaml, src/workflows.js, src/jobs.js, scripts/sweep.js. The AI agents run as Render Workflows tasks with retries (the tribunal fans its two advocates out in parallel); money never moves inside a task. An hourly cron job reauthorizes holds past PayPal's 3-day honor period and flags overdue milestones.

Project layout

src/        server, pacts, paypal, ai, audit, jobs, workflows, analytics, studioAi, mcp, store
public/     app (vanilla JS), timeline (Bryntum), analytics (AG Studio), styles
scripts/    smoke, seed-demo, sweep, build-dashboard
test/       lifecycle tests against a fake PayPal API, bridge and workflow tests
site/       this documentation (GitHub Pages)

Limitations

  • Buyer and seller roles are switched in the UI; production would add authentication and separate links.
  • Storage is a JSON file; swap in a database for production.
  • PayPal authorizations are honored for 3 days and valid for 29; long pacts rely on the reauthorize sweep.
  • Next steps: PayPal webhooks for capture reconciliation, Payouts to split one pact across several sellers, Disputes API sync.