Rightshold™ Sign up

Answers · agent safety

How do I record what triggered an AI agent, the permission decision and the exact tool call outside the agent's own memory, so the record can't be rewritten?

Last updated

TL;DR: An agent's memory (memory files, conversation summaries, a vector store, its scratchpad) is built to be rewritten, by the agent and by whatever content it reads, so it can't double as the record of what the agent did. Keep a separate action record that the agent can append to but never edit, written by the code that runs tools rather than by the model. For each consequential action write one entry before the tool runs: the trigger (the message, event, schedule or upstream agent that started this step, by id and hash), the permission decision (which policy or approval allowed it, its version, allow or deny), and the exact call (tool name, server, a hash of the canonical arguments, call id). Write a second entry after it runs with the result hash or error, and chain both to the previous entry by hash. Then if memory is poisoned or wiped, you can still show what the agent was asked, what it was allowed and what it actually called.

What should I check, step by step?

1. Decide which actions get a record: anything that writes, sends, pays, deletes, changes permissions or calls an outside service. Read-only lookups can go to normal logs.

  1. Write the record from the tool-execution layer (your tool runner, a hook, a proxy or gateway), never from a tool the model calls to 'log' itself. The model chooses what to call; it shouldn't choose what gets written about it.
  2. Before the call, write an intent entry: trigger type and id (user message id, webhook delivery id, cron job id, parent agent and task id), a hash of the trigger content, the policy or approval id and version that allowed it, the decision, tool name and server, call id and a hash of the canonical arguments.
  3. After the call, write an outcome entry with the same call id: result hash or typed error, duration and whether the tool reported a side effect. A missing outcome after a crash is itself evidence.
  4. Chain each entry to the previous one by hash, and sign or anchor the chain head now and then, so a deleted or edited entry shows up as a break.
  5. Store it where the agent's credentials can append but not update or delete: a separate service, an append-only table with no update grant, or an outside ledger. The agent's memory directory and working folder are the wrong place.
  6. Never let the agent read its own action record back into trusted memory as instructions. If it needs history, give it a summary marked as data.
  7. Check memory against the record now and then: if memory says 'the user approved refunds over $500' and no approval entry exists, treat the memory as poisoned.

Why can't an agent's memory be the record of what it did?

Memory is meant to change. Anthropic's memory tool docs describe Claude creating, reading, updating and deleting files in a memory directory that persists between sessions, with your application running each operation. That is useful for continuity and wrong for evidence.

What should be recorded for each agent action?

Trigger: what started this step and where it came from. Record the source (user, webhook, schedule, another agent), its id and a hash of the content, so you can tell a person's request from an instruction that arrived inside a fetched page.

Why write the record before the tool runs?

Writing the intent entry first means a crash, timeout or killed process mid-call still leaves a trace that the call was attempted and under which permission.

How is this different from a tool-call log?

A tool-call audit log answers 'what did the agent call'. This record also ties each call to why it ran (the trigger) and what allowed it (the decision), and it's written before the call, so the chain holds up when the agent's own state doesn't.

What are the common failure modes?

The 'audit log' is a file in the agent's working folder, which a later step tidies up or overwrites.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Before this agent runs the tool call, record a signed entry with what triggered it, the permission decision, and the exact call (tool, server, call id, argument hash), then record the result hash after it runs.”

One-click setup

{
  "tool": "record_ai_run",
  "arguments": {
    "model": "<agent or model id>",
    "provider": "<runtime or framework>",
    "prompt_sha256": "<sha256 of the trigger content + canonical tool-call arguments>",
    "output_sha256": "<sha256 of the tool result, or of the intent entry before the call>",
    "params": {
      "phase": "intent",
      "trigger_type": "webhook",
      "trigger_id": "<delivery id>",
      "decision": "allow",
      "policy_id": "pol_…",
      "policy_version": 7,
      "tool": "send_invoice",
      "server": "<mcp server or connector>",
      "call_id": "call_…",
      "args_sha256": "<sha256>",
      "prev_entry_sha256": "<sha256 of previous entry>"
    },
    "ran_at": "2026-11-07T08:00:00Z"
  }
}

Rightshold records the hashes and fields your tool runner sends and signs them. It doesn't run your agent, see its memory, intercept tool calls or stop a call your code didn't record. The record only covers actions your execution layer writes to it. Not legal advice.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'