The same system, on your own hardware

Self-hosting is not a reduced edition. It is every layer, every endpoint and every governance control, without quotas — in exchange for running a stateful service properly.

  • MIT licence, full permissive grant
  • Seven compose services
  • Postgres 16 with pgvector

What the licence actually permits

Memory OS is released under the MIT licence — a full permissive grant. There is no Commons Clause, no Business Source Licence and no open-core carve-out where the useful half is withheld. You may run it commercially, modify it and deploy it for your own customers.

The source is not on a public host today. If you want to self-host, write to support@pcnaid.com and we will arrange access. Publishing it openly is a decision we have not yet taken, and we would rather say that than imply a download link exists.

What you take on

  • A Postgres 16 instance with pgvector, and its backups
  • TLS, DNS and whatever sits in front of Caddy
  • Provider keys, if you want model-backed summarisation
  • Monitoring, and someone who notices when it breaks

What you do not take on: licence fees, seat counts, quota ceilings or a vendor deciding your retention policy.

Seven services, one compose file

The production profile. Nothing here is a managed service you have to buy.

ServiceImageWhat it does
postgres pgvector/pgvector:pg16 The canonical store. Embeddings via pgvector, full-text via tsvector and GIN, tenant isolation via forced row-level security.
falkordb falkordb/falkordb:latest Graph memory in production, password-protected. Optional — graph memory is off by default and NetworkX serves local use.
migrate application image Applies migrations as the schema owner, then exits. Runs with a different Postgres role from the API.
backend application image The FastAPI service and the operator dashboard at /ui/.
worker application image Drains the transactional outbox: graph upserts, fact extraction, knowledge-base refreshes, tenant exports and email.
backup application image Scheduled logical backups written outside the container volume.
caddy caddy:2 The sole public ingress. Terminates TLS via ACME and sets HSTS, CSP, frame, referrer and content-type headers.
Caddy is the only service that should be reachable from the public internet. Everything else talks over the compose network.

The one thing people get wrong

Row-level security is the floor this whole system stands on, and a Postgres superuser walks straight through it — even on tables declared FORCE ROW LEVEL SECURITY. If the API connects as a superuser, tenant isolation is decorative.

So production splits the roles. The migration role owns the schema and is used only by the migrate service. The runtime role is NOSUPERUSER NOBYPASSRLS, owns nothing, and is the only role the API and worker ever use.

Verify it rather than assume it. The deployment notes give the exact query, and are blunt about the result: treat anything other than the expected answer as a deployment-blocking security failure. Our own CI asserts the same property on every run.

How tenant isolation is enforced

Before you call it production

Eleven things worth confirming, most of which are a single environment variable away from being wrong.

  • Runtime role is NOSUPERUSER and NOBYPASSRLS, and is not the schema owner.
  • POSTGRES_MIGRATION_DSN is set separately and used only by the migrate service.
  • FERNET_KEY is set before any provider credential is registered.
  • AUTH_ENABLED is true and AUTH_LEGACY_FALLBACK is false.
  • REQUIRE_TENANT_ID is true, so a request without a tenant claim is refused.
  • QUOTA_ENFORCEMENT_ENABLED is set according to whether you meter.
  • ALLOW_SEMANTIC_FORGET remains false.
  • SYSTEM_CONTROL_ENABLED remains false unless you deliberately want remote compose control.
  • CORS_ORIGINS is an explicit allowlist, never a wildcard.
  • ALERT_RECEIVER_TOKEN is set if you route alerts into the receiver.
  • A restore has actually been rehearsed, and the restore time and data-loss window are written down.

Backups are python scripts/backup.py, restores are python scripts/restore.py into a staging database followed by migrations, the row-level-security tests and a smoke query. A backup you have never restored is a hypothesis, not a backup.

Want the source?

Write to us and we will arrange access. It is MIT licensed — there is no negotiation, just a link we have not made public yet.