OpenOpps

OpenOpps docs / Reference

Configuration

Runtime settings, environment variables, and concurrency controls.

CLI-onlylocal ledgerconfiguration

OpenOpps loads settings from OPENOPPS_ environment variables and an optional local .env file. Unknown .env keys are ignored. Treat configuration as local runtime wiring: the CLI writes to the SQLite URL you point it at and reads plugins from the Python environment that launched the command.

Invocation Scope

Both invocation styles use the same settings model:

uv run openopps status
uv tool install -e .
openopps status

The editable uv tool install -e . path makes the openopps command available directly from the current checkout. Relative SQLite URLs such as sqlite:///openoppsdb.sqlite are resolved by the running process, so keep your working directory and OPENOPPS_DB_URL explicit when switching between projects or smoke-test databases.

Environment Variables

VariableDefaultPurpose
OPENOPPS_DB_URLsqlite:///openoppsdb.sqliteDatabase URL used by storage commands and sync jobs.
OPENOPPS_MAX_CONNECTIONS40Maximum HTTP connection pool size.
OPENOPPS_SOURCE_CONCURRENCY4Source adapter concurrency during source sync and provider health checks, not the isolated scout.
OPENOPPS_SOURCE_TIMEOUT_SECONDS900.0Maximum seconds one source adapter can run before timed-out skip.
OPENOPPS_SOURCE_FRESHNESS_SECONDS0.0Skip recently synced source catalogs during unscoped full-sync retries.
OPENOPPS_BOARD_CONCURRENCY16Concurrent ready board routes and board-scoped listing/detail work during job sync, route health checks, and providers that fan out across job pages.
OPENOPPS_JOB_ROUTE_TIMEOUT_SECONDS180.0Maximum seconds one executable provider route may run during job sync before OpenOpps records a timeout and continues with remaining routes.
OPENOPPS_JOB_ROUTE_FRESHNESS_SECONDS0.0Skip recently synced provider routes during job sync when above 0; 0 refreshes every selected route.
OPENOPPS_JOB_ROUTE_LIMITunsetCap stale or never-synced routes processed in one job sync; unset processes every selected route.
OPENOPPS_PROVIDER_CONCURRENCY12Concurrent provider route probes when OpenOpps detects executable job-board routes (for example during admin providers probe-routes). Not job-fetch parallelism.
OPENOPPS_WORKDAY_CONCURRENCY2Conservative limit for public Workday CXS careers-site requests.
OPENOPPS_DB_BATCH_SIZE500Batch size for SQLite writes.
OPENOPPS_HTTP_TIMEOUT30.0HTTP timeout in seconds.
OPENOPPS_RETRY_ATTEMPTS3Number of retry attempts for retriable upstream requests.
OPENOPPS_USER_AGENTopenopps/0.1 openopps@wyattowalsh.comUser agent sent to public source and provider endpoints.
OPENOPPS_CACHE_ENABLEDtrueEnables the shared JSON request cache in the SQLite database.
OPENOPPS_CACHE_TTL_SECONDS3600Default cache freshness window in seconds.
OPENOPPS_CACHE_REFRESHfalseBypasses cache reads while still updating successful responses.
OPENOPPS_CACHE_STALE_ON_ERRORfalseAllows eligible stale cache data after retryable upstream errors.
OPENOPPS_PLUGIN_AUTOLOADfalseExecute every discovered plugin entry point without allow-listing.
OPENOPPS_PLUGIN_DISABLEDemptyComma-separated plugin entry-point names to skip.
OPENOPPS_PLUGIN_ALLOWEDemptyComma-separated plugin entry-point names allowed to execute.
OPENOPPS_NO_INTROunsetSuppress the interactive startup portal animation.

Isolated discovery scout

The isolated scout uses a separate settings model (DiscoverySettings in src/openopps/discovery/settings.py). OPENOPPS_DISCOVERY_* budget fields are not part of OpenOppsSettings, do not load .env, and do not change openopps sync. Values must be canonical positive decimals. Invalid values fail closed without echoing the input.

Scout output is an explicit directory, not the operational database. openopps discovery scout --output /absolute/quarantine-root --json (also openopps admin sources scout) writes one evaluation quarantine bundle under that required --output path. There is no scout-output environment variable. OPENOPPS_DB_URL still names the CLI SQLite ledger for sync, cache, and admin db commands; the scout does not open or mutate that file, catalogs, Git, Kaggle, or Cloudflare.

