---
name: namidb-guide
description: |
  Use when the user is working with NamiDB, the cloud-native graph
  database whose state lives in an S3-compatible bucket. Triggers on
  Cypher queries (MATCH, CREATE, MERGE, RETURN), `tg.Client(...)` calls
  in Python, `namidb::storage::parse_uri` in Rust, the `namidb-server`
  HTTP daemon, `/v0/cypher` endpoint calls, NamiDB URI schemes
  (`memory://`, `file://`, `s3://`, `gs://`, `az://`), `NAMIDB_*`
  environment variables, manifest CAS, single-writer-per-namespace
  fencing, columnar SST format, factorized execution, and LDBC SNB
  Interactive (IC01–IC12) workloads.
when_to_use: |
  Also fire when the user troubleshoots a NamiDB connection
  ("PreconditionFailed", "epoch fenced", "manifest CAS"), tunes the
  cost-based optimizer or caches (`NAMIDB_ADJACENCY`, `NAMIDB_SST_CACHE`,
  `NAMIDB_FACTORIZE`), runs the bench harness, or migrates from
  Kùzu / Neo4j to NamiDB.
paths:
  - "**/*.cypher"
  - "**/*.cql"
  - "**/*.py"
  - "**/*.rs"
  - "**/Cargo.toml"
  - "**/pyproject.toml"
  - "**/docker-compose.y*ml"
---

# NamiDB Guide

You are assisting a developer working with **NamiDB** — a cloud-native
graph database (Rust, BSL 1.1) that stores its state as plain objects
in an S3-compatible bucket. Three deployments share one engine:

- **Embedded** library (Python `pip install namidb`, Rust `cargo add namidb`)
- **`namidb-server`** HTTP daemon (REST: `/v0/cypher`, bearer-token auth)
- **NamiDB Cloud** (managed multi-tenant SaaS, closed beta)

The engine speaks a **strict subset of Cypher / GQL (ISO/IEC
39075:2024) + openCypher 9**. It targets LDBC SNB Interactive
Complex Read queries IC01–IC12.

## Mental model (memorize)

1. **The bucket is the database.** No control plane. No Raft. No
   etcd. Coordination is `If-Match` / `If-None-Match` conditional
   writes on a `manifest.json` object per namespace.
2. **Namespaces are folders.** Multi-tenancy = one namespace per
   tenant. URI carries the namespace: `s3://bucket/prefix?ns=tenant`.
3. **Single-writer per namespace** (enforced via epoch fencing on
   manifest CAS). Many readers are fine. Two writers race → loser
   gets `412 Precondition Failed`, re-reads, retries.
4. **Cypher writes are durable on return.** `CREATE`/`MERGE`/`SET`/
   `DELETE` commit (WAL append + manifest CAS) before `cypher()`
   returns. Call `flush()` periodically to push memtable → L0 SSTs.
5. **Six backends**: `memory://` (test only), `file://` (CAS via
   `flock` + atomic rename), `s3://` (AWS / R2 / MinIO / Tigris /
   LocalStack — anything S3-compatible), `gs://` (GCS), `az://`
   (Azure Blob). Same Cypher, same APIs everywhere.

## What to do when invoked

Always start by figuring out which surface the user is on:

| Signal in user's code/question | Surface |
|---|---|
| `import namidb as tg` / `tg.Client(...)` | Python SDK |
| `use namidb::` / `parse_uri(...)` / `WriterSession` | Rust embedded |
| `namidb run`, `namidb explain`, `namidb parse` | CLI |
| `POST /v0/cypher`, bearer token, `namidb-server` | HTTP daemon |
| `s3://...?ns=...&region=...` URI grammar | Operations / config |
| `MATCH`, `CREATE`, `MERGE`, `RETURN` in a string | Cypher subset |

Then load the matching reference file (only when needed — they're
heavier and cost context):

- **[references/cypher-subset.md](references/cypher-subset.md)** —
  what Cypher works, what doesn't (esp. `_id` vs `id` since v0.3),
  function reference, IC01–IC12 templates
- **[references/uris.md](references/uris.md)** — full URI grammar
  per backend, env var matrix, IAM minimums, MinIO/R2/LocalStack
  recipes
- **[references/sdks.md](references/sdks.md)** — Python sync + async,
  Rust embedded, CLI, HTTP REST mapping (Cypher ↔ JSON types)
- **[examples/queries.md](examples/queries.md)** — copy-pasteable
  Cypher snippets (single-node CRUD, bulk inserts, IC01-shaped
  queries, EXPLAIN VERBOSE)

## Top-5 patterns

These show up constantly. Memorize them so you can answer without
loading the reference files.

### 1. Open a namespace

```python
import namidb as tg
client = tg.Client("s3://my-bucket/data?ns=prod&region=us-east-1")
```

```rust
use namidb::storage::{parse_uri, WriterSession};
let (store, paths) = parse_uri("s3://my-bucket?ns=prod&region=us-east-1")?;
let mut writer = WriterSession::open(store, paths).await?;
```

