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.
SESSION_IP_BINDING Controls how Windshift handles a session that changes client IP address. Start with the default log mode.
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, DB_REQUEST_TIMEOUT, ALLOW_LOCAL_CONNECTIONS, and WINDSHIFT_MEMORY_LIMIT_MB.
  • 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, and CODING_AGENT_ENABLED.

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.
- SESSION_IP_BINDING log Handle a client-IP change on an existing session. Accepted values are log, strict, and off.

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 BASE_URL host WebAuthn relying-party ID. Use a hostname, or a full HTTP or HTTPS URL from which Windshift extracts the hostname.
- WEBAUTHN_RP_NAME Windshift Display name shown by authenticators.

Set BASE_URL and ALLOWED_HOSTS correctly before enabling passkeys/WebAuthn.

The RP ID resolves in this order: WEBAUTHN_RP_ID, then the hostname from BASE_URL, then the process host name. In a container the process host name is the container ID, which no browser will match, so set WEBAUTHN_RP_ID explicitly in containerized deployments. See WebAuthn relying-party ID in containers.

localhost is a valid RP ID. The development exception also permits WebAuthn over HTTP when the host is localhost. A single-label hostname such as windshift is not a valid RP ID for passkeys. Use a dotted hostname or localhost.

Windshift 0.8.5 and later accept values such as https://windshift.example.com:8443 for WEBAUTHN_RP_ID. Windshift stores only windshift.example.com as the protocol RP ID.

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.

Process memory and cache budget

Flag Env var Default Description
--memory-limit-mb WINDSHIFT_MEMORY_LIMIT_MB 2048 MiB Total Windshift process-memory budget. Values below 512 MiB fail at startup.

The environment variable wins when both forms are set. The value uses MiB.

Windshift derives two soft budgets from the process budget:

  • The Go runtime receives a soft heap target equal to 80% of the process budget.
  • BigCache receives 25% of the process budget, capped at 512 MiB.

The cache budget is shared by item, permission, notification, activity, and authentication caches. Cache eviction affects performance, not correctness. Windshift reloads an evicted value from persistent storage.

The Go target is not a hard RSS limit. Database allocations, goroutine stacks, memory-mapped files, and temporary request data can raise process RSS above it. Set the container memory limit to at least the Windshift process budget. Do not set a lower container limit and rely on garbage collection.

Administrators can inspect the resolved budget, cache capacity, entries, hits, misses, and evictions under Admin → Diagnostics → Cache memory.

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.
- TLS_SKIP_VERIFY false Disable certificate-chain and hostname verification for outbound TLS connections. Use only with trusted self-signed destinations.

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

Keep TLS_SKIP_VERIFY=false in production. If you set it to true, Windshift accepts unverified certificates for outbound HTTPS, SMTP, IMAP, and LDAP connections. This setting affects the whole process, not one integration.

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 true Allow server-side HTTP clients to reach local, loopback, and private-network addresses.

By default, Windshift allows server-side outbound HTTP to local, loopback, and private-network destinations. This affects SCM integrations, Jira import, LLM providers, webhooks, OIDC, and SMTP. Public endpoints work without configuration.

To restore blocking for private-address destinations, set the flag or environment variable to false:

./windshift --allow-local-connections=false
ALLOW_LOCAL_CONNECTIONS=false

Keep the default when Windshift must reach an internal endpoint. Examples include self-hosted Gitea or GitHub Enterprise, Jira Data Center, a private identity provider, a local LLM gateway, and an internal SMTP server:

ALLOW_LOCAL_CONNECTIONS=true

This global switch is not a per-endpoint allowlist. It permits egress to the entire private network. If you set it to false, integrations that use local or private endpoints cannot connect. Use network policy to keep sensitive endpoints, such as cloud metadata services and admin panels, out of reach of the Windshift host.

See Production-ready self-hosting for deployment profiles and a production checklist.

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 allows LLM calls to local and private endpoints. Public provider endpoints need no extra configuration. If you set ALLOW_LOCAL_CONNECTIONS=false, local or private models, such as Ollama, LM Studio, or an internal gateway, cannot receive inference requests or model-list refreshes.

ALLOW_LOCAL_CONNECTIONS=false

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.