Show HN: Mnestiq – tamper-evident logs of what an AI agent saw and did A developer released Mnestiq, an open-source "flight recorder" for AI agents that produces tamper-evident, signed records of what an agent saw, decided and did, aimed at incident response rather than dashboards. Mnestiq hash-chains records using RFC 8785 canonical JSON and SHA-256 and periodically seals them with Ed25519-signed Merkle checkpoints under RFC 9162 trees, so edits, deletions, insertions and reordering fail verification. The tool captures provenance tags for system, user, model, tool_output, retrieved_doc, web, agent_msg and memory context, records outbound HTTP and raw TCP connections with local and remote IP and port, and ships as a drop-in SDK wrapping the Anthropic and OpenAI clients plus a `mnestiq proxy` mode that records model calls without code changes. A flight recorder for AI agents. Tamper-evident, signed evidence of what an agent saw, decided and did, built for incident response rather than dashboards. When an agent emails the customer list to an attacker, observability traces tell you that it happened. Evidence tells you which run and step did it, that the instruction came from a web page rather than the user, that an auto-approve policy waved it through, and lets you prove none of that was edited after the fact. php firewall: 10.0.4.17:53120 - 198.51.100.9:25 50 bytes no agent identity mnestiq: agent=support-bot run=c7831ff7 step=6 sandbox=container:7f3a9c operator=acme-helpdesk untrusted input earlier in the run: step 4: web via fetch page authorized by policy:email-auto-approve policy : recipient not checked against customer domain - Attribution: every event carries run id , step id , parent run id , agent id , operator id and sandbox id auto-detected for containers and k8s pods . - Egress identity: outbound HTTP gets X-Mnestiq-Run-Id / X-Mnestiq-Egress-Id headers, and every outbound request and raw TCP connection SMTP, databases, sockets is recorded with its local and remote IP and port: the join key to flow and firewall logs. - Provenance: every piece of model context is tagged at capture time: system , user , model , tool output , retrieved doc , web , agent msg , memory . That's what makes prompt-injection analysis possible afterwards. - Tamper evidence: records are hash-chained RFC 8785 canonical JSON, SHA-256 and periodically sealed by Ed25519-signed Merkle checkpoints RFC 9162 trees . Edits, deletions, insertions and reordering fail verification. - Redaction that keeps the proof: strip prompts, tool arguments and tool output before handing evidence to an auditor; the chain still verifies. - Drop-in SDK capture: wraps the Anthropic and OpenAI clients sync and async, Chat Completions and Responses APIs . Recording fails open: it never breaks the agent. - No code changes needed: mnestiq proxy records an agent's model calls from outside it, whatever language or framework it is written in. Point its base URL at the proxy. pip install "mnestiq anthropic " or mnestiq openai mnestiq keygen --out keys python import anthropic from mnestiq import FileSink, Recorder from mnestiq.keys import load private key from mnestiq.egress import instrument egress from mnestiq.integrations.anthropic import instrument anthropic recorder = Recorder FileSink "evidence.jsonl" , agent id="support-bot", operator id="acme-helpdesk", signing key=load private key "keys/signing.key" @recorder.tool source="web" output of this tool is untrusted web content def fetch page url: str - str: ... client = instrument anthropic anthropic.Anthropic , recorder instrument egress stamp + record outbound connections during runs with recorder.run effective permissions={"email": "send"} : client.messages.create model="claude-sonnet-5-5", max tokens=1024, messages= ... recorder.close writes the final signed checkpoint mnestiq verify evidence.jsonl --trusted-key keys/signing.pub mnestiq inspect evidence.jsonl mnestiq redact evidence.jsonl evidence.redacted.jsonl A key file the agent can read is fine for trying it out. In production, keep the key where the agent can't read it: signer=SignerClient.from env with mnestiq signer serve running under another account, or signer=AzureKeyVaultSigner ... . See docs/signing.md https://github.com/mnestiq/mnestiq/blob/main/docs/signing.md . mnestiq proxy evidence.jsonl --agent support-bot --key keys/signing.key export OPENAI BASE URL=http://127.0.0.1:8787/openai/v1 and/or export ANTHROPIC BASE URL=http://127.0.0.1:8787/anthropic The agent runs unchanged. Every model call it makes is written to evidence.jsonl , signed. What the proxy can and cannot see, and how to deploy it so an agent can't go around it: docs/proxy.md https://github.com/mnestiq/mnestiq/blob/main/docs/proxy.md . A scripted support agent reads a poisoned web page and emails customer data out. You then investigate the evidence it left behind. git clone https://github.com/mnestiq/mnestiq && cd mnestiq python -m venv .venv && . .venv/bin/activate Windows: .venv\Scripts\activate pip install -e python httpx python examples/injection incident.py --out evidence mnestiq dashboard evidence --trusted-key evidence/incident.pub mnestiq dashboard evidence/ --trusted-key keys/signing.pub A local investigation view at the link it prints http://127.0.0.1:8765/?key=... , whose key keeps other accounts on the machine out : runs and sub-runs, a step-by-step timeline with every piece of model context colored by provenance, findings below , the verification status of every record sealed, unsealed, or tampered , and a connection finder: paste an ip:port from a firewall or flow log and jump to the agent step that opened it. It live-updates while agents write. | Rule | Name | Fires when | |---|---|---| | MNQ-001 | untrusted argument | A tool call's arguments carry an email address, URL, account number or long number that appears in untrusted content and nowhere in the system prompt or the user's messages. | | MNQ-002 | auto-approval | An action was approved without a human after untrusted content reached the model, and the approved call carries a value from that content. A policy approving a routine reply is not a lead. | | MNQ-003 | egress after taint | An outbound connection not to loopback followed untrusted content reaching the model. | | MNQ-004 | untrusted sensitive action | A sensitive action credentials, permissions, deletion, cancellations, account changes, payments, bookings ran with an argument value that appears in untrusted content and not in the user's or system's words. Mark tools with @recorder.tool sensitive=True . Unmarked tools are judged by name. | | MNQ-005 | untrusted link in answer | The model's answer carries an image, or a link with data in its query, to a host that appears in untrusted content and not in the user's or system's words. An image is fetched as soon as the answer is shown, so it can carry data out with no tool call. | | MNQ-006 | internal data to new recipient | A tool sent data from the company's own systems tool output labelled internal to an address or host that appears neither in those systems nor in the system prompt, such as the price list to a "new customer". No injection is needed. | MNQ-001 is the signature of a hijack: an injected instruction has to put the attacker's address, account or URL into a tool call. MNQ-004 covers hijacks with no destination, such as "change the password to ...", "delete file 13" or "cancel order 4100". MNQ-005 covers leaks through the answer itself, such as an injected image link that carries the customer's email address. MNQ-006 covers data handed to someone who simply asked for it. Findings describe what was observed, not a verdict: an agent that visits a link a colleague posted triggers MNQ-001 too. The same rules are available in Python as mnestiq.findings . It stays on your machine: it binds to loopback only, rejects non-local Host headers, renders evidence strictly as text, and its Content-Security-Policy forbids the page from loading or contacting anything but the local server. To see it with live data no API keys needed : python examples/live agent.py --out evidence keeps a scripted agent running mnestiq dashboard evidence --trusted-key evidence/live.pub See examples/injection incident.py https://github.com/mnestiq/mnestiq/blob/main/examples/injection incident.py for a full incident: an injected web page leads to exfiltration over a raw TCP connection; a firewall log entry is traced back to the exact agent step; a tampered approval is caught; a redacted copy is shared. The recorder runs inside your agent, so it is built to never be the thing that breaks it. | Concern | Behaviour | |---|---| | Recording fails disk full, closed sink, odd values | The agent carries on. Failures are counted in recorder.failures , logged on the mnestiq logger, and warned about once. Pass strict=True to raise instead, if an unrecorded action is worse than a failed one. | | Process dies mid-write | On restart, FileSink moves the torn last line to