Quickstart: Self-host on Node
Run the webhook server and one-shot review worker with shared SQLite state, OpenRouter and a managed sandbox.
Use an authorized checkout of son-of-anton-review on feat/cloudflare-native. The repository is recorded as private in the handoff, and the checkout has no LICENSE. Obtain access and terms from the owner; this is not an anonymous public-clone workflow. The operator-parity engine worktree and the UI worktrees are separate deployments.
1. Prepare the host
Use Node 25, matching the native image. Node 20 is not sufficient: the entrypoints import stores backed by node:sqlite / DatabaseSync. Install git, GitHub CLI (gh) and the dependencies from the authorized checkout:
node --version
git --version
gh --version
npm ciThe worker clones with gh repo clone, then uses git fetch and checkout operations. Its OS user needs working GitHub CLI and Git transport authentication for every reviewed private repository. A human can provision a restricted credential or complete gh auth login and gh auth setup-git under that user. App publishing credentials alone do not establish this clone authentication on Node; the broker-based clone wiring is native-runtime-only.
Use a dedicated service account. Do not hand an agent a broad personal token or print credentials to prove authentication.
2. Create a dedicated environment file
Neither entrypoint automatically loads .env. Create an owner-readable environment file outside the checkout, for example /etc/son-of-anton/engine.env, using approved secret tooling. Substitute your real values for the descriptive placeholders below. Do not overwrite an existing environment file or source an unreviewed shell file.
GITHUB_WEBHOOK_SECRET=YOUR_WEBHOOK_SECRET
GITHUB_APP_ID=YOUR_NUMERIC_APP_ID
GITHUB_APP_PRIVATE_KEY_PATH=/etc/son-of-anton/app.private-key.pem
GILF_DB_PATH=/var/lib/son-of-anton/anton.db
GILF_REVIEW_WORK_ROOT=/var/lib/son-of-anton/workspaces
GILF_REPOS=YOUR_OWNER/YOUR_REPOSITORY
GILF_CODEX_PROVIDER=openrouter
GILF_CODEX_MODEL=YOUR_APPROVED_OPENROUTER_MODEL
OPENROUTER_API_KEY=YOUR_MODEL_KEY
GILF_OPENROUTER_REQUIRE_FREE=1
GILF_VALIDATION_EXECUTOR=managed-e2b
E2B_API_KEY=YOUR_SANDBOX_KEY
GILF_E2B_TIMEOUT_MS=600000
PORT=8787Create the database parent directory and workspace directory with ownership assigned to the service user. Choose capacity for concurrent clones and persistent state; there is no source-backed universal CPU, RAM or disk minimum.
Important distinctions:
- Inline
GITHUB_APP_PRIVATE_KEY, if present, takes precedence overGITHUB_APP_PRIVATE_KEY_PATH. Configure one, not both. - The server exits 1 without
GITHUB_WEBHOOK_SECRET. Without App ID/key configuration it uses a recording publisher, so/healthcan succeed without live publication. GILF_REPOSseeds repository config, not a deny-by-default allowlist. Unlisted repos use defaults too. Restrict the App installation to intended repos and use explicit repository policy for additional exclusions.- Use the legacy provider/model names for this Node entrypoint.
worker.mjsdoes not pass provider/model arguments, and the runner constructor readsGILF_CODEX_PROVIDERandGILF_CODEX_MODEL, falling back tocodex/gpt-5.5. The modernresolveModelConfig()helper is not called on this path:GILF_MODEL_PROVIDER,GILF_MODELandGILF_MODEL_PRIMARYalone do not select the Node runner's model. Set an explicit valid OpenRouter model and approveGILF_OPENROUTER_REQUIRE_FREE=0deliberately for paid usage. The native entrypoint wires the modern pair separately. - E2B is the explicit choice here. Unset executor selection falls back through legacy validation config to Crabbox. Missing executor prerequisites are recorded as missing validation, not a host-execution fallback.
- The explicit E2B timeout avoids differing source defaults. See Upgrading.
OpenAI, Anthropic and Codex alternatives are documented under Model providers. Cloudflare Sandbox is not wired into the standalone Node worker.
3. Start the server
Run from the engine root, under the prepared service account:
node --env-file=/etc/son-of-anton/engine.env server.mjsThe server stays running. In another terminal:
curl --fail-with-body --silent --show-error http://localhost:8787/healthExpect ok: true and service: "son-of-anton-pr-review". The validation.provider field comes from legacy GILF_VALIDATION_PROVIDER and can say crabbox even when GILF_VALIDATION_EXECUTOR=managed-e2b selects E2B. Health is a listener/config probe, not a model, queue-drain or sandbox readiness check.
4. Configure GitHub and receive a PR event
A human creates/configures the App, installs it on selected repositories, and supplies its private key and webhook secret. See Requirements for permissions and subscriptions.
Expose the server through an approved HTTPS proxy or tunnel. Set the App webhook to your public /github/webhooks URL, using the same secret. Keep optional operator routes private.
Open a non-draft PR targeting main or dev, the default auto-review branches, or deliver a PR event for an existing PR. Confirm the delivery in GitHub. The Node command handler needs a stored PR head; installation alone does not populate one. An authorized owner, member or collaborator may then post a new comment:
@anton review@anton rerun requests another run. @anton status and @anton help can reply on Node once the head is stored. @gilf is a parser alias.
5. Drain and verify
In a separate terminal, with the same service user, environment and absolute database path:
node --env-file=/etc/son-of-anton/engine.env worker.mjsThe worker reconciles state, processes a bounded batch and exits. Defaults are one job and concurrency one; configure GILF_WORKER_MAX_JOBS and GILF_WORKER_CONCURRENCY for your workload. Re-run after another queued event, or schedule it as described in Run on a Node box.
Do not equate exit 0 or drained=0 with a successful review: per-job failures are collected by the drainer and can leave the process successful. With the optional sqlite3 CLI, inspect state read-only:
sqlite3 -readonly /var/lib/son-of-anton/anton.db 'SELECT review_key,status FROM review_runs ORDER BY rowid DESC LIMIT 10;'Match the run to the canary head, inspect its validation gaps, and confirm the actual GitHub review and check run. With App credentials present, Node publishes directly: GILF_PUBLISH_MODE=shadow is not a Node safety switch. Use an explicitly approved canary repository.
State and dashboard
For this quickstart, leave GILF_QUEUE_URL and GILF_QUEUE_DB_PATH unset so both processes use GILF_DB_PATH for queue and state. With no persistent paths they get separate in-memory stores/queues and cannot form a working two-process deployment. A remote queue does not replace the shared run store.
The optional Node dashboard needs both GILF_OPERATOR_UI_ENABLED=1 and GILF_OPERATOR_UI_TOKEN. An enabled dashboard with no token rejects requests. It is read-only and is not the expanded parity API or WorkOS UI.
Next: Agent onboarding, Secrets and keys, Environment reference.