Metadata-Version: 2.4
Name: neruva-record
Version: 0.6.3
Summary: Auto-record AI agent activity into Neruva. Two paths: (1) Claude Code hook installer — run `neruva-record-install` to capture every chat turn + tool call in every Claude Code session; (2) Anthropic Python SDK wrapper — wrap your client to auto-record messages.create() round-trips. Client-side secrets redaction (14 patterns: OpenAI/Anthropic/Neruva/GitHub/AWS/Stripe keys, JWT, BEARER_TOKEN, BASIC_AUTH, PRIVATE_KEY_PEM). Recalled-context prompt-injection guard. Cross-session, portable.
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"

# neruva-record

Auto-capture everything an AI agent does into [Neruva](https://neruva.io).
Two 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 |
| **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).

## 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: 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.

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

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