Configuration
lumen works with zero configuration. lumen.config.json in your project root (or the path in LUMEN_CONFIG) is for when you want to tune budgets, swap providers, or move the failure line.
The file
{
"providers": {
"keywords": "wikipedia-demand",
"serp": "ddg-serp"
},
"severityOverrides": {
"og-tags-missing": "warning"
},
"crawl": {
"maxPages": 250,
"maxDepth": 4,
"maxDurationMs": 600000,
"maxConcurrency": 5,
"perHostMinDelayMs": 500
},
"failThreshold": "warning",
"byok": {
"pagespeed": "LUMEN_PSI_KEY",
"crux": "LUMEN_CRUX_KEY",
"openpagerank": "LUMEN_OPR_KEY"
},
"plugins": []
}A missing file means full defaults. A malformed file, a non-object root, or an unknown key at a closed-vocabulary level is a ConfigError that lists the valid keys — lumen would rather refuse than guess what you meant.
Keys
| Key | What it controls |
|---|---|
providers | provider name per boundary (keywords, serp, pagespeed, crux, authority); unknown names are a config error listing the options |
severityOverrides | per-rule severity overrides by rule id |
crawl | budgets: maxPages, maxDepth, maxDurationMs, maxConcurrency, perHostMinDelayMs |
failThreshold | lowest severity that fails a run: error | warning | info | off (default error) |
byok | env-var NAMES for provider keys (values never enter the file) |
plugins | local plugin files implementing extra audit rules (Node-only) |
Crawl defaults
| Budget | Default | Note |
|---|---|---|
maxPages | 100 | hard-clamped at 10,000 |
maxDepth | 5 | link depth from the seed |
maxDurationMs | 300,000 | wall-clock stop; the report is marked incomplete |
maxConcurrency | 5 | global in-flight cap |
perHostMinDelayMs | 250 | per-host politeness floor |
Error behavior
- Unknown config keys fail loudly with the list of valid keys — at any closed-vocabulary level.
- Boundary inputs have defined behavior: non-http(s) URLs are rejected, oversized pages and sitemaps are capped and skipped with a reason, malformed robots.txt falls back to the conservative default, IDN hostnames are normalized.
- Provider failures are typed and carry the provider name, after bounded retries with exponential backoff and jitter (Retry-After honored).
- Interrupted runs produce a report labeled
incomplete: truewith a stop reason, safe to re-run without duplicated side effects. - Plugins are Node-only — dynamically loaded local rule files; they never load in the Worker.
Fetch safety & etiquette
All fetching goes through one guarded layer: http/https only, private / loopback / link-local targets refused, re-validated after every redirect hop, per-request timeouts. On the crawl side, robots.txt is respected by default (with a documented override if you own the site and insist), the User-Agent identifies lumen with a contact URL, sitemaps feed discovery, and each host is rate-limited. Treat other people’s servers the way you’d want your logs to look.
For provider keys and what each one sends, see providers & BYOK. For the rules all this feeds, see the rules reference.