Back to operationkit

Setup guide

From zero to a running board

This guide walks a competent developer from an empty Ubuntu 24.04 server to a logged-in OperationKit board. The steps match the current source tree (V1, reseeded 2026-08-28).

The source is public at github.com/m1keluka/OperationKit. These docs describe exactly what install.sh, docker-compose.yml, and .env.example contain today. Nothing here is invented or forward-looking.

Two setup paths. The DigitalOcean installer (install.sh) provisions Docker, Caddy, and all secrets for you on a fresh droplet. Manual is any Linux host where you run the steps yourself. The manual path is described below.

Prerequisites

Host
Ubuntu 24.04
Any modern Linux with Docker works; Ubuntu 24.04 is the tested target.
Docker
Engine + Compose v2
docker compose version must work. Install from Docker's official repo.
Resources
4 GB RAM, 2 vCPU
Baseline for three containers. More headroom for heavy concurrent sessions.
Claude subscription
Pro or Max
How agent sessions are powered. Not an API key; an OAuth-authenticated subscription. Required.
Domain + DNS
Optional (for TLS)
Only needed for a public HTTPS deployment. Local runs work on 127.0.0.1.

Model keys are optional. ANTHROPIC_API_KEY powers a small server-side summarizer, not agent sessions. Agent sessions run under your Claude Code subscription (authenticated separately). OpenAI and Gemini keys are also optional and off by default.

Get the source

Clone the repo to your server:

# On your server (not your laptop)
git clone https://github.com/m1keluka/OperationKit.git
cd OperationKit

The source is public. Clone or star the repo at github.com/m1keluka/OperationKit.

Configure .env

cp .env.example .env

The .env.example documents every variable. The seven you must fill before the stack will start:

VariableWhat it isRequired?
CC_JWT_SECRET Signs session cookies. Rotating this logs everyone out. required
LITELLM_MASTER_KEY Auth key for the LiteLLM proxy. Use sk- prefix by convention. required
LITELLM_SALT_KEY Encryption salt for LiteLLM credential storage. required
POSTGRES_PASSWORD Password for the LiteLLM Postgres database (internal only, loopback). required
ANTHROPIC_API_KEY Powers the server-side session summarizer only. Agent sessions do not use this key. optional
OPENAI_API_KEY OpenAI models via LiteLLM. Leave blank to skip. optional
GEMINI_API_KEY Google Gemini models via LiteLLM. Leave blank to skip. optional

Generate the secrets you invent yourself with:

openssl rand -hex 32      # for CC_JWT_SECRET, LITELLM_SALT_KEY, POSTGRES_PASSWORD
openssl rand -hex 24      # then prepend sk- for LITELLM_MASTER_KEY

Never commit .env. It is git-ignored and contains live keys.

Start the stack

docker compose up -d

Compose starts three services: litellm-db (Postgres) first, then litellm (model proxy on port 4000), then command-center (the app on port 3002). The first run pulls images and builds the app container, so give it a few minutes.

# Watch the logs as it comes up:
docker compose ps
docker compose logs -f command-center

Authenticate your Claude subscription

This step is required before any objective can run. Agent sessions are powered by a Claude Pro or Max subscription, not by an API key. The subscription authenticates via OAuth into an account slot on the host.

Once the stack is up, authenticate at least one Claude Code account using the helper:

# Interactive (prompts you to authorize in a browser):
./scripts/claude-auth.sh a

# Headless / server-only path:
./scripts/claude-auth.sh a --setup-token

The installer supports up to five account slots (a through e) plus a Codex slot. Add more subscriptions later to increase concurrent session throughput. Full details are in docs/CLAUDE-CODE-AUTH.md in the source tree.

Health check

Both services expose health endpoints. Check them before moving on:

# OperationKit app (should return HTTP 200 with {"status":"ok"}):
curl -f http://127.0.0.1:3002/api/health

# LiteLLM model proxy (loopback only — never exposed to the internet):
curl -f http://127.0.0.1:4000/health/liveliness

