Skip to content
Self-hosting

Quickstart

A minimal self-host boot path for maintainers: start the service, verify readiness, and keep the first rollout safe.

1. Copy the sample env

.env.selfhost.example is the short path: required secrets plus a conservative first-boot config, with nothing about the Cloudflare Worker deploy. Copy it and fill in the placeholders — keep your real .env out of git and prefer mounted secret files for multiline values like the GitHub App private key.

cp .env.selfhost.example .env
# edit .env
bash
The webhook secret and static bearer tokens (GITHUB_WEBHOOK_SECRET, GITTENSORY_API_TOKEN, GITTENSORY_MCP_TOKEN, INTERNAL_JOB_TOKEN, SELFHOST_SETUP_TOKEN) ship commented out on purpose. Generate a distinct random value for each one (e.g. openssl rand -hex 32) — never reuse the same string across more than one of them. The app refuses to boot if any of these is left at a known-placeholder or too-short value.
.env.selfhost.example already ships a conservative starting config — dry-run mode, a small repo allowlist, unified comments, safety, and grounding, with AI, RAG, and REES left off. Switch to live only after webhook delivery, logs, and review output match expectations. For every optional env var (observability, backup, additional AI providers) see .env.example's self-host section or the generated reference table.

2. Choose your AI provider (optional)

Skip this step for a fully deterministic review (no AI). Otherwise uncomment ONE of the three blocks below in .env.selfhost.example — they're mutually exclusive, each sets its own AI_PROVIDER. The self-host image bundles both CLIs by default; credentials and provider choice are runtime-only.

.env — Claude Code only
AI_PROVIDER=claude-code
CLAUDE_CODE_OAUTH_TOKEN=          # from `claude setup-token`
.env — Codex only
AI_PROVIDER=codex
GITTENSORY_ENABLE_UNSAFE_CODEX_REVIEWER=1   # required opt-in; see Callout below
.env — both, synthesized into one decision
AI_PROVIDER=claude-code,codex
AI_COMBINE=synthesis
CLAUDE_CODE_OAUTH_TOKEN=
GITTENSORY_ENABLE_UNSAFE_CODEX_REVIEWER=1
Codex is fail-closed by default
Codex stores its OAuth credential in auth.json on the same filesystem that prompt-influenced reviews can read, so it requires explicit opt-in (GITTENSORY_ENABLE_UNSAFE_CODEX_REVIEWER=1) and a mounted /data/codex auth volume. Claude Code has no equivalent restriction. See AI providers for the full reference.

3. Boot the stack

Recommended: pull the published image. No local build, no Node toolchain — the script pulls, restarts, and waits for the health check to pass.

./scripts/deploy-selfhost-image.sh
curl http://localhost:8787/health
curl http://localhost:8787/ready
bash

Pin a specific release instead of :latest, or point at your own registry:

./scripts/deploy-selfhost-image.sh ghcr.io/jsonbored/gittensory-selfhost:orb-v0.1.0
GITTENSORY_IMAGE=ghcr.io/jsonbored/gittensory-selfhost@sha256:... ./scripts/deploy-selfhost-image.sh
bash
Building from source instead
Contributors and anyone customizing the Dockerfile can still build locally — docker compose up -d --build builds the gittensory service from the checkout instead of pulling a published image. Everything else in this quickstart (env, health checks, GitHub App) is identical either way. Two build-args trim the image: --build-arg INSTALL_AI_CLIS=false skips the Claude Code/Codex CLIs (default true), and --build-arg INSTALL_VISUAL_REVIEW=true adds puppeteer-core for visual capture (default false — needs a BROWSER_WS_ENDPOINT at runtime).
/health
Liveness. It confirms the HTTP process is up.
/ready
Readiness. It returns 200 only after database access, migrations, and every configured backend (Redis, GitHub App auth, the AI provider, and any of Qdrant/Postgres you've enabled) are healthy.
/metrics
Prometheus metrics for queue, jobs, HTTP traffic, uptime, and AI usage.

4. Install or connect the GitHub App

Point your App webhook to https://your-host.example/v1/github/webhook, set the same webhook secret in GITHUB_WEBHOOK_SECRET, install the App on one test repo, and open a small PR. The direct App and Orb modes are covered in GitHub App and Orb.

Set ADMIN_GITHUB_LOGINS to a comma/whitespace-separated list of GitHub logins before signing in to the control panel — it's the only allowlist for the operator role (operator dashboard, drift status). No login is authorized as operator without it.

5. Watch the first review

Look for these logs during boot and the first webhook:

selfhost_listening
selfhost_migrations_applied
selfhost_ai_provider          # only when AI_PROVIDER is set
selfhost_job_dead             # investigate immediately if present
review_context_fetch_failed   # REES/RAG/grounding context failure

A cold first boot on SQLite commonly logs a one-time selfhost_migrations_applied burst and a brief Redis connection retry while the sidecar finishes starting — both are expected and stop once the stack is warm. Anything else that looks wrong, or a /ready that stays unhealthy past a couple minutes, is covered in Troubleshooting.

After the deterministic path is stable, continue with Configuration and then layer in AI, REES, or RAG deliberately.

Defaults at a glance

Nothing below needs a flag to start; everything past the first row needs an explicit --profile (combine freely) or an explicit AI_PROVIDER.

ENABLED BY DEFAULT (no flags needed)
  gittensory app + Redis        SQLite database, dry-run-friendly, Orb telemetry (see Callout below)

RECOMMENDED FOR PRODUCTION (opt-in)
  --profile postgres             shared/multi-instance database (pgvector-capable)
  --profile pgbouncer            connection pooling in front of Postgres
  --profile caddy                automatic HTTPS via Let's Encrypt
  --profile litestream            continuous SQLite backup to S3-compatible storage
  --profile observability        Prometheus + Alertmanager + Loki + Grafana

OPT-IN, NOT REQUIRED FOR A TRIAL INSTANCE
  --profile qdrant                dedicated RAG vector store (else sqlite-vec/pgvector)
  --profile ollama                local model for AI review or embeddings
  --profile tailscale             private network sidecar
  --profile runners               self-hosted GitHub Actions runner
  --profile backup                scheduled backup + backup-exporter jobs
  AI_PROVIDER=...                 off by default; reviews are deterministic-only until set
text
Orb fleet-calibration telemetry (verdict, outcome, cycle time — never repo names, code, or logins) starts automatically once your GitHub App is configured — this is the self-hosting contract, not a flag you turn on. The one way to disable it is the explicit air-gap flag: set ORB_AIR_GAP=true for an instance that sends nothing.