Autonomous procurement for AI workloads — agents buy evidence before they buy services.
ProcureGraph is the layer that makes it safe for an AI agent to spend a company's money on outside vendors. It buys evidence before it buys services, it lets deterministic code — never the language model — decide who gets paid, and it proves every dollar on a tamper-evident ledger.
📖 Full documentation: https://mrrobot-ec.github.io/procure-graph/
Everyone is handing agents wallets. The hard question was never "can it pay?" — it's "should it, to whom, and can you prove it wasn't drained?" An agent that picks a vendor on vibes buys blind; an agent that trusts a vendor's own claims gets scammed; an agent that pays with no record leaves finance with nothing to sign off on.
The model proposes; deterministic code decides; the payment rail executes. The LLM never computes money and never holds a credential.
Two separate jobs, and neither is ever done by the model:
- Who is best? → a deterministic tournament scores vendors on measured evidence.
- Who is allowed? → a deterministic policy engine enforces the mandate's rules.
A bad vendor loses the tournament; a malicious action hits the policy wall. The component that can be tricked — the LLM — never has the authority to move money.
flowchart LR
LLM["🧠 LLM<br/>proposes"] -->|structured proposal| CODE["⚖️ Deterministic code<br/>tournament + policy engine<br/><b>decides</b>"]
CODE -->|allowed & selected| RAIL["💳 Payment rail<br/>x402 · Rain card<br/><b>executes</b>"]
CODE -.->|blocked| LEDGER["📒 Evidence ledger<br/>hash-chained"]
RAIL --> LEDGER
classDef untrusted fill:#f3f4f6,stroke:#9ca3af,color:#111;
classDef trusted fill:#fde7ef,stroke:#ff3377,color:#111;
class LLM untrusted;
class CODE,RAIL,LEDGER trusted;
- A mandate defines the outcome and the budget ("process 1,000 support tickets at ≥95% quality for ≤$20").
- The agent buys evidence — paying vendors cent-sized fees to be measured on a real task.
- It selects the winner by arithmetic on those measurements — the model doesn't vote.
- It pays on a scoped, single-use credential.
- A rogue "authorize $5 to GiftCardHub" injection is blocked —
$0.00 moved, 0 rail calls— and written to the ledger. - It verifies the delivered outcome on a held-out sample, then reconciles every cent to a mandate, a vendor, a receipt, and a transaction.
Any team whose AI agents autonomously spend on outside services — a spend platform (Ramp/Brex) buying document intelligence, a support platform (Zendesk/Intercom) buying translation, a sales-intelligence tool (Clay/Apollo) buying enrichment. Same engine — only the mandate changes. See Use Cases.
cp .env.example .env # fill in secrets for live mode; mock mode needs almost nothing
make dev # docker compose up --build — API, Postgres, providers, frontendThen open the narrated browser demo at http://localhost:4173/. Add ?fixture=1 for a
zero-cost, fully deterministic run (no external calls) — ideal for screenshots and walkthroughs.
make install # cd backend && uv sync
make seed # seed providers + the demo agent (idempotent)
make demo # run a full mission end-to-end in the terminalProcureGraph runs the identical graph against mocks or the real world; the mode is chosen by environment flags, and the mocks are always kept as a first-class path.
| Rung | What's real |
|---|---|
| Mock (default) | Deterministic fixtures; no keys, no network, no spend. |
| Live LLM | Real gpt-4o-mini, eval-gated before it can act. |
| Live x402 | Real USDC settlement on Monad testnet (real tx hashes). |
| Live Rain | Real scoped virtual card; Rain enforces the merchant category at authorization. |
The same checks run locally (make lint && make test) and in CI:
- ~3,000 tests at 100% branch coverage on authored code (
pytest). - Ruff lint + format, mypy --strict, and import-linter architecture contracts.
- Source/test-mirror and typed-environment-inventory checks;
pip-auditvulnerability scan. - Frontend: ESLint,
tsc --noEmit, Vitest coverage, and Playwright demo journeys.
Status: high-assurance prototype. A full mission runs live (LLM + Monad + Rain) with a real attack blocked and a full audit trail — but this is execution alpha, not a production-hardened service.
| Path | What lives here |
|---|---|
backend/ |
Python 3.12 · FastAPI · LangGraph. Clean architecture (domain / application / infrastructure / interfaces) + composition root. |
frontend/ |
React 19 · Vite · TypeScript. Evidence-first UI with five trust registers and SSE. |
providers-mock/ |
Deterministic vendor endpoints the demo auditions and buys from. |
evals/ |
Agent prompt fixtures + eval suites that gate every role before it can act. |
scripts/ |
Seed, demo verification, evals, and the live canary. |
docs/ |
Product + design documentation (published via MkDocs). |
vendor/langfuse/ |
Self-hosted Langfuse for LLM observability. |
The docs are built with MkDocs Material and published to GitHub Pages:
👉 https://mrrobot-ec.github.io/procure-graph/
Preview locally:
pip install -r requirements-docs.txt
mkdocs serve # http://127.0.0.1:8000Python 3.12 · FastAPI · LangGraph · PostgreSQL 16 · React 19 + Vite + TypeScript · Docker · OpenTelemetry + Langfuse · two payment rails (x402 micropayments on Monad, Rain scoped virtual card) · a hash-chained evidence ledger.