Skip to content

Latest commit

 

History

340 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cogitator

A Rust recorder and verifier for agent runs.

CI Protocol Release Rust License: Apache-2.0

Cogitator records an agent run and seals the parts that matter under one cryptographic fingerprint, called the witness root.

It records what the agent did, which tools it asked to call, which calls actually ran, and which calls policy blocked or intercepted. Another machine can recompute the root from the bundle and check whether those committed records still match.

That gives you tamper evidence.

It does not prove that the run happened in the first place. For that, you need a copy of the root from somewhere outside the bundle.

Why Cogitator exists

A normal agent log is easy to trust too much.

It is usually produced by the same program you are trying to inspect. Entries can disappear. Files can change. A clean-looking log does not tell you whether somebody edited it after the run.

Cogitator records the run in a form that can be checked later.

Every witnessed event gets deterministic JSON encoding. Tool requests pass through policy before dispatch. Allowed calls and refused calls both become part of the record. Cogitator then folds those events into a domain-separated BLAKE3 hash chain.

The last digest is the witness root.

Agent step
  -> tool request
  -> policy gate
     -> allow:          executed ToolCall
     -> block/phantom:  PhantomEntry
  -> canonical JSON witness events
  -> domain-separated BLAKE3 chain
  -> witness root

Change a committed field, remove an operation, reorder the transcript, or insert something that was not there before, and recomputing the witness root produces a different result.

Some information should not affect the result. Timestamps, hostnames, toolchain versions, thread counts, and similar machine details are recorded as provenance but excluded from the witness commitment.

The same logical run can therefore produce the same witness root on different machines.

What exists today

Cogitator is the reference implementation of the Cogitator Witness Protocol.

It can record deterministic agent runs, apply policy before tool dispatch, seal the committed run semantics, replay recorded tool transcripts, detect drift, and verify run bundles.

The current agents and tools are fixtures.

clawdbot is a small scripted demo agent.

ordeal is a fixed 50-task regression suite with stubbed tool responses. Its witness root is pinned in CI so accidental protocol changes are obvious. It is not an agent benchmark, and passing it says nothing about the quality of a real model.

llm.generate is also stubbed. Cogitator does not contact an external model or service during these runs.

There is no drop-in integration for an outside agent yet. To connect one today, your code has to drive Cogitator's Rust APIs and provide the tool transcript and witness data it expects.

What a witness root proves

This distinction matters enough to state plainly.

If you recompute a bundle and get the expected witness root, you know that its committed semantics match that root.

Those semantics include the witnessed metadata, agent trace, executed tool calls, blocked or phantom calls, and the policy digest when a policy file was used.

That detects edits, reordered operations, missing committed operations, injected operations, and other changes covered by the protocol.

It does not prove that the run originally happened.

Someone who can manufacture a fresh bundle can manufacture its matching root too.

For evidence of occurrence, keep the root somewhere outside the bundle before you need to verify it. Publish it, timestamp it through another system, store it separately, or pass a root you obtained out of band to --expect.

Cogitator also does not prove that the machine which produced the run was trustworthy. It does not make external models deterministic.

Quick start

Build Cogitator:

cargo build --release

Run the drift demo and verify one of its bundles:

cargo run --release -- demo drift --seed 42 --threads 1 --fault-profile stress --out-dir demo_out --clean

cargo run --release -- verify --witness demo_out/drift/baseline_faults
cargo run --release -- verify --witness demo_out/drift/baseline_faults --recompute-witness-root

The verifier should report no bundle issues. The recompute should report matched=true.

To record and verify a fixture agent run:

cargo run --release -- run --agent ordeal --runs 1 --out-dir out --clean
cargo run --release -- verify --witness out/run_0000 --recompute-witness-root

--clean refuses dangerous output locations such as the filesystem root, home directory, repository root, .git, and symlinked directories.

--nix-provenance=auto|on may run bounded local Nix commands to collect diagnostic provenance. Those commands use closed stdin, a three-second timeout, and capped output. Nix provenance does not affect the witness root.

Policy

Cogitator evaluates policy before it dispatches a tool call.

The first matching rule wins.

