docs
Getting started
inkcap is a single stateful process: a web server and an agent runtime in one. You bring PostgreSQL and an LLM provider; it keeps your conversations running even when no browser is watching.
Requirements
- Bun (runtime, package manager, and test runner)
- PostgreSQL with an
inkcapdatabase (plusinkcap_testif you want to run the test suite) - Something to chat with: a running
llama-server, any OpenAI-compatible endpoint, or a ChatGPT subscription
Install and run
git clone https://github.com/jakswa/inkcap
cd inkcap
bun install
cp .env.example .env.local # set DATABASE_URL and SESSION_SECRET
bun run db:migrate
bun run dev
Open http://localhost:3000 and register — outside production, registration is open by default. Your account is created together with a personal workspace that owns your providers and MCP servers.
Add a provider
Providers live server-side; API keys are stored in the database and never reach the browser. Add one under Providers → Add provider, or seed a llama-server provider from the CLI:
# uses DEV_LLAMA_SERVER / DEV_LLAMA_KEY from your env
bun src/tasks/seed-provider.ts --user you@example.com
Chat on your ChatGPT subscription (Codex)
Providers → Add provider → “Sign in with ChatGPT”. The server runs the Codex CLI’s OAuth flow; OpenAI always redirects back to localhost:1455, which inkcap listens on while a sign-in is pending. Tokens stay server-side and refresh automatically.
Browsing from a different machine than the one running inkcap? After you approve the login, the redirect lands on your browser’s localhost and shows a connection error — that’s expected. Copy the failed http://localhost:1455/auth/callback?… address and paste it into the “Finish a remote ChatGPT sign-in” form on the Add provider page. No tunnel needed: the server holds the pending sign-in state and completes the exchange itself.
Import llama.cpp web UI history
Coming from llama.cpp’s built-in web UI? The importer is idempotent and takes a JSONL export or a zip, including attachments and branch trees:
bun src/tasks/import-llama-ui.ts export.jsonl --user you@example.com
Environment reference
| Variable | What it does |
|---|---|
DATABASE_URL | PostgreSQL connection string |
SESSION_SECRET | Encrypts the session cookie; in production it must be ≥32 bytes and not a placeholder |
ASSET_VERSION | Cache-busting version for static assets; required in production (pass as a Docker build arg) |
PORT | HTTP port (default 3000) |
REGISTRATION | open or closed; defaults to closed in production, open elsewhere |
PUBLIC_ORIGIN, CSRF_TRUSTED_ORIGINS, OUTBOUND_TRUSTED_HOSTS | Opt-ins for split-origin deployments (TLS-terminating proxy and/or direct LAN IP access); see .env.example |
DEV_LLAMA_SERVER / DEV_LLAMA_KEY | Feed the seed-provider task in development |
Production (Docker)
The build bundles everything into build/; the image ships no src/ and no node_modules/.
docker build --build-arg ASSET_VERSION=$(git rev-parse --short=7 HEAD) -t inkcap .
docker run -p 3000:3000 --env-file .env.production inkcap
Run migrations inside the image with bun build/tasks/migrate.js. Registration defaults to closed in production — bootstrap your first user from the CLI:
CREATE_USER_PASSWORD=... bun build/tasks/create-user.js --name You --email you@example.com
Digging deeper
- README — architecture shape, scripts, development rules
- docs/STATUS.md — current state of the project
- docs/specs/ — provider, export, and MCP protocol notes