Environment overrides¶
This page covers every environment variable the application reads, generated
from the live settings model. Environment overrides are advanced deployment
and development configuration: every user workflow works without them through
prompts, command flags, and aeat config commands. Set an override only when
you administer a deployment and know why the default does not fit.
An annotated template with the same variables lives at env/.env.example in
the repository. The application itself reads only the process environment;
env/.env is not a production source. For local development and the test
suite, the repository’s conftest.py bridges env/.env into the process
environment before tests run, filling only variables not already set; a
value already present in your shell always wins.
Variable |
Type |
Default |
What it controls |
|---|---|---|---|
|
str |
|
Authoritative language for domain terminology (modelos, registry definitions, references). |
|
str |
(derived) |
AEAT sede electrónica base URL |
|
str |
(derived) |
URL template for AEAT’s auth-method selector page used by the Cl@ve Permanente login flow. |
|
str |
(derived) |
URL template for AEAT’s auth-method selector page. |
|
Path |
(derived) |
Root directory for the structured AEAT Manual práctico corpus |
|
Path |
(derived) |
Root directory for the bundled legal normatives corpus |
|
str |
(derived) |
AEAT Sede path for «Mis expedientes»; the default post-auth target used by Cl@ve Móvil login and the expedientes reader. |
|
str |
(derived) |
URL path template for an expediente detail page. Must contain «{expediente_id}». Override only when AEAT changes the corresponding route. |
|
str |
(derived) |
URL path for the «Mis notificaciones» listing page. Joined against aeat_base_url. Override only when AEAT changes the corresponding route. |
|
Path |
(derived) |
Root directory for the attachment byte and manifest store |
|
int |
|
Acquisition lock TTL (seconds) for certificate-backed AEAT auth flows |
|
int |
|
Headroom (seconds) added to |
|
AuthProviderKind |
unset |
Default auth provider for |
|
int |
|
Playwright navigation timeout for protected AEAT authentication in milliseconds |
|
str |
|
Authoritative language for internal code and documentation |
|
Path |
unset |
Directory holding the published registry authority descriptor |
|
Path |
(derived) |
Directory containing the encrypted blob store (content-addressed, classification-aware) |
|
int |
|
Settle delay (ms) after the AEAT «Buscar» button before reading the results table |
|
str |
|
Playwright browser channel to use (e.g., «chrome», «chromium», «msedge») |
|
int |
|
Best-effort timeout (ms) for Playwright browser context/session cleanup during AEAT live auth and read flows. Cleanup must not leave a command hanging after the primary operation has already failed or timed out. |
|
int |
|
Timeout for individual form interactions (fill/click/wait) in milliseconds |
|
bool |
|
Run browser in headless mode |
|
str |
|
Default browser locale passed to Playwright context (BCP-47 tag) |
|
int |
|
Default Playwright navigation timeout (milliseconds) for AEAT sede pages |
|
int |
|
Selector visibility probe timeout (ms) used by GROI/NIF-IVA check stages |
|
str |
|
Default IANA timezone string passed to Playwright context |
|
int |
|
Timeout (ms) for the AEAT declarations «Ver» button click and navigation |
|
int |
|
Default Playwright viewport height (px) for AEAT sede sessions |
|
int |
|
Default Playwright viewport width (px) for AEAT sede sessions |
|
int |
|
Fallback idle-lock window (minutes) when a bucket manifest omits the value |
|
int |
|
Fallback absolute session-lifetime cap (minutes) when a bucket manifest omits session_absolute_minutes; fixed at login and never refreshed, so a touched-forever session still seals at this cap (default 4 h, 12 h hard ceiling) |
|
float |
|
Polling interval (seconds) for bucket lockfile acquisition retries |
|
float |
|
Delay (seconds) waiting for Google Sheets server-side recalculation between parity polls |
|
int |
|
Critical threshold (days) for the certificate pre-expiry gate: certificates with <= this many days remaining are CRITICAL and must be renewed before authenticated AEAT work continues |
|
int |
|
Warning threshold (days) for the certificate pre-expiry gate: certificates with <= this many days remaining are surfaced as WARN |
|
str |
unset |
Optional human-readable label for the certificate |
|
SecretStr |
(secret) |
PKCS#12 passphrase (env only, never logged or persisted) |
|
Path |
unset |
Filesystem path to the operator’s PKCS#12 (.p12/.pfx) bundle |
|
str |
unset |
DNI validity / expiry date (YYYY-MM-DD) used by the non-QR Cl@ve Móvil fallback form. Applies when the configured identity is a DNI. |
|
SecretStr |
(secret) |
Taxpayer DNI/NIE for |
|
SecretStr |
(secret) |
NIE support number (número de soporte) used by the non-QR Cl@ve Móvil fallback form. Applies when the configured identity is a NIE. AEAT-regulated personal identifier; typed as SecretStr to prevent leakage. |
|
int |
|
Maximum time (milliseconds) the Cl@ve Móvil provider waits for AEAT browser-side authentication completion before aborting. Production runs must fail fast enough for an operator to retry deliberately rather than leaving a pending request dangling. |
|
SecretStr |
(secret) |
Taxpayer DNI/NIE for |
|
SecretStr |
(secret) |
Cl@ve Permanente password for the DNI/NIE + password login form. Same treatment as the certificate passphrase: env var only, never stored in a committed env file, never logged. |
|
int |
|
Maximum time (milliseconds) the Cl@ve Permanente provider waits for the AEAT/Cl@ve IdP login form round-trip to complete before aborting. Routine Cl@ve Permanente login is headless-automatable (DNI/NIE + password, no SMS), so this window is shorter than the human-in-the-loop Cl@ve Móvil timeout. |
|
bool |
|
When true, the Cl@ve Móvil provider uses the non-QR fallback (DNI/NIE + contraste) rather than the QR code. This still requires operator-mediated completion in Cl@ve. |
|
bool |
|
Reveal raw profile and bucket identifiers in CLI success output instead of the paste-safe |
|
Path |
(derived) |
Directory for the corpus-search lexical index (a SQLite database built from bundled normative extractions and rebuilt when their exact content identity changes) |
|
str |
empty |
SQLAlchemy URL for the primary persistence backend. When empty, the model validator resolves the URL through the active-profile precedence chain to |
|
int |
|
Days before an obligation’s closes_on date that flag ObligationStatus.DUE_SOON in the deadline engine |
|
SecretStr |
(secret) |
Development/test-only password used by secure-storage subprocess tests. |
|
bool |
|
If true, build_draft raises FilingValidationError when any WARNING- or ERROR-severity finding is produced |
|
Path |
(derived) |
Directory where filing drafts are written as JSON files |
|
bool |
|
Whether this deployment permits reading taxpayer evidence at an off-host model at all. Default off: every evidence read stays on the host. When True, an explicit per-invocation operator acknowledgement is still required for each read, and gestor deployments stay barred. |
|
bool |
|
Gestor/professional deployment flag for evidence reading. When True, an off-host evidence read is categorically refused regardless of cadrumo_evidence_cloud_upload_permitted or any per-invocation acknowledgement. |
|
str |
|
Comma-separated fallback chain consulted when the target language is missing. |
|
float |
|
Sleep interval (seconds) between non-blocking file-lock acquire attempts |
|
float |
|
Default exclusive file-lock acquisition timeout (seconds) |
|
Path |
(derived) |
Directory for filed-declaration observations captured from AEAT. Derived under cadrumo_local_storage_root unless explicitly set. |
|
bool |
|
If true, archive fetched detail-page HTML under <cadrumo_filing_history_dir>/pages/ |
|
int |
|
TTL in seconds for per-expediente filing-history cache entries (default 15 min) |
|
Path |
(derived) |
Directory where the persisted ModeloHistory JSON file lives |
|
Path |
(derived) |
Directory where the transaction catalogue JSON file is stored |
|
bool |
|
Force ANSI colour output even when stdout is not a TTY. Operators set this when piping Cadrumo output through a terminal renderer (less -R, gh actions, etc.). Defaults to False; the should_use_color() helper consults this and the standard NO_COLOR convention through Settings rather than reading os.environ directly. |
|
int |
|
Timeout (seconds) for one ECB Data Portal euro reference-rate lookup. A ledger import resolves one lookup per distinct currency/date, so this budget bounds a single observation query rather than the whole import. |
|
str |
unset |
Drive folder ID under which |
|
str |
|
Folder name created under the Google Drive root for the Cadrumo vault |
|
int |
|
Clock-skew buffer (seconds) before nominal expiry when refreshing Google access tokens |
|
int |
|
Lead window (days) for notification deadline reporting: surface CRITICAL/HIGH notifications whose appeal_deadline falls within the next N days |
|
Path |
(derived) |
Directory where the invoice catalogue JSON file is stored |
|
Path |
(derived) |
Directory for Modelo 303 compensation-history capture reports. Derived under cadrumo_local_storage_root unless explicitly set. |
|
Path |
(derived) |
Directory for IVA remote-state read-evidence reports. Derived under cadrumo_local_storage_root unless explicitly set. |
|
JustificanteParserBackendSetting |
|
Parser backend for |
|
Path |
(derived) |
Directory where parsed justificante PDFs and metadata are stored |
|
int |
|
Timeout (ms) for one AEAT filed-declaration register query for a single modelo/year. Bulk filed-history reads use this per-query budget so one slow modelo cannot block all later modelos from returning typed failures. |
|
int |
|
Drain delay (ms) after a bounded live IVA read surface is cancelled, giving Playwright browser tasks time to report cancellation-only errors before the loop handler is restored. |
|
int |
|
Top-level CLI watchdog timeout (ms) for the combined read-only IVA remote-state command. This must exceed the normal auth and surface budgets but remain below operator shell/tool timeouts so the CLI can cancel and clean up inside its own process. |
|
int |
|
Timeout (ms) for one Modelo 303 filed-declaration observation inside a combined live IVA filed-history read. Must be lower than the outer live IVA surface timeout so partial filed-history failures can return a structured report before the whole surface is cancelled. |
|
int |
|
Outer timeout (ms) for each live IVA read surface inside a combined remote-state acquisition. Individual browser stages have their own shorter timeouts; this bounds the whole filed-history or wallet/cartera surface. |
|
Path |
(derived) |
Directory for live AEAT state and remote-state evidence |
|
str |
empty |
Opt-in flag (set to «1») to run @pytest.mark.aeat_live tests against real external services |
|
str |
empty |
Opt-in flag (set to «1») to run @pytest.mark.aeat_live Google (OAuth / Drive) tests against real Google services |
|
SecretStr |
(secret) |
Anthropic API key (env only, never logged) |
|
Path |
(derived) |
Directory for on-disk LLM cache entries |
|
int |
|
Maximum number of LLM response-cache entries retained; oldest excess entries are pruned |
|
int |
|
Retention window in days for on-disk LLM response-cache entries; older entries are pruned |
|
str |
|
Hosted model used to name what each column of a delimited table holds. The cloud counterpart of cadrumo_llm_ollama_mapping_model, kept separate for the same reason: column-role mapping is the easiest job in the product and must be sizeable DOWN independently rather than inheriting a harder role’s model |
|
str |
|
Hosted model used to classify an already-extracted text layer off-host. The cloud counterpart of cadrumo_llm_ollama_text_model. This model reads only extracted text and selects from the registry allow-list; it never emits a regulated number |
|
str |
|
Hosted model used to read scanned/image evidence when a request is routed off-host. The cloud counterpart of cadrumo_llm_ollama_vision_model, and it exists for the same reason the local roles do: without a role-named cloud setting every off-host read falls through to the single global cadrumo_llm_model, so each new cloud consumer silently re-inherits whatever tier that happens to name. Defaults to the lowest-bound capable current Claude model |
|
bool |
|
Admit a local model load even when free headroom could not be measured. Default false: an unreadable free figure fails CLOSED at the act, because «could not tell» is not evidence of headroom. Set true only on a machine known to have capacity that this build cannot read (a non-NVIDIA accelerator, or NVML absent because cadrumo[llm] is not installed). It does not override a MEASURED shortfall – a load whose requirement exceeds measured free memory is refused regardless of this setting |
|
int |
|
Headroom kept free ABOVE a model’s declared memory requirement before a load is admitted. A model does not occupy exactly its weight size: the KV cache grows with the context window, the runtime allocates scratch buffers, and the display server keeps taking frames while the read runs. Admitting a load that fits with zero margin is how a measured-safe load still ends as an OOM kill mid-read. 1 GiB covers the default 8192-token context plus normal desktop churn; raise it on a machine that also drives a display, lower it on a headless box |
|
int |
|
Default maximum output tokens when an LLM request omits |
|
float |
|
Default sampling temperature when an LLM request omits |
|
int |
|
Default timeout for LLM provider calls in seconds |
|
SecretStr |
(secret) |
Google Gemini API key (optional) |
|
str |
|
Google Gemini generateContent endpoint template ( |
|
int |
|
How many on-host inference requests this process may run at once. Default one, because two concurrent reads on consumer hardware are the same out-of-memory kill the contention check exists to prevent, reached by another route: each load individually fits the measured headroom, and together they do not. A request arriving while the arena is full is REFUSED rather than queued – a queued request would wait holding its decoded pages in the memory under pressure, and would run against headroom measured before it waited. Raise it only on a machine with headroom for a second concurrent model load; it does not bound off-host dispatch, which occupies none of this machine’s device memory |
|
int |
|
Maximum retry attempts for retryable LLM failures |
|
str |
|
Default LLM model identifier – the last-resort fallback for any request that names no model and belongs to no declared role. It previously carried a hand-typed frontier-tier identifier, which made it the single point where every unrouted call silently reached the most expensive tier available; the value is now read from the core model catalogue’s lowest-bound capable cloud default. Prefer a role-named setting (cadrumo_llm_cloud_vision_model and siblings) over this field: a caller resolving through a role gets a model chosen for its job, while this one is only a floor |
|
int |
|
Minimum total system memory the local model runtime needs before a vision read is worth attempting. Sized for the default vision model (qwen3-vl:2b, ~1.9 GB of weights) plus the 8192-token context window and normal OS residency, which is why the floor sits well above the weight size alone. Below it the runtime does not refuse – it loads and thrashes, or is killed mid-read, which reaches the operator as an unexplained timeout rather than as a hardware shortfall. Tunable because the floor tracks the configured model: raise it when overriding upward to a larger catalogued candidate |
|
str |
|
Local Ollama /api/chat endpoint; override for non-localhost Ollama deployments |
|
str |
|
Local Ollama model used to name what each column of a delimited table holds, from its header strings alone. Deliberately its own setting rather than sharing the text one: column-role mapping is strictly EASIER than the text read – a selection over a short closed vocabulary given a handful of short headers, not a document read – so it must be sizeable DOWN independently. Sharing the field would silently drag it upward the next time the text role needs a larger model. It defaults to the same qwen3:1.7b (Apache-2.0, ~1.4 GB), so it introduces no new hardware floor and no second model to pull. This model never emits a regulated number; it selects from the closed column-role vocabulary |
|
int |
|
Ollama context window (num_ctx) for local requests. The vision read sends the full registry allow-list prompt plus the encoded invoice image, which exceeds Ollama’s 4096 default; 8192 fits the prompt + image + output with headroom and still runs on consumer hardware |
|
str |
|
Local Ollama TEXT model used to classify a text-layer document on-host. Chosen under the same constraints that bind the vision default rather than beside it: qwen3:1.7b is Apache-2.0 and ~1.4 GB, comfortably under the declared memory floor, so a machine provisioned for the vision default is provisioned for this one. It replaces qwen2.5:3b, which is one of the two Qwen2.5 sizes released under the Qwen Research licence rather than Apache-2.0 – easy to miss, and the reason the licence flag is declared per candidate. This model reads only the extracted text and selects from the registry allow-list; it never emits a regulated number |
|
str |
|
Local Ollama vision model used to read scanned/image evidence on-host (the default, gestor-allowed posture); must be a multimodal model pulled into the local Ollama runtime. The default is the weakest catalogued candidate that clears the capability bars under a COMMERCIAL licence posture – qwen3-vl:2b, Apache-2.0, ~1.9 GB. It replaces qwen2.5vl:3b, which is measured-equivalent at this discipline but carries the Qwen Research licence and therefore bars commercial use. Every accepted value and its licence are declared in the core model catalogue; overriding to a research-licensed candidate is permitted and surfaces a licence advisory |
|
SecretStr |
(secret) |
OpenAI API key (optional) |
|
str |
|
OpenAI Chat Completions endpoint; override for OpenAI-compatible proxies |
|
LLMProvider |
|
Default LLM provider name |
|
Path |
(derived) |
Directory for append-only local LLM run-timing telemetry logs |
|
int |
|
Maximum number of local LLM run-telemetry records retained; oldest excess records are pruned |
|
int |
|
Retention window in days for local LLM run-telemetry records; older records are pruned |
|
Path |
(derived) |
Directory for append-only LLM usage JSONL logs |
|
int |
|
Maximum number of LLM usage records retained; oldest excess records are pruned |
|
int |
|
Retention window in days for LLM usage records; older records are pruned |
|
int |
|
Per-request timeout for the on-host local vision read; larger than the general LLM timeout because a local vision model on consumer hardware (CPU or a modest GPU) can take one to several minutes to read an invoice |
|
Path |
(derived) |
Root directory for the LocalFileSystemProvider backend. Each namespace becomes a subdirectory; each object is a |
|
Path |
unset |
Diagnostic-log root directory. The |
|
int |
|
Number of rotated cadrumo.log backups retained by the rotating file handler |
|
str |
|
Log level for the file handler installed by |
|
int |
|
Size cap (bytes) for cadrumo.log before the rotating file handler rolls over; default 10 MiB |
|
str |
empty |
Optional default CLI log level override: quiet, default, verbose, or debug |
|
str |
|
Root logger level installed by |
|
str |
|
Log level for the stderr handler installed by |
|
float |
|
HTTP timeout (seconds) for AEAT manual PDF downloads |
|
OutputLanguage |
|
Target ISO 639-1 language code for user-facing content. Invalid values coerce to None and fall back to the default. |
|
bool |
|
Whether profile-custody KDF calibration MEASURES the parameter grid on this host. True (the default, and the only production posture) samples real supervised derivations to pick the strongest grid point that still lands inside the operator latency band. False skips the measurement loop and adopts the fixed fallback point the calibrator already falls back to when the grid cannot be measured in time. This changes only whether the host is MEASURED, never how strongly a profile is wrapped: the fallback point is stronger than the measured band’s floor, and the derivation itself is the same real Argon2id through the same supervised worker. |
|
str |
empty |
Comma-separated list of domains to bypass the proxy |
|
SecretStr |
(secret) |
Password for proxy authentication |
|
str |
empty |
Proxy URL (e.g., «http://proxy.example.com:8080») |
|
str |
empty |
Username for proxy authentication |
|
float |
|
Minimum delay between AEAT requests in seconds |
|
Path |
(derived) |
Directory where run traces and JSONL event logs are persisted (one subdirectory per run_id, containing trace.json + events.jsonl) |
|
int |
|
Trace-store byte cap; after age pruning, remove oldest runs but always retain the newest |
|
int |
|
Retention window in days for per-run trace directories; older run directories are pruned |
|
SecretStr |
(secret) |
Passphrase that derives the encrypted-secret-store master key. With the default of None, the master-key loader refuses operation on None or empty values to preserve fail-closed behaviour. The environment name CADRUMO_SECRET_PASSPHRASE belongs to the separately governed programmatic substrate; CLI secret input uses explicit stdin or descriptor channels and does not fall back to this setting. |
|
Path |
(derived) |
Directory for the encrypted secret-store master-key file and ciphertext records |
|
str |
|
Backend for |
|
bool |
|
Raise instead of warn when AEAT credential artifact permission hardening fails |
|
Path |
(derived) |
Directory where ModeloPresentado JSON audit records are persisted |
|
str |
unset |
Remote telemetry collector URL, consumed by HttpTelemetrySink when a call site opts into real transmission. Unset means no dial target. |
|
bool |
|
Gestor/professional deployment flag. When True, remote telemetry emission is categorically refused regardless of cadrumo_telemetry_opt_in, cadrumo_telemetry_tier, or per-invocation consent. |
|
bool |
|
Whether this deployment permits transmitting remote telemetry at all. Default off: all telemetry stays local. When True, a per-invocation operator consent acknowledgement is still required for each emit, and cadrumo_telemetry_tier must not be «off». |
|
TelemetryTier |
|
Remote telemetry tier: «off» (no remote emission regardless of opt-in), «crash_only» (error/outcome counters only), or «full» (counters plus timing percentiles). Only remote_allowed=True metric keys are ever eligible for transmission at any tier. |
|
Path |
(derived) |
Directory for cached authentication token and lock files. The the relative default here is a placeholder: when the field is not explicitly set, the model validator roots it at |
|
TuiAppearance |
|
Appearance for the full-screen terminal surfaces. auto = follow the host terminal. light = the warm-paper appearance. dark = the low-light appearance. |
|
Path |
(derived) |
User-configured per-category usage ratio overrides |
|
Path |
unset |
Opt-in diagnostic capture directory for the IVA compensation wallet (cartera) read. The |
|
int |
|
Retention window in days for wallet diagnostic dump files; when the opt-in dump directory is configured, dump files older than this are pruned |
|
Path |
(derived) |
Directory where WorkflowResult JSON audit records are persisted |
|
str |
|
Fallback ISO 4217 currency used when a financial source omits a per-row currency |
|
str |
|
Preferred encoding attempted first when decoding financial CSV sources |
|
bool |
|
Disable ANSI colour output regardless of TTY state. Mirrors the widely-adopted no-color.org convention via the NO_COLOR environment variable; pydantic-settings reads NO_COLOR (uppercased field name) out of os.environ on Settings() instantiation, so the no-color convention is honoured without per-call-site os.environ reads. |
|
str |
(derived) |
AEAT Sede URL the site-health probe navigates to |
|
int |
|
Fallback Retry-After seconds when a 429/503 omits the header |
Secrets are never printed by the application and are marked (secret) above. Defaults marked (derived) are computed from the storage root or project location at runtime.