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 32Keep 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, andDB_REQUEST_TIMEOUT. - CLI flag wins:
ALLOWED_HOSTS,BASE_URL,WINDSHIFT_CONTEXT_PATH,LLM_PROVIDERS_FILE, andAI_PROMPTS_DIR. - Boolean settings combine: An enabled flag or a
trueenvironment variable enables the setting. A flag cannot disable a setting that its environment variable enables. This includesUSE_PROXY,DISABLE_PLUGINS,SSH_ENABLED,CODING_AGENT_ENABLED, andALLOW_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_URLsuch ashttp://myhost.internal:8080fails at startup withFailed to create CORS middleware ... insecure origin patterns. Credentialed CORS refuses insecure origins other than localhost. Serve HTTPS through a reverse proxy withUSE_PROXY=true, or directly with--tls-certand--tls-key. On a trusted LAN, you can setALLOW_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=/windshiftSecrets 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=infoPlugins
| 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=trueThis 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_CIDRSandLLM_ALLOWED_PRIVATE_CIDRS. Windshift ignores these removed variables. UseALLOW_LOCAL_CONNECTIONSinstead.
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=trueSee 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/v1or:
http://172.17.0.1:11434/v1Only 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:
Important:
ai_chat.txtcontains 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.dbProduction 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 jsonLocal LLM on the host
ALLOW_LOCAL_CONNECTIONS=true \
./windshift --base-url http://localhost:8080Then add a Local / Custom AI connection in the UI with http://localhost:11434/v1.