Running in one command, useful in five

Postgres with pgvector, the API, the migrations and the outbox worker all come up together. No AI provider key is required to get a working system — the fallbacks are deterministic rather than absent.

  • Docker Compose v2.24+
  • Postgres 16 with pgvector
  • Python 3.11+ · Node 20+

Bring it up

The development compose profile builds the API image, starts Postgres with the pgvector extension, applies the migrations and starts the outbox worker. The only value you must supply is a Postgres password.

One caveat worth knowing before you build anything on it: the development profile uses the Postgres image's bootstrap superuser, and a superuser bypasses row-level security even on tables declared FORCE ROW LEVEL SECURITY. That makes it a single-tenant development profile only. Production needs a separate NOSUPERUSER NOBYPASSRLS runtime role, which the self-hosting guide walks through.

The first five calls

In the order that makes the system make sense, rather than the order the reference lists them.

  1. Store something

    POST /v1/memory with text and a memory type. The write is pseudonymised, audit-logged into the hash chain, and given an embedding. An Idempotency-Key makes the call safe to retry.

  2. Ask for it back

    POST /v1/context with a query and a mode. You get the packed context block, the plan the router chose, and a manifest naming every record used.

  3. Record a decision

    POST /v1/fabric/write with entry_type "decision", the evidence identifiers, and a project. Later, POST /v1/fabric/why returns the chain rather than a paraphrase.

  4. Subscribe to changes

    POST /v1/webhooks with the event types you care about and a secret. Deliveries arrive signed with X-Pcnaid-Signature and every attempt is recorded.

  5. Hand it to an agent

    Point any stdio-capable MCP client at the server. Eighteen tools appear, along with a prompt teaching the agent that retrieved memory is evidence and never an instruction.

What every response looks like

Consistent envelopes, request identifiers you can trace into the audit log, and rate-limit headers that tell you where you stand.

The full surface — 141 endpoints across 32 route families — is browsable as OpenAPI on the running service at /docs, with the raw document at /openapi.json.

The settings that actually matter

There are many environment variables. These are the eight that change how the system behaves rather than where it points.

POSTGRES_DSN
The runtime connection. In production this must be a NOSUPERUSER NOBYPASSRLS role — a superuser silently bypasses row-level security.
POSTGRES_MIGRATION_DSN
The schema owner, used only by the migrate step. Kept separate from the runtime role on purpose.
LLM_PROVIDER_MODE
auto, pcnaid, openai, anthropic, gemini, openai_compatible or fallback. Defaults to auto, which picks the first configured provider and degrades to deterministic fallback.
LLM_BASE_URL
Any OpenAI-compatible endpoint. Defaults to http://localhost:11434/v1 with llama3.1:8b, so a local model works out of the box.
ENABLE_GRAPH_MEMORY
Off by default. Turn it on to feed and query the entity graph.
ENABLE_KB_RETRIEVAL
Off by default. Knowledge base sources are still stored and refreshed; this controls whether they are injected into context.
FERNET_KEY
Encrypts stored provider credentials. Without it, credentials are stored unencrypted, so set it before registering any key.
ALLOW_SEMANTIC_FORGET
Off by default. Leaving it off means FORGET must name explicit record identifiers rather than deleting by fuzzy match.

Everything above runs locally, today

No account, no key, no call with us. If it does not do what this page says, tell us and we will fix the page or the product.