### 2. Write Cypher (durable on return)

```python
client.cypher("CREATE (a:Person {name: 'Alice', age: 30})")
client.cypher("""
  MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
  CREATE (a)-[:KNOWS {since: 2020}]->(b)
""")
```

### 3. Address the internal NodeId via `_id` (NOT `id`)

```cypher
-- v0.3 breaking change: `id` is now a user property
MATCH (n:Person {_id: $uuid}) RETURN n
RETURN id(n)                -- function form
RETURN n._id                -- accessor form
```

Old `{id: $uuid}` semantics now refer to a user-defined `id` property,
**not** the internal NodeId. Flag this when migrating from v0.2 code.

### 4. Bulk ingest with `merge_nodes` / `merge_edges` (Python)

```python
client.merge_nodes("Person", [
    {"id": str(uuid.uuid4()), "name": f"p{i}"} for i in range(10_000)
])
client.merge_edges("KNOWS", [
    {"src": uuid_a, "dst": uuid_b, "since": 2020}
])
client.commit()      # WAL + manifest CAS
client.flush()       # memtable -> L0 SSTs
```

These amortize one mutex+runtime hop across thousands of rows. **Always
prefer this over per-row `CREATE` Cypher for ingestion.**

### 5. HTTP daemon

```bash
namidb-server \
  --store 's3://my-bucket?ns=prod&region=us-east-1' \
  --listen 0.0.0.0:8080 \
  --auth-token "$NAMIDB_AUTH_TOKEN"

curl -X POST http://localhost:8080/v0/cypher \
  -H "Authorization: Bearer $NAMIDB_AUTH_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"query": "MATCH (p:Person) RETURN count(*) AS n"}'
```

## Common pitfalls — flag these proactively

- ❌ Using `{id: $uuid}` to refer to the internal NodeId (broken
  since v0.3 — use `{_id: $uuid}` or `id(n)`).
- ❌ Running two writers against the same namespace expecting both to
  commit. Only one wins per epoch; the other gets `412`.
- ❌ Pointing a `file://` URI at NFS or EFS. NFS `flock` semantics are
  not strict enough — `file://` requires a local POSIX filesystem.
- ❌ Forgetting `flush()` after a long write burst — memtable fills,
  read latency suffers, restart re-reads the WAL.
- ❌ Booting `namidb-server` without `--auth-token` in production —
  the server warns loudly but doesn't refuse.
- ❌ Running NamiDB on AWS while pointing at an out-of-region bucket
  for hot reads. Move daemon to the same region.
- ❌ Unbounded variable-length paths (`-[*]->`) — not in scope.
  Always bound: `-[*1..N]->`.

## Configuration cheat sheet

| Env var | Default | Purpose |
|---|---|---|
| `NAMIDB_ADJACENCY` | on | CSR adjacency cache (RFC-018) |
| `NAMIDB_NODE_CACHE` | on | NodeView lookup cache (RFC-019) |
| `NAMIDB_SST_CACHE` | on | SST body + edge prop streams (RFC-020) |
| `NAMIDB_FACTORIZE` | off | Factorized exec for path-heavy queries (RFC-017) |
| `NAMIDB_PROFILE_DUMP` | off | Per-stage timing to stderr |
| `NAMIDB_STORE` | — | Server: URI to open |
| `NAMIDB_LISTEN` | `0.0.0.0:8080` | Server: bind addr |
| `NAMIDB_AUTH_TOKEN` | unset (warn) | Server: bearer token |
| `NAMIDB_FLUSH_INTERVAL` | `30s` | Server: memtable → L0 cadence |

Storage credentials use standard provider chains: `AWS_*` for S3/R2,
`GOOGLE_APPLICATION_CREDENTIALS` for GCS, `AZURE_STORAGE_*` for Azure.
IAM roles on EC2/EKS/Lambda work transparently.

## Authoritative references (online)

- **Engine repo**: https://github.com/namidb/namidb
- **Full docs**: https://docs.namidb.com (EN + ES)
- **Machine-readable digest**: https://docs.namidb.com/llms-full.txt
- **18 design RFCs**: https://docs.namidb.com/en/internals/rfcs

When the answer needs more depth than this file provides, prefer
loading one of the local reference files in this skill before pulling
from the web.

## Style for your responses

- Be precise about which surface (Python / Rust / CLI / HTTP) the
  user is on. Don't mix idioms.
- Cypher snippets: use the v0.3 conventions (`_id`, no unbounded
  paths, parameters as `$name`).
- For ingestion: recommend `merge_nodes`/`merge_edges` over per-row
  `CREATE` Cypher unless the user has a specific reason.
- For multi-tenancy: recommend one namespace per tenant (`?ns=`).
- For self-hosting: point at the Docker Compose recipe at
  https://docs.namidb.com/en/operations/self-host-docker-compose.
- License questions: BSL 1.1, auto-converts to Apache 2.0 after 3
  years per release. Free for any non-competing-SaaS use.
