Pact
Staked agreements resolved by verification - four shapes over one machinery. An oath stakes on your own commitment, a bounty pays the hunter who proves the work, a market runs pari-mutuel predictions over outcomes, and a pool collects premiums and pays out when a covered event is verified. Stakes are escrowed in real Treasury wallets, every resolution passes through a verifier (manual, LLM arbiter, or human approval), and settlement produces a hash-stamped receipt.
When to reach for it: habit commitments with real consequences, task bounties paid on verified proof, internal forecasting markets, item insurance in a game economy, staked SLAs between agents.
When not to: competitive price discovery for one item belongs to Auction; plain transfers with no outcome to verify belong to Treasury; an approval flow with no stake attached belongs to HITL.
Concepts
- Stakes are real Treasury balance. A pact names a Treasury
domainandcurrency_id, gets its own escrow wallet at creation, and moves money by multi-leg transfers. Everyone who stakes must already hold a wallet in that domain and currency - a missing wallet fails with400 wallet_unresolved, so provision wallets first. - Four kinds, one lifecycle -
open(->claimedfor bounties) ->resolved->settled, withdisputedandvoidedas branches. - Money moves at settlement, not resolution. Resolving records the verdict and opens a dispute window; payouts happen only when the window closes (swept by a background worker) or a dispute is dismissed.
- The creator operates the pact. Only the creator or a platform admin
may resolve, void, or judge disputes. With a
manualverifier the creator's word is the verdict - pick anarbiterorhitlverifier when the creator should not be trusted unilaterally. - Self-exclusion: the creator may not claim their own bounty or stake
their own market (
403 self_stake_forbidden). - Disputes are bonded. During the post-resolution window anyone may file one dispute by escrowing a bond. Upheld: the resolution rewinds and the bond returns. Dismissed: the bond forfeits to the creator and the pact settles immediately.
Create a pact
snug pact create --kind oath --domain game --currency cur_gold --title "Run 3x this week" --stake 100
snug pact create --kind bounty --domain game --currency cur_gold --title "Fix the flaky test" --stake 500
snug pact create --kind market --domain game --currency cur_gold --title "Ship by Friday?" \
--outcome yes:Yes --outcome no:No --fee-bps 500
snug pact create --kind pool --domain game --currency cur_gold --title "Item insurance" \
--stake 200 --pool-payout 300Oaths and bounties require a positive --stake (escrowed immediately);
markets must not have one (400 invalid_stake - their pools are seeded by
positions); a pool stake is an optional seed contribution. Over HTTP the
same create is POST /api/v1/pacts; the enveloped response, captured
live:
curl -X POST -H "Authorization: Bearer $SNUG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind":"oath","domain":"docs4-pact","currency_id":"cur_gold",
"title":"docs4: no sugar for 30 days","stake_amount":250,
"forfeit_destination":{"kind":"sink"}}' \
http://localhost:4000/api/v1/pacts{
"status": 201,
"msg": "Created",
"data": {
"pact_id": "pact_0d73134d7e614e0782c6ae10133d9cb6",
"kind": "oath",
"status": "open",
"stake": {
"currency_id": "cur_gold",
"amount": 250,
"escrow_wallet": "wal_efd7fecf54673398e18523f2dad7f051",
"escrow_transfer_id": "txn_2bacca5a76cb4b4d999daba549a38d8f"
},
"created_at": "2026-08-28T14:17:17.625562Z"
}
}An oath's forfeit_destination routes a failed stake: sink burns it,
counterparty:<id> pays a named beneficiary, pool returns it to the
creator. An optional deadline blocks claims and positions once passed
(409 deadline_passed) but does not resolve the pact by itself.
Bounties: claim
snug pact claim --pact-id pact_94e4...Claims are exclusive and first-wins: the claimant gets status: claimed
plus an expires_at (claim TTL, 48 h by default), and every later
claimant gets 409 already_claimed. The background sweeper reopens a
claim whose TTL lapses without resolution. Claiming a non-bounty is
400 invalid_pact.
Markets: stake on an outcome
snug pact stake --pact-id pact_5ddc... --outcome yes --amount 600Each position escrows immediately and returns the live picture - after a
600 stake on yes and a 400 stake on no:
{ "implied_odds": 0.4, "total_pool": 1000, "position": { "outcome_id": "no", "amount": 400, "settled": false } }implied_odds is the outcome's share of the total pool. An unknown
outcome id is 400 unknown_outcome; per-position amounts are bounded by
the configured min/max stake. At settlement, winners split the losing pool
pro-rata after the creator's basis-point fee - verified live: with a 5%
fee the 600 winner collected 980 and the creator 20 of the 1000 pool.
Pools: join
snug pact join --pact-id pact_a3da... --amount 300Each contribution escrows into the reserve and appears in the pact's
contributions. On a fulfilled resolution the beneficiary receives the
parametric payout (capped at the reserve) and the remainder refunds
contributors pro-rata - verified live: a 500 reserve with a 300 payout
settled as 300 to the beneficiary plus refunds of 80 and 120.
Resolve, dispute, settle
snug pact resolve --pact-id pact_b95d... --fulfilled --evidence "proof attached"
snug pact resolve --pact-id pact_5ddc... --outcome yes # markets name a winner
snug pact void --pact-id pact_0d73... --reason "mis-set" # refund everyoneResolution verdicts, the three verifier kinds, dispute bonds, rewinds, and settlement receipts have their own page: Resolution, disputes, and settlement.
Finding pacts
snug pact list --kind market --status open --domain game
snug pact list -q insurance # full-text over title/description
snug pact list --filter created_by:eq:alice --sort-by created_at --sort-order desc
snug pact positions # the caller's market positionsList responses are a pacts array plus standard pagination; q,
filter, and sort_by follow the
shared search grammar. positions shows
each position's settled flag and final payout.
Limits and configuration
Stakes are bounded (1 to 1,000,000 by default), markets take 2-32
outcomes, creator fees are capped at 10%, the dispute bond is 100, and
windows default to 24 h (dispute) and 48 h (claim) - all tunable, along
with the settlement sweeper, via the PACT_* variables in the
Pact CONFIG reference.