Configuration Options

Windshift can be configured with command-line flags and environment variables. Flags win over environment variables when both are present. The Docker image is usually configured with environment variables; the standalone binary can use either style.

Production checklist

For a self-hosted production deployment, set these first:

Setting Why it matters
SSO_SECRET Required. Signs session cookies and SSO state. Generate once and keep it stable across restarts.
BASE_URL Required for correct email links, SSO redirects, WebAuthn origins, calendar feeds, and runner callbacks.
ALLOWED_HOSTS Restricts accepted hostnames and protects deployments behind proxies.
USE_PROXY=true Required when TLS terminates at a reverse proxy. Only enable when Windshift is not directly internet-reachable.
ATTACHMENT_PATH Required if users upload attachments and you want them persisted outside the database/container filesystem.
POSTGRES_CONNECTION_STRING Recommended for multi-user production. SQLite is fine for small or single-node installs.

Generate a secret with:

openssl rand -hex 32

Keep the value. Changing SSO_SECRET invalidates existing sessions and can break encrypted SSO/provider credentials.

Configuration precedence

Windshift resolves configuration in this order:

  1. Explicit CLI flag
  2. Environment variable, where supported
  3. Built-in default

Example:

PORT=8080 ./windshift --port 3000

Windshift listens on 3000, because the flag wins.

HTTP, proxy, and public URL

Flag Env var Default Description
--port, -p PORT 8080 HTTP server port.
--base-url BASE_URL - Public URL users access Windshift from, for example https://windshift.example.com.
--context-path CONTEXT_PATH - Optional subpath such as /windshift when served below a domain root.
--allowed-hosts ALLOWED_HOSTS - Comma-separated hostnames Windshift should accept, for example windshift.example.com.
--allowed-port - - Extra port used for CORS and WebAuthn origin validation.
--use-proxy USE_PROXY false Trust X-Forwarded-Proto and X-Forwarded-For from trusted proxies.
--additional-proxies ADDITIONAL_PROXIES - Comma-separated trusted proxy IPs in addition to private network ranges.
--no-csrf - false Disable CSRF protection. Development only.

When USE_PROXY=true, Windshift trusts forwarded headers. Make sure only your reverse proxy can reach the Windshift port. Do not expose the backend port directly to the internet.

For subpath deployments, include the path in both BASE_URL and CONTEXT_PATH:

BASE_URL=https://example.com/windshift
CONTEXT_PATH=/windshift

Secrets and authentication

Flag Env var Default Description
- SSO_SECRET required Preferred session and SSO signing/encryption secret.
- SESSION_SECRET - Backward-compatible fallback when SSO_SECRET is unset.
--enable-fallback ENABLE_ADMIN_FALLBACK false Enable password-based admin fallback for restrictive SSO setups.
- RECOVER_USER - Recovery helper for emergency user access flows.

SSO_SECRET is required at startup. SESSION_SECRET is accepted only as a fallback for older deployments.

WebAuthn

Flag Env var Default Description
- WEBAUTHN_RP_ID host name WebAuthn relying-party ID, usually the public hostname.
- WEBAUTHN_RP_NAME Windshift Display name shown by authenticators.

Set BASE_URL and ALLOWED_HOSTS correctly before enabling passkeys/WebAuthn.

Database

Flag Env var Default Description
--db DB_PATH windshift.db SQLite database file path.
--postgres-connection-string, --pg-conn POSTGRES_CONNECTION_STRING - PostgreSQL connection string. When set, PostgreSQL is used instead of SQLite.
- DB_TYPE - Set to postgres to build a connection string from POSTGRES_* variables.
- POSTGRES_HOST postgres Host used when DB_TYPE=postgres and no connection string is supplied.
- POSTGRES_PORT 5432 PostgreSQL port for generated connection strings.
- POSTGRES_USER windshift PostgreSQL user for generated connection strings.
- POSTGRES_PASSWORD - PostgreSQL password for generated connection strings.
- POSTGRES_DB windshift PostgreSQL database for generated connection strings.
--max-read-conns MAX_READ_CONNS 120 SQLite read connection pool size.
--max-write-conns MAX_WRITE_CONNS 1 SQLite write connection pool size.

Use POSTGRES_CONNECTION_STRING when possible; use the POSTGRES_* family when Docker Compose or secret managers make separate variables easier.

