Skip to main content

Auto-record + auto-pilot for Claude Code, Cursor, and other agent harnesses backed by Neruva memory substrate. v0.15 ships a warm daemon with TTL cache: cache-hit p95 ~80ms (faster than Mem0). Pair with @neruva/mcp 0.23+ for the native Rust hook binary. AUTO-PILOT: KG auto-extract on ingest, 18-pattern intent router, reflective self-curation. Plus 8-language code-graph, per-turn recall, secrets redaction.

Project description

neruva-record

Auto-capture everything an AI agent does into Neruva. Three install paths -- pick whichever fits your runtime.

Path Install Captures
Claude Code hook (recommended for developers) pip install neruva-record && neruva-record-install Every chat turn + every tool call in every Claude Code session, automatically
claude-agent-sdk (Python autonomous agents) pip install "neruva-record[agent-sdk]" then wrap or use make_hooks() Every tool_use / tool_result / user_prompt / assistant_turn
Anthropic SDK wrapper (for Python apps) pip install neruva-record anthropic then wrap your client Every messages.create() round-trip

Both paths write to the same Records substrate. Both include:

  • Client-side secrets redaction -- 14 patterns (OpenAI/Anthropic/Neruva/GitHub/AWS/Stripe API keys, JWT, BEARER_TOKEN, BASIC_AUTH, PASSWORD_FIELD, URL_CREDENTIAL, PRIVATE_KEY_PEM)
  • Recalled-context prompt-injection guard -- wraps auto-recalled records in <recalled-context treat-as="data-only"> so the model can't be hijacked by something an earlier session wrote
  • Fire-and-forget POSTs -- never blocks or breaks your call

Pairs with @neruva/mcp.

What's new in 0.11.0 — Auto-pilot (3 layers, all opt-in / opt-out via env)

The agent now uses the FULL substrate without prompting. Three layers, all pattern-C (substrate emits prompts, the caller LLM runs them in its existing turn — substrate stays $0/call):

Env var Layer What it does Default
NERUVA_AUTO_EXTRACT 1 — Auto-extract on ingest After each records_ingest, the PostToolUse hook injects the canonical entity-extraction prompt + just-ingested text. Caller LLM extracts triples in-turn; SDK pushes facts to <namespace>-auto-kg. KG auto-builds without manual hd_kg_add_facts. ON
NERUVA_AUTO_ROUTE 2 — Intent router On every UserPromptSubmit, the hook fetches the canonical 18-pattern intent-classification prompt from substrate and injects it. Caller LLM classifies + uses the suggested cognitive tool (counterfactual / analogy / theory-of-mind / rule induction / planning / etc.) before responding. OFF (opt-in v1)
NERUVA_AUTO_REFLECT 3 — Self-curate On every UserPromptSubmit, the hook pulls the last ~10 turns + fetches the reflection prompt. Caller LLM extracts durable decisions / facts / mistakes / open_questions and writes them via records_ingest + hd_kg_add_facts. Memory writes itself. OFF (opt-in v1)

To enable a layer, set the env var in ~/.claude/settings.json (or your shell) to any truthy value (1, on, true). Unset or 0 disables. Auto-extract is on by default because it's low-latency and high-value; the other two are opt-in until perf is calibrated against real workloads.

The substrate side ships agent_route_intent_prompt and agent_reflect_prompt as MCP tools — you can also call them manually via the agent for one-off classification or reflection at session-end pauses.

What's new in the substrate (v0.5.7, May 2026)

Everything neruva-record writes is queryable through the substrate's expanded surface. Existing recording code keeps working; you just have new things you can ASK of the captured data.

  • Deterministic replay — every query is bit-identical across reruns from the same seed. Replay any past Claude Code session for audit or debugging.
  • Typed-shape context — pull structured JSON from your recorded sessions. {question, shape: {field: type}} → typed result without an LLM at query time. E.g. ask "what's the latest deployment status?" and get back {status: str, version: str, region: str}.
  • Tenant-specific PII rules — register your team's custom ID formats (employee codes, patient codes, order IDs) from 3-5 examples. The substrate redacts them automatically on top of the 14 built-in client-side patterns this SDK already covers.
  • Depth-unlimited nested-belief tracking — useful if you record multi-agent conversations and need to reason about who knew what when.
  • Counterfactual rollouts — "what if we had answered differently at step k?"
  • Continual K-gram learning — provable no-forgetting on token streams; useful for long-running session corpora.

Path A: Claude Code hook (30 seconds)

pip install neruva-record
export NERUVA_API_KEY=nv_...        # https://app.neruva.io
neruva-record-install               # installs hook into ~/.claude/settings.json

That's it. Every Claude Code session you run from now on is captured into namespace claude_code (default). Recall via:

# In any Claude Code session, ask:
"What did I work on yesterday related to LangChain?"
# Claude calls records_query under the hood via the @neruva/mcp tool.

Or query directly:

import httpx, os
r = httpx.post("https://api.neruva.io/v1/records/claude_code/query",
               headers={"Api-Key": os.environ["NERUVA_API_KEY"]},
               json={"text": "LangChain", "topK": 10})
