Skip to main content

Drop-in auto-record wrapper for the Anthropic Python SDK — every LLM turn captured to Neruva Memory. Recall later via the Neruva MCP / API. Cross-session, cross-vendor, portable.

Project description

neruva-record

Drop-in auto-record wrapper for the Anthropic Python SDK. Every messages.create() call captures both directions to a Neruva Memory namespace as a side-effect. Stop manually saving things; query the namespace later for "what did this agent do?"

Pairs with @neruva/mcp (captures MCP tool calls). Together: full agent-loop capture.

Install

pip install neruva-record anthropic
export NERUVA_API_KEY=...        # https://app.neruva.io

Use

import anthropic
from neruva_record import auto_record

client = auto_record(
    anthropic.Anthropic(),
    index="brain",                # one per user/account
    namespace="main",             # one per agent (free-form)
    ttl_days=30,                  # optional: auto-expire records after N days
)

# Drop-in: client behaves identically to bare Anthropic.
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=200,
    messages=[{"role": "user", "content": "Hi!"}],
)

# Recording happened as a side-effect. Query it later via the MCP
# or the REST API.

Async

from anthropic import AsyncAnthropic
from neruva_record import auto_record

client = auto_record(
    AsyncAnthropic(),
    index="brain", namespace="main",
)

response = await client.messages.create(
    model="claude-opus-4-7", max_tokens=200,
    messages=[{"role": "user", "content": "Hi!"}],
)

Naming convention

Field What Example
index One per user/account. Agent-type-neutral. brain
namespace One per agent the user runs. Free-form. main, support-bot, research
# multi-agent setup -- same brain, one namespace per agent
support  = auto_record(Anthropic(), index="brain", namespace="support-bot")
research = auto_record(Anthropic(), index="brain", namespace="research")
ops      = auto_record(Anthropic(), index="brain", namespace="orchestrator")

What gets recorded

Per LLM turn, one record:

{
  "id": "llm-<unix-ms>-<rand>",
  "text": "USER: <user-message>\n\nASSISTANT: <response>",
  "metadata": {
    "kind": "llm_turn",
    "vendor": "anthropic",
    "model": "claude-opus-4-7",
    "stop_reason": "end_turn",
    "input_tokens": 12,
    "output_tokens": 87,
    "latency_ms": 1240,
    "ts": <unix-ms>,
    "_auto_expire_at": <unix-ms-or-omitted>
  }
}

User text is truncated at 600 chars, assistant at 1800 chars (for embedding quality and storage cost). The full conversation history isn't stored — only the most recent user message and the response. For full trace capture, also use @neruva/mcp which records every tool call alongside this.

Querying back

Use the Neruva MCP or the REST API to query the recorded turns:

curl -X POST https://api.neruva.io/v1/indexes/brain/text/query \
  -H "Api-Key: $NERUVA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "namespace": "main",
    "text": "what did I ask about deployment?",
    "topK": 5,
    "includeMetadata": true,
    "filter": { "vendor": { "$eq": "anthropic" } }
  }'

Failure mode

Recording is fire-and-forget. If the recording POST fails for any reason, your messages.create() call returns normally — the recorder swallows its own errors. You will never get fewer responses than you asked for; you may get fewer records than you'd see in a perfect world.

TTL / decay

Set ttl_days=N and each record carries _auto_expire_at = ts + N days. The Neruva server-side decay sweep automatically removes records past their expiry on the next query/upsert touch (max once per 15 minutes per namespace). No background job to run.

client = auto_record(
    anthropic.Anthropic(),
    index="brain", namespace="main",
    ttl_days=7,    # only the last week is retained
)

Claude Code hook recorder (0.2.0+)

Capture everything in a Claude Code session — built-in tool calls (Bash, Read, Write, Edit, Grep, Glob, WebFetch, WebSearch), every MCP tool call, every user prompt, every assistant turn end, every subagent invocation, every task — into one Neruva namespace. No code change in your agent; one settings snippet.

