Skip to main content
Glama

Postcondition

Agents call tools. Postcondition checks whether the world changed.

CI npm license

Postcondition is a local-first MCP server, TypeScript SDK and CLI for anyone who lets an AI agent act on real systems. You declare the outcome that should be true; Postcondition observes it with constrained read-only verifiers and keeps a hash-chained receipt of every observation.

intent → action in any tool → independent observation → honest verdict
                                         ├─ satisfied
                                         ├─ violated
                                         └─ unknown

It does not execute the action, expose hidden chain-of-thought, or turn an agent's own claim into external proof.

Try it in two minutes

Requires Node.js 20 or newer. In Claude Code:

claude mcp add postcondition -- npx -y postcondition-mcp serve

In any other MCP client:

{
  "mcpServers": {
    "postcondition": {
      "command": "npx",
      "args": ["-y", "postcondition-mcp", "serve"]
    }
  }
}

The agent then has postcondition_define and postcondition_check. The verify-before-done prompt asks it to define the observable result before it reports a task as done, check it, and report satisfied, violated or unknown exactly as returned.

The database defaults to ~/.postcondition/postcondition.db. Set POSTCONDITION_DB to use a different absolute path.

The smallest useful flow, from the command line

Define the world state that should be true:

npx -y postcondition-mcp define --json '{
  "statement": "soul-mcp 4.0.1 is visible in the public npm registry",
  "subject": "npm:soul-mcp@4.0.1",
  "verifier": {
    "kind": "npm",
    "package": "soul-mcp",
    "check": { "op": "version_exists", "version": "4.0.1" }
  }
}'

After the publishing action, check the returned contract id:

npx -y postcondition-mcp check pc_...

The result contains an observation, an evidence digest, the previous receipt hash, and the current receipt hash. npx -y postcondition-mcp verify-ledger recomputes the chain. After npm install -g postcondition-mcp the same CLI is available as postcondition.

Related MCP server: @humanaccepted/mcp

Why it exists

An agent receiving success: true from a tool only knows that the call returned. It does not know that a release is public, a file contains the intended data, a commit reached a remote-tracking branch, or an API now exposes the required state. Postcondition adds that missing step.

The closest alternative is a check you script yourself after the action: npm view <package>@<version> version, git branch -r --contains <commit>, a curl. It observes the same thing. Postcondition adds what such a script usually lacks: the expected outcome is written down before the action, a failed observation is reported as unknown instead of a pass or a fail, and every observation lands in a local, hash-chained receipt that labels where the evidence came from.

How it works

Verifiers

Kind

Supported checks

Network/process behaviour

file

exists, absent, SHA-256, text, JSON pointer, size

Local read only; content inspection capped at 16 MiB

http

status, text, JSON pointer

GET only; no custom headers; 3 redirects; 30 s maximum

git

branch, clean state, HEAD, tag, remote containment

Fixed read-only git argument sets; no shell; no fetch/push

npm

published version, dist-tag

Public registry GET

manual

explicit human or agent attestation

No automatic observation

HTTP and registry checks block loopback, link-local, private, and reserved addresses by default. For intentional local development checks, opt in with POSTCONDITION_ALLOW_PRIVATE=1. Read the threat model before enabling it in an environment that can reach sensitive services.

Evidence is classified, not flattened

Evidence class

Meaning

externally_observed

A remote HTTP/npm endpoint was read independently

configured_verifier

A constrained local file or Git check ran

manual_attestation

A human supplied the result

self_attestation

An agent supplied its own result

These labels remain in every receipt. An attestation can be useful, but it is never silently presented as external observation.

MCP surface

Seven tools:

  • postcondition_define — record a testable outcome and verifier.

  • postcondition_check — observe now and append a receipt.

  • postcondition_get — read one contract and its history.

  • postcondition_list — filter recent contracts by verdict.

  • postcondition_attest — record a labelled human or agent attestation.

  • postcondition_retract — invalidate a bad contract without deleting history.

  • postcondition_verify_ledger — recompute evidence digests and the receipt chain.

Resources:

  • postcondition://status

  • postcondition://contracts

  • postcondition://receipts

  • postcondition://contract/{id}

Prompt: verify-before-done.

TypeScript SDK

import { PostconditionRuntime } from 'postcondition-mcp';

const runtime = new PostconditionRuntime({ dbPath: './postconditions.db' });

const contract = runtime.define({
  statement: 'The generated manifest declares version 1.2.0',
  verifier: {
    kind: 'file',
    path: './package.json',
    check: { op: 'json_equals', pointer: '/version', value: '1.2.0' },
  },
});

const receipt = await runtime.check(contract.id);
console.log(receipt.verdict); // satisfied | violated | unknown