Files and attachments

Flag Env var Default Description
--attachment-path ATTACHMENT_PATH - Directory for uploaded attachments.

In Docker, mount a persistent volume at /data and use /data/attachments.

TLS

Flag Env var Default Description
--tls-cert - - TLS certificate path when Windshift terminates TLS directly.
--tls-key - - TLS private key path when Windshift terminates TLS directly.

Most deployments should terminate TLS at a reverse proxy and run Windshift over an internal network.

SSH TUI and MCP

Flag Env var Default Description
--ssh SSH_ENABLED false Enable the SSH TUI server.
--ssh-port SSH_PORT 23234 SSH server port.
--ssh-host SSH_HOST localhost SSH bind address.
--ssh-key - .ssh/windshift_host_key SSH host key path.
--mcp MCP_ENABLED false Enable the MCP server at /mcp.

Logging and rate limits

Flag Env var Default Description
--log-level LOG_LEVEL info debug, info, warn, or error.
--log-format LOG_FORMAT text text, json, or logfmt.
--disable-ip-rate-limit DISABLE_IP_RATE_LIMIT false Disable IP-based rate limiting. Use only behind trusted controls.

For container production logs, use:

LOG_FORMAT=json
LOG_LEVEL=info

Plugins

Flag Env var Default Description
--disable-plugins DISABLE_PLUGINS false Disable the plugin system.
- PLUGIN_DIR - Primary plugin directory.
- PLUGIN_DIRS - Extra plugin directories, comma-separated.

SSO and private identity providers

Flag Env var Default Description
--oidc-allowed-private-cidrs OIDC_ALLOWED_PRIVATE_CIDRS - Private/CGNAT CIDRs that OIDC discovery, JWKS, and token HTTP calls may dial.

By default, OIDC HTTP clients block private, loopback, link-local, multicast, and CGNAT addresses to reduce SSRF risk. If your IdP is internal, allow only the exact CIDR(s) needed.

Examples:

# Internal IdP subnet
OIDC_ALLOWED_PRIVATE_CIDRS=10.20.30.0/24

# A single private IdP host
OIDC_ALLOWED_PRIVATE_CIDRS=10.20.30.15/32

AI and LLM providers

AI features are configured in the Windshift admin UI after startup. Operators can customize the provider catalog and network policy here.

Flag Env var Default Description
--llm-providers LLM_PROVIDERS_FILE - Path to a custom LLM providers JSON file. Replaces the built-in provider catalog.
--llm-allowed-private-cidrs LLM_ALLOWED_PRIVATE_CIDRS - Private/loopback/CGNAT CIDRs that admin-configured LLM inference and model-list calls may dial.
--ai-prompts-dir AI_PROMPTS_DIR /data/prompts in Docker Directory containing custom AI prompt override files.
- LLM_ENDPOINT - Legacy/fallback OpenAI-compatible inference endpoint. Prefer in-app AI connections for normal use.

Windshift's built-in provider catalog includes Anthropic, OpenAI, Google Gemini, Z.AI, OpenRouter, and Local / Custom. OpenRouter includes a seed model list so admins can pick a model immediately; the Refresh button can still fetch the live catalog.

Local and internal LLM endpoints

LLM calls are SSRF-protected by default. Public provider endpoints work without extra configuration, but local or private models require an explicit allowlist. This applies to both inference requests and model-list refreshes.

For an Ollama or LM Studio server on the same host as the Windshift process:

LLM_ALLOWED_PRIVATE_CIDRS=127.0.0.1/32,::1/128

For Windshift running in Docker and reaching a host service through Docker's bridge gateway:

LLM_ALLOWED_PRIVATE_CIDRS=172.17.0.1/32

Then create a Local / Custom AI connection in the admin UI with a base URL such as:

http://host.docker.internal:11434/v1

or:

http://172.17.0.1:11434/v1

Only allow the exact host or subnet you need. Do not allow broad ranges such as 10.0.0.0/8 unless your network policy already prevents access to sensitive services.

Custom provider catalog

To add providers, change default models, or route a provider to a proxy, copy the built-in catalog and point Windshift at your copy:

internal/llm/llm_providers.json

Minimal OpenAI-compatible provider:

