Self-Hosted Installation
Runtime is MIT. These are the steps for standing up Vocion on your own infrastructure — local dev, a single VPS, or a Kubernetes cluster. Same codebase, same data model, same MCP surface as Vocion Cloud.
If you'd rather we run it for you, see Vocion Cloud.
Install topology
Vocion is layered. You'll touch up to four kinds of repos:
@vocion/core ─────► framework + dashboard + Postgres schema (this repo)
@vocion/sdk ──────► plugin contract (npm package)
@vocion/plugin-* ─► plugins, one per repo (npm packages)
vocion-starter ───► forkable example install (separate repo)
<client>-vocion ──► your production install (you own this)
For local dev (this guide), you only need core + whatever plugins you want. Full layering doc: repo-architecture.md.
Requirements
| Minimum | Recommended | |
|---|---|---|
| Node.js | 20.x | 22.x LTS |
| Postgres | 16 | 16 or 17 |
| Docker | optional | recommended (Postgres + retrieval stack) |
| Memory | 2 GB | 8 GB+ |
| Disk | 5 GB | depends on document volume — plan ~1 GB per 100k indexed chunks |
| OS | macOS, Linux, WSL2 | Linux (for production) |
You'll also need API keys for at least one LLM provider — OpenAI or Anthropic is enough to start.
Quick start (local dev)
# 1. Clone + install
git clone https://github.com/metacto/context-stack.git
cd context-stack
npm install
# 2. Configure env
cp .env.example .env.local
# Edit .env.local — at minimum set:
# DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:5432/vocion
# AUTH_SECRET=... # generate with: openssl rand -base64 32
# OPENAI_API_KEY=sk-...
# 3. Start Postgres
docker compose up -d postgres
# 4. Apply schema + reference context
npm run db:migrate
npm run workspace:apply
# 5. Run dev server
npm run dev:next
# → http://localhost:3000
That's the whole thing. Sign in with email + password (auth.js is the default — no external auth service), land on the dashboard, poke around.
Environment variables
Full list lives in .env.example. The essential ones:
Required
| Var | Purpose |
|---|---|
DATABASE_URL | Postgres connection string |
AUTH_SECRET | Signing secret for auth.js sessions. Generate with openssl rand -base64 32 |
OPENAI_API_KEY | At least one LLM provider. See "LLM providers" below for alternatives |
Recommended
| Var | Purpose |
|---|---|
ANTHROPIC_API_KEY | Enables skills with provider: anthropic |
LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY | LLM observability |
VOCION_ORG_ID | Default org for MCP server (otherwise uses the signed-in session) |
WORKSPACE_PATH | Path to workspace directory. Default workspace/metacto |
VOCION_PLUGINS | Comma-separated plugin specifiers — npm packages or local paths |
Optional
| Var | Default | Purpose |
|---|---|---|
WORKSPACE_AUTO_COMMIT | true | MCP workspace_write_* commits to git |
WORKSPACE_AUTO_APPLY | true | MCP workspace_write_* applies to DB after write |
VOCION_AUTH_PROVIDER | local | Auth backend. local (default → auth.js, email + password) or clerk (hosted/cloud only) |
CLERK_SECRET_KEY / NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | — | Only used when VOCION_AUTH_PROVIDER=clerk |
STRIPE_SECRET_KEY | — | Billing (skip if not using) |
SENTRY_DSN | — | Error monitoring |
BETTER_STACK_SOURCE_TOKEN | — | Log aggregation |
Branding (white-label)
The sidebar brand is a white-label slot. All three are NEXT_PUBLIC_*, so they're inlined at build time — set them as Docker --build-args (not runtime env), or in .env.local before next build.
| Var | Default | Purpose |
|---|---|---|
NEXT_PUBLIC_BRAND_NAME | Vocion | Wordmark text next to the mark |
NEXT_PUBLIC_BRAND_TAGLINE | — | Optional subhead under the wordmark (e.g. agents by Vocion) |
NEXT_PUBLIC_BRAND_MARK | — | Optional glyph image src — a path or a data: URI. When set, it replaces the built-in Vocion mark, so your build carries no third-party art. |
NEXT_PUBLIC_BRAND_LOCKUP | — | Full lockup image (mark + wordmark as one asset). When set it replaces both the glyph and the wordmark text — only the tagline renders beneath it. Takes precedence over BRAND_MARK/BRAND_NAME. |
docker build \
--build-arg NEXT_PUBLIC_BRAND_NAME="Acme" \
--build-arg NEXT_PUBLIC_BRAND_TAGLINE="agents by Vocion" \
--build-arg NEXT_PUBLIC_BRAND_MARK="data:image/svg+xml;base64,$(base64 -w0 acme-mark.svg)" \
-f packages/core/Dockerfile .
Database setup
Managed Postgres
Any Postgres 16+ works — Neon, Supabase, RDS, Cloud SQL. Set DATABASE_URL and run:
npm run db:migrate
Self-hosted Postgres
The repo ships a docker-compose.yml for local dev:
docker compose up -d postgres
For production, run Postgres separately (Helm chart, Terraform, apt install, whatever fits your ops).
Migrations
Migrations are Drizzle-managed. To apply schema:
npm run db:migrate
To generate a new migration after editing src/models/Schema.ts:
npm run db:generate
npm run db:migrate
Migrations are idempotent; safe to re-run.
Context seeding
Context (agents, skills, object types, workflows) lives in workspace/<org>/ as YAML + markdown. Apply to DB:
npm run workspace:apply
This is idempotent — subsequent runs only touch rows that changed. Every apply records a workspace_version audit row.
To bootstrap a new tenant from existing DB state:
npm run workspace:export -- --org <orgId> --name <dirName>
See workspace/README.md for authoring.
LLM providers
Vocion supports multiple LLM hosts; each plugin skill picks one via the provider field. Set at least one provider's API key — OPENAI_API_KEY or ANTHROPIC_API_KEY — or skill execution will throw on first invocation.
Full provider table + per-skill manifest example: writing-a-plugin.md → Pluggable LLM provider. The platform never silently falls back to a default; missing creds throw with a clear message.
MCP server
The MCP server lets you author skills + workflows and inspect runs from Claude Code, Claude Desktop, Cursor, Zed, or any MCP client.
Claude Code
claude mcp add vocion -- npm --prefix /absolute/path/to/context-stack run mcp:serve
Or add to .mcp.json:
{
"mcpServers": {
"vocion": {
"command": "npm",
"args": ["--prefix", "/abs/path", "run", "mcp:serve"],
"env": {
"VOCION_ORG_ID": "org_...",
"OPENAI_API_KEY": "sk-..."
}
}
}
}
Other MCP clients
Point any stdio-capable client at tsx src/interfaces/mcp/bin.ts. See MCP reference for the full tool reference.
Plugins
Plugins are npm packages (or local paths) that register additional skills. Install via the VOCION_PLUGINS env var:
export VOCION_PLUGINS=@acme/plugin-a,./local-plugins/my-skill.ts
npm run mcp:serve
Authoring guide: Writing a plugin.
Production deployment
Docker
Build the Next.js image:
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app ./
ENV NODE_ENV=production
EXPOSE 3000
CMD ["npm", "run", "start"]
Deploy with any container orchestrator (Fly, Railway, Render, ECS, GKE, EKS).
Reverse proxy + TLS
Terminate TLS at nginx / Caddy / your load balancer; forward to the app on port 3000. Set NEXT_PUBLIC_APP_URL to your public URL so auth callbacks resolve correctly.
Scaling considerations
- Stateless app tier — run as many replicas as you need behind a load balancer. Session is a JWT/cookie issued by auth.js.
- Postgres is the source of truth — for high-traffic deployments, use a managed service with read replicas.
- MCP server is single-tenant today (stdio-only). HTTP + OAuth transport lands in Phase 2 for multi-tenant use.
- Workflow durability — in v1 workflows store state in
workflow_runrows. If the process dies mid-run, the run sits paused at its last persisted step. Temporal-backed durability is Phase 7 work.
Backups
Back up Postgres. That's where every skill run, approval decision, context version, and audit record lives. The workspace/<org>/ directory is also important, but it's in git — git is the backup.
Multi-tenant setup
Out of the box, Vocion is multi-tenant — each organization is its own tenant. Rows are scoped by org_id via the oRPC auth guards, and each org has its own workspace/<org>/ directory applied independently.
To onboard a new tenant:
- Create the organization
- Create
workspace/<new-org>/workspace.yaml+ empty subdirectories WORKSPACE_PATH=workspace/<new-org> VOCION_ORG_ID=<org-id> npm run workspace:apply- (Optional) seed objects via scripts or admin UI
Each tenant can have its own plugins enabled via VOCION_PLUGINS — if you're running multi-tenant from one process, list the union. Per-tenant plugin enablement is planned for Phase 3 v0.3.
Observability
- LLM traces — Langfuse is wired by default. Set
LANGFUSE_PUBLIC_KEY+LANGFUSE_SECRET_KEY+LANGFUSE_HOST. Every skill run creates a trace. - Errors — Sentry via
SENTRY_DSN. - Logs — LogTape writes to stdout by default, Better Stack if configured.
- Skill + workflow history — in the DB. Visit
/dashboard/reviewfor pending items, or queryskill_run/workflow_rundirectly.
Upgrading
git pull
npm install
npm run db:migrate
npm run workspace:apply
Migrations are forward-only and idempotent. Context applies are idempotent. No downtime needed for typical upgrades; new schema changes that would break the running app are released with migration notes.
Troubleshooting
npm run dev aborts with Aborted() from PGLite.
The built-in db-server:file target uses PGLite and sometimes gets into a bad state. Switch to Docker Postgres: docker compose up -d postgres && npm run dev:next.
npm run workspace:apply fails with context manifest not found.
Your WORKSPACE_PATH is wrong or workspace/<org>/workspace.yaml is missing. The loader walks from the path root.
MCP server reports OPENAI_API_KEY is not set.
Env not getting loaded. If running via npm run mcp:serve, the dotenv -c -- prefix should handle it. Direct tsx src/interfaces/mcp/bin.ts requires the env already exported.
Plugin loader errors on first boot.
The specifier in VOCION_PLUGINS must resolve as a Node ES module — either an npm package name or an absolute/relative path to a .js, .mjs, or .ts file. The loader logs every failure + still starts with whatever did load.
Workflows get stuck at "paused".
Paused workflows are waiting for approval. Visit /dashboard/review or call workflow_run_resume via MCP.
"Database is inconsistent with context."
Run npm run workspace:check to see the diff. If something was written to the DB outside workspace-as-code (old seed scripts, manual edits), either export with npm run workspace:export to capture it, or edit the workspace repo to match and re-apply.
What's not self-hostable (today)
Nothing critical — everything in the runtime is MIT and runs on your infra. Some optional integrations require accounts with third parties:
- auth.js (built-in — no external auth service)
- Stripe (billing) — optional, only if you're charging end users
- Langfuse — optional, and can be self-hosted itself
A fully-offline deploy works out of the box — auth.js (email + password) is the default auth backend, so no external auth service is required. Clerk is available as an optional VOCION_AUTH_PROVIDER=clerk path for hosted/cloud builds, but it's not needed to self-host.
Support
- Docs:
/dashboard/docs(in-product) ordocs/in the repo - Source: the repo
- Issues: GitHub issues on the public repo (Phase 8 once OSS launches)
- Managed ops: MetaCTO Cloud (when a second set of eyes + SLAs make sense)