When you load a policy file, Cogitator commits its SHA-256 digest into the witness root. This binds the run to the exact policy file used.

With no policy file, the current behavior is allow-all and no policy digest is committed.

schema_version = 1

[[rules]]
id = "trade-budget"
tool_pattern = "trade.*"
history_tool_pattern = "trade.*"
history_max_calls = 2
verdict = "block"
reason = "trade call budget exceeded"

[[rules]]
id = "research-phantom"
tool_pattern = "research.**"
verdict = "phantom"
reason = "observe only"

For tool patterns, * stays within one dot segment and ** may cross segments.

The three current verdicts are:

  • allow executes the call and records a real ToolCall.
  • block refuses the call and records a PhantomEntry with disposition blocked.
  • phantom does not execute the call and records a PhantomEntry with disposition phantom.

A refusal is evidence too. Cogitator does not silently drop it from the run history.

Verification

Cogitator has three useful levels of checking.

Check Command What it tells you
Bundle consistency verify --witness <dir> Manifest paths stay inside the bundle and recorded SHA-256 artifact and bundle hashes match.
Witness recompute verify --witness <dir> --recompute-witness-root The witness root recomputes from the recorded run semantics and the transcript is structurally complete and consistent.
External root comparison verify --witness <dir> --recompute-witness-root --expect <root> The recomputed root matches a root you already obtained from somewhere else.

The last check is the one that can detect wholesale replacement of a bundle, provided you trust the expected root you supply.

--expect requires --recompute-witness-root. A plain verify --witness <dir> does not currently consult it.

The witness_root.txt inside a bundle is useful for local checking. It is not an external anchor.

Inside a run bundle

A fixture run currently looks like this:

out/run_0000/
├── meta.json
├── agent_trace.json
├── tool_transcript.json
├── chaos_profile.json
├── drift_report.json
├── hash_chain.txt
├── witness_manifest.json
├── witness_root.txt
├── verify_report.json
└── nix_provenance.json

The witness root commits to:

  • witnessed metadata
  • agent trace entries
  • executed tool-call witness views
  • phantom entries
  • the policy digest when present

Other files have different jobs.

Artifact hashes and the bundle hash are consistency diagnostics. drift_report.json and verify_report.json are reports. Provenance records describe the environment.

None of those becomes part of the witness root merely because it lives in the same directory.

Replay and drift

Cogitator can replay a recorded single-run bundle:

cargo run --release -- run --replay <bundle_dir> --runs 1

During replay, recorded tool responses replace tool execution.

Cogitator compares the new transcript with the recorded one and writes differences to drift_report.json. It can localize changes in tool requests, outcomes, injected faults, phantom entries, and the policy digest.

The drift report only compares the tool transcript.

If the agent trace itself changes, such as its recorded thoughts, actions, or finality, that difference appears as a witness-root mismatch instead.

Fault injection is deterministic. With --faults on --fault-profile ci|stress, Cogitator derives the schedule from the seed, run, step, and call. Repeating the same inputs therefore gives the same fault schedule.

Development

Run the normal checks with:

cargo fmt --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo run --locked -- ordeal check --golden goldens/ordeal_witness_root.txt

CI also checks the pinned ordeal root, runs cargo audit, verifies builds without Git metadata, and requires SHA-pinned GitHub Actions.

Releases use cargo-dist and GitHub artifact attestations.

A Nix development shell is available with:

nix develop

Protocol and further reading

The Cogitator Witness Protocol is the source of truth for the current schemas, witness commitment, and verification rules.

It is still a draft and deliberately tracks the implementation closely.

Other useful files:

  • schemas/ contains JSON Schemas for bundle artifacts.
  • main.pdf contains the design write-up and determinism experiments.
  • CONTRIBUTING.md covers development and contribution setup.

If you want a bundle to inspect, generate one locally with the commands above. That is more useful than a pre-made example because you can keep the root yourself and then try modifying the bundle.

License

Apache-2.0.

About

Tamper-evident AI agent audit harness. Cryptographic witness chain, pre-call policy interception, and byte-stable replay. Prove what your agent did, tried to do, and was blocked from doing. Written in Rust.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages