
# Self-Hosting (Community Edition)

ContextNest Community Edition is a **self-hosted context governance server for AI
workflows**, part of the [PromptOwl](https://promptowl.ai) platform. It stores,
versions, and governs markdown-based context documents ("nests") and serves the
approved slice to AI agents over MCP or HTTP.

The server is a Node.js backend (the [Hono](https://hono.dev) framework) paired
with a React frontend, shipped as a single deployable. It runs on your own
laptop, a VM, or a container platform — your data stays on infrastructure you
control, while your PromptOwl account handles authentication entitlement and
license validation.

> **Commercial software.** Community Edition is proprietary, licensed by
> Promptowl LLC, and requires a (free) PromptOwl account. It is **not** open
> source. Redistribution and hosting-as-a-service are prohibited without a
> commercial agreement — contact `hoot@promptowl.ai`.

## Requirements

- **Node.js** 20.x or later
- A free **PromptOwl account** (<https://app.promptowl.ai/signup>) to obtain a
  Community License key (`pk_...`)
- **OS:** Windows, macOS, or Linux
- **Disk:** ~200 MB for the server, plus room for your nests

## Deploy

### npm / npx (quickest)

```bash
# Run the community server
npx @promptowl/contextnest-community

# Then open the UI
#   http://localhost:3838
# On first boot with no license it lands on the License Setup Page.
```

The server listens on `http://localhost:3838` by default. Without a valid
license it still boots and serves **reads**, but every write returns `503` until
you activate.

### Docker / CI / scripted deploys

Pass configuration as environment variables — set them in your shell, a `.env`
file, a Docker image, or your process manager. The simplest licensed boot:

```bash
PROMPTOWL_KEY=pk_... npx @promptowl/contextnest-community
```

For a built image the production entrypoint is `node dist/index.js` (or
`npm start`).

## Licensing at runtime

A Community License key (`pk_...`) is created for free from the PromptOwl
**Overview → Community License** menu. Install it one of two ways:

1. **Browser setup page** — start the server, open it with no license installed,
   and paste the `pk_...` key on the **License Setup Page**. It is validated
   against PromptOwl and persisted (see storage note below) — no restart needed.
2. **`PROMPTOWL_KEY` env var** — read at boot and validated on startup.

Runtime behaviour:

- **Unlicensed / setup mode** — reads work; every non-GET (write) request returns
  `503` until a valid key is installed.
- **Live revocation** — a long-poll watcher tracks license state against
  PromptOwl; a revoked key blocks writes within seconds and returns to setup
  mode, no restart required.
- **Admin identity follows the license** — the admin user is whichever PromptOwl
  account owns the installed key, resolved live. Transferring the license
  promotes the new owner and demotes the old one.

## Authentication modes

Pick one per instance with `AUTH_MODE`.

| Mode | Behaviour | Use when |
|---|---|---|
| `key` (default) | Every request needs `Authorization: Bearer cnst_...` (or a browser session cookie). Real user accounts, per-user API keys, rate-limited login. | Any multi-user or internet-facing deployment. |
| `open` | No auth — every request is the anonymous admin user; everyone effectively owns every anon-created nest. The server prints a loud startup warning. | Local single-user (`bind 127.0.0.1`), a trusted LAN, or behind a proxy that already authenticates. |

Do **not** use `open` mode on a publicly reachable port, for multiple isolated
users, or where you need audit trails (every write is attributed to "anonymous
admin"). See [Authentication & API Keys](https://nest.promptowl.ai/d/promptowl-documents/protocol/authentication-api-keys) for the
`cnst_` key model.

### Single sign-on (OIDC)

Community Edition supports generic **OpenID Connect** SSO against any
spec-compliant IdP — Microsoft Entra ID and Google are first-class presets, and
Okta / Keycloak work as standard issuers. Turn it on with `OIDC_ENABLED=true`
plus `OIDC_ISSUER`, `OIDC_CLIENT_ID`, and `OIDC_CLIENT_SECRET` (all three
required before the login button appears), or configure it live from
**Settings → Single sign-on**. Set `PUBLIC_BASE_URL` so the OIDC redirect URI is
derived from your canonical address rather than the incoming `Host` header. A
separate one-click PromptOwl SSO exists only on the official hosted deployment
(gated by `OFFICIAL_COMMUNITY_SSO_SECRET`, which stays unset on self-hosted).

## Storage backends

The governance/auth metadata (users, sessions, nests registry, stewards,
reviews, version index, comments, telemetry) lives in a relational database; the
actual document content and version history live on the filesystem under
`$DATA_ROOT/nests/`.

| Backend | Selected by | Notes |
|---|---|---|
| **SQLite** (default) | nothing — it's the default | Single file at `DATABASE_PATH` (defaults to `$DATA_ROOT/community.db`). Zero-config, ideal for a single box or local use. |
| **PostgreSQL / Cloud SQL** | `DB_DRIVER=postgres`, or setting `DATABASE_URL` / `CLOUD_SQL_CONNECTION_NAME` | For deployments where local disk isn't durable (e.g. Cloud Run). All horizontally-scaled instances share one consistent database. |

The server creates its schema automatically on first connect (idempotent); there
is no built-in SQLite→Postgres data migration — a new Postgres backend starts
empty.

> **Cloud Run durability warning.** Cloud SQL persists only the *metadata
> database*. Document content and version history live under `$DATA_ROOT/nests/`,
> which on Cloud Run is **ephemeral**. Put `$DATA_ROOT` (or `NEST_STORAGE_ROOT`)
> on durable shared storage — e.g. a GCS bucket mounted via Cloud Storage FUSE —
> or documents disappear on redeploy. On a GCS mount, set
> `DRIFT_SCAN_INTERVAL_MS=0` and run a single instance (GCS FUSE has no file
> locking).

Separating the vault from the DB: `NEST_STORAGE_ROOT` (default
`$DATA_ROOT/nests`) can point at a different volume (e.g. a GCS mount) while the
SQLite DB stays on `DATA_ROOT`. The app does **not** relocate existing files —
copy them before switching or nests appear empty.

## Key environment variables

The full reference lives in [REST API Reference](https://nest.promptowl.ai/d/promptowl-documents/protocol/rest-api-reference)'s
source (`CONFIGURATION.md`); the essentials:

| Var | Default | Purpose |
|---|---|---|
| `PORT` | `3838` | HTTP port the server listens on. |
| `DATA_ROOT` | `./data` (relative to cwd) | Root for the SQLite DB + nest vaults. Use an absolute path in production. |
| `AUTH_MODE` | `key` | `key` or `open`. |
| `PROMPTOWL_KEY` | _(empty)_ | Community License key (`pk_...`). Unlicensed instances serve reads only. Can also be set from the browser License Setup Page. |
| `NEST_STORAGE_ROOT` | `$DATA_ROOT/nests` | Where nest vault files live; override to store nests on a separate/GCS volume. |
| `DATABASE_PATH` | `$DATA_ROOT/community.db` | Explicit SQLite file location (SQLite backend only). |
| `DB_DRIVER` | `sqlite` | `sqlite` or `postgres`. Inferred `postgres` if `DATABASE_URL` / `CLOUD_SQL_CONNECTION_NAME` is set. |
| `DATABASE_URL` | _(empty)_ | Postgres TCP connection string, e.g. `postgres://user:pass@host:5432/db`. |
| `CLOUD_SQL_CONNECTION_NAME` | _(empty)_ | Cloud SQL instance name (`project:region:instance`); connects over the Auth Proxy unix socket. |
| `PUBLIC_BASE_URL` | _(empty)_ | This server's canonical external URL. Set it whenever OIDC is enabled or behind a reverse proxy. |
| `OIDC_ENABLED` | `false` | Turn on generic OIDC SSO (requires `OIDC_ISSUER` + `OIDC_CLIENT_ID` + `OIDC_CLIENT_SECRET`). |
| `CORS_ORIGINS` | `*` (open) / `http://localhost:5173,http://localhost:3838` (key) | Comma-separated allowlist. `*` is only safe in open mode. |
| `TELEMETRY_ENABLED` | `true` | Batched anonymized usage events to PromptOwl; set `false` to disable. |

Changing any env var requires a restart — they are read at boot. Settings you
change from the UI (sign-in gate, logo, base URL, feature flags, OIDC, connectors)
plus the installed license key persist in the database (`server_settings`),
which survives rebuilds and is shared across instances; the deploy environment
still overrides a UI change when its value for that key changes.

## Plugins (1.24+)

Nest Plugins connect outside sources — Google Drive, GitHub, transcripts, mail — to nests, raw or summarized, and add live search over those sources. Off by default. See [Plugins](https://nest.promptowl.ai/d/promptowl-documents/platform/plugins/plugins).

| Variable | Default | Purpose |
|---|---|---|
| `FEATURE_PLUGINS` | unset (off) | `true` enables the per-nest Plugins tab, `/nests/:id/plugins`, `/plugin-hooks/:token`, and `include_live` search. Also a superadmin toggle under Settings → Plugins. |
| `PLUGINS` | empty | Comma-separated allowlist of plugin packages to load: npm package names installed on the server (e.g. `@promptowl/contextnest-plugin-google-drive`) or absolute paths to an ESM module. Nothing outside this list ever loads. Editable live from Settings → Plugins. |
| `PLUGIN_MIN_INTERVAL_MINUTES` | `5` | Floor for a plugin's pull cadence. |

Install a plugin the way you would any dependency of the server (`npm install @promptowl/contextnest-plugin-google-drive` in the deploy, or bake it into the image), then name it in `PLUGINS`. Secrets a plugin needs are entered per nest and stored write-only in the nest's env store.

## Typical deployments

**Local dev / single user:**

```bash
AUTH_MODE=open DATA_ROOT=./my-data npm run dev
```

**Team / multi-user behind a reverse proxy:**

```bash
AUTH_MODE=key \
CORS_ORIGINS="https://team.example.com" \
DATA_ROOT=/var/lib/contextnest \
PROMPTOWL_KEY=pk_... \
npm start
```

Terminate TLS at the proxy, forward `X-Forwarded-For` / `X-Real-IP` (the rate
limiter reads them), and bind the server to `127.0.0.1` so only the proxy can
reach it. For a hosted/SaaS-style rollout, run N instances behind a load balancer
on the PostgreSQL / Cloud SQL backend with durable shared storage for the vault.

## See also

- [REST API Reference](https://nest.promptowl.ai/d/promptowl-documents/protocol/rest-api-reference) — the hosted-nest HTTP surface
- [Authentication & API Keys](https://nest.promptowl.ai/d/promptowl-documents/protocol/authentication-api-keys) — `cnst_` keys vs. the `pk_` license
- [Hosted Nest](https://nest.promptowl.ai/d/promptowl-documents/platform/hosted-nest/hosted-nest) — what the server gives you over a local vault

## Sources

- `README.md` (Community server repo) — what it is, quickstart, license setup, requirements, feature matrix.
- `CONFIGURATION.md` (Community server repo) — auth modes, full env var reference, database backends, Cloud Run notes, typical deployments.
