Observer Protocol is the open layer that refuses and proves. A mandate signed by the principal and out of the agent's reach. A request outside it that produces no instruction at all. A signed record of what was decided, verifiable by anyone without asking us. On any rail.
The control is designed to be the same on every one of them, and it has been demonstrated on Lightning. It has never run on a fiat rail. The register below says exactly where each one stands.
Every institution deploying agents already has two systems that look like they cover this. Neither one does, and neither can stop the other.
Your application writes down what the agent did and when. It is a record produced after the fact, by the same system that took the action, and it can be reconstructed, backfilled, or simply be wrong. It answers what happened. It cannot answer whether the thing that happened was permitted.
Your rail writes down that value moved. It is authoritative about settlement and silent about everything before it. By the time the instruction reaches the rail the decision is already made, and on the instant rails there is no state left in which it can be recalled.
Which human granted this machine the right to act, bounded how, for how long, and against which counterparties. That fact exists at the moment of delegation and nowhere afterwards. It is not in the decision log, because the log is written by the thing being constrained. It is not in the payment record, because the rail never saw it. When a supervisor asks whether an agent acted inside its authority, there is no artifact to hand them.
Two systems record two things, and neither one can stop the other. Observer Protocol records the third, and refuses before either of the other two is reached.
Three artifacts. Each one is a signed object, each one is checkable by someone who does not trust us, and the second one is the product.
A credential the human signs, not the machine. It states a ceiling, a counterparty set, a window, and whether a decision must be cited before the action is permitted. The agent holds a key that can spend inside it and no key that can widen it. Rewriting the mandate is not a permission the agent has to escalate to; it is a signature it cannot produce.
Not a warning. Not a flag on a dashboard for someone to review on Monday. No instruction is emitted, so there is nothing downstream to recall, reverse, or dispute. The check fails closed: if the mandate cannot be read, or the revocation status cannot be established, the answer is no. And the refusal is itself a signed record, which is the part nobody else publishes.
A signed statement naming the decision, the policy version and its content hash, a digest of the inputs it ran over, the outcome, and the party that decided, kept separate from the party that issued the mandate. It verifies offline, against public keys, with nothing from us — for the credentials the published engine knows how to read. That set is delegation credentials today, and it does not yet include the refusal record below. The signature on a refusal is sound and checks out under standard Data Integrity tooling, but reconstructing the payload that signature covers needs code we have not published, so verifying one end to end is currently something only we can do. Publishing that is the work; claiming it before then would make this whole page worth less. It travels with the counterparty rather than living in our database.
A successful payment demonstrates that a system can move money. It says nothing about whether the system could have stopped. So here is the other record: a payment that was requested, was fully fundable, had a route, and did not happen. One entry, on a live rail, with the money there.
lnd-custom op-mandate maxi-l402-v1The payment could have succeeded. There was more than four times the balance required, a live channel to a well-connected peer, and a working node. Nothing about the network prevented it. The mandate did.
The control matters as much as the refusal. Ten sats to the same destination, over the same channel, by the same RPC method, settled. So the denial is the mandate acting on the amount, not a broken node, a closed channel, or a route that was never there. A refusal you cannot distinguish from a failure is not evidence of anything.
Stripping the caveat does not help: it dies on the macaroon HMAC chain. A hand-rolled gRPC client running as a different user with a sanctioned macaroon was refused by the node the same way, and the middleware defaults to deny across all 70 RPC methods and fails closed if it dies.
did:key, not Observer Protocol's production issuer.
· One node, ours, so this is enforcement at a node and not closure of the Lightning network.
· The macaroon caveat is a sender-side trigger in the payer's own credential; it is not visible to the payee, who sees an HTLC and a preimage like any other payment.
This register has one entry because one refusal has happened on a live rail with funds present. It will grow as more do. We would rather show you one you can check than a list you have to sort.
The strongest claim we make is that you do not need our cooperation to check our work. That claim is worth nothing unless you can run it, so here it is, against a credential that is live on this domain right now. What you can check this way is a delegation credential. It does not yet include the refusal record above: that signature is sound and verifies under standard Data Integrity tooling, but reconstructing the payload it covers needs code we have not published, so verifying a refusal end to end is currently something only we can do. Publishing it is the work.
$ npm install @observer-protocol/policy-engine $ curl -O https://observerprotocol.org/credentials/\ maxi-0001-trading-mandate-2026-08.json // verify.mjs import { verifyCredentialObject } from '@observer-protocol/policy-engine'; import fs from 'node:fs'; const credential = JSON.parse( fs.readFileSync('./maxi-0001-trading-mandate-2026-08.json')); const config = { credentialPath: 'maxi-0001-trading-mandate-2026-08.json', // pin the issuer. a verifier that trusts // whoever the credential names is not // verifying, it is agreeing. issuerDid: 'did:web:bitcoinsingularity.ai', schemaAllowlist: ['https://observerprotocol.org' + '/schemas/delegation/v2.2.json'], revocation: { maxStalenessHours: 24, onUnreachable: 'cache-then-deny', fetchTimeoutMs: 5000 }, didCache: { maxStalenessHours: 24 }, cacheDir: '/tmp/op-cache', auditLog: '/tmp/op-cache/audit.log', rails: {}, allowContractCalls: false, }; console.log(await verifyCredentialObject( credential, config, Date.now())); $ node verify.mjs { allow: true, reason: 'credential verified' }
Everything the verifier checks is public: the issuer's DID document and the revocation status list, which it fetches over ordinary HTTPS from the origins the credential names, and the schema, which it checks by $id against your allowlist without fetching anything. There is no Observer Protocol API in the path, nothing to authenticate to, and nothing we can withhold to make a credential stop verifying.
Point offline.didDocumentPath at a local copy of the issuer's DID document and it makes no network call at all. That is the mode an examiner uses.
It fails closed, and it will refuse us too. onUnreachable: 'cache-then-deny' is the only accepted value: if the revocation list cannot be fetched, a cached answer is used and then the credential is denied. A status list hosted on an origin other than the pinned issuer's is refused until you allowlist it, and Observer Protocol's own clause-zero revocation demonstration is exactly such a pair, so it does not verify out of the box. That limit is published in the package.
This is not a design preference. It falls out of the message specifications for the real-time rails, and it is the reason the control sits where it does.
Faster Payments, SEPA Instant, FAST and PayNow carry no state in which a submitted instruction can still be stopped. There is no pending window, no recall leg that a supervisor can reach, no status the receiving institution is obliged to honour a reversal from. Settlement is the first and last state.
Where an institution does offer a hold, it sits in that bank's own API, above the clearing rail and inside one perimeter. It is a product feature of a single participant, not a property of the rail, and it does not travel to a counterparty at another institution.
If the only stoppable moment is before the instruction exists, then that is where the control has to be. Everything after it is reporting.
A rail identifier that needs a branch for fiat is a rail identifier that will grow a parallel schema. ClearingSystemCode:PaymentProduct mirrors CAIP-2's namespace:reference, so one field carries both and eip155:8453 already parses under it unchanged. The left half resolves against the ISO 20022 external clearing system code set, which appears in every pain.001, so it is not a vocabulary we invent or maintain.
| Identifier | Rail | Why the right half exists |
|---|---|---|
| USABA:ACH.CCD | ACH credit, United States | ACH and Fedwire share a clearing system and are different products |
| GBDSC:FPS | Faster Payments, United Kingdom | Distinguishes FPS from Bacs and CHAPS on the same code |
| SGIBG:PAYNOW | PayNow, Singapore | Distinguishes PayNow from GIRO and FAST |
| eip155:8453 | Base | CAIP-2 already; no change, no branch |
Status: proposed. This grammar is a design decision, not yet a published schema. Credentials issued today carry rail as a free-text string, and the shipped delegation/v2.6 schema documents it that way. Published schema URLs are immutable, so adopting this convention means a new schema version rather than an edit to an existing one. Until that version ships, this is what the field is becoming, not what it currently contains.
OP is what refuses and what proves. Agentic Terminal is how an institution operates it. The line between them is not open-versus-paid; it is primitive-versus-operation.
Signed attestations for decisions, refusals and approvals. Verification that needs nothing from us. Spec-governed, and you can run all of it yourself without telling us you have.
The approver cannot set the terms of what they are approving. Deployed inside your infrastructure, operated by your team or ours. Never holds funds. Never takes custody of credentials — the enforcement point reads the mandate it enforces, and holds no key that could issue, alter or re-sign one.
Written so that a reader who checks it finds it accurate rather than generous. Where a claim is weaker than we would like it to be, the claim moves toward the evidence.
wdk-op-policy), MPP/Tempo (mppx-op-account) and OWS (ows-op-policy), from a shared core. The Aqua demonstration runs in an instrumented build on Liquid; the hook is not in shipped Aqua.@observer-protocol/policy-engine 1.0.0-rc.6 on npm, MIT. Section 05 is a transcript of it running against a credential served from this domain.PolicyEvaluationCredential artifacts carry no credentialSchema and are refused by our own verifier on structure; one older trading mandate is missing authorizationConfig.policy. Re-issuing them is a signing operation, not an edit, and it has not happened yet.verified_events table holds 56 rows; 55 of them predate the current cutover and carry proof_strength = 'unverified', which is what that column exists to record. We do not count them as verifications and neither should you.did:key, cryptographically distinct from the enforcement point, and you can verify that separation offline from its own DID. What it is not is a second party. It is a fixture we generated and control — not a published organisation and not an independent third party with its own interests. The separation is real as cryptography and currently means nothing as governance. Proving a decider is genuinely independent needs a real second party, and until one exists this row says fixture rather than independent.v0.9, review record in the public repository. Additive over v0.6; a v0.6 implementation remains conforming.delegation/v2.7.json, carrying requiresDecisionAttestation, served at a URL that is immutable from the moment it went live. Note precisely what this does and does not change: the shape is now pinned and public, and there is still no verifier path for a PolicyEvaluationCredential. A published schema is not a verifier.Four commitments that do not bend to convenience, including when the convenience would be ours.
What a system did is checkable. What it says about itself is not. Every artifact this protocol produces is built to be checked by someone who has no reason to believe us.
A machine holds no authority it was not explicitly given by a human who signed for it. Absence of a mandate is not permission to proceed carefully; it is refusal. The default is no.
Verification logic is public, reproducible and auditable. No authority required. Self-hostable by design: OP does not custody funds, execute payments, or control access.
An attestation that only means something inside our system is a log entry. Ours verify against public keys, in your hands, after we are gone. We are not the custodian of the proof.
On 22 February 2026 two agents built by different developers, running on different stacks, settled a payment on Bitcoin mainnet against authority that had been granted in advance. The point was never that no human was in the loop. The point is that the human was in the loop first, at the moment the authority was granted, and that what happened afterwards can be checked by anyone against the payment hash.