{
  "providers": [
    {
      "type": "local",
      "name": "Local / Custom",
      "api_format": "openai",
      "base_url": "http://127.0.0.1:11434/v1",
      "models_endpoint": "/v1/models",
      "models_auth_scheme": "bearer",
      "models_response_format": "openai",
      "models": [
        { "id": "llama3.1:8b", "name": "Llama 3.1 8B", "max_tokens": 4096 }
      ]
    }
  ]
}

Supported api_format values are:

Value Use for
openai OpenAI-compatible chat completions APIs.
anthropic Anthropic Messages API.

Provider model-refresh settings:

Field Description
models_endpoint Endpoint to fetch a model list, joined with the provider base URL.
models_base_url Optional separate base URL for the model-list endpoint.
models_auth_scheme bearer, anthropic, or google.
models_response_format openai, anthropic, or google.
chat_path Optional chat path override for OpenAI-compatible providers, for example /chat/completions.

AI prompt overrides

Every AI feature uses an embedded system prompt. To override one prompt, place a <name>.txt file in AI_PROMPTS_DIR. Missing files keep the built-in default.

Filename Feature
plan_my_day.txt Plan My Day
catch_me_up.txt Catch Me Up
find_similar.txt Find Similar
decompose.txt Decompose
release_notes.txt Release Notes
dependency_analysis.txt Dependency Analysis
ai_chat.txt AI Chat
daily_briefing.txt Daily Briefing
summarize_test_plan.txt Summarize Test Plan
coding_agent_initial.txt Coding agent initial run prompt

Default prompts are here:

internal/llm/prompts/

Important: ai_chat.txt contains four runtime placeholders — %s (today's date), %s (current user's name), %d (user ID), and %d (assignee ID for "my items" lookups), in that order. Preserve all four in the same order when overriding this prompt.

Coding agent runner

See Coding Agent Runner for the full deployment guide.

Env var Default Description
CODING_AGENT_RUNNER_IMAGE - Enables the local in-process coding-agent runner with this container image.
CODING_AGENT_DOCKER_BINARY docker Docker executable path/name.
CODING_AGENT_WORKTREE_ROOT - Host path for prepared worktrees. Required when the runner image is set.
CODING_AGENT_GLOBAL_CAP 8 Max concurrent local agent runs.
CODING_AGENT_WS_API_URL BASE_URL API URL agent containers use to reach Windshift. Override when BASE_URL is not reachable from containers. Must end in /api.
CODING_AGENT_NETWORK coding-agent-egress Docker network for agent containers.
CODING_AGENT_PIDS_LIMIT 512 Container PID limit.
CODING_AGENT_MEMORY 4g Container memory and memory-swap limit.
CODING_AGENT_CPUS 2 Container CPU limit.
CODING_AGENT_LLM_MODEL - Fallback LLM model for agent containers. Usually configured per binding instead.

Remote runner hosts use WSRUNNER_* variables in the runner process or runner container, not in the Windshift server process. See Coding Agent Runner for the supported Docker runner compose file and the full remote-runner configuration table.

Notifications, Jira, and sidecars

Env var Default Description
NOTIFICATION_FLUSH_INTERVAL built-in Notification write-batcher flush interval, Go duration such as 5s.
NOTIFICATION_BATCH_SIZE built-in Notification write-batcher batch size.
NOTIFICATION_SYNC_INTERVAL built-in Notification synchronization interval.
WINDSHIFT_NOTIFICATION_BATCH_INTERVAL built-in Email notification batch scheduler cadence.
JIRA_CAPTURE_PAYLOADS - Directory for Jira import request/response payload debugging.
LOGBOOK_ENDPOINT - URL of a Logbook sidecar service, if used.

Examples

Minimal SQLite

SSO_SECRET=$(openssl rand -hex 32) \
BASE_URL=http://localhost:8080 \
./windshift --db /data/windshift.db

Production behind a reverse proxy

./windshift \
  --postgres-connection-string "postgres://windshift:secret@db:5432/windshift?sslmode=require" \
  --use-proxy \
  --allowed-hosts windshift.example.com \
  --base-url https://windshift.example.com \
  --attachment-path /data/attachments \
  --log-level info \
  --log-format json

Local LLM on the host

LLM_ALLOWED_PRIVATE_CIDRS=127.0.0.1/32,::1/128 \
./windshift --base-url http://localhost:8080

Then add a Local / Custom AI connection in the UI with http://localhost:11434/v1.