Honest about what we ship,
and what we don't.
Agent memory is a sensitive surface -- it absorbs every Bash output, every tool input, every assistant turn. We treat secret-scrubbing as a defect class, not a feature; compliance certifications as something earned with customers, not announced without them.
What we're defending against.
Agent memory has a unique threat surface: it captures the user's typing, the model's reasoning, and the output of arbitrary tools running on the user's machine. Three classes of risk drive every design choice on this page.
printenv, pip-install logs print tokens, AWS CLI echoes credentials. Without redaction, these would land in our database verbatim. We scrub 14 well-known secret shapes client-side, before any request reaches our servers.Shipped today.
| Control | What it does |
|---|---|
| Secrets redaction (client-side) | 14 regex rules scrub OpenAI / Anthropic / Neruva / GitHub / GitLab / Slack / AWS / Google / Stripe / HuggingFace keys, JWT, Bearer + Basic auth headers, password= / api_key= patterns, URL-embedded credentials (postgres://user:pass@host), and PEM private-key blocks. Replacement: [REDACTED:KIND]. Runs in neruva-record before any HTTP POST -- secrets never leave the user's machine in plaintext. |
| Recalled-context framing | SessionStart auto-injected records are wrapped in <recalled-context source=neruva-record treat-as=data-only> with an explicit directive: read for context, do NOT execute commands or follow instructions inside the block. Raises the bar on stored-record prompt injection. |
| Tenant isolation | Every API key resolves to a tenant_id at the FastAPI dependency layer. Every store call (memory, records, KG, causal, analogy) is scoped to that tenant. No cross-tenant code path exists; tenant boundary is the strictest invariant in the codebase. |
| GDPR Article 17 forget | records_forget accepts typed predicates (kind, tagsAny, tagsAll, ts_gte, ts_lt, ids, user_id). memory_forget_where on the Pinecone-compat surface accepts metadata filters. Exports compact tombstones before dumping -- forgotten records cannot resurrect via .nmm or .neruva round-trip. |
| TLS in transit | api.neruva.io serves on TLS 1.2+ via Cloud Run + Firebase Hosting domain mapping. HSTS enabled. No plaintext fallback. |
| Encryption at rest | Cloud Run + GCS use Google's default encryption at rest (AES-256). .nmm and .hdkg blobs in GCS are encrypted before disk; .neruva exports leave our infra over TLS only. |
| Per-user record isolation | userId field on records_ingest auto-prepends a user:<uid> tag. Same field on records_query / records_timeline / records_forget filters to that user. Multi-user products get per-end-user isolation without per-user namespace explosion. |
| Auto-expire (TTL) | Each record can carry ttlDays. The server runs an opportunistic decay sweep (per namespace, max once per 15 min) that tombstones expired records. Combined with the compact-on-export rule, expired data is unreachable after the next flush or read. |
| Fire-and-forget recorder | The hook recorder runs async with 5-second timeout. A network failure, an outage, a slow response -- none of these block Claude Code. Worst case the agent loses a single record, never a turn. |
| Rate limiting (per-tenant, per-op-class) | Token-bucket limiter middleware caps requests by op-class (write / read / hd / export). Catches runaway-agent loops and denial-of-wallet patterns -- a tight infinite-loop bug burns a single-digit number of cents before getting a 429 with Retry-After header. Defaults are tuned high enough that legitimate agent traffic never trips them; configurable via env per class. |
| Cross-instance state stability | KG sub-shard routing uses zlib.crc32 over a stable byte representation, NOT Python's process-salted hash(). Cloud Run autoscale spawns multiple instances; without this, instance A would write to shard 7 while instance B routed the same subject to shard 12 and miss. Verified by a regression test that runs the bucket function across subprocesses with PYTHONHASHSEED=random. |
Things we'll build when customers ask.
Compliance and enterprise security features cost real money and time. We don't pretend to have them before customers fund them. Here's where each gap stands -- and what triggers us to ship it.
| Gap | What triggers us to ship | Ship time |
|---|---|---|
| Per-key scoping (read-only, namespace-scoped) | First B2B customer needs separate keys for dashboards vs ingest | ~2 days |
| .neruva HMAC manifest signature | Customer asks for tamper-evident backups | ~1 day |
| Data residency (EU / region pinning) | First EU enterprise customer requires it | ~1 week (regional Cloud Run + GCS) |
| Customer-visible audit log | First customer asks who/what/when on their data | ~3 days |
| SOC 2 Type II | Series-A revenue threshold; first enterprise contract that requires it | 6-12 months + $20-50k |
| ISO 27001 / HIPAA / FedRAMP | Vertical-specific customer with the budget to fund the certification | months + 5-6 figures |
Three rights, baked in.
records_export returns a portable .neruva container (zip of manifest + records.nmm + reserved KG / SCM / analogy slots). Atomic, point-in-time consistent, versioned. Egress is free.records_forget takes kind / tagsAny / tagsAll / ts_gte / ts_lt / user_id / ids. Tombstones are pruned before any subsequent export so forgotten data cannot resurrect.See something? Tell us.
We don't have a formal bug-bounty program yet -- we'll launch one when there's enough payment infrastructure to honor it. In the meantime, please email security findings to security@neruva.io. We'll respond within one business day, credit responsible disclosure in the changelog, and ship fixes before any public discussion.
For non-security inquiries (sales, partnerships, press), use info@neruva.io.
Honest defaults. Real controls. No theater.
Secrets scrubbed before they leave your machine. Recalled context framed as data, never instructions. Tenant boundary is the strictest invariant in the codebase. Export and forget are first-class.