Configuration

Optio is configured through environment variables, Helm chart values, and per-repository settings in the dashboard. This page covers all three layers.

Environment Variables

These are set on the API server. In Kubernetes, they are configured via the Helm chart's api.env section or directly as environment variables on the deployment.

Core

VariableDefaultDescription
DATABASE_URL(required)PostgreSQL connection string
REDIS_URL(required)Redis connection string for BullMQ and pub/sub
REDIS_MODEstandalonestandalone for one Redis server, cluster for Redis Cluster or ElastiCache Serverless (REDIS_URL then lists seed nodes)
OPTIO_QUEUE_PREFIXbull / {optio}BullMQ key prefix; cluster mode requires a {hash-tag} so each queue stays in one slot
OPTIO_ENCRYPTION_KEY(required)AES-256-GCM key for secret encryption (32-byte hex)
PUBLIC_URLhttp://localhost:30400Public URL of the API server (used for OAuth callbacks)
PORT4000API server port

Concurrency & Tuning

VariableDefaultDescription
OPTIO_MAX_CONCURRENT5Global maximum running tasks across all repos
OPTIO_REPO_POD_IDLE_MS600000Idle timeout for repo pods in milliseconds (10 min default)
OPTIO_REPO_INIT_TIMEOUT_MS120000Repo clone/init timeout in milliseconds (2 min default)
OPTIO_PR_WATCH_INTERVAL30000PR polling interval in milliseconds
OPTIO_HEALTH_CHECK_INTERVAL60000Health check and cleanup interval in milliseconds
OPTIO_IMAGE_PULL_POLICYIfNotPresentKubernetes image pull policy for agent pods (Never for local dev)

Authentication

VariableDefaultDescription
OPTIO_AUTH_DISABLEDfalseDisable all auth checks (local dev only)
OPTIO_SETUP_TOKENgeneratedOne-time token unlocking the setup wizard's Sign-in step while nobody can sign in
OPTIO_DEPLOYMENT_ADMINS—Comma-separated emails that may change how everyone signs in
GITHUB_OAUTH_CLIENT_ID—GitHub OAuth app client ID
GITHUB_OAUTH_CLIENT_SECRET—GitHub OAuth app client secret
GOOGLE_OAUTH_CLIENT_ID—Google OAuth client ID
GOOGLE_OAUTH_CLIENT_SECRET—Google OAuth client secret
GITLAB_OAUTH_CLIENT_ID—GitLab OAuth client ID
GITLAB_OAUTH_CLIENT_SECRET—GitLab OAuth client secret
GITLAB_OAUTH_BASE_URLhttps://gitlab.comBase URL for self-hosted GitLab
OIDC_ISSUER_URL—OIDC issuer URL (enables generic OIDC provider)
OIDC_CLIENT_ID—OIDC client ID
OIDC_CLIENT_SECRET—OIDC client secret
OIDC_DISPLAY_NAMESSOLogin button label
OIDC_SCOPESopenid email profileSpace-separated OIDC scopes

Info

