λx.xDocs← app

Self-Hosting

Vinculum is AGPL v3. This guide gets you from zero to a running self-hosted instance — copy-pasteable and end-to-end.

Self-hosted installs receive the product app (dashboard, MCP server, runner) only — the marketing and pricing pages at vinculum.run are not included and are not needed.

Not published yet

The public repo and the vinculum-runpackage aren't live — Vinculum ships to the public at v1, not before. This guide documents the install path exactly as it will work at launch; the git clone and uvx vinculum-runcommands below won't resolve until then. Track the release at vinculum.run/changelog.

Vinculum deployment topology — illustrative

Install

Three commands, and there are no prerequisites. No Docker, no Node, no repo checkout, and no database to go find.

bash
curl -fsSL https://vinculum.run/install/server | sh
vinculum init                 # guided setup, ~2 min
vinculum run                  # listens on 127.0.0.1:31415

The first command installs uvif you don't have it, then Vinculum as a uv tool. It resolves the wheel from the published manifest and verifies its SHA-256 before installing — a curl | shthat pulls a binary and doesn't check it is one compromised object away from running someone else's code.

vinculum init sets up a built-in PostgreSQL 16 with pgvector, shipped as a platform wheel. It stores data under ~/.local/share/vinculum/pgdata and listens on a private UNIX socket, so no TCP port is opened for it. Then open http://127.0.0.1:31415/login — it signs you straight in — and connect Claude Code:

bash
vinculum config --client=claude-code --write -y

Using your own PostgreSQL

An option, not a step. Set VINCULUM_DATABASE_URL before init and it uses that instead — 15 or newer, 17 recommended; pgvector is optional and only the semantic-search half needs it. Neon, Supabase, RDS and a local install all work.

bash
export VINCULUM_DATABASE_URL=postgresql://user:pass@host:5432/vinculum
vinculum init

Connect as a superuser or a CREATEROLE role for init: it creates the six vinculum_* roles that background jobs and operator routes SET ROLE into. A least-privilege managed role can run Vinculum afterwards but cannot bootstrap it. Run vinculum doctor after init — it checks for exactly this.

Other paths

Docker and a from-source build are supported, but neither is the recommended route and both are more work than the one-liner. They also need the repository, which is not public yet — so the clone below will not work for you today. It is documented for operators who already have the source.

Docker Compose (from source)

bash
cd vinculum      # the repo is not published yet — see above
cp env.example .env

Edit .env — at minimum:

bash
VINCULUM_DATABASE_URL=postgresql://vinculum_app:changeme@db:5432/vinculum
VINCULUM_BASE_URL=https://your-domain.example.com
VINCULUM_GITHUB_CLIENT_ID=<your-github-oauth-app-client-id>
VINCULUM_GITHUB_CLIENT_SECRET=<your-github-oauth-app-client-secret>
VINCULUM_JWT_SECRET=$(openssl rand -hex 32)

Then start:

bash
docker compose up -d

The server starts on port 31415. Point your reverse proxy at it.

Caddy reverse proxy

caddyfile
your-domain.example.com {
    reverse_proxy localhost:31415
}

nginx reverse proxy

Disable proxy buffering for SSE

The dashboard SSE stream (/api/dashboard/stream) requires buffering to be disabled. Without this, real-time updates won't reach the browser.

nginx
server {
    listen 443 ssl;
    server_name your-domain.example.com;

    location / {
        proxy_pass http://127.0.0.1:31415;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_buffering off;
    }
}

Manual path — bare metal

Always install editable

Use uv pip install -e . (with -e). Without the editable flag, git pullupdates won't reach the running server until you reinstall — a silent divergence that has caused outages.

bash
cd vinculum      # the repo is not published yet — see "Other paths"
uv pip install -e .
cp env.example .env
# edit .env
vinculum migrate
vinculum run

Verify the install is editable:

bash
cat ~/.local/lib/python*/site-packages/vinculum_run-*.dist-info/direct_url.json
# Should show: "dir_info": {"editable": true}

Spawn runner

Spawning is runner-only. spawn_grunt enqueues a spawn_request row that a paired vinculum-runner — a small Go binary on the machine where grunts should execute — claims and runs. The runner long-polls the server over outbound HTTPS (/runner/poll); there is no in-process Popen path, no host-shim, and no daemon to install.

Pair a runner by generating a token (generate_pairing_token MCP tool, or Settings → Runners → Connect a runner in the dashboard) and running the install one-liner it emits:

bash
# Linux / macOS native install (registers a start-at-login unit)
curl -fsSL https://vinculum.run/install.sh | bash

The Docker runner image is not published yet

Some older docs show a docker run … ghcr.io/whalefall-media/vinculum-runner variant. That image has never been published, so the pull fails with denied. Use the native installer above — it is the default on every platform, including Windows and macOS. The Docker variant will be documented here again when the image ships.

PlatformSupervisorArtifact
Linux + systemd + lingersystemd user unit (auto-restart)runner's own start-at-login unit
macOSlaunchd LaunchAgent~/.config/vinculum/runner/ + launchd plist
WindowsScheduled Task%LOCALAPPDATA%\\Vinculum\\
Any OS (Docker)docker run --restart unless-stoppedcontainer

Server-side reconciliation

spawn_log.status reconciliation runs server-side as the spawn_reconcile watchdog tick — there is no host-side reconciler script or timer.

Environment variables

Required for a public, multi-user install

None of these are needed for a local install

vinculum init sets all of it for you: it generates VINCULUM_JWT_SECRET, sets VINCULUM_SINGLE_USER=1, binds the server to 127.0.0.1, and signs you straight in at /login. You do not need a GitHub OAuth app, a domain, or a connection string to run Vinculum for yourself. The table below is what changes when you put an install on the internet for other people.

VariableDescription
VINCULUM_DATABASE_URLPostgreSQL connection string. Role must have CREATE on the vinculum schema. Omit it and init uses the built-in PostgreSQL instead.
VINCULUM_BASE_URLPublic URL of your install, e.g. https://vinculum.example.com.
VINCULUM_GITHUB_CLIENT_IDGitHub OAuth app client ID. Callback: <BASE_URL>/api/auth/github/callback.
VINCULUM_GITHUB_CLIENT_SECRETGitHub OAuth app client secret.
VINCULUM_JWT_SECRETRandom secret for signing session JWTs. Generate: openssl rand -hex 32. Never reuse across installs.

AI intelligence (optional, but recommended)

VariableDescription
VINCULUM_ANTHROPIC_API_KEYAnthropic key for Haiku. Enables per-entry delta classification and thread auto-titling.
VINCULUM_VOYAGE_API_KEYVoyage AI key for embedding generation (semantic search via pgvector).

Server tuning

VariableDefaultDescription
VINCULUM_HOST0.0.0.0Listen address.
VINCULUM_PORT31415Listen port.
VINCULUM_TRANSPORTstreamable-httpMCP transport.
VINCULUM_WEB_BASE_URLSame as VINCULUM_BASE_URLFrontend URL if different origin.

Auth extras

VariableDescription
VINCULUM_FORGEJO_CLIENT_ID / _SECRETForgejo OAuth (self-hosted Gitea).
VINCULUM_INGEST_SECRETBearer token for /api/ingest/conversation.
VINCULUM_AUTH_TOKEN_*Capability-scoped bearer tokens for MCP tool access.

Billing (hosted tiers only)

Leave unset to disable Stripe entirely. Self-hosted installs don't need these.

VariableDescription
STRIPE_SECRET_KEYStripe secret key.
STRIPE_WEBHOOK_SECRETSigning secret from the Stripe webhook dashboard.
STRIPE_PRICE_ID_PROStripe price ID for the Pro tier.
STRIPE_PRICE_ID_TEAMStripe price ID for the Team tier.

Infrastructure tools

All default to false. Enable to unlock MCP tools for inspecting your infrastructure from a Claude session.

VariableUnlocks
VINCULUM_INFRA_DATABASE_ENABLED=truequery_db, list_tables tools
VINCULUM_INFRA_DOCKER_ENABLED=truedocker_status, docker_logs tools
VINCULUM_INFRA_SYSTEM_ENABLED=truesystem_stats tool
VINCULUM_INFRA_TYPESENSE_ENABLED=trueFull-text search via Typesense

Verifying the install

1

Server is up

bash
curl http://localhost:31415/healthz
# → {"ok": true, "service": "vinculum"}
2

Dashboard loads

Open https://your-domain.example.com/login (or http://localhost:31415/login for bare-metal) and sign in — you land on your own dashboard at /d/<your-username>, showing the empty-project state with six branch cards.

3

Sign in works

Click Sign In → GitHub. You should be redirected to GitHub and back, then land on the dashboard as a signed-in user.

4

MCP endpoint responds

bash
curl -X POST https://your-domain.example.com/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}'
# → {"jsonrpc":"2.0","result":{"protocolVersion":"2024-11-05",...}}
5

Connect Claude Code and spawn a grunt

bash
cd ~/your-project
uvx vinculum-run config --client=claude-code --write -y

Then in Claude Code, call spawn_gruntwith a test directive. You're fully operational when a grunt session appears in the Sessions panel.

After deployment, the dashboard MetricStrip shows live health — branch counts, active sessions, and entry velocity at a glance.

The MetricStrip (mission control) shows branch health, active sessions, and entry velocity — this is the real component from the dashboard, fed static demo data.

Cross-platform notes

The vinculum-runner ships native installers for Linux, macOS, and Windows, plus a Docker image that runs anywhere. There is no platform-specific daemon — the runner is the single spawn path on every OS.

Backup and restore

bash
# Backup
pg_dump -Fc "$VINCULUM_DATABASE_URL" > vinculum_$(date +%Y%m%d).dump

# Restore to a fresh database
createdb vinculum
pg_restore -d "$VINCULUM_DATABASE_URL" vinculum_20260101.dump

Automated backups

An R2 automated backup pipeline is specced for post-launch (#125). Until then, set up a cron job or Coolify backup policy for the Postgres volume.

Upgrading

Docker Compose

bash
cd vinculum
git pull
docker compose pull
docker compose up -d

Migrations run automatically on startup.

Bare metal

bash
cd vinculum
git pull
uv pip install -e .
vinculum migrate
systemctl --user restart vinculum-mcp