VariableDefaultPurpose
OPENOPPS_DISCOVERY_WHOLE_RUN_TIMEOUT_SECONDS300Whole isolated invocation wall-clock limit (max 3600).
OPENOPPS_DISCOVERY_CHANNEL_TIMEOUT_SECONDS120Per-channel wall-clock limit (max 1800).
OPENOPPS_DISCOVERY_CHANNEL_QUERY_LIMIT20Trusted predeclared queries per channel (max 1000).
OPENOPPS_DISCOVERY_CHANNEL_REQUEST_LIMIT100Requests including retries, redirects, and pagination per channel (max 5000).
OPENOPPS_DISCOVERY_ORIGIN_LIMIT25Distinct validated public HTTPS origins per channel (max 500).
OPENOPPS_DISCOVERY_REDIRECT_LIMIT5Manually validated redirect hops per logical request (max 10).
OPENOPPS_DISCOVERY_PER_HOST_CONCURRENCY2Simultaneous connections per origin (max 16).
OPENOPPS_DISCOVERY_OVERALL_CONCURRENCY8Simultaneous requests across channels (max 64).
OPENOPPS_DISCOVERY_RESPONSE_MAX_BYTES1048576Decoded bytes admitted from one response (max 10485760).
OPENOPPS_DISCOVERY_AGGREGATE_RESPONSE_MAX_BYTES67108864Decoded bytes admitted across the invocation (max 268435456).
OPENOPPS_DISCOVERY_CANDIDATE_LIMIT1000Candidate occurrences per channel before remaining work is unstarted (max 10000).
OPENOPPS_DISCOVERY_RETRY_ATTEMPT_LIMIT3Total attempts per logical request (max 10).
OPENOPPS_DISCOVERY_PAGINATION_LIMIT20Pagination requests per logical enumeration (max 1000).
OPENOPPS_DISCOVERY_PARSER_MAX_DEPTH32Trusted structural nesting depth (max 128).
OPENOPPS_DISCOVERY_EVIDENCE_RETENTION_SECONDS86400Maximum age for exact verified quarantine evidence to be reusable by a later scout (max 604800).
VariablePublic/CI/offline valuePurpose
OPENOPPS_DISCOVERY_NETWORKdisabledGate flag for public CI, just ci-discovery / just source-discovery-*, and scripts/source_discovery_gates.py. Not a DiscoverySettings field.

Public CI (the discovery job in .github/workflows/ci.yml), local offline recipes, and other CI-shaped runs require OPENOPPS_DISCOVERY_NETWORK=disabled. The gate refuses any other value; unset defaults to disabled. Public CI replays committed sanitized fixtures and does not run a live scout.

A live scout schedule is a separate, unexercised maintainer authority gate. This page does not provision GitHub Actions schedule:, Cloudflare Cron, hosted runners, or a private live-network profile, and it does not document a live-scheduler environment as if one were enabled.

Remote content cannot raise a trusted limit. The scout does not use the runtime SQLite HTTP cache or stale-on-error behavior. See CLI for command strings.

Web app public data release

These variables configure the Fumadocs/Next.js host when it loads public search artifacts. They are not part of the CLI OpenOppsSettings model. Server and browser values should select the same v7 origin and channel; the NEXT_PUBLIC_ values are embedded into the browser build.

VariableDefaultPurpose
OPENOPPS_PUBLIC_DATA_ORIGINsite URLTrusted origin for server-side snapshot reads (never the request Host). Must be https:// in production unless the insecure override is explicit.
OPENOPPS_PUBLIC_DATA_CHANNELunsetSafe lowercase v7 channel, normally production. When unset, server consumers use the bounded v6 transition reader.
OPENOPPS_PUBLIC_DATA_ORIGIN_ALLOW_INSECUREunset (1 allows)Allow non-HTTPS origins. Implicitly allowed in development and Vercel preview.
OPENOPPS_PUBLIC_DATA_ORIGIN_ALLOW_HOSTSemptyComma-separated extra hostnames allowlisted in production (alongside the configured site host and VERCEL_URL).
NEXT_PUBLIC_OPENOPPS_PUBLIC_DATA_ORIGINunsetBrowser-visible v7 publication origin used by Jobs/Explorer and its search worker.
NEXT_PUBLIC_OPENOPPS_PUBLIC_DATA_CHANNELunsetBrowser-visible safe lowercase v7 channel; normally the same value as OPENOPPS_PUBLIC_DATA_CHANNEL.

When neither channel is set, the web app reads the committed v6 transition tree. When v7 is enabled, both browser and server clients resolve the channel once, validate the manifest, pin its immutable release, and verify each asset before use. Production origins require HTTPS. Server-side production origins must also pass the explicit hostname allowlist; add the Workers hostname to OPENOPPS_PUBLIC_DATA_ORIGIN_ALLOW_HOSTS when it differs from the site host.

OPENOPPS_PUBLIC_DATA_ORIGIN=https://openopps-data-production.<account-subdomain>.workers.dev
OPENOPPS_PUBLIC_DATA_CHANNEL=production
OPENOPPS_PUBLIC_DATA_ORIGIN_ALLOW_HOSTS=openopps-data-production.<account-subdomain>.workers.dev
NEXT_PUBLIC_OPENOPPS_PUBLIC_DATA_ORIGIN=https://openopps-data-production.<account-subdomain>.workers.dev
NEXT_PUBLIC_OPENOPPS_PUBLIC_DATA_CHANNEL=production

