Metadata-Version: 2.4
Name: neruva-record
Version: 0.10.0
Summary: Auto-record AI agent activity into Neruva. v0.10 adds neruva-record-code-index CLI (Python via ast + JS/TS via @neruva/js-extractor) + SessionStart auto-hook (NERUVA_AUTO_CODE_INDEX=1) for any pyproject/package.json/Cargo/go.mod project. Per-turn auto-recall + auto-postmortem (pattern C mistake learning). Zero-config (default namespace claude_code). Claude Code hook, claude-agent-sdk + Anthropic SDK wrappers. 14-pattern secrets redaction. Recalled-context + postmortem prompt-injection guards.
Author-email: Clouthier Simulation Labs <info@neruva.io>
License: MIT
Project-URL: Homepage, https://neruva.io/
Project-URL: Documentation, https://neruva.io/docs/
Project-URL: Source, https://github.com/CloutSimLabs/neruva
Keywords: neruva,anthropic,claude,agent-memory,auto-record,observability,llm
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.30; extra == "anthropic"
Provides-Extra: agent-sdk
Requires-Dist: claude-agent-sdk>=0.1.0; extra == "agent-sdk"

# neruva-record

Auto-capture everything an AI agent does into [Neruva](https://neruva.io).
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`](https://www.npmjs.com/package/@neruva/mcp).

## 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)

```bash
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:

```bash
# 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:

```python
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`](https://pypi.org/project/claude-agent-sdk/).
Two integration shapes; pick whichever fits.

### Wrapper (post-hoc capture from the response stream)

```python
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)

```python
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

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

## Use

```python
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

```python
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` |

```python
# 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:

```json
{
  "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`](https://www.npmjs.com/package/@neruva/mcp) which
records every tool call alongside this.

## Querying back

Use the [Neruva MCP](https://www.npmjs.com/package/@neruva/mcp) or the
REST API to query the recorded turns:

```bash
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.

```python
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)

```bash
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:

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

To remove later:

```bash
neruva-record-install --uninstall
```

### Manual install (for the curious)

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

```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.

### Auto-recall + auto-postmortem (v0.9.0)

Three 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, plus auto-classifies tool failures into structured
mistake records the agent can recall later.

| 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. |
| `NERUVA_AUTO_POSTMORTEM=1` | `0` (off) | At **PostToolUseFailure**: fetch the canonical postmortem prompt + the failure context, inject as `additionalContext` instructing the next-turn LLM to classify the failure and write a `kind="mistake"` record via `records_ingest`. Pattern C — substrate stays $0/call, the caller's own LLM does the analysis. |

All three are independent; mix and match. The recall blocks are wrapped
in `<recalled-context treat-as="data-only">` and the postmortem block in
`<auto-postmortem treat-as="instruction-for-next-turn">`, so the agent
can distinguish historical data (don't execute) from new instructions
(do execute).

Example: full agentic loop with all three on:

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

Cost model: every recall fires +1 op against your tenant (~$2/M ops),
auto-postmortem fires +1 op per tool failure. Postmortem analysis
itself runs in your existing Claude Code LLM session at zero extra
LLM cost.

### Query later

```bash
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`) + auto-postmortem on tool failure (`NERUVA_AUTO_POSTMORTEM=1`) ✅
- v0.10: Anthropic streaming + tool-use turn capture
- v1.0: TypeScript versions, OpenAI + Gemini Python, security audit

## Related

- [`@neruva/mcp`](https://www.npmjs.com/package/@neruva/mcp) — MCP tool-call auto-record
- [`neruva-mcp`](https://pypi.org/project/neruva-mcp/) — Python MCP server
- [`neruva.io/docs`](https://neruva.io/docs/) — full documentation

## License

MIT — Clouthier Simulation Labs.