runtime.close();

Design rules

  • Outcome, not execution: Postcondition observes after an action; it is not a second orchestration framework.

  • Unknown is a valid result: timeouts, parsing failures, blocked targets, and unavailable evidence do not become false violations or fabricated success.

  • No arbitrary command verifier: Git checks use fixed argument sets and execFile, never a user-provided shell command.

  • Corrections stay visible: contracts can be retracted, not erased through the public API.

  • Protocol-clean stdout: MCP mode reserves stdout for JSON-RPC.

  • Local-first: no account, telemetry, hosted control plane, or API key is required.

Verify it yourself

git clone https://github.com/christian140903-sudo/postcondition-mcp && cd postcondition-mcp
npm ci && npm test        # expected: 55 passing (last verified 2026-10-09, Node 22, fresh clone)

The tests cover the SDK, SQLite persistence, receipt mutation, the CLI, an actual MCP stdio handshake, file limits, fixed Git checks, redirects, network blocking, and npm registry responses. CI runs them on Node 20, 22 and 24.

What they do not cover: no test contacts the public npm registry or a real website (HTTP and npm checks run against a local test server on 127.0.0.1); CI runs on Linux only; there is no test against an attacker who rewrites the database and recomputes the whole chain, because that attack is out of scope (see below).

To watch the tamper check fail on purpose, after npm ci && npm test:

export POSTCONDITION_DB="$PWD/demo.db"
node dist/src/index.js define --file examples/file-exists.json   # prints a contract id
node dist/src/index.js check pc_...                              # "verdict": "violated" (./dist/release.tgz does not exist)
node -e "require('better-sqlite3')(process.env.POSTCONDITION_DB).prepare(\"UPDATE observations SET verdict = 'satisfied'\").run()"
node dist/src/index.js verify-ledger                             # "valid": false, "firstInvalidId": "obs_...", exit code 1

Further checks: npm run test:coverage (coverage report) and npm run smoke:pack (packs the tarball, installs it into a scratch project, runs the CLI and imports the SDK).

What it does not do

  • It does not act. Postcondition observes after an action; it does not run, retry or roll back anything, and it has no policy engine.

  • It does not provide non-repudiation. Each observation stores a canonical evidence digest and the prior receipt hash, so verify-ledger detects modified evidence, modified receipt fields, reordered receipts, or a broken link in the local chain. Someone who can rewrite the database and recompute the entire chain is not detected, and neither is deleting the newest receipts, which needs no recomputation. Signed checkpoints and external anchors are not implemented.

  • It does not reach private or authenticated systems by default. HTTP checks are unauthenticated public GETs; there are no database, cloud or authenticated API verifiers.

  • It does not turn attestations into observations. Manual and self-attested receipts stay labelled as such.

  • The npm release 0.1.0 does not fail the process on a broken chain. Its verify-ledger reports "valid": false but exits with code 0, so scripts using that release must read the valid field. The code in this repository exits with code 1 on a broken chain or an unreadable database (Unreleased in the changelog).

The full list is in LIMITATIONS.md; the threat model is in SECURITY-MODEL.md.

How this was built

Most of the code was written by AI coding agents under my direction. I wrote the specification, set the constraints, decided what to test, reviewed the result and rejected what did not hold. Release decisions and every claim in this README are mine.

The public history starts at the finished 0.1.0 code (two commits on 2026-07-17); the agent sessions behind it are not published. The idea comes from my earlier agent projects, where one rule kept recurring: autonomy should carry evidence. This repository is a clean public implementation, not an export of their code or memory (ORIGINS.md).

Status

0.1.0 on npm (2026-07-17) · experimental · single maintainer · no known external users · last verified 2026-10-08.

Contract and receipt schemas may gain fields before 1.0; existing SQLite data will be migrated rather than silently discarded. Please report security issues through the private process in SECURITY.md.

License

MIT © Christian Bucher

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    B
    maintenance
    An MCP server that enforces fail-closed deterministic checks, independent refute-first review, and tamper-evident hash-chained receipts for AI agent outputs before claiming completion.
    4
    3
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    MCP server that auto-emits tamper-evident receipts for every tool call, enabling EU AI Act Article 12 compliance with signed, chain-linked receipts.
    1
    -
  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    An MCP server that validates tool calls against JSON Schema, performs deterministic repair, redacts secrets, and maintains a hash-chained audit ledger.
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    This MCP server provides a stateful, resettable, verifiable API runtime that gates every tool call, enabling agents to run long workflows against provider-shaped environments without live provider write access. It records decisions, side effects, and outcome evidence for replayable, verifiable benchmark runs.
    Apache 2.0