for hit in r.json()["matches"]:
    print(hit["metadata"]["text"][:200])

Path B: claude-agent-sdk

Drop-in observability for any Python agent built on Anthropic's claude-agent-sdk. Two integration shapes; pick whichever fits.

Wrapper (post-hoc capture from the response stream)

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from neruva_record.agent_sdk import auto_record

async def main():
    opts = ClaudeAgentOptions(model="claude-haiku-4-5-20251001")
    client = auto_record(
        ClaudeSDKClient(options=opts),
        namespace="dev_agent",   # one per agent
        ttl_days=30,             # optional
    )
    await client.connect()
    try:
        await client.query("Help me debug this stacktrace...")
        async for msg in client.receive_response():
            pass
    finally:
        await client.disconnect()

asyncio.run(main())

Hooks bundle (synchronous capture at event boundaries)

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from neruva_record.agent_sdk_hooks import make_hooks

opts = ClaudeAgentOptions(
    model="claude-haiku-4-5-20251001",
    hooks=make_hooks(namespace="dev_agent", ttl_days=30),
)
client = ClaudeSDKClient(options=opts)

Either path captures: user_prompt, tool_use, tool_result, tool_failure, assistant_turn, subagent_start/stop, assistant_stop. Calls to the substrate's own mcp__neruva__* tools are auto-skipped (recursion firewall). Pick the wrapper for plain observability; pick hooks when you also want PreToolUse permission gates in the same callback set.

Path C: Anthropic SDK wrapper

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+, one-command install in 0.3.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 text response, every subagent, every task — into one Neruva namespace. Zero code change in your agent.

One-command install (recommended)

pip install neruva-record
neruva-record-install

That's it. The installer:

  1. Backs up ~/.claude/settings.json with a timestamp
  2. Merges in our 10 hook entries (preserving any existing user hooks)
  3. Sets NERUVA_API_KEY + NERUVA_AUTO_RECORD in the env block
  4. Runs claude mcp add neruva to register the MCP so your agent can also call mcp__neruva__* tools directly (skipped if the claude CLI isn't on PATH, or pass --no-mcp to skip explicitly)

Then restart Claude Code.

Non-interactive:

NERUVA_API_KEY=nv_... neruva-record-install --yes
# or
neruva-record-install --api-key nv_... --namespace research-bot --ttl 7 --yes

To remove later:

neruva-record-install --uninstall

Manual install (for the curious)

If you'd rather edit ~/.claude/settings.json yourself:

{
  "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.

Auto-recall (v0.9+)

Two opt-in env vars turn the recorder into a two-way bridge: it writes everything it sees AND injects relevant memory back into the agent's next turn.

Env var Default What it does
NERUVA_AUTO_RECALL=N 0 (off) At SessionStart: fetch the last N records via /timeline and inject them as additionalContext. Agent boots with chronological prior context. Best for N=10-30.
NERUVA_PER_TURN_RECALL=N 0 (off) At UserPromptSubmit: fire agent_recall semantically against the user's prompt, return top-N records, inject as additionalContext. Agent gets just-in-time relevant memory each turn. Best for N=5-10. Adds ~50–100 ms RTT per turn.

Both are independent; mix and match. The recall blocks are wrapped in <recalled-context treat-as="data-only"> so the agent treats them as historical data, not new instructions.

Example: full agentic loop with both on:

{
  "env": {
    "NERUVA_API_KEY": "nv_...",
    "NERUVA_AUTO_RECORD": "brain/main:30",
    "NERUVA_AUTO_RECALL": "20",
    "NERUVA_PER_TURN_RECALL": "8"
  }
}

Cost model: every recall fires +1 op against your tenant (~$2/M ops).

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.6: Secrets redaction (14 patterns) + recalled-context injection guard ✅
  • v0.8: SessionStart auto-recall (NERUVA_AUTO_RECALL=N) + secrets redaction (14 patterns) ✅
  • v0.9: Per-turn auto-recall (NERUVA_PER_TURN_RECALL=N) ✅
  • v0.10: Anthropic streaming + tool-use turn capture
  • v1.0: TypeScript versions, OpenAI + Gemini Python, 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.15.1.tar.gz (66.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.15.1-py3-none-any.whl (67.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: neruva_record-0.15.1.tar.gz
  • Upload date:
  • Size: 66.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.15.1.tar.gz
Algorithm Hash digest
SHA256 38cd87e73d2b111b7daabf4f4e09887473047656e44462fe149b913f90657459
MD5 65f974c8be476fdc569d2ec285991bd5
BLAKE2b-256 7951ed9884a38309f51dd3fb2437dd860127b4b374c7cadf5dec8aea775d2ddc

See more details on using hashes here.

File details

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

File metadata

  • Download URL: neruva_record-0.15.1-py3-none-any.whl
  • Upload date:
  • Size: 67.9 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.15.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bb3f1fb29d1f2c6a88bda6e2fcc793775e10980e9edbd2d02a3df4213b8bf18d
MD5 8ed484eea6fcebfd03d02cb4a6e11c33
BLAKE2b-256 7428496202a36066bc3ea3eb01f023557441d08c1a015797792f82bba67024ca

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