CRIERhow it worksaudit

how it works

A trading floor where the traders are programs
and the bell is a person.

Crier runs an open-outcry pit: agents shout bids and offers, a matching engine prints what crosses, a double-entry ledger moves the money, and every word is signed and chained. What it does not do is let any of that settle without somebody accountable for it. The human is not a control bolted on at the end - the hold pile is the centre of the room.

A trade, start to finish
01

The seats

Once the instruments are picked, the seed shuffles the houses into the pits, sets the opening print of each pit, and gives every seat a strategy, a reputation and a stack of money. The same seed on another machine seats the same houses with the same intentions - that is what makes a run reproducible rather than a story.

core/world.ts
02

The shouts

One seat speaks per round. Its policy reads the book and its own state, then decides whether to bid, offer, hit the tape, or walk away. Every shout is signed by that seat before the clerk sees it, so a word said on the floor cannot be quietly rewritten afterwards.

core/policy.ts
03

The crossed book

A central limit order book, price-time priority, resting limits and immediate-or-cancel market orders alike. It matches whatever crosses, and it never refuses a trade for being too big or too odd - that is not a call the book gets to make.

core/book.ts
04

The books

A print is only a promise until money moves. Escrow is funded as a debit and a credit, the fee is booked when the capture lands, the payout clears against the seller, and a refund walks the same postings in reverse. The trial balance has to tie at every step or the floor stops.

core/ledger.ts
05

The hold

Before capture, a set of rules reads the ticket. Anything they catch is put on the human pile with the reason written in plain words - not "held by rule concentration" but the actual size, the actual counterparty. Nothing above the line settles without a person signing.

core/settlement.ts
06

The tape

Every message - each shout, print, hold, release, capture, refund - is canonicalised, signed with Ed25519, and sealed into a hash chain. One character changed anywhere in the middle breaks that seal and every seal after it, which is the only proof a settlement needs.

core/protocol.ts
07

The processor

One interface, two bodies behind it: a local processor that behaves like PayPal well enough to run the whole floor with no credentials, and the real sandbox, which mints orders, waits for a buyer, captures, voids, refunds and pays out. The floor cannot tell them apart except by the mode string.

gateway/paypal.ts
08

The webhook

The processor tells us what it did on its own schedule. Every event is verified against its signature before it is believed, attributed to the trade it names, and put on the tape as it arrived. An event nobody can attribute is still recorded - a floor should say out loud what it could not place.

gateway/paypal.ts
What the floor holds itself to

Read from the module that enforces them, in US dollars - the pit would print them in its own currency. Change them and the sealed record says so.

The interpreter

The engine speaks in minor units and rule ids; a person on the pile reads sentences. When a settlement stops, the chit can be read out in plain English by the floor's interpreter — a language model when one answers on this machine, and a fixed template when none does. The card says which of the two wrote it, because somebody is about to sign a decision off those words.

A hosted model

AI_BASE_URL, AI_API_KEY and AI_MODEL point the room at any OpenAI-compatible chat endpoint. All three or none: a base and a key without a named model would answer with a default the screen cannot name.

A model on this machine

With no endpoint configured the floor asks a local Ollama server what it holds and takes the smallest completion-capable model installed. A laptop with `ollama serve` running is a talking floor with nothing pasted into it.

The desk template

Deterministic prose built from the same facts, in the same words the card already shows. This is what a fresh clone, the test suite and any public demo speak — and a chit never goes blank because a model was unreachable.

This machine is read by: the desk template. What no channel gets to do is touch a number: the model is handed the amounts the engine already decided and asked to talk about them, it sets no price and approves nothing, and its prose is never sealed into the tape. A brief that contradicts the card loses.

Check it without trusting us

The tape is the record. Take it from the audit room — or write it out with --json — and you hold every shout, print, hold, signature and posting the session produced; nothing about the run lives only in this process. A stranger with the file, and no access to the machine that made it, can re-derive the balances from the postings, floor every account against the ledger, and walk the chain using only the public keys visible inside it.

# play a session and keep its tape
npm run pit -- --seed opening-bell --ticks 12 --json tape.json
# audit that recording, trusting nothing it says about itself
npm run audit:ledger -- --file tape.json
# or watch it on a screen
npm install && npm run dev
The surface
Take the real leg apart yourself

This address runs on the local processor, and it says so when asked: a public floor must not be opening orders under anybody's account. The real PayPal API is one environment variable away from the identical screens, and the sandbox it talks to is free.

  1. On the PayPal developer site, open Apps & Credentials and create a sandbox app. The client id and secret are on its own page.
  2. Note the sandbox buyer email next to it. This is the step no hosted floor can do for you: past the approval page is a sign-in, and the sign-in belongs to the sandbox, not to this app.
  3. Put the pair in your own environment and start the floor. Nothing else changes - the same screens, the same rules, the same tape.
  4. Tick settle on the real processor on the front door, open a floor, ring the bell. Each crossed book mints a real order; a held chit grows a link that opens PayPal's own approval page.
  5. Approve it as that buyer, then come back and press the chit. The floor asks the processor what the order's state is now, captures it, books the fee and pays the seller - no webhook needed for any of that.
# the whole of what the real leg needs
GATEWAY=sandbox
PAYPAL_CLIENT_ID=...
PAYPAL_CLIENT_SECRET=...
# then
npm install && npm run dev
# optional: only if you want pushed events believed
PAYPAL_WEBHOOK_ID=...
PAYPAL_WEBHOOK_URL=https://your.host/api/webhooks/paypal
# with no id set, every pushed event is refused at the door -
# and the money still moves, because the floor asks

Worth knowing which half is whose. The approval page, the order number and the capture receipt are PayPal's; a settlement stopping on the pile is ours, and so is refusing to let the platform complete one alone. With no credentials at all the floor runs on a local processor that emits the same event names, which is why every screen, rule and posting here is the same code a sandbox would be driving.