The Autonomous Stack
Agent Escrow Release icon

Agent Escrow Release · Business · v1.0

Evidence-based escrow release decisions

Decide whether escrowed funds may be released — from evidence, not from optimism.

$3.00one-timePay with crypto

Buy on Gumroad → https://6355137346884.gumroad.com/l/tas-agent-escrow-release-v1

escrow delivery-verification dispute-handling release-gate byo-llm

agent ⟶ theautonomousstack.xyz

01GET /api/v1/pack/agent-escrow-release-v1

402 Payment RequiredPAYMENT-REQUIRED

02sign TransferWithAuthorization3.00 USDC · Base (eip155:8453)

03GET + PAYMENT-SIGNATURE

200 OKapplication/zip · 20 files

pay per pack over x402no account

What's inside

  • CHANGELOG.md
  • CHECKLIST.md
  • CUSTOMIZE.md
  • OPERATING_COST_ESTIMATE.md
  • PROMPTS.md
  • README.md
  • SOUL.md
  • SPEC.md
  • agent-escrow-release-v1.json
  • agent-escrow-release-v1.service
  • agent.py
  • deploy.sh
  • examples/canonical_task.json
  • examples/escrow_ledger.json
  • install.sh
  • llm_adapter.py
  • pack_memory.py
  • requirements.txt
  • smoke_test.sh
  • test_agent.py

An autonomous payer is holding USDC for a job that an agent claims to have delivered. Something has to answer one question before the money moves: does the supplied evidence actually prove delivery? This pack answers it offline, deterministically, and refuses to answer "yes" whenever the evidence is incomplete, contradictory, unreadable, or disputed.

It never moves money. It produces the decision a human — or a policy engine you control — approves.

What it reads

Input What it is
escrow_terms The agreement: payer, payee, amount, asset, deadline, declared deliverables
delivery_proofs What the payee says it delivered: deliverable id, timestamp, artifact hash
webhook_receipts What your own systems recorded: receipt id, artifact hash, signature validity
disputes Open or resolved objections attached to an escrow

What it emits

Every supplied escrow lands in exactly one decision bucket:

Bucket Meaning
release_ready Every gate passed. Cleared for a human release decision.
hold Something is missing, inconsistent, late, or disputed.
refund The deadline passed without delivery, or a dispute resolved for the payer.
manual_review A field could not be read, or evidence points at an escrow you never supplied.

Alongside, three flag buckets explain the decisions and are emitted independently of them:

Flag Raised when
missing_proof A declared deliverable has no proof, no artifact hash, or no readable delivery time
late_delivery Delivery is after the deadline (with accepted_by_terms so you can see whether the terms forgive it)
inconsistent_receipts Hash mismatch, invalid signature, no corroborating receipt, or a receipt for an undeclared deliverable

The exact flag codes emitted (see SPEC.md): NO_DELIVERY_PROOF, PROOF_WITHOUT_ARTIFACT_HASH, PROOF_WITHOUT_READABLE_DELIVERY_TIME, DELIVERED_AFTER_DEADLINE, NO_CORROBORATING_RECEIPT, INVALID_SIGNATURE, ARTIFACT_HASH_MISMATCH, RECEIPT_FOR_UNKNOWN_DELIVERABLE. No other codes are ever produced.

A flag is not a veto: an escrow whose terms accept late delivery is still release_ready, and the late_delivery flag still appears so the approver sees exactly what they are signing off.

The release gate

release_ready is the only outcome that requires all of the following:

  1. Every declared deliverable has a delivery proof.
  2. Every proof carries a readable artifact hash and a readable delivery time.
  3. Every proof is corroborated by a webhook receipt with signature_valid: true and the same artifact hash.
  4. No receipt refers to a deliverable the terms never declared.
  5. No delivery is late, unless the terms explicitly set late_delivery_accepted: true.
  6. No dispute is open, unreadable, or resolved for the payer.

Fail any one of them and the money stays where it is.

Quick start

bash install.sh --no-service
./venv/bin/python agent.py demo                     # decide on the bundled sample
./venv/bin/python agent.py --ledger my_escrows.json decide
./venv/bin/python agent.py --ledger my_escrows.json report --out escrow_report.md
./venv/bin/python agent.py status

Deadlines are judged against the as_of instant you supply (in the ledger or via --as-of). The agent owns no clock: without as_of it will hold, but never declare a deadline missed.

Safety properties

  • No network, no API key, no database. Standard library only.
  • Nothing is executed. release_executed is false on every row and in the summary; no transfer, capture, or refund is ever performed.
  • No invention. Text in the payload — operator notes included — is data, not instruction. Evidence referencing an unsupplied escrow goes to manual_review, never into a decision.
  • Unreadable never means yes. Ambiguous amounts, non-ISO dates, unknown dispute statuses and unrecognised resolutions all hold or escalate.
  • Deterministic. Same input, same output, byte for byte.

Optional: bring your own LLM

llm_adapter.py can drive a coding-agent CLI you already pay for (Claude Code, Kimi Code, Codex) to write a human-readable brief or a dispute note. It is briefing only — the decision is already made when a prompt is used, and the pack is fully functional with no LLM installed at all.

Tests

python3 test_agent.py     # 51 offline tests, no network, no keys
bash smoke_test.sh

Licence: single-buyer commercial use. See SPEC.md for the exact output contract and CUSTOMIZE.md for wiring your own escrow, delivery and webhook sources.

Use a local model (Ollama)

The optional LLM step can also run on your own machine through Ollama, so no text leaves your server. No account and no API key.

ollama pull <model>               # any chat model you like
export PACK_LLM=ollama            # prefer Ollama even if a coding-agent CLI is installed
export PACK_OLLAMA_MODEL=<model>  # optional: default is the first chat model the server lists
python3 -c "import llm_adapter; print(llm_adapter.detect())"   # prints: ollama
  • PACK_OLLAMA_HOST points to another server (default http://127.0.0.1:11434); OLLAMA_HOST is also read when PACK_LLM=ollama.
  • PACK_OLLAMA_NUM_CTX sets the context size if your reports or prompts are long.
  • Without PACK_LLM, a local Ollama server is used only when no Claude Code, Kimi Code or Codex CLI is found.
  • If the server is down or the model is missing, the pack keeps working in its deterministic mode.

Learning memory (local and private)

Every LLM call this pack makes is journaled in ./.pack_memory/ next to the code, so the pack can improve for you. Nothing is ever sent anywhere.

  • What is kept: the task name, the masked input, the masked answer, status and latency. Keys, tokens, e-mails, phone numbers, IP addresses, card and IBAN numbers and personal paths are masked before writing; the system prompt is never stored.
  • Teach it: python3 pack_memory.py feedback last ok confirms a result, python3 pack_memory.py feedback last bad --fix "the right answer" corrects it. Confirmed and corrected runs are reused as validated examples when a similar input comes in. Unrated runs are never injected into a prompt.
  • Find similar cases: python3 pack_memory.py similar "some text" and python3 pack_memory.py clusters (groups of near-identical failures) work in plain Python, no model needed. Optional meaning-based matching uses an embedding model you already run locally: python3 pack_memory.py enable-semantic (Ollama on this machine only).
  • Share, only if you want: python3 pack_memory.py export writes an anonymised summary (counts, statuses, size buckets, no text) for you to review.
  • Control: PACK_MEMORY=0 turns it off, PACK_MEMORY_STORE_TEXT=0 keeps fingerprints only, python3 pack_memory.py purge --yes wipes it.