If command-center is not healthy, check docker compose logs command-center. The most common first-run causes are a missing or blank required variable in .env or a bind-mount path that does not exist on your host.

Seed the first user

The app ships with no users. Run the seed script once:

docker compose exec command-center npm run seed

This creates an admin user with the initial password changeme and a sample member user ava. The script prints Change passwords after first login! Do that immediately.

Log in

Open your browser and navigate to:

http://127.0.0.1:3002

Log in with username admin and password changeme. Change the password from the account settings UI before doing anything else.

Login issues a JWT signed with CC_JWT_SECRET. If you rotate that secret later, all sessions are invalidated and everyone must log in again.

Create your first objective

1

Create a workspace

A workspace scopes objectives, users, and credentials to a project or team. Create a new one from the board UI for your project.

2

Write an objective

An objective is a goal statement plus "done when..." acceptance criteria. Give it a clear title and a concrete description of what done looks like.

3

Let it run

The board moves the card through planning, working, and review. Each stage is a live agent session with a terminal you can watch in real time.

TLS with Caddy (public deployments)

For an internet-facing deployment, the app ports stay bound to 127.0.0.1. Caddy on the host terminates TLS on ports 80 and 443 and reverse-proxies to :3002. Only SSH (22), HTTP (80), and HTTPS (443) are ever exposed.

The DigitalOcean installer (install.sh) wires the Caddyfile for you. For a manual setup, run scripts/bootstrap.sh to install Caddy, a firewall (ufw: 22/80/443), and fail2ban. Read SECURITY.md before exposing the board to the internet.

A recommended starting point is a 4 GB / 2 vCPU droplet (~$24/month) on DigitalOcean plus your Claude Pro/Max subscription. TLS certificates from Let's Encrypt are free.

Model keys

OperationKit routes model calls through LiteLLM, which supports every major provider. Out of the box, the stack is configured for Claude (Anthropic), OpenAI, and Google Gemini via the keys in .env.

To add Grok (xAI) or any other provider LiteLLM supports, add the provider's API key to .env and update config/litellm/config.yaml with a model entry pointing at that key. To apply new config, run docker compose restart litellm.

ProviderKey variableNotes
Anthropic (Claude)ANTHROPIC_API_KEYOptional; agent sessions run on Claude subscription, not this key.
OpenAIOPENAI_API_KEYOptional; add to .env and config.yaml.
Google GeminiGEMINI_API_KEYOptional; add to .env and config.yaml.
xAI / GrokXAI_API_KEY (or similar)Add as a custom provider in config.yaml. LiteLLM supports xAI natively.
Ollama (self-hosted)GPU_OLLAMA_URLSet to your Ollama host URL. Leave blank if not using a local model.
Any LiteLLM providervariesAdd the key and a model entry in config/litellm/config.yaml.

Teams and workspaces

OperationKit is multi-tenant from day one. Each workspace is a hard boundary: objectives, files, credentials, and users stay scoped to the workspace they belong to. Nothing from workspace A is visible in workspace B.

  • Create workspaces per team, project, or client from the board UI.
  • Invite users into a workspace. Each user gets their own board view scoped to that workspace.
  • Admin users can see and manage all workspaces. Members see only theirs.
  • Credentials (API keys, integration tokens) stored in a workspace are only available to agents in that workspace.

Troubleshooting first-run

SymptomLikely fix
command-center container restarts / unhealthy Missing or blank required value in .env. Run docker compose logs command-center.
Health check on :3002 fails but container is running Give it ~15 seconds to boot (start_period), then retry. Check the log for a bind-mount path that doesn't exist on your host.
LLM calls fail with auth errors Bad or missing provider key in .env. Fix the key and run docker compose restart litellm.
Objectives queue but no sessions start No Claude Code account is authenticated. Run ./scripts/claude-auth.sh a.
Can't log in after rotating CC_JWT_SECRET Expected. Rotating the JWT secret invalidates all existing tokens. Log in again with the new secret active.

Still stuck? Open a bug report in the GitHub repo. Onboarding friction is a first-class V1 bug.

Back to landing Star on GitHub