Self-hosting
Day-2 operations
Metrics
Prometheus metrics are served at /metrics. It is gated with the rest of the API surface: once auth is on, it requires the service token, a session, or a read-only personal access token.
Worth alerting on:
| Signal | Why |
|---|---|
Episodic-memory gauge is false |
pgvector is unavailable and recall is silently off. |
| Review duration p95 | Budgeted at under 60 seconds webhook-to-comment. |
| Webhook error rate | A rise usually means a credential expired, not a code bug. |
Episodic memory and embedders
Recall lets a review cite what this repository did before. It stores embeddings in a vector column, so it needs pgvector — see install for the silent-degradation trap.
The embedder is selectable:
| Variable | Meaning |
|---|---|
GARBOARD_EMBEDDER |
hash (default), voyage, openai, openrouter |
GARBOARD_EMBEDDER_MODEL |
Override the provider’s default model |
GARBOARD_EMBEDDER_DIM |
The stored dimension — must match the model’s output |
GARBOARD_EMBEDDER_URL |
Redirect the provider endpoint (proxies, tests) |
The default is hash, offline, and it is also the fallback for every unconfigured path. That is what keeps garboard scan, garboard mcp and a keyless serve working with no network at all. A hosted embedder is an upgrade in recall quality, never a requirement.
If you change the dimension, the stored vectors are the wrong width. Re-embed, then widen the column:
ALTER TABLE episodes ALTER COLUMN embedding TYPE vector(<dim>);
A missing key or an unparseable dimension falls back to the offline embedder with a startup log line. It never fails the boot.
Outbound network
A self-hosted install makes outbound calls in exactly three cases, and you can switch all three off:
- A hosted embedder, if you configured one.
hashis offline. garboard schema sync, when you deliberately refresh the pinned provider CRD cache.- The Anthropic API, if you set a key, for prose and fixes.
The deterministic gate makes none of them.
Audit retention
GARBOARD_AUDIT_RETENTION_DAYS sets the retention window for the audit log; the default is to keep it forever. A periodic pruner enforces it, organisation-scoped.
Capacity
One binary and one Postgres. Scanning is budgeted at under two minutes per 500 resources, and reviews at p95 under 60 seconds from webhook to comment. Both are performance tests in the build rather than SLAs.
Reviews are the load, and reviews are bursty — a busy morning is many pull requests in a few minutes. Capacity planning is about the burst, not the daily total.
Health
/healthz returns ok. Note what it does not tell you: it says ok on any version, and it keeps saying ok when the database credential has expired — existing pooled connections keep working while new ones fail. If sign-in breaks while /healthz is green, suspect the database URL first.