Local next start / Playwright e2e may use an explicitly allowed loopback origin. Do not enable OPENOPPS_PUBLIC_DATA_ORIGIN_ALLOW_INSECURE=1 in production merely to bypass a configuration error.

Examples

OPENOPPS_DB_URL=sqlite:///data/openopps.db uv run openopps admin db status
OPENOPPS_BOARD_CONCURRENCY=8 OPENOPPS_JOB_ROUTE_LIMIT=100 uv run openopps jobs sync --provider workday --metrics-json
OPENOPPS_PROVIDER_CONCURRENCY=4 uv run openopps admin providers probe-routes --source a16z --provider any --limit 25 --json
OPENOPPS_USER_AGENT='openopps/0.1 (contact: jobs@example.com)' uv run openopps admin sources test yc
OPENOPPS_DISCOVERY_NETWORK=disabled uv run python scripts/source_discovery_gates.py ci
uv run openopps discovery scout --output /absolute/quarantine-root --json

For repeated local use from the repository checkout, place values in .env at the repository root:

OPENOPPS_DB_URL=sqlite:///openoppsdb.sqlite
OPENOPPS_SOURCE_CONCURRENCY=4
OPENOPPS_SOURCE_TIMEOUT_SECONDS=900
OPENOPPS_SOURCE_FRESHNESS_SECONDS=0
OPENOPPS_BOARD_CONCURRENCY=16
OPENOPPS_JOB_ROUTE_TIMEOUT_SECONDS=180
OPENOPPS_JOB_ROUTE_FRESHNESS_SECONDS=0
OPENOPPS_PROVIDER_CONCURRENCY=12
OPENOPPS_CACHE_TTL_SECONDS=3600
OPENOPPS_PLUGIN_ALLOWED=trusted-plugin
OPENOPPS_PLUGIN_DISABLED=broken-plugin

DiscoverySettings ignores .env; do not put OPENOPPS_DISCOVERY_* or OPENOPPS_DISCOVERY_NETWORK in that file. Unscoped jobs sync targets all persisted ready routes. Use explicit CLI filters such as --source, --board, or --provider for one-off scoped syncs.

The Jobs and Explorer surfaces use the committed v6 snapshot only while no v7 channel is configured. Refresh that transition artifact with just web-search-index after updating the local kaggle/openoppsdb.sqlite export. See Public Data Releases for v7 configuration, governance, delivery, and cutover gates.

Docs-app telemetry is configured separately from CLI runtime settings. When instrumentation is enabled, keep collection env-gated: default to a no-op sink in local development, use local-event-lake for canonical raw events on persistent disk, and set OPENOPPS_POSTHOG_PROJECT_API_KEY only when a sanitized hosted product-analytics mirror is desired. Browser PostHog replay is a separate opt-in through NEXT_PUBLIC_OPENOPPS_POSTHOG_PROJECT_API_KEY; it remains gated by NEXT_PUBLIC_OPENOPPS_TELEMETRY_ENABLED=true, disables automatic PostHog pageview/autocapture events, masks text and inputs, disables network body/header capture, and leaves replay sampling plus trigger controls to the PostHog project. See Data Model for the event shape and Operations for operating guidance.

Flags vs Persistent Settings

Prefer flags for one run and environment variables for durable local policy:

NeedPrefer
Refresh one upstream read--refresh-cache
Always bypass cache reads in a shell/sessionOPENOPPS_CACHE_REFRESH=true
Narrow one job sync--source, --board, or --provider
Lower Workday pressure across all runsOPENOPPS_WORKDAY_CONCURRENCY=1 or 2
Cap one unscoped job sync batchOPENOPPS_JOB_ROUTE_LIMIT=500
Skip recently synced routes in job syncOPENOPPS_JOB_ROUTE_FRESHNESS_SECONDS=86400
Lower concurrent job-route executionOPENOPPS_BOARD_CONCURRENCY=8
Lower concurrent route probingOPENOPPS_PROVIDER_CONCURRENCY=6
Hide the animation once--no-intro
Hide the animation everywhereOPENOPPS_NO_INTRO=1
Bound one isolated scoutOPENOPPS_DISCOVERY_*
Write scout output--output <dir> (not OPENOPPS_DB_URL)
Keep public/CI/offline discovery gates offlineOPENOPPS_DISCOVERY_NETWORK=disabled

By default, discovered plugins are visible but not executed. Set OPENOPPS_PLUGIN_ALLOWED to run specific trusted entry points. If OPENOPPS_PLUGIN_AUTOLOAD=true, every discovered plugin is eligible unless its entry-point name appears in OPENOPPS_PLUGIN_DISABLED. Disabled entries are still skipped even if also allow-listed.

For CLI one-offs, prefer command flags such as --source and --refresh-cache over persistent environment changes.

Do not commit .env files with private or environment-specific values.

On this page