Install

pip install neruva-record

This installs the neruva-record-hook console script.

Wire into ~/.claude/settings.json (or per-project .claude/settings.json)

{
  "env": {
    "NERUVA_API_KEY": "nv_...",
    "NERUVA_AUTO_RECORD": "brain/main:30"
  },
  "hooks": {
    "UserPromptSubmit": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "PostToolUse": [
      { "matcher": "*", "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "PostToolUseFailure": [
      { "matcher": "*", "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "Stop": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "SessionStart": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "SessionEnd": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "SubagentStart": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "SubagentStop": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "TaskCreated": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ],
    "TaskCompleted": [
      { "hooks": [{ "type": "command", "command": "neruva-record-hook", "async": true }] }
    ]
  }
}

async: true is the magic — Claude Code fires the hook fire-and-forget without waiting for it to return, so your tool calls never slow down. Recording happens in parallel.

What gets recorded

Per Claude Code event, one record. Each carries metadata.kind and metadata.event so you can filter at query time.

Event metadata.kind What's captured
UserPromptSubmit user_prompt The user's prompt text
PostToolUse tool_call tool name + input summary + result
PostToolUseFailure tool_failure tool name + input + error
Stop assistant_stop session boundary marker
SessionStart session_start source + model + cwd
SessionEnd session_end end reason
SubagentStart subagent_start agent type + prompt
SubagentStop subagent_stop agent type
TaskCreated task_created task title + description
TaskCompleted task_completed task title

Events to/from Neruva's own MCP (mcp__neruva__memory_*) are auto-skipped to prevent recording the recording.

Query later

curl -X POST https://api.neruva.io/v1/indexes/brain/text/query \
  -H "Api-Key: $NERUVA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "namespace": "main",
    "text": "what bash commands did I run?",
    "topK": 10,
    "filter": { "kind": { "$eq": "tool_call" }, "tool": { "$eq": "Bash" } }
  }'

Or via the Neruva MCP installed in another agent: memory_query_text.

Stacks with auto_record(Anthropic())

You can run both at once. The hook recorder captures Claude Code's tool calls + prompts + assistant turns; auto_record(Anthropic()) captures the LLM turns of any Python script you write that uses Anthropic SDK directly. They share the same namespace if you want.

Roadmap

  • v0.1: Anthropic Python (sync + async, non-streaming) ✅
  • v0.2: Claude Code hook recorder (neruva-record-hook) ✅
  • v0.3: Anthropic streaming + tool-use turn capture
  • v0.4: OpenAI Python
  • v0.5: Google Gemini Python
  • v0.6: TypeScript versions of all the above
  • v1.0: Stable API, security audit

Related

License

MIT — Clouthier Simulation Labs.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

neruva_record-0.2.0.tar.gz (13.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

neruva_record-0.2.0-py3-none-any.whl (12.4 kB view details)

Uploaded Python 3

File details

Details for the file neruva_record-0.2.0.tar.gz.

File metadata

  • Download URL: neruva_record-0.2.0.tar.gz
  • Upload date:
  • Size: 13.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for neruva_record-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b43e16b0ed1a61d6db3e2c94286103ff2280a2d05942923a3afcc2abde83c6ea
MD5 221089ca7489c719b1941eb09a87476d
BLAKE2b-256 02ac19f8f4510a4226b1a3427b580ba18e007dcd45fb38e4ac2d38d2310b7f9c

See more details on using hashes here.

File details

Details for the file neruva_record-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: neruva_record-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 12.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for neruva_record-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7dac0ada38b676d886a5b9b50dc4226cca5008f6a73f594b4dd76628732a27f2
MD5 60369b27fdd11fb02c8a193f1091a46e
BLAKE2b-256 dff2b16463df97eac705c724598f7fbc0a67478c5a95555320d3ea68460bdebe

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page