-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration
Everything is read from environment variables. docker compose loads them from
.env in the repository root, which ./scripts/gen-env.sh creates for you.
Never commit a filled-in .env — the shipped .gitignore already excludes it.
With the default ENVIRONMENT=production the coordinator refuses to boot if
any of these is missing, blank, or shorter than 32 characters. That is
deliberate: HS256 signs happily with an empty key, so a half-filled template
would otherwise leave your token-signing secret publicly known — anyone could
forge an owner session.
./scripts/gen-env.sh generates all of them.
| Variable | Generate with |
|---|---|
WRIT_JWT_SECRET |
openssl rand -hex 32 |
API_SECRET_KEY |
openssl rand -hex 32 |
HMAC_SECRET_KEY |
openssl rand -hex 32 |
RECORDER_AUTH_SECRET |
openssl rand -hex 32 |
INTERNAL_API_SECRET |
openssl rand -hex 32 |
GATEWAY_SECRET |
openssl rand -hex 32 |
DOC_EXTRACT_SECRET |
openssl rand -hex 32 |
SECRET_ENCRYPTION_KEY |
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
WRIT_JWT_SECRET is the operator-facing name; compose maps it onto the
JWT_SECRET_KEY the app reads. Set one, not both.
It encrypts stored credentials, TOTP seeds and cookies at rest. A database backup without it cannot be decrypted. Replacing it is as destructive as losing it — every persona and secret already stored becomes unreadable, with no error at boot. See Backup and restore.
| Variable | Default | What it does |
|---|---|---|
WRIT_PUBLIC_URL |
— | Public base URL, e.g. https://writ.example.com. Agents dial back using this, so it must be reachable from wherever they run. Getting it wrong is the most common cause of an agent that never connects. |
ALLOWED_HOSTS |
— | Comma-separated hostnames this coordinator answers on, no scheme or port. Spoofed Host headers are rejected in production. |
CORS_ORIGINS |
http://localhost:8000 |
Comma-separated allowed origins. * is refused in production. |
WRIT_SOURCE_URL |
https://github.com/usewrit/writ |
Where the corresponding source of this build can be obtained. Change it if you deploy a modified build — AGPL §13. |
ENVIRONMENT |
production |
production enforces strong secrets, a Host allowlist and non-wildcard CORS. |
FORWARDED_ALLOW_IPS |
127.0.0.1 |
Which proxy IPs may set X-Forwarded-For. Never set this to * — it lets any client spoof its IP and bypass every per-IP control. |
| Variable | Default | What it does |
|---|---|---|
DOC_EXTRACT_URL |
http://127.0.0.1:8092 |
Where the extractor is as your agents see it. Agents call it directly; the coordinator never does. Blank turns the lane off. |
DOC_EXTRACT_SECRET |
— | Shared secret. Required in production. |
DOC_EXTRACT_OCR_MODE |
auto |
auto reads the text layer and OCRs only true scans. off never OCRs. force OCRs everything. |
The coordinator hands these to each agent at connect time, so co-located agents need no configuration. Agents on other machines cannot reach a loopback address — see Documents and OCR.
| Variable | What it does |
|---|---|
WRIT_ADMIN_EMAIL / WRIT_ADMIN_PASSWORD
|
Provision the owner automatically on first boot. Leave unset to register through the UI instead. |
WRIT_ADMIN_NAME |
Display name for that account. |
| Variable | Default | What it does |
|---|---|---|
WRIT_DB_PATH |
/data/writ.db (in Docker) |
The SQLite file. Pinned to the volume by compose. |
WRIT_FILES_DIR |
/data/files (in Docker) |
Where screenshots and uploads are written. Leave it set — without it they are base64-encoded into the database and bloat it. |
FILE_MAX_BYTES |
104857600 (100 MB) | Per-file hard cap. |
RUN_RETENTION_DAYS |
90 | Days before run records are purged. |
LOG_RETENTION_DAYS |
90 | Days before audit/event logs are purged. |
DETECTED_CHANGE_RETENTION_DAYS |
90 | Days before detected-change records are purged. |
| Variable | Default | What it does |
|---|---|---|
ALLOW_PRIVATE_TARGETS |
false |
Whether monitored/crawled/webhook targets may resolve to private or loopback addresses. Leave false unless you deliberately monitor an internal host — it is the SSRF guard. |
TARGET_DOMAIN_RATE_LIMIT |
30 | Max runs dispatched against one target host per window. |
TARGET_DOMAIN_RATE_WINDOW_SECS |
60 | That window, in seconds. |
RATE_LIMIT_REQUESTS / RATE_LIMIT_WINDOW
|
100 / 60 | Generic API rate limit. |
MAX_CONCURRENT_RUNS |
5 | Scheduled runs dispatched to the fleet at once. |
QUORUM |
2 | Agents that must agree before a change is confirmed. |
| Variable | Default | What it does |
|---|---|---|
REQUIRE_ADMIN_MFA |
false |
Require TOTP or a passkey for admin endpoints. The coordinator warns at boot while this is off. Enrol a second factor first, then enable it — otherwise you lock yourself out. |
REGISTRATION_ENABLED |
true |
The coordinator is single-owner; registration self-closes once the owner exists. |
LOGIN_ENABLED |
true |
Set false for an emergency lockdown. |
MAINTENANCE_MODE |
false |
Non-admin requests get 503. |
| Variable | Default | What it does |
|---|---|---|
LOG_LEVEL |
info |
critical…trace. |
WRIT_EXPOSE_OPENAPI |
false in production |
Serve /openapi.json, /docs and /redoc. Off in production because the schema enumerates every route to anyone who reaches the host, and nothing in the product reads it at runtime. |
ALLOW_INSECURE_DEV |
false |
With ENVIRONMENT=development, permits the insecure default secrets. Local throwaway only.
|
WRIT_AGENT_REPO |
usewrit/writ-agent |
Where generated install commands fetch the agent. Point at your fork. |
WRIT_AGENT_DOCKER_IMAGE |
ghcr.io/usewrit/writ-agent:latest |
Image used in the generated Docker command. |
Optional; configure whichever you use. SMTP (SMTP_HOST, SMTP_PORT,
SMTP_USERNAME, SMTP_PASSWORD, SMTP_FROM_EMAIL, SMTP_USE_TLS), Pushover
(PUSHOVER_APP_TOKEN, PUSHOVER_USER_KEY) and Twilio (TWILIO_ACCOUNT_SID,
TWILIO_AUTH_TOKEN, TWILIO_FROM_PHONE, TWILIO_TO_PHONE) are driven against
your own accounts — no third party sits in between.
GET /api/fleet/connect-info (admin) reports the agent WS URL and whether the
document-extraction lane is enabled. GET /health reports database and cache
health without authentication.
usewrit/writ · AGPL-3.0-only · Issues · Discussions · Report a vulnerability
Getting started
Using it
Integrations
Operations
Reference