Self-Hosting
Run the production server — queue, approvals, runner — on your own infrastructure.
Production mode needs a server: it holds repo credentials, queues stakeholder requests, and runs the agent. Self-hosting is the primary deployment — your code and tokens never leave your infrastructure.
docker compose
git clone https://github.com/kyechan99/paintless
cd paintless
# 1. put a clone the runner may branch/commit/push in at ./repo
# 2. add a paintless.config.* to that repo (see Configuration)
# 3. cp .env.example .env and set PAINTLESS_ADMIN_KEY
docker compose upThe dashboard is at http://localhost:7328; the widget submits to
/api/requests.
Environment
| Variable | Purpose |
|---|---|
PORT | Port the server listens on (default 7328); --port overrides it |
PAINTLESS_REPO | Repository root the runner works in |
PAINTLESS_DATA | Request store path — SQLite (.db, default) or JSON (.json); swap the store via the RequestStore interface |
PAINTLESS_PROJECT_KEY | Required as x-paintless-key on submissions |
PAINTLESS_ADMIN_KEY | Required. Protects list/approve/reject and dashboard actions (Authorization: Bearer). Without it the server refuses to start, because approving a request runs the agent on your repository |
PAINTLESS_ALLOW_OPEN_TRIAGE | 1 starts anyway with triage wide open — only for an instance nothing else can reach |
PAINTLESS_TRUST_PROXY | 1 reads the client IP from x-forwarded-for. Set it only behind a proxy that sets the header; without it the rate limiter uses the socket address, which nobody can forge |
PAINTLESS_SUBMIT_RATE_LIMIT | Submissions per client IP per minute (default 20; 0 disables). Bodies over ~5MB are rejected with 413 |
PAINTLESS_PUSH_REMOTE | Push agent branches here before PR delivery (e.g. origin) |
GITHUB_TOKEN / LINEAR_API_KEY / ANTHROPIC_API_KEY | Destination and agent credentials |
Request lifecycle
widget/extension → POST /api/requests (project key)
→ pending (queued)
→ dashboard approve (admin key)
→ runner: branch → agent → commit → push
→ destinations fan out (PR, Linear, webhook…)
→ delivered — receipts (links) shown to the requester
No-agent routes skip the queue entirely: the request is delivered as a structured ticket at submit time.
Security posture
- Agent-created PRs always go through human review — the runner never merges.
- Approval-before-run is the default for anything that executes an agent.
- The runner works on a branch and restores the original checkout afterwards, succeed or fail.
- Screenshots may contain user data: treat the request store accordingly.
