Runs onSelf-hosted
On this page
Your server, your coordinator.
The open-core coordinator runs on hardware you own. The only requirement is Docker — no external database, cache or queue to operate, and no feature gates inside what ships.
install ▸ three commands
Stand it up.
install.sh
git clone https://github.com/usewrit/writ.git && cd writ
./scripts/gen-env.sh
docker compose up -d --build Then open http://localhost:8000 and create your account. The first build is slow because the document and OCR runtime is baked in, so extraction works offline from then on.
The coordinator launches no browsers itself. Nothing executes until you connect an agent — that is the whole design, not a limitation of the free tier.
Connect the first agent
In the app: Fleet → Connect a new agent, which mints a pairing code. Then, on the machine that will do the work:
connect-agent.sh
curl -fsSL http://localhost:8000/agent.sh | sh -s -- WRIT-4K2P-9XQ Pairing codes are single-use and expire in 15 minutes. The agent dials outbound to the coordinator, so there are no inbound ports to open on the machine.
domain ▸ one command
Public domain and HTTPS.
One command takes an install from localhost to a real hostname with a real certificate:
deploy.sh
./scripts/deploy.sh writ.example.com [email protected] - Checks Docker, the ports, and that your domain already points at this server.
- Writes every domain-derived setting into the env file, consistently.
- Brings up the bundled reverse proxy with automatic Let’s Encrypt certificates.
- Waits for the certificate and verifies the live HTTPS URL.
It is safe to re-run: use it to change the domain, to repair a half-finished deploy, or after a docker compose down. Existing secrets are never rotated.
Day-to-day
Ordinary Docker Compose, because that is all it is. Add --profile tls to any of these if you deployed with the reverse proxy:
operate.sh
docker compose logs -f
docker compose restart
docker compose down
# Removes the data volumes too — this deletes your data.
docker compose down -v
# Add --profile tls to any of these if you deployed with the reverse proxy.
docker compose --profile tls logs -f secrets ▸ eight required
Secrets the stack will not start without.
./scripts/gen-env.sh generates all eight for you. In production the stack refuses to start if any one of them is missing, blank, or shorter than 32 characters:
WRIT_JWT_SECRET |
API_SECRET_KEY |
HMAC_SECRET_KEY |
RECORDER_AUTH_SECRET |
INTERNAL_API_SECRET |
GATEWAY_SECRET |
DOC_EXTRACT_SECRET |
SECRET_ENCRYPTION_KEY |
Back up SECRET_ENCRYPTION_KEY somewhere separate from your data volume. It is the key your stored secrets are encrypted with. Lose it and those secrets cannot be recovered — not by you, and not by anyone else.
Production settings
Four settings carry real weight once you are past localhost:
| Setting | Why it matters |
|---|---|
WRIT_PUBLIC_URL | Load-bearing: agents dial it and the install script embeds it. Production refuses to start without it. |
ENVIRONMENT=production | Keep it. It is what enforces the secret strength and the rules below. |
CORS_ORIGINS | Set explicit origins. A wildcard is refused in production. |
FORWARDED_ALLOW_IPS | Set it when you run behind your own proxy, so client addresses are read correctly. |
runtime ▸ two containers
What actually runs.
Two containers, plus an optional reverse proxy. There is no external database, cache or queue for you to operate, back up or upgrade.
| Container | Port | What it is |
|---|---|---|
| Coordinator | 8000 | The API, the web app, and its own embedded database. |
| Document extraction | 8092 | Document and OCR extraction, bundled so it works offline. |
| Reverse proxy | 80 · 443 | Optional, under the tls compose profile. Automatic certificates. |
Both services expose a health endpoint, so your own monitoring has something to poll.
account ▸ single owner
The first account.
Set the admin email, password and name in the env file before first boot — or leave the password blank and finish setup in the browser, with the email pre-filled on the setup page.
WRIT_ADMIN_EMAIL | The owner’s email, or just the address pre-filled on the setup page. |
WRIT_ADMIN_PASSWORD | Leave blank to complete setup in the browser instead. |
WRIT_ADMIN_NAME | Display name for the owner account. |
This build is single-owner: once an account exists, a second registration attempt is refused with 403. There is no email-based password reset — recover with the bundled reset script, which you run on the server itself.
mcp ▸ writ-selfhost
Point an assistant at your own coordinator.
Your coordinator registers as writ-selfhost, on purpose — so it coexists with the Writ desktop app, which registers as writ, and with Writ Cloud, which registers as writ-cloud.
connect-mcp.sh
claude mcp add writ-selfhost -e WRIT_API_KEY=<YOUR_API_KEY> \
-- npx -y writ-mcp --url http://localhost:8000 mcp config — any Streamable-HTTP client
{
"mcpServers": {
"writ-selfhost": {
"type": "http",
"url": "http://localhost:8000/mcp",
"headers": { "Authorization": "Bearer <YOUR_API_KEY>" }
}
}
} The API key must carry the mcp:execute scope, or every call is refused. Add the resource scopes you want the assistant to have alongside it.
scope ▸ in and out
What is in the box, and what is not.
Included, with no feature gates
All of this ships in the self-hosted build and is not restricted by any plan:
- Recording and step editing
- The AI assistant in the recorder, using your own provider key
- Personas with TOTP and OTP, and warm sessions
- Running and scheduling
- Monitors — availability, certificates and change history
- Automations
- Distributed crawl across your own fleet
- Document and OCR extraction
- Publishing REST endpoints
- MCP tools
- An OpenAI-compatible chat surface
- Datasets, with export
Not in the self-hosted build
These are surfaces Writ operates rather than ships. They are absent, not degraded:
- The marketplace
- Billing and plan enforcement
- Multi-tenant organizations
- Managed AI — self-host is bring-your-own-key only
- Managed residential egress
- Provisioned cloud agents and autoscaling
- SSO and SCIM
- Scribe
upgrade ▸ license
Upgrades and license.
To upgrade, pull the repository and rebuild — the same three commands you started with, minus the clone.
Licensed AGPL-3.0-only, except the MCP connector (MIT) and the bundled fonts (SIL OFL 1.1). Because this is a network copyleft license, your install serves its own source offer at /api/about, linked from the login screen and from settings.
reference ▸ next
Keep going
Pairing codes, the fleet surface, and what runs where.
→ Where it runsDesktop, your own machines, or a server you own.
→ MCPThe same workflows as tools for any MCP client.
→ Managed endpointsPublish a workflow as a REST endpoint.
→ Notification channelsWire alerts to email, chat or a webhook.
→ Personas and secretsLogins, TOTP and warm sessions.
→faq
Self-hosting questions, answered.
What do I need on the server?
Why does nothing run after I bring the stack up?
What happens if I lose SECRET_ENCRYPTION_KEY?
How do I put it on a real domain with HTTPS?
Can I add a second user?
I forgot the admin password and there is no reset email.
end ▸ deploy
Clone it and bring it up.
Three commands to a working coordinator, one more to put it on your own domain.