Observer Protocol is the open layer that makes a determination checkable by someone who was not there. A record names the rule version it was decided under, the inputs it ran over, and who decided. Anyone holding that record can re-derive the same result offline, against a published key, with nothing from us.
Each one runs without telling us you did it. That is the property, and it is the only property this site is about.
A determination record or a refusal record can be checked at /check. No account, nothing reaches us. The check runs in the visitor's own browser against a key recovered from the decider's own identifier.
A change is a new URL, never an edit to an old one. A record is checked against the version it was issued under, by $id, not against the newest published version. The schema index lists them.
No API key, no call back to us at verification time. npm install @observer-protocol/policy-engine, and the section below is a transcript of it running against a credential served from this domain.
A signature establishes that a named key signed those exact bytes and that nobody has altered them since. It does not establish that you have been shown every record.
A firm can hand over a hundred clean determinations and withhold the hundred-and-first, and all hundred verify. That is a governance problem, not a cryptographic one, and we have not solved it.
The register in section 06 carries this as a row, alongside every other thing this protocol does not yet do. The supervisors page states what solving it would actually require.
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 without us: delegation credentials, refusal records, lapse records and decision attestations. What you cannot: policy evaluation credentials, resolutions, instructions and releases.
$ 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, }; const { allow, reason, notes, checks } = await verifyCredentialObject(credential, config, Date.now()); console.log({ allow, reason, notes, checks }); $ node verify.mjs { allow: true, reason: 'credential verified', notes: [ 'credential carries no credentialStatus entry — revocation not checkable for this credential' ], checks: { validityWindow: 'passed', issuerResolution: 'network', issuerProof: 'eddsa-jcs-2022-verified', signerBoundary: 'not-configured', revocation: 'status-absent' } }
The credential fetched above was issued under delegation/v2.2 and is checked against the version it was issued under, by $id, not against the newest published version; schema URLs are immutable once published, so every version stays served at its own URL.
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.
Without installing anything: a decision attestation or an enforcement refusal record can be pasted into /check and checked in your own browser, which also derives, from the record you paste, which of its fields that signature actually reaches. A delegation credential is the one artifact the box above is still the route for, because verifying it resolves a did:web issuer over the network and that page makes no request.
Observer Protocol is open, MIT, self-hostable, and it is not the product we sell. Agentic Terminal converts an institution's written rules and produces the determinations. Observer Protocol is how anyone else checks them.
Which means the two sites answer two different questions. If you are deciding whether to buy something, agenticterminal.io is the page. If you have been handed a determination and want to know whether it holds up, you are on the right 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.
@observer-protocol/policy-engine 1.0.0-rc.22 on npm, MIT. Section 04 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.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.instructed, report records, and no version of the engine ever published rebuilds their signed bytes, so there is nothing to verify a signature against. This is not a version pin and it is not a gap that a reader can work around by installing something else: those records carry a signature that no counterparty, and no one here, can check. Principle 04 below says the evidence is portable or it isn't evidence. For better than a quarter of what we sign, it isn't. A second class, resolution records, was rebuildable at some published version but not at the one npm install served, for four releases. That count is now 0; section 02 of /verify carries what happened. Every figure in this row is read from results/ and fails the build if the copy and the measurement disagree. The population closes on 2026-08-15 and predates op.enforcement.refusal.v3; no v3 record is counted here.verifyDecisionAttestation is exported by the version npm install serves, and verify-samples/ppp-determination-refused-outcome.json is a published decision attestation it returns attested on. The record carries the document that was signed as base64 beside a documentHash, and sha256 over those stored bytes reproduces that hash, so the input to the signature is rebuildable from the record alone, by someone who holds nothing else and was present for none of it. Checked in CI in both directions, so a regression and a silent repair both break the build. What it establishes is narrower than the word verifier suggests, and the narrowness is stated where the check is run rather than here: a named key signed those exact bytes and nobody has altered them since, while policyRef.hash, vocabularyRef.hash and deciderArtifactDigest.value are confirmed present and never resolved against anything. The field-level account is on the docs page./check was published carrying no script of its own, and the page a browser received loaded static.cloudflareinsights.com/beacon.min.js. Nothing in our repository had changed, and it was injected only for requests carrying browser headers, so a build check reading the file and a plain fetch of the same URL both reported it clean. It was disabled at the zone the same day. Two runs of the audit an hour apart, on 17 and 18 August 2026, both found it absent, which is what corroborated means here and is the whole of what it means: it rules out a transient and rules out nothing else.
scripts/served-page-audit.mjs fetches the page as a browser and compares what it carries against what the page discloses, failing when something undisclosed appears, when something disclosed is no longer there, and when one of the page's own scripts is missing or altered. That third direction is the one a subtraction hides in: an injected script is loud, and the page's own verifier being removed leaves a page that renders and decides nothing. It also refuses to treat an absence as established on one observation: a thing that is disclosed and not there may have been removed at the zone or the edge may transiently have stopped adding it, so that answer is held open until a second run separated in time sees the same thing. It is a standalone file with no dependency on this repository, so it can run on a clock rather than on a commit, which is the only shape that catches a change nobody committed.
v0.9, review record in the public repository. Additive over v0.6 through v0.8; an implementation conforming to any of those 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 published rule sometimes sets a standard and gives no test a system can apply to a case without further facts or judgment. Where that happens the clause is recorded as unsettled. Silence in the text is not permission to pick a number carefully; it is a hold.
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.