Skip to content

How to choose your storage backend

Arun Soman edited this page Aug 31, 2026 · 1 revision

How-to: choose your storage backend

One rule, every front-end (cie.config.resolve_backend; shipped v0.1.3). Default path works with zero decisions; the explicit knob exists for when you care.

The rule (first hit wins)

  1. explicit --backend {auto,embedded,neo4j}
  2. CIE_BACKEND env naming embedded/neo4j (a stray value falls through to auto — never fatal)
  3. the --embedded alias (every entry cie init ever wrote keeps working)
  4. auto: serve <root>/.cie/graph.db when it exists, else Neo4j
cie-mcp /path/to/project                    # auto: serves your index
cie-mcp /path/to/project --backend neo4j    # explicit, always honored
CIE_BACKEND=embedded                          # one env var, CLI + server

The MCP server states its choice on stderr at startup:

cie-mcp: backend=embedded storage=/path/.cie/graph.db policy=readonly project=- transport=stdio

stdout stays byte-clean (it is the JSON-RPC channel).

When Neo4j?

Embedded SQLite is the zero-config default and fine for one repo. Switch when you want a team-shared graph, many projects in one graph (--project namespaces), or the HTTP tool-mount (Neo4j today) — see run the Neo4j team mode.

Selection is orthogonal to configuration: however you selected Neo4j, it is configured by NEO4J_URI/NEO4J_USERNAME/NEO4J_PASSWORD (or legacy CIE_NEO4J_* overrides, or --neo4j-* flags).

Front-end matrix

Front-end Selection
cie query commands --backend / CIE_BACKEND / auto
cie-mcp same + --embedded alias; stderr states the choice
cie index / cie load purpose-pinned (embedded / Neo4j)
HTTP tool-mount (routes.py) Neo4j today — documented, not claimed otherwise

From the README (migrated, verified at v0.1.4)

Storage backends & config (config.py, factory.py)

Choosing storage — one rule, every front-end (motto: least friction to users and their existing infrastructure). You never have to choose for the default path to work; one explicit knob exists for when you care, and it's the same everywhere:

Front-end How to select
cie CLI (query commands) --backend {auto,embedded,neo4j} (also rides CIE_BACKEND env); default auto
cie-mcp (MCP server) same --backend choices + CIE_BACKEND; --embedded stays a permanent alias (every entry cie init ever wrote keeps working)
cie-mcp auto (no flags) serves <root>/.cie/graph.db when it exists, else Neo4j — the quickstart contract, and the choice is stated on stderr at startup (backend=… storage=…), never silent
cie index / cie load / watch / serve purpose-pinned: index → embedded SQLite; load/watch/serve/bootstrap → Neo4j (they say so honestly if you ask for embedded)
HTTP tool-mount (cie/routes.py) Neo4j today — the forge/CI path; embedded-over-HTTP is not claimed

Resolution order (first hit wins): explicit --backend naming embedded/neo4j › CIE_BACKEND naming one (a stray value falls through, never crashes a run) › --embedded alias › auto (graph file exists?). Selection is orthogonal to configuration: Neo4j connection settings come from NEO4J_URI/NEO4J_USERNAME/NEO4J_PASSWORD (or legacy CIE_NEO4J_* overrides, or --neo4j-* on cie-mcp) however you selected it. Auto means an indexed project just serves — no Neo4j running, no decision forced; a team on Neo4j sets CIE_BACKEND=neo4j once and every front-end obeys.

  • Neo4jConfig.from_env() — reads NEO4J_* (or legacy CIE_NEO4J_* override) plus per-operation timeouts (CIE_NEO4J_QUERY_TIMEOUT_S, ..._WRITE_TIMEOUT_S, ..._SCHEMA_TIMEOUT_S). Driver-level bounds alone don't stop a lock-wait hang; cie.timeouts enforces independent wall-clock budgets around each query round trip.
  • CieConfig — one explicit bootstrap object for an external caller (project root, project name, Neo4j config, allowed root, file-size ceiling, language adapters). No "disable the jail" toggle — the file tools jail unconditionally (cie.tools.view._jail).
  • factory.py builds ToolService three ways: build_tool_service (Neo4j, per-project cached engines/task-repos sharing one driver), build_tool_service_from_config (one-call, no env vars), and build_tool_service_embedded (SQLite graph + EmbeddedTaskRepository by default, NullTaskRepository opt-in via task_tracking=False).

Clone this wiki locally