Enable an OAuth provider by setting both its CLIENT_ID and CLIENT_SECRET. Google can instead be configured in the app (Settings → Access → Sign-in, or the setup wizard's Sign-in step on a fresh install), with the Google Workspace domains allowed to sign in; a stored client takes precedence over the environment. Register the callback URL as {PUBLIC_URL}/api/auth/{provider}/callback.

Generic OIDC Provider

Any OpenID Connect-compatible identity provider (Keycloak, Authentik, Authelia, Zitadel, Okta, Auth0, etc.) can be used via the generic OIDC provider. Set OIDC_ISSUER_URL to the issuer URL and configure the client credentials. The discovery document is fetched automatically from <issuer>/.well-known/openid-configuration.

Keycloak example
OIDC_ISSUER_URL=https://auth.example.com/realms/optio
OIDC_CLIENT_ID=optio
OIDC_CLIENT_SECRET=your-client-secret
OIDC_DISPLAY_NAME="Company SSO"

# Register the callback URL in your IdP:
# {PUBLIC_URL}/api/auth/oidc/callback

Helm Chart Values

The Helm chart at helm/optio/ deploys the full stack. Here are the key configuration sections.

Database & Redis

values.yaml
# Use built-in instances (dev only)
postgresql:
  enabled: true
  auth:
    password: "optio_dev"
redis:
  enabled: true

# Use external managed services (production)
postgresql:
  enabled: false
externalDatabase:
  url: "postgresql://user:pass@your-db:5432/optio"
redis:
  enabled: false
externalRedis:
  url: "redis://your-redis:6379"

Encryption

terminal
# Generate a 32-byte hex key
openssl rand -hex 32
values.yaml
encryption:
  key: "your-64-character-hex-string-here"

Warning

The encryption key is required and is used for AES-256-GCM encryption of all secrets stored in the database. Losing this key means losing access to all stored secrets.

Agent Images

values.yaml
agent:
  # For local dev (images loaded directly into K8s containerd)
  imagePullPolicy: Never

  # For production (images in a container registry)
  imagePullPolicy: IfNotPresent
  # or: Always

Ingress

values.yaml
ingress:
  enabled: true
  hosts:
    - host: optio.example.com
  tls: true

Services

values.yaml
# Local dev (NodePort for direct access)
api:
  service:
    type: NodePort
    nodePort: 30400
web:
  service:
    type: NodePort
    nodePort: 30310

# Production (ClusterIP behind ingress)
api:
  service:
    type: ClusterIP
web:
  service:
    type: ClusterIP

Auth

values.yaml
auth:
  # Disable for local development
  disabled: true

  # Production: configure OAuth providers
  github:
    clientId: "your-client-id"
    clientSecret: "your-client-secret"
  google:
    clientId: "your-client-id"
    clientSecret: "your-client-secret"

What the Chart Creates

  • Namespace, ServiceAccount, and RBAC (pod/exec/secret management)
  • API deployment + service with health probes
  • Web deployment + service
  • Conditional PostgreSQL and Redis deployments
  • Configurable Ingress resource

Per-Repository Settings

Each connected repository has its own settings, configured in the dashboard under Repos → Settings.

General

SettingDefaultDescription
imagePresetauto-detectAgent image: node, python, go, rust, full
defaultBranchmainBranch to create worktrees from
autoMergefalseAuto-merge PRs when CI passes and review is approved
autoResumetrueAuto-resume agent when reviewer requests changes
maxConcurrentTasks2Max concurrent tasks in this repo
maxPodInstances1Max pod replicas for this repo (1-20)
maxAgentsPerPod2Max concurrent agents per pod (1-50)

Claude Settings

SettingDefaultDescription
claudeModelsonnetModel for coding tasks (sonnet, opus, haiku)
claudeContextWindownullContext window override (null = model default)
claudeEffortnullEffort level override
maxTurnsCodingnullMax agent turns for coding tasks
maxTurnsReviewnullMax agent turns for review tasks
promptTemplateOverridenullCustom prompt template for this repo

Review Settings

SettingDefaultDescription
reviewEnabledfalseEnable automatic code review agent
reviewTriggeron_ci_passWhen to trigger: on_ci_pass or on_pr
reviewModelsonnetModel to use for review (often a cheaper model)
reviewPromptTemplatenullCustom review prompt template

Prompt Templates

System prompts use a simple template language with variable substitution and conditionals.

Available Variables

VariableDescription
{{TASK_FILE}}Path to the task description markdown file
{{BRANCH_NAME}}Git branch name for this task
{{TASK_ID}}Unique task identifier
{{TASK_TITLE}}Task title
{{REPO_NAME}}Repository name (owner/repo)
{{AUTO_MERGE}}Whether auto-merge is enabled
{{PR_NUMBER}}PR number (review tasks only)
{{TEST_COMMAND}}Detected test command (review tasks only)

Conditionals

prompt template
{{#if AUTO_MERGE}}
After CI passes, the PR will be auto-merged.
{{else}}
Wait for manual review before merging.
{{/if}}

Priority Chain

Templates are resolved in order of specificity:

  1. Per-repo override (repos.promptTemplateOverride)
  2. Global default (prompt_templates table)
  3. Hardcoded fallback in @optio/shared

Review prompts follow the same chain: repos.reviewPromptTemplate → default review template.

Secrets

Secrets are managed in the dashboard under Secrets and are encrypted at rest with AES-256-GCM. Key secrets to configure:

  • CLAUDE_AUTH_MODE — api-key or oauth-token
  • ANTHROPIC_API_KEY — Your API key (if using api-key mode)
  • CLAUDE_CODE_OAUTH_TOKEN — OAuth token (if using oauth-token mode)
  • GITHUB_TOKEN — GitHub personal access token for PR watching, issue sync, and repo detection

Tip

Secret values are never logged or returned via the API. Only secret names and scopes are visible in the dashboard.

Next Steps