Configuration Options

Configure Windshift with command-line flags or environment variables. Docker deployments usually use environment variables. The standalone binary can use either style. Do not set both for one setting because current releases do not use one precedence rule for every setting.

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 Optional browser-origin allowlist. It is derived from BASE_URL for a single-domain deployment; set it explicitly only when you need additional origins.
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

Current releases resolve flags and environment variables for each setting. Avoid setting both for one setting.

  • Environment variable wins: PORT, DB_PATH, POSTGRES_CONNECTION_STRING, ATTACHMENT_PATH, LOG_LEVEL, LOG_FORMAT, SSH_PORT, SSH_HOST, MAX_READ_CONNS, MAX_WRITE_CONNS, MAX_USER_CONCURRENCY, POSTGRES_REPLICA_COUNT, POSTGRES_CONNECTION_HEADROOM, and DB_REQUEST_TIMEOUT.
  • CLI flag wins: ALLOWED_HOSTS, BASE_URL, WINDSHIFT_CONTEXT_PATH, LLM_PROVIDERS_FILE, and AI_PROMPTS_DIR.
  • Boolean settings combine: An enabled flag or a true environment variable enables the setting. A flag cannot disable a setting that its environment variable enables. This includes USE_PROXY, DISABLE_PLUGINS, SSH_ENABLED, CODING_AGENT_ENABLED, and ALLOW_LOCAL_CONNECTIONS.

Built-in defaults apply when neither source provides a value. Until releases standardize this behavior, use one configuration style for each setting.

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 WINDSHIFT_CONTEXT_PATH - Optional subpath such as /windshift when served below a domain root.
--allowed-hosts ALLOWED_HOSTS derived from BASE_URL Comma-separated browser origins for CORS, CSRF, WebAuthn, and SSO redirect validation. This is not a Host-header request filter.
--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.
--allow-insecure-http ALLOW_INSECURE_HTTP false Allow browser access via plain http on non-localhost origins. Trusted LANs and testing only.
--additional-proxies ADDITIONAL_PROXIES - Comma-separated trusted proxy IPs in addition to private network ranges.
- FORM_EMBED_ORIGINS - Comma-separated origins permitted to embed public forms.
--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.

ALLOWED_HOSTS configures browser-security middleware. It does not reject requests based on their Host header. For a normal single-domain deployment, leave it unset. Windshift then derives the origin from BASE_URL. An explicit value overrides that derivation.

Plain HTTP is localhost-only by default. A BASE_URL such as http://myhost.internal:8080 fails at startup with Failed to create CORS middleware ... insecure origin patterns. Credentialed CORS refuses insecure origins other than localhost. Serve HTTPS through a reverse proxy with USE_PROXY=true, or directly with --tls-cert and --tls-key. On a trusted LAN, you can set ALLOW_INSECURE_HTTP=true. See Docker for details.

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

BASE_URL=https://example.com/windshift
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.
- SESSION_VALIDATION_CACHE_TTL 5s How long session-validation results are cached. Accepts a Go duration such as 5s.

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_SSLMODE disable TLS mode for a connection built from the split POSTGRES_* variables: disable, allow, prefer, require, verify-ca, or verify-full. Use require or stricter for remote or managed PostgreSQL.
- 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 30 Read connection pool size. On PostgreSQL this also sizes the pool (max open = this value, max idle = half). Keep it under the server's max_connections.
--max-write-conns MAX_WRITE_CONNS 1 SQLite write connection pool size.
--postgres-replica-count POSTGRES_REPLICA_COUNT 1 Number of Windshift replicas sharing PostgreSQL, used to validate the aggregate connection budget.
--postgres-connection-headroom POSTGRES_CONNECTION_HEADROOM 10 PostgreSQL connections reserved for migrations, administration, and other clients when validating the connection budget.
--db-request-timeout DB_REQUEST_TIMEOUT 12s Maximum database-work duration for normal HTTP requests. Accepts a Go duration such as 12s or 1m.
--max-user-concurrency MAX_USER_CONCURRENCY 16 Maximum simultaneous in-flight /api requests per authenticated user. 0 disables the cap.

Use POSTGRES_CONNECTION_STRING when possible. Use POSTGRES_* variables when Docker Compose or a secret manager makes separate values 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.

Private network egress

Flag Env var Default Description
--allow-local-connections ALLOW_LOCAL_CONNECTIONS false Allow server-side HTTP clients to reach loopback and private addresses.

By default, Windshift blocks server-side outbound HTTP to private, loopback, link-local, multicast, and CGNAT destinations. This covers SCM integrations, Jira import, LLM providers, OIDC, and webhooks. Public endpoints work without configuration.

If Windshift must reach an internal endpoint, enable the switch. Examples include self-hosted Gitea or GitHub Enterprise, Jira Data Center, a private identity provider, and a local LLM gateway:

ALLOW_LOCAL_CONNECTIONS=true

This global switch is not a per-endpoint allowlist. It opens egress to the entire private network. Enable it only when network policy keeps sensitive endpoints, such as cloud metadata services and admin panels, out of reach of the Windshift host.

Earlier releases used the per-endpoint allowlists OIDC_ALLOWED_PRIVATE_CIDRS and LLM_ALLOWED_PRIVATE_CIDRS. Windshift ignores these removed variables. Use ALLOW_LOCAL_CONNECTIONS instead.

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.
--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 select a model immediately. The Refresh button can still fetch the live catalog.

Local and internal LLM endpoints

By default, Windshift protects LLM calls from SSRF. Public provider endpoints need no extra configuration. Local or private models, such as Ollama, LM Studio, or an internal gateway, require the global private-egress switch. This applies to inference requests and model-list refreshes:

ALLOW_LOCAL_CONNECTIONS=true

See Private network egress for what this switch covers.

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 a provider, change default models, or route a provider through a proxy, copy the built-in catalog. Then point Windshift to 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. In order, they are %s (today's date), %s (current user name), %d (user ID), and %d (assignee ID for "my items" lookups). Preserve all four in this order when you override the prompt.

Coding agent runner

See Coding Agent Runner for the full deployment guide.

The coding-agent system is opt-in. Enable it with --enable-coding-agent or CODING_AGENT_ENABLED=true. The Windshift server dispatches runs to windshift-runner hosts. It does not run agent containers. The server reads only these two variables:

Flag / Env var Default Description
--enable-coding-agent / CODING_AGENT_ENABLED false Enable the coding-agent system (orchestration only).
CODING_AGENT_WS_API_URL BASE_URL + /api API URL agent containers use to reach Windshift. Override when BASE_URL is not reachable from containers. Must end in /api.

Configure the agent image, Docker binary, worktree and cache location, concurrency, and container resource limits on the runner host. Use WSRUNNER_* variables, not Windshift server variables. See Coding Agent Runner for the runner Compose file and the full WSRUNNER_* 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

ALLOW_LOCAL_CONNECTIONS=true \
./windshift --base-url http://localhost:8080

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