NixOS Module Options#

Generated from the flake’s mkOption declarations with nix-options-doc, pinned as a flake input and run inside nix build .#docs — this page regenerates on every docs build and cannot go stale. just docs-gen runs the same script to refresh the working-tree copy for local serving.

options.compliance.evidence#

Structured attestation record for all applied SCF controls. Each entry contains: scf_id, name, domain, frameworks_covered, framework_references, config_applied, and assessment_objectives (with per-AO status and evidence text).

Inspect with: nix eval .#nixosConfigurations..config.compliance.evidence –json | jq .

Type: list of attribute set

Default: []

options.darwin.legacyCatalina.enable#

Whether to enable Pin to nixpkgs and nix-darwin 24.11 for Catalina compatibility.

Type: boolean

Default: false

Example: true

options.renderers.likec4.output#

LikeC4 DSL output directory containing topology.c4

Type: path

options.services.dell-idrac-fan-controller.checkInterval#

Seconds between each temperature check.

Type: signed integer

Default: 60

options.services.dell-idrac-fan-controller.cpuTemperatureThreshold#

CPU temperature threshold in °C. When exceeded, Dell’s default fan control will be re-enabled to protect hardware.

Type: signed integer

Default: 50

options.services.dell-idrac-fan-controller.disableThirdPartyPcieCoolingResponse#

Disable Dell’s default cooling response for third-party PCIe cards (which often lack temperature sensors and trigger aggressive cooling).

Type: boolean

Default: false

options.services.dell-idrac-fan-controller.enable#

Whether to enable Dell iDRAC fan controller service.

Type: boolean

Default: false

Example: true

options.services.dell-idrac-fan-controller.fanSpeed#

Fan speed as decimal (0-100%) or hexadecimal (0x00-0x64).

Type: signed integer or string

Default: 5

options.services.dell-idrac-fan-controller.idracHost#

iDRAC host address. Set to “local” for local IPMI access via /dev/ipmi0, or specify the IP address of your remote iDRAC.

Type: string

Default: "local"

options.services.dell-idrac-fan-controller.idracPasswordFile#

Path to file containing the iDRAC password. This is more secure than specifying the password directly.

Type: null or path

Default: null

options.services.dell-idrac-fan-controller.idracUsername#

iDRAC username (only needed for remote access).

Type: string

Default: "root"

options.services.dell-idrac-fan-controller.keepCoolingResponseStateOnExit#

Keep the third-party PCIe card cooling response state when the service exits. If false, resets to Dell default on exit.

Type: boolean

Default: false

options.services.dell-idrac-fan-controller.package#

The Dell iDRAC fan controller package to use.

Type: package

Default: pkgs.callPackage ../../pkgs/dell-idrac-fan.nix {}

options.tsunaminoai.actualBudget.dataDir#

Host directory bind-mounted at /data. Holds server-files/account.sqlite (hashed server password, budget-file index, session token) and user-files/*.blob (one blob per budget file). Single-digit MB in practice, so the btrfs root is fine — no kur LV needed.

Type: path

Default: "/var/lib/actual"

options.tsunaminoai.actualBudget.enable#

Whether to enable Actual Budget sync server.

Type: boolean

Default: false

Example: true

options.tsunaminoai.actualBudget.externalUrl#

Public URL Actual is served at (behind Cloudflare Access). Non-null drops the container publish to loopback, closes the firewall for port, and supplies ACTUAL_OPENID_SERVER_HOSTNAME — which is what Actual builds its OIDC redirect_uri from (<url>/openid/callback).

Type: null or string

Default: null

Example: "https://budget.inaba.network"

options.tsunaminoai.actualBudget.image#

Container image, pinned to a release tag (mirrors tsunaminoai.docPipeline.paperlessImage). Pinning is load-bearing here: upstream’s Dockerfile already creates an actual user (uid 1001) and chowns /data to it, but emits no USER directive, so the container still runs as root and the root-owned bind mount below works. If a future image starts dropping privileges, dataDir needs a chown to 1001:1001 before the bump.

Type: string

Default: "docker.io/actualbudget/actual-server:26.8.1"

options.tsunaminoai.actualBudget.oidcEnvFile#

sops EnvironmentFile enabling OIDC login. Must define ACTUAL_OPENID_DISCOVERY_URL, ACTUAL_OPENID_CLIENT_ID and ACTUAL_OPENID_CLIENT_SECRET. It cannot be rendered declaratively — these come from an Entra app registration created in the portal, and the client secret is displayed exactly once.

For Entra the discovery URL is https://login.microsoftonline.com//v2.0/.well-known/openid-configuration and the app needs <externalUrl>/openid/callback registered as a Web redirect URI.

The FIRST account to log in via OIDC becomes the permanent server owner and cannot be changed from the UI. Actual keys that identity off the USERINFO response (preferred_username ?? login ?? email ?? id ?? sub), and Entra’s userinfo endpoint does not return preferred_username — so the owner lands on email, or on the opaque sub GUID if the account has no mail attribute. Worth checking before that first login, because it cannot be changed afterwards.

Type: null or path

Default: null

Example: "/run/secrets/actual-budget/oidc-env"

options.tsunaminoai.actualBudget.port#

Host port for Actual Budget (HTTP). HTTPS = port + 1.

Type: port

Default: 5006

options.tsunaminoai.apple.clock24h#

Whether to enable Use 24-hour clock.

Type: boolean

Default: false

Example: true

options.tsunaminoai.apple.remapCapsLockToEscape#

Whether to enable Remap Caps Lock to Escape.

Type: boolean

Default: false

Example: true

options.tsunaminoai.autoUpgrade.allowReboot#

Whether autoUpgrade may reboot for kernel/initrd changes (default: human-gated).

Type: boolean

Default: false

options.tsunaminoai.autoUpgrade.dates#

OnCalendar time for the upgrade run.

Type: string

Default: "04:30"

options.tsunaminoai.autoUpgrade.enable#

Whether to enable pull-based auto-upgrade to the tagged release flake.

Type: boolean

Default: false

Example: true

options.tsunaminoai.autoUpgrade.flakeRef#

Flake ref to converge on (the moving ‘latest release’ pointer, served by the internal Forgejo mirror).

Type: string

Default: "git+http://voile:8418/tsunaminoai/nix-flake-final?ref=release"

options.tsunaminoai.autoUpgrade.mirrorApi#

Forgejo REST base (on the same mirror flakeRef fetches from) for the ‘not already ahead’ compare check. Unauthenticated — replacing the old github compare API + PAT, whose expiry silently froze fleet convergence (2026-08). If unreachable the guard skips the run rather than switching blind — see the fail-closed note in the header.

Type: string

Default: "http://voile:8418/api/v1/repos/tsunaminoai/nix-flake-final"

options.tsunaminoai.autoUpgrade.randomizedDelaySec#

Randomized delay added to the upgrade schedule.

Type: string

Default: "30min"

options.tsunaminoai.barcodeScanner.deviceName#

Case-insensitive substring matched against evdev input device names. The first matching device is grabbed exclusively. Inspect candidate names with cat /proc/bus/input/devices or evtest.

Type: string

Default: "Barcode"

options.tsunaminoai.barcodeScanner.discoveryPrefix#

Home Assistant MQTT discovery prefix.

Type: string

Default: "homeassistant"

options.tsunaminoai.barcodeScanner.enable#

Whether to enable HID barcode scanner -> MQTT bridge for Home Assistant.

Type: boolean

Default: false

Example: true

options.tsunaminoai.barcodeScanner.friendlyName#

Friendly name shown in Home Assistant.

Type: string

Default: "Kitchen Barcode Scanner"

options.tsunaminoai.barcodeScanner.id#

Short identifier used in MQTT topics and the HA unique_id.

Type: string

Default: "kitchen"

options.tsunaminoai.barcodeScanner.mqtt.host#

MQTT broker host (defaults to the Home Assistant Green broker).

Type: string

Default: "192.168.0.55"

options.tsunaminoai.barcodeScanner.mqtt.passwordFile#

Path to a file containing the broker password. Defaults to the sops secret declared by this module; override to point elsewhere.

Type: string

Default: config.sops.secrets."barcode-scanner/mqtt-password".path

options.tsunaminoai.barcodeScanner.mqtt.port#

MQTT broker port.

Type: port

Default: 1883

options.tsunaminoai.barcodeScanner.mqtt.username#

Broker username. Set to “” to connect without authentication.

Type: string

Default: "homeassistant"

options.tsunaminoai.barcodeScanner.topicPrefix#

Base MQTT topic. Scans publish to //state.

Type: string

Default: "barcode-scanner"

options.tsunaminoai.borg.enable#

Whether to enable Enable borg backups.

Type: boolean

Default: false

Example: true

Also declared in: - modules/nixos/borg/default.nix

options.tsunaminoai.borg.enableCron#

Whether to enable Enable cron job for borgwarehouse.

Type: boolean

Default: false

Example: true

options.tsunaminoai.borg.hostname#

Hostname for the backup.

Type: string

Default: config.networking.hostName

options.tsunaminoai.borg.repo#

Repo key for voile.

Type: string

Also declared in: - modules/nixos/borg/default.nix

options.tsunaminoai.ci.autoUpdate.branch#

Integration branch the update PR targets.

Type: string

Default: "master"

options.tsunaminoai.ci.autoUpdate.ciCommand#

Override the CI command .#update runs (sets UPDATE_CI_CMD). Leave null to use the app default (om ci run, the full fleet). Scope it here if some remote builders (e.g. darwin) aren’t reliably online.

Type: null or string

Default: null

Example: "om ci run '.#default'"

options.tsunaminoai.ci.autoUpdate.enable#

Whether to enable scheduled flake input update + om ci + auto-merged PR.

Type: boolean

Default: false

Example: true

options.tsunaminoai.ci.autoUpdate.gitUserEmail#

git author email for automation commits.

Type: string

Default: "flake-bot@inaba.network"

options.tsunaminoai.ci.autoUpdate.gitUserName#

git author name for automation commits.

Type: string

Default: "flake-bot"

options.tsunaminoai.ci.autoUpdate.notifyFailure#

Whether to enable webhook notification on failure.

Type: boolean

Default: false

Example: true

options.tsunaminoai.ci.autoUpdate.notifyStart#

Whether to enable webhook notification when a run starts.

Type: boolean

Default: false

Example: true

options.tsunaminoai.ci.autoUpdate.notifySuccess#

Whether to enable webhook notification on success.

Type: boolean

Default: false

Example: true

options.tsunaminoai.ci.autoUpdate.randomizedDelaySec#

Randomized delay added to the schedule.

Type: string

Default: "30min"

options.tsunaminoai.ci.autoUpdate.repoUrl#

HTTPS git URL of the flake repo (authenticated via the gh token).

Type: string

Default: "https://github.com/tsunaminoai/nix-flake-final.git"

options.tsunaminoai.ci.autoUpdate.schedule#

systemd OnCalendar cadence for the update run.

Type: string

Default: "Sun 03:00"

options.tsunaminoai.ci.autoUpdate.webhookUrl#

Discord webhook URL for notifications ({“content”: …} payload). This is interpolated into the script and lands in the world-readable /nix/store, so prefer webhookUrlFile for a real (secret) webhook.

Type: string

Default: ""

options.tsunaminoai.ci.autoUpdate.webhookUrlFile#

Path to a file containing the Discord webhook URL, read at runtime. Takes precedence over webhookUrl and keeps the URL out of the store/git. Point it at a sops secret.

Type: null or path

Default: null

Example: "config.sops.secrets.\"discord/notify-webhook\".path"

options.tsunaminoai.ci.autoUpdate.workDir#

Persistent working clone the timer maintains.

Type: string

Default: "/var/lib/flake-autoupdate/repo"

options.tsunaminoai.cloudflare.enable#

Whether to enable Cloudflare Zero Trust origin vhosts for public services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.cloudflare.monitorPublicEdge#

Whether to enable synthetic checks against the public URLs (https://) in addition to the loopback backends. Off by default: probes from this host egress via the myon exit node and Cloudflare — a flaky path that measures the tunnel, not the service.

Type: boolean

Default: false

Example: true

options.tsunaminoai.cloudflare.originAllowFrom#

Source IPs allowed to reach the identity-trusting origin vhosts when the tunnel runs on another host (ignored when tunnel.enable = true, which forces loopback).

Type: list of string

Default: ["10.0.0.2"]

options.tsunaminoai.cloudflare.origins#

Services exposed through Cloudflare Access; this attrset is the entire public surface.

Type: attribute set of submodule

Default: {}

options.tsunaminoai.cloudflare.tunnel.credentialsSecret#

sops secret holding the tunnel credentials JSON.

Type: string

Default: "cloudflare/tunnel-credentials"

options.tsunaminoai.cloudflare.tunnel.enable#

Whether to enable in-flake locally-managed cloudflared tunnel on this host.

Type: boolean

Default: false

Example: true

options.tsunaminoai.cloudflare.tunnel.tunnelId#

Cloudflare tunnel UUID (from cloudflared tunnel create).

Type: string

options.tsunaminoai.compliance.enable#

Whether to enable SCF compliance controls.

Type: boolean

Default: false

Example: true

options.tsunaminoai.compliance.exceptions#

Risk acceptances keyed by SCF control ID. A declared exception suppresses that control’s live monitoring rules (so the alert stops firing) and records the acceptance in compliance.evidence as risk_acceptance, so the attestation reports an accepted risk rather than silently claiming a pass.

Rule suppression is not automatic: the host must also pass these to the telemetry server that compiles the rules — tsunaminoai.telemetry.server.complianceExceptions.

Type: attribute set of submodule

Default: {}

Example:

{
  "LGO-02" = {
    monitors = ["lgo-02-auditd-active"];
    justification = "Host runs with kernel audit=0 (audit=1 caused queue-overflow spam).";
    acceptedBy = "Ben Craton";
    acceptedOn = "2026-08-12";
  };
}

options.tsunaminoai.compliance.exceptions.<name>.acceptedBy#

WHO accepted the risk (the accountable human).

Type: string

options.tsunaminoai.compliance.exceptions.<name>.acceptedOn#

WHEN the risk was accepted (ISO date).

Type: string

Example: "2026-08-12"

options.tsunaminoai.compliance.exceptions.<name>.justification#

WHY the risk is accepted. Required — an undocumented exception is indistinguishable from a broken control.

Type: string

options.tsunaminoai.compliance.exceptions.<name>.monitors#

Monitor names within this control whose live verification is waived. Empty list waives every monitor the control declares. Only the monitoring (alerting) is waived — the control’s configToApply still applies.

Type: list of string

Default: []

Example: ["lgo-02-auditd-active"]

options.tsunaminoai.compliance.exceptions.<name>.review#

Optional date to revisit the acceptance.

Type: null or string

Default: null

Example: "2027-02-12"

options.tsunaminoai.compliance.frameworks#

SCF Focal Document Identifiers (FDIs) for the authoritative sources this host must comply with. Controls required by any selected framework are automatically applied and attested. Valid FDIs are defined in modules/compliance/scf-data.nix (authoritativeSources keys).

Example FDIs: general-nist-800-53-r5 NIST SP 800-53 Rev 5 general-pci-dss-4-0-1 PCI DSS 4.0.1 us-federal-fedramp-r5-low FedRAMP R5 Low us-federal-fedramp-r5-mod FedRAMP R5 Moderate us-federal-cmmc-2-l2 CMMC 2.0 Level 2 general-cis-csc-8-1 CIS Controls v8.1 general-iso-27001-2022 ISO/IEC 27001:2022

Type: list of string

Default: []

Example: ["general-nist-800-53-r5" "general-pci-dss-4-0-1"]

options.tsunaminoai.core.appimage#

Whether to enable appimage-run support.

Type: boolean

Default: true

Example: true

options.tsunaminoai.core.domain#

Domain to use with hostnames throughout the flake

Type: string

Default: "gensokyo"

options.tsunaminoai.core.glances#

Whether to enable glances system monitor.

Type: boolean

Default: true

Example: true

options.tsunaminoai.core.manageNixpkgs#

Whether to set nixpkgs.config. Disable in test VMs where nixpkgs is read-only.

Type: boolean

Default: true

options.tsunaminoai.deploy.auto.branch#

Git branch to track

Type: string

Default: "main"

options.tsunaminoai.deploy.auto.checkInterval#

How often to check for updates

Type: string

Default: "10min"

options.tsunaminoai.deploy.auto.deployUser#

User to run deployments as

Type: string

Default: "root"

options.tsunaminoai.deploy.auto.enable#

Whether to enable automatic deployment on git updates.

Type: boolean

Default: false

Example: true

options.tsunaminoai.deploy.auto.notifyFailure#

Whether to enable send notification on failed deployment.

Type: boolean

Default: false

Example: true

options.tsunaminoai.deploy.auto.notifyStart#

Whether to enable send notification when deployment starts.

Type: boolean

Default: false

Example: true

options.tsunaminoai.deploy.auto.notifySuccess#

Whether to enable send notification on successful deployment.

Type: boolean

Default: false

Example: true

options.tsunaminoai.deploy.auto.repoDir#

Local directory for repository

Type: path

Default: "/var/lib/auto-deploy/repo"

options.tsunaminoai.deploy.auto.repoUrl#

Git repository URL

Type: string

Default: "http://voile:8418/tsunaminoai/nix-flake-final.git"

options.tsunaminoai.deploy.auto.webhookUrl#

Webhook URL for notifications (e.g., Slack, Discord)

Type: string

Default: ""

options.tsunaminoai.desktop.appIds#

List of desktop applications to install

Type: list of string

Default: defaultApplications

options.tsunaminoai.desktop.displayManager#

Display manager for the plasma session. SDDM is the natively matched DM for Plasma 6 and avoids GDM-specific workarounds (wireplumber state dir hack, gdm user-instance service failures, gnome-keyring PAM noise). Default after a successful mokou trial (2026-06 to 2026-07); a host can still override back to “gdm”.

Type: one of "gdm", "sddm"

Default: "sddm"

options.tsunaminoai.desktop.enable#

Whether to enable Enable desktop environment configuration.

Type: boolean

Default: false

Example: true

Also declared in: - modules/nixos/desktop/default.nix

Whether to enable Enable desktop configuration.

options.tsunaminoai.desktop.razer.enable#

Whether to enable Enables Razer product support.

Type: boolean

Default: false

Example: true

options.tsunaminoai.desktop.windowManager#

The window manager to use.

Type: one of "sway", "plasma"

Default: "plasma"

options.tsunaminoai.docPipeline.anythingLlm.embeddingModel#

Ollama model for document embeddings (already loaded on mokou).

Type: string

Default: "nomic-embed-text"

options.tsunaminoai.docPipeline.anythingLlm.enable#

Whether to enable AnythingLLM document chat interface.

Type: boolean

Default: true

Example: true

options.tsunaminoai.docPipeline.anythingLlm.port#

Host port for AnythingLLM web UI (HTTP). HTTPS = port + 1.

Type: port

Default: 13001

options.tsunaminoai.docPipeline.cfAccess.backendPort#

Loopback host port the paperless-web container binds when cfAccess is enabled (nginx proxies to it).

Type: port

Default: 8010

options.tsunaminoai.docPipeline.cfAccess.enable#

Whether to enable front Paperless with nginx for the cloudflared tunnel + CF Access header SSO.

Type: boolean

Default: false

Example: true

options.tsunaminoai.docPipeline.cfAccess.originAllowFrom#

Source IPs/CIDRs allowed to reach the HTTPS origin vhost — i.e. ONLY the host(s) running cloudflared (voile). This is the anti-spoofing control: a LAN client cannot reach the identity-trusting origin to forge the CF header. The LAN http vhost forces the header empty, so it stays open.

Type: list of string

Default: ["10.0.0.2"]

Example: ["10.0.0.2" "192.168.0.2"]

options.tsunaminoai.docPipeline.cfAccess.originPort#

HTTPS port nginx serves as the tunnel origin (cloudflared target).

Type: port

Default: cfg.paperlessPort + 1

options.tsunaminoai.docPipeline.cfAccess.publicHostname#

Public hostname served via the (externally-managed) cloudflared tunnel.

Type: string

Default: "paperless.inaba.network"

options.tsunaminoai.docPipeline.cfAccess.userHeader#

Header Cloudflare Access injects with the authenticated user’s email. The voile-restricted origin vhost maps it to X-Remote-User; Paperless (PAPERLESS_ENABLE_HTTP_REMOTE_USER) logs the user in as that account.

Type: string

Default: "Cf-Access-Authenticated-User-Email"

options.tsunaminoai.docPipeline.curate.catchup.enable#

Whether to enable nightly paperless-backfill –missing-only –apply for newly-arrived docs.

Type: boolean

Default: false

Example: true

options.tsunaminoai.docPipeline.curate.catchup.schedule#

OnCalendar schedule for the summary catch-up timer.

Type: string

Default: "03:30"

options.tsunaminoai.docPipeline.curate.ownerCorrespondent#

The archive owner’s correspondent name. Since the owner’s handle appears in nearly every document, a doc involving one other person matches owner+them. When set, the backfill excludes the owner for disambiguation: owner + exactly one other candidate -> assign the other. Empty disables owner-exclusion.

Type: string

Default: ""

Example: "Benjamin Arthur Craton"

options.tsunaminoai.docPipeline.curate.package#

The paperless-curate toolset package (installed on PATH).

Type: package

Default: pkgs.paperless-curate

options.tsunaminoai.docPipeline.curate.visionModel#

Ollama vision model used by paperless-reocr (VISION_MODEL). Defaults to the pipeline VLM (ollamaModel, minicpm-v) so paperless-gpt and paperless-reocr use the same model. Override only to run re-OCR through a different vision model than on-arrival OCR. Must be present in the Ollama host’s loadModels.

Type: string

Default: cfg.ollamaModel

options.tsunaminoai.docPipeline.curate.visionNumCtx#

VISION_NUM_CTX for paperless-reocr: the Ollama context window per vision call. A full page of image tokens plus the transcription must fit or Ollama silently truncates the image and returns empty text (the qwen2.5vl failure). minicpm-v is fine at 8192; olmocr2 (Qwen2.5-VL-based) needs 16384.

Type: signed integer

Default: 8192

Example: 16384

options.tsunaminoai.docPipeline.enable#

Whether to enable Document OCR/VLM/Paperless-NGX pipeline.

Type: boolean

Default: false

Example: true

options.tsunaminoai.docPipeline.enableProvisioning#

Whether to enable idempotent Paperless provisioning (Shared group, consume workflow, saved views).

Type: boolean

Default: true

Example: true

options.tsunaminoai.docPipeline.ollamaHost#

Hostname or IP of the machine running Ollama. Use mokou’s Tailscale FQDN for remote GPU inference, e.g.: “mokou.’‘${config.tsunaminoai.nix.tailscaleDomain}”

Type: string

Default: "localhost"

options.tsunaminoai.docPipeline.ollamaModel#

Ollama vision model (VLM) for the whole pipeline: paperless-gpt image OCR (VISION_LLM_MODEL) and, by default, paperless-reocr (curate.visionModel). minicpm-v (~5.5GB, ~615 image tokens/page) fits mokou’s 8GB GTX 1080 on-GPU. The previous qwen2.5vl:7b was a poor fit — ~11GB (spills to CPU) and its per-page vision tokens overflow the context, so Ollama truncated the image and returned empty OCR. Must be present in the Ollama host’s loadModels.

Type: string

Default: "minicpm-v"

options.tsunaminoai.docPipeline.paperlessGpt.autoTag#

Documents tagged with this are auto-processed on arrival. Apply via a Paperless workflow: Trigger = document added, Action = assign tag “paperless-gpt-auto”.

Type: string

Default: "paperless-gpt-auto"

options.tsunaminoai.docPipeline.paperlessGpt.contextLength#

Ollama context window size (OLLAMA_CONTEXT_LENGTH). Must be large enough to hold tokenLimit input plus generated output.

Type: string

Default: "8192"

options.tsunaminoai.docPipeline.paperlessGpt.createNewTags#

Whether paperless-gpt may invent new tags (CREATE_NEW_TAGS). Default false locks on-arrival tagging to the existing controlled vocabulary — this is what stops tag drift. Run paperless-tags-propose/apply to curate the vocabulary that paperless-gpt then chooses from.

Type: boolean

Default: false

options.tsunaminoai.docPipeline.paperlessGpt.enable#

Whether to enable paperless-gpt LLM auto-tagging sidecar.

Type: boolean

Default: true

Example: true

options.tsunaminoai.docPipeline.paperlessGpt.llmModel#

Ollama model for text-based tagging/titling. The vision model (ollamaModel) is used separately for image OCR. Must be present in mokou’s services.ollama.loadModels so it stays warm.

Type: string

Default: "qwen2.5:7b-instruct-q4_K_M"

options.tsunaminoai.docPipeline.paperlessGpt.managePrompts#

Whether to overwrite paperless-gpt’s prompt templates in /var/lib/paperless-gpt/prompts with the repo’s ./prompts/*.tmpl on each start. Default false: the template variable names are paperless-gpt version-specific, so FIRST diff the repo templates against what the running container wrote there, then enable this.

Type: boolean

Default: false

options.tsunaminoai.docPipeline.paperlessGpt.manualTag#

Tag a document with this to trigger on-demand LLM processing.

Type: string

Default: "paperless-gpt"

options.tsunaminoai.docPipeline.paperlessGpt.port#

Host port for paperless-gpt web UI (HTTP). HTTPS = port + 1.

Type: port

Default: 8013

options.tsunaminoai.docPipeline.paperlessGpt.tokenLimit#

Max tokens of document text sent to the LLM (TOKEN_LIMIT). Raised from the original 1000 to match the Conversions pipeline approach of feeding substantially more document content for better title/tag/date accuracy.

Type: string

Default: "4000"

options.tsunaminoai.docPipeline.paperlessImage#

Paperless-NGX container image. Strongly recommended to PIN a specific 2.x tag (not :latest) before enabling cfAccess — remote-user auth and the saved-view/UISettings API behaviour are version-dependent.

Type: string

Default: "ghcr.io/paperless-ngx/paperless-ngx:latest"

Example: "ghcr.io/paperless-ngx/paperless-ngx:2.14.7"

options.tsunaminoai.docPipeline.paperlessPort#

Host port for Paperless-NGX web UI.

Type: port

Default: 8011

options.tsunaminoai.docPipeline.rag.chatModel#

Generation model — must satisfy the proxy’s model-parity contract.

Type: string

Default: cfg.paperlessGpt.llmModel

options.tsunaminoai.docPipeline.rag.embeddingHost#

Always-on embeddings Ollama (NOT the failover proxy — indexing must not depend on upstreams).

Type: string

Default: "http://127.0.0.1:11435"

options.tsunaminoai.docPipeline.rag.embeddingModel#

Embedding model (768-dim; keep in the local ollama’s loadModels).

Type: string

Default: "nomic-embed-text"

options.tsunaminoai.docPipeline.rag.enable#

Whether to enable paperless-rag (qdrant + indexer + ask service).

Type: boolean

Default: false

Example: true

options.tsunaminoai.docPipeline.rag.extraEnv#

Extra environment variables for paperless-ask and paperless-index — e.g. the scoped-retrieval knobs (RAG_TOP_K_SCOPED, RAG_SCORE_FLOOR_SCOPED) or the dropdown cache TTL (RAG_CORRESPONDENTS_TTL) — without a module edit.

Type: attribute set of string

Default: {}

Example:

{
  RAG_TOP_K_SCOPED = "16";
  RAG_SCORE_FLOOR_SCOPED = "0.28";
}

options.tsunaminoai.docPipeline.rag.indexSchedule#

OnCalendar for the incremental index run.

Type: string

Default: "*-*-* *:20:00"

options.tsunaminoai.docPipeline.rag.package#

The paperless-rag package (paperless-index + paperless-ask).

Type: package

Default: pkgs.paperless-rag

options.tsunaminoai.docPipeline.rag.port#

Loopback port for paperless-ask (fronted by the CF origin vhost).

Type: port

Default: 8015

options.tsunaminoai.docPipeline.rag.publicHostname#

Public hostname (CF Access app; used by the Homer tile).

Type: string

Default: "ask.inaba.network"

options.tsunaminoai.docPipeline.rag.qdrantImage#

Pinned qdrant image.

Type: string

Default: "docker.io/qdrant/qdrant:v1.18.2"

options.tsunaminoai.docPipeline.rag.qdrantPort#

Loopback port for qdrant’s REST API.

Type: port

Default: 6333

options.tsunaminoai.docPipeline.rag.reconcileSchedule#

OnCalendar for the weekly deletion-reconcile sweep.

Type: string

Default: "Sun *-*-* 05:00:00"

options.tsunaminoai.docPipeline.reconcileExisting#

One-time: also grant the Shared group permissions on EXISTING documents already tagged sharedTag (bulk_edit set_permissions, merge=true). Touches existing data — leave false except for a deliberate backfill run.

Type: boolean

Default: false

options.tsunaminoai.docPipeline.sharedGroup#

Paperless group granted view+change on consumed documents.

Type: string

Default: "Shared"

options.tsunaminoai.docPipeline.sharedTag#

Tag used to scope the ‘Shared with Me’ view and reconcileExisting.

Type: string

Default: "shared"

options.tsunaminoai.docPipeline.summaryField#

Name of the Paperless custom field that holds LLM summaries.

Type: string

Default: "Summary"

options.tsunaminoai.docPipeline.timezone#

Timezone for Paperless-NGX.

Type: string

Default: "America/Indiana/Indianapolis"

options.tsunaminoai.docPipeline.voileSharePath#

NFS export path on voile (Synology DSM).

Type: string

Default: "/volume2/Books"

options.tsunaminoai.docPipeline.wifeUsername#

Username of the secondary (non-admin) user to provision saved views for. For CF Access header SSO this MUST equal her Cloudflare Access email (Entra UPN), or SSO will create a second account. Empty disables the user-specific provisioning steps.

Type: string

Default: ""

options.tsunaminoai.documentScanner.buttonFilter#

scanbd action filter matching the scanner’s button name. Inspect with scanbd -d if the button doesn’t trigger.

Type: string

Default: "^scan.*"

options.tsunaminoai.documentScanner.device#

Explicit SANE device id (e.g. “fujitsu:libusb:001:005”). Empty = autodetect the first device from scanimage -L. Pin it here if more than one scanner is present.

Type: string

Default: ""

options.tsunaminoai.documentScanner.enable#

Whether to enable SANE ADF scanner button -> Paperless-NGX intake.

Type: boolean

Default: false

Example: true

options.tsunaminoai.documentScanner.mode#

SANE –mode (“Color”, “Gray”, “Lineart”).

Type: string

Default: "Color"

options.tsunaminoai.documentScanner.paperlessUrl#

Base URL of the Paperless-NGX instance (defaults to ereshkigal over the LAN).

Type: string

Default: "http://192.168.0.20:8011"

options.tsunaminoai.documentScanner.resolution#

Scan resolution in DPI. 300 is a good mail/OCR default; lower is faster and lighter on the Pi.

Type: signed integer

Default: 300

options.tsunaminoai.documentScanner.source#

SANE –source (e.g. “ADF Duplex”, “ADF Front”).

Type: string

Default: "ADF Duplex"

options.tsunaminoai.documentScanner.titlePrefix#

Title prefix for uploaded documents (a date is appended).

Type: string

Default: "Mail"

options.tsunaminoai.documentScanner.tokenFile#

Path to a file holding the Paperless API token (defaults to the shared sops secret).

Type: string

Default: config.sops.secrets."paperless/api-token".path

options.tsunaminoai.documentScanner.workDir#

Scratch directory for in-flight scans (cleaned up per run).

Type: string

Default: "/var/lib/document-scanner"

options.tsunaminoai.esphome.configDir#

Host path mounted as /config inside the container.

Type: string

Default: "/var/lib/esphome"

options.tsunaminoai.esphome.enable#

Whether to enable ESPHome dashboard/builder container.

Type: boolean

Default: false

Example: true

options.tsunaminoai.esphome.lanInterface#

LAN-facing interface; firewall port and Avahi are scoped to this.

Type: string

Default: "vmbr0"

options.tsunaminoai.esphome.port#

Host port for the ESPHome dashboard web UI.

Type: port

Default: 6052

options.tsunaminoai.esphome.timezone#

TZ identifier passed to the container.

Type: string

Default: "America/Indiana/Indianapolis"

options.tsunaminoai.film-tools.comfyui.dataDir#

Where the ComfyUI checkout, venv, models, and outputs live. Point at external storage when checkpoints outgrow the internal disk.

Type: string

Default: "${config.home.homeDirectory}/comfyui"

options.tsunaminoai.film-tools.comfyui.enable#

Whether to enable ComfyUI Stable Diffusion / Flux UI (Metal/MPS).

Type: boolean

Default: false

Example: true

options.tsunaminoai.film-tools.comfyui.extraArgs#

Additional CLI args passed to ComfyUI main.py.

Type: string

Default: ""

options.tsunaminoai.film-tools.comfyui.fp16#

Pass –force-fp16 for better Metal performance on M-series.

Type: boolean

Default: true

options.tsunaminoai.film-tools.comfyui.port#

Local port ComfyUI listens on.

Type: port

Default: 8188

options.tsunaminoai.film-tools.comfyui.python#

Python interpreter to use for the venv.

Type: package

Default: pkgs.python312

options.tsunaminoai.film-tools.tts.defaultModel#

Default Coqui TTS model name. Override per-session with: FILM_TTS_MODEL=tts_models/en/vctk/vits film-tts “text” out.wav

Some useful models: tts_models/en/ljspeech/tacotron2-DDC (fast, single speaker) tts_models/en/vctk/vits (multi-speaker, slower) tts_models/multilingual/multi-dataset/xtts_v2 (best quality, heavy)

Type: string

Default: "tts_models/en/ljspeech/tacotron2-DDC"

options.tsunaminoai.film-tools.tts.defaultSpeaker#

Default speaker ID for multi-speaker models (e.g. p225 for tts_models/en/vctk/vits); empty for single-speaker models. Override per-session with FILM_TTS_SPEAKER, or per-line in film-tts-batch via “speakerIDtext” lines. List a model’s speakers with: tts –model_name tts_models/en/vctk/vits –list_speaker_idxs

Type: string

Default: ""

options.tsunaminoai.film-tools.tts.enable#

Whether to enable Coqui TTS scratch-voice pipeline for solo film production.

Type: boolean

Default: false

Example: true

options.tsunaminoai.film-tools.tts.python#

Python interpreter to use for the TTS venv.

Type: package

Default: pkgs.python312

options.tsunaminoai.flatpak.autoUpdate#

Enable autoupdates

Type: boolean

Default: true

options.tsunaminoai.flatpak.enable#

Enable flatpak support

Type: boolean

Default: false

options.tsunaminoai.flatpak.extraApps#

List of Flatpak apps to install system-wide

Type: list of string

Default: []

Example:

[
  "org.mozilla.firefox"
  "org.libreoffice.LibreOffice"
]

options.tsunaminoai.flatpak.withRecommended#

Whether to enable Enable recommended Apps.

Type: boolean

Default: false

Example: true

options.tsunaminoai.fonts.enable#

Enable font configuration

Type: boolean

Default: false

options.tsunaminoai.haosVm.bridge#

Host bridge the VM’s virtio NIC attaches to (LAN, so HA is a first-class host).

Type: string

Default: "vmbr0"

options.tsunaminoai.haosVm.enable#

Whether to enable Home Assistant OS libvirt/qemu VM.

Type: boolean

Default: false

Example: true

options.tsunaminoai.haosVm.imagePath#

Persistent path for the decompressed HAOS disk (the VM’s data lives here).

Type: string

Default: "/var/lib/libvirt/images/haos.qcow2"

options.tsunaminoai.haosVm.imageSha256#

Hex sha256 of the .xz at imageUrl (verified before decompression).

Type: string

Default: "60df08773901e1eac9b9cfe03d53e1d939e67b669c172c3a41037fb3cd295b9d"

options.tsunaminoai.haosVm.imageUrl#

URL of the HAOS OVA qcow2 (.xz) VM image. Bump with imageSha256 together.

Type: string

Default:

"https://github.com/home-assistant/operating-system/releases/download/18.1/haos_ova-18.1.qcow2.xz"

options.tsunaminoai.haosVm.iotLeg.bridge#

Name of the L2-only bridge the VM’s second NIC attaches to.

Type: string

Default: "br-iot"

options.tsunaminoai.haosVm.iotLeg.enable#

Whether to enable an L2 VLAN bridge leg from the VM onto the IoT VLAN.

Type: boolean

Default: false

Example: true

Trunk interface carrying the tagged IoT VLAN (ereshkigal’s LAN bond behind vmbr0).

Type: string

Default: "bond1"

options.tsunaminoai.haosVm.iotLeg.vlanId#

802.1Q tag of the IoT VLAN (matches HA Green’s old end0.3 → 192.168.2.0/24).

Type: lib.types.ints.between 1 4094

Default: 3

options.tsunaminoai.haosVm.memoryMiB#

RAM (MiB) for the HAOS VM.

Type: positive

Default: 4096

options.tsunaminoai.haosVm.radioPci#

PCI address of a USB controller to VFIO-passthrough wholesale to the VM (see header WARNING).

Type: null or string

Default: null

Example: "0000:41:00.0"

options.tsunaminoai.haosVm.radioUsb#

USB “vendor:product” of a single coordinator to pass through (alternative to radioPci).

Type: null or string

Default: null

Example: "10c4:ea60"

options.tsunaminoai.haosVm.vcpu#

vCPUs for the HAOS VM.

Type: positive

Default: 2

options.tsunaminoai.haosVm.vncListen#

VNC listen address for the console (loopback → reach via SSH tunnel for onboarding/restore).

Type: string

Default: "127.0.0.1"

options.tsunaminoai.homer.domain#

Domain to use at the end of the hostName (currently unused)

Type: null or string

Default: null

options.tsunaminoai.homer.enable#

Whether to enable Expose a Homer dashboard on this host.

Type: boolean

Default: false

Example: true

options.tsunaminoai.homer.extraOptions#

Extra top level Homer options See Homer Documentation

Type: attribute set

Default: defaultConfig

options.tsunaminoai.homer.hostName#

Virtual host served by Nginx for the dashboard.

Type: string

Default: "localhost"

Declarative list of dashboard tiles (Homer links).

Type: list of linkOption

Default: []

options.tsunaminoai.homer.links.<name>.icon#

Material-Design icon name (or path to a local SVG).

Type: null or string

Default: null

Example: "mdi-safe"

options.tsunaminoai.homer.links.<name>.name#

Human-readable label shown on the dashboard.

Type: string

Default: name

Example: "Vault"

options.tsunaminoai.homer.links.<name>.target#

HTML target attribute for the link (opens in same or new tab).

Type: one of "_self", "_blank"

Default: "_self"

options.tsunaminoai.homer.links.<name>.url#

Absolute URL the tile links to.

Type: string

Example: "https://vault.sc2.lan"

options.tsunaminoai.homer.openFirewall#

Whether to automatically open the chosen port in networking.firewall.allowedTCPPorts. Disable if you expose Homer only behind a reverse proxy or VPN.

Type: boolean

Default: true

options.tsunaminoai.homer.port#

TCP port Nginx listens on for the dashboard.

Type: port

Default: 8080

options.tsunaminoai.homer.services#

Declarive list of dashboard services See Homer Documentation

Type: list of attribute set

Default: []

options.tsunaminoai.kurVolumes.diskoParity#

Whether to enable emit a format-only disko.devices.lvm_vg layout (no mountpoints) as source-of-truth for a clean rebuild. Off by default; does not affect the live system’s mounts (the provisioner owns those).

Type: boolean

Default: false

Example: true

options.tsunaminoai.kurVolumes.vg#

Existing LVM volume group to carve volumes from. Must already exist (this module never creates the VG).

Type: string

Default: "kur"

options.tsunaminoai.kurVolumes.volumes#

Volumes to provision on the VG and mount.

Type: attribute set of submodule

Default: {}

options.tsunaminoai.laptop.enable#

Whether to enable Enable laptop-specific optimizations.

Type: boolean

Default: false

Example: true

options.tsunaminoai.laptop.hibernate.enable#

Whether to enable Enable hibernate support with proper driver management.

Type: boolean

Default: false

Example: true

options.tsunaminoai.laptop.hibernate.gpuPciAddress#

PCI address of the GPU for power management (e.g., ‘0000:c4:00.0’)

Type: null or string

Default: null

Example: "0000:c4:00.0"

options.tsunaminoai.laptop.hibernate.wifiDrivers#

List of WiFi driver modules to unload/reload on hibernate/resume

Type: list of string

Default: []

Example: ["ath11k" "ath11k_pci"]

options.tsunaminoai.media.beets.dbPath#

Directory holding musiclibrary.db, the import log and beets’ own runtime state. Deliberately not under any user’s home — this is a system service, and the media user’s home is the share itself.

Type: path

Default: "/var/lib/beets"

options.tsunaminoai.media.beets.enable#

Whether to enable beets as a read-only indexer over the music library.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.beets.group#

Group that owns the beets state.

Type: string

Default: mediaUser.group

options.tsunaminoai.media.beets.libraryPath#

Root of the music tree to index. beets only ever reads it — see the import.copy/move/write block in this module.

If this is a network mount, beets-index.service gets a RequiresMountsFor on it so it cannot silently index an unmounted automount point and record an empty library.

Type: path

Example: "/mnt/voile/Inaba/Yunohost/yunohost.multimedia/share/Music"

options.tsunaminoai.media.beets.package#

beets package to wrap.

Type: package

Default: pkgs.beets

options.tsunaminoai.media.beets.user#

User that owns the beets state and runs the index. The voile share is mounted forceuid/forcegid to the media user, so this should be that user unless the library lives somewhere else.

Type: string

Default: mediaUser.username

options.tsunaminoai.media.consumer.enable#

Whether to enable Enable media consumer services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.server.audio#

Whether to enable Enable audio and music services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.server.books#

Whether to enable Enable eBook services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.server.enable-portal#

Whether to enable Enable portal for media services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.server.jellyfin.nvencDeviceUuid#

CUDA device UUID (from nvidia-smi -L) to pin Jellyfin’s NVENC/NVDEC to. ereshkigal has three NVIDIA GPUs but only the Quadro P400 (Pascal) has an NVENC encoder — the two Tesla K80s (Kepler) do not. Without pinning, ffmpeg may select a K80, fail NVENC init, and fall back to slow software transcode on a no-AVX2 Xeon (the choppiness). Set this to the P400’s UUID. null leaves device selection to ffmpeg.

Type: null or string

Default: null

Example: "GPU-deadbeef-0000-1111-2222-333344445555"

options.tsunaminoai.media.server.jellyfin.provision.apiTokenFile#

Path to a file containing a Jellyfin API key (Dashboard -> API Keys). Read at runtime into a RuntimeDirectory EnvironmentFile; never in the store. Required when provision.enable = true.

Type: null or path

Default: null

options.tsunaminoai.media.server.jellyfin.provision.audioLanguagePreference#

Preferred audio language (ISO 639-2/T, e.g. “jpn”). Empty means no language preference; combined with playDefaultAudioTrack = true this plays each file’s default (usually original) track.

Type: string

Default: ""

Example: "jpn"

options.tsunaminoai.media.server.jellyfin.provision.enable#

Whether to enable declarative reconcile of Jellyfin library metadata language + per-user audio/subtitle defaults via the REST API (idempotent oneshot + self-healing timer, modelled on paperless-provision).

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.server.jellyfin.provision.liveTv.listings#

XMLTV listings providers to keep registered. Matched on xmltvUrl; an already-correct provider is left untouched so channel mappings made in the UI survive, and so Jellyfin’s guide-refresh task is not re-queued on every timer fire.

Type: list of submodule

Default: []

options.tsunaminoai.media.server.jellyfin.provision.liveTv.listings.<name>.enableAllTuners#

Apply these listings to every registered tuner.

Type: boolean

Default: true

options.tsunaminoai.media.server.jellyfin.provision.liveTv.listings.<name>.name#

Label used in the provisioning log (Jellyfin does not store it).

Type: string

Example: "WeatherStar 4000"

options.tsunaminoai.media.server.jellyfin.provision.liveTv.listings.<name>.xmltvUrl#

XMLTV guide URL — becomes ListingsProviderInfo.Path.

Type: string

Example: "http://127.0.0.1:9798/guide.xml"

options.tsunaminoai.media.server.jellyfin.provision.liveTv.tuners#

M3U tuner hosts to keep registered in Jellyfin Live TV. Reconciled against /System/Configuration/livetv, matching on m3uUrl, so an entry deleted in the UI comes back on the next timer fire.

This is a plain list, so several modules can contribute — see tsunaminoai.media.weatherChannel.

Type: list of submodule

Default: []

options.tsunaminoai.media.server.jellyfin.provision.liveTv.tuners.<name>.m3uUrl#

M3U playlist URL. Also the identity key for reconciliation.

Type: string

Example: "http://127.0.0.1:9798/playlist.m3u"

options.tsunaminoai.media.server.jellyfin.provision.liveTv.tuners.<name>.name#

Tuner FriendlyName in the Live TV dashboard.

Type: string

Example: "WeatherStar 4000"

options.tsunaminoai.media.server.jellyfin.provision.liveTv.tuners.<name>.tunerCount#

Concurrent stream limit. With stream sharing on, one tuner serves every viewer of the same channel.

Type: unsigned

Default: 1

options.tsunaminoai.media.server.jellyfin.provision.liveTv.tuners.<name>.userAgent#

Override the User-Agent used to fetch the playlist/stream.

Type: string

Default: ""

options.tsunaminoai.media.server.jellyfin.provision.metadataCountryCode#

Per-library metadata country code.

Type: string

Default: "US"

options.tsunaminoai.media.server.jellyfin.provision.metadataLanguage#

Per-library preferred metadata language (ISO 639-1).

Type: string

Default: "en"

options.tsunaminoai.media.server.jellyfin.provision.playDefaultAudioTrack#

Play the file’s default audio track regardless of language preference.

Type: boolean

Default: true

options.tsunaminoai.media.server.jellyfin.provision.refreshExistingMetadata#

Trigger a one-time full metadata re-scrape (replaceAllMetadata) of every library after setting its language, so already-scraped (e.g. Japanese) titles get re-fetched in metadataLanguage. Expensive; guarded by a state file under /var/lib/jellyfin so it runs at most once per library even though the timer fires daily.

Type: boolean

Default: false

options.tsunaminoai.media.server.jellyfin.provision.subtitleLanguagePreference#

Preferred subtitle language (ISO 639-2/T).

Type: string

Default: "eng"

options.tsunaminoai.media.server.jellyfin.provision.subtitleMode#

Subtitle playback mode. “Always” forces the preferred-language subs on for every title — right for original-audio + English-subs viewing.

Type: one of "Default", "Always", "OnlyForced", "None", "Smart"

Default: "Always"

options.tsunaminoai.media.server.jellyfin.provision.users#

Usernames to apply the audio/subtitle defaults to. Empty = all users.

Type: list of string

Default: []

Example: ["nyssa" "tsunami"]

options.tsunaminoai.media.server.tdarr.cpuWorkers#

Number of CPU workers to use for transcoding and health checks

Type: signed integer

Default: 1

options.tsunaminoai.media.server.tdarr.enable#

Whether to enable Enable tdarr transcoding services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.server.tdarr.gpuWorkers#

Number of GPU workers to use for transcoding and health checks

Type: signed integer

Default: 0

options.tsunaminoai.media.server.tdarr.isServer#

Whether to enable Enable server node (as opposed to a worker node).

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.server.video#

Whether to enable Enable video services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.weatherChannel.enable#

Whether to enable a retro WeatherStar 4000 channel (ws4kp + ws4channels) for Jellyfin Live TV.

Type: boolean

Default: false

Example: true

options.tsunaminoai.media.weatherChannel.jellyfin.enable#

Register the stream with Jellyfin Live TV as an M3U tuner plus an XMLTV listings provider, via jellyfin-provision.

Type: boolean

Default:

config.tsunaminoai.media.server.video
&& config.tsunaminoai.media.server.jellyfin.provision.enable

options.tsunaminoai.media.weatherChannel.jellyfin.friendlyName#

Tuner name shown in Jellyfin’s Live TV dashboard.

Type: string

Default: "WeatherStar 4000"

options.tsunaminoai.media.weatherChannel.location.latLon#

Permalink latLon — used directly, with no geocode round-trip. Preferred for a headless capture.

Type: null or submodule

Default: null

Example:

{
  lat = 40.4167;
  lon = -86.8753;
}

options.tsunaminoai.media.weatherChannel.location.latLon.lat#

Latitude in decimal degrees.

Type: number

options.tsunaminoai.media.weatherChannel.location.latLon.lon#

Longitude in decimal degrees.

Type: number

options.tsunaminoai.media.weatherChannel.location.query#

Permalink latLonQuery — the text shown in ws4kp’s location box. If latLon is null this string is geocoded through ArcGIS on every page load; set both to avoid that.

Type: string

Default: ""

Example: "Lafayette, IN, USA"

options.tsunaminoai.media.weatherChannel.location.zipCode#

ws4channels ZIP_CODE. Only consulted on the non-permalink path (ws4channels.usePermalink = false), where ws4channels types it into ws4kp’s location box with Puppeteer.

Type: string

Default: "90210"

Example: "47905"

options.tsunaminoai.media.weatherChannel.ws4channels.cpus#

podman --cpus limit. Upstream’s docs say 1.0; that is a throughput cliff, not a safe default — Chromium’s rasteriser and PNG encoder, ffmpeg’s PNG decode, and libx264 all contend for it. Measured capture rate on ereshkigal at 1280x720: 1.8 fps at 1.0, 3.2 fps at 4.0, 3.3 fps at 8.0. Past ~4 the limit is per-screenshot latency, which is serialised, so there is nothing more to win.

Type: string

Default: "4.0"

options.tsunaminoai.media.weatherChannel.ws4channels.frameRate#

Screenshot/encode frame rate, and the single most important setting here.

It must be lower than the rate the host can actually screenshot at. ws4channels hands ffmpeg -framerate <this> on an image2pipe input, so every captured frame is stamped as 1/frameRate of a second no matter when it really arrived. Capture slower than the declared rate and the HLS timeline advances slower than wall clock — permanently, with no catch-up — until the playlist is hours behind and no player can tune it. Upstream files this as “stream gets 30+ minutes behind”.

Nothing detects this for you: /health still reports ready: true the whole time. Measure the real ceiling before setting it — see the recipe in docs/services/weather-channel.md — and leave ~30% headroom.

Measured on ereshkigal (Xeon E5-2650 v2, cpus = "4.0"): 640x480 → 5.1 fps, 1280x720 → 3.4 fps. The default of 4 suits a standard view mode on hardware of that vintage; a modern CPU manages upstream’s 10 at 720p.

Type: positive

Default: 4

options.tsunaminoai.media.weatherChannel.ws4channels.image#

Capture/transcode/publish image.

Type: string

Default: "ghcr.io/rice9797/ws4channels:latest"

options.tsunaminoai.media.weatherChannel.ws4channels.memory#

podman --memory limit. Upstream suggests ~1 GB, but headless Chromium settles at ~850 MB steady-state, i.e. 79% of a 1 GB cap — close enough to the ceiling to keep it collecting garbage instead of rendering.

Type: string

Default: "2g"

options.tsunaminoai.media.weatherChannel.ws4channels.music#

Build the music bed from a library query instead of curating a directory by hand.

A systemd oneshot (ws4channels-music.service, ordered Before=podman-ws4channels.service) runs the query, takes up to limit results, materializes them into ${materializedMusicDir} as flat, real, uniform .mp3 files, prunes whatever is no longer selected, and points musicDir at the result.

Nix cannot build that directory: a derivation is sandboxed and pure, so it can read neither the share nor the beets database, and a music library has no business in the store. The flake declares the recipe; the oneshot does the I/O against live data.

Type: null or submodule

Default: null

Example:

{
  query = "genre:jazz";
  limit = 40;
}

options.tsunaminoai.media.weatherChannel.ws4channels.music.limit#

Take at most this many of the matched tracks (in the order the backend returns them). This is also the disk budget — normalized copies live on local disk, and an unbounded query over a 16.6k track library would be a few hundred GB.

Type: positive

Default: 40

options.tsunaminoai.media.weatherChannel.ws4channels.music.normalize#

Transcode everything to 44.1 kHz stereo mp3.

Strongly recommended, for two reasons. The container concatenates the bed with ffmpeg’s concat demuxer under -stream_loop -1, which glitches at track boundaries when sample rates or channel layouts differ; and .m4a — 2,701 files of this library — is invisible to a container that filters on .mp3, so normalizing is what makes them eligible at all.

With this off, non-mp3 matches are skipped with a warning and mp3s are passed through as-is, parameters unchecked.

Type: boolean

Default: true

options.tsunaminoai.media.weatherChannel.ws4channels.music.query#

Query in the backend’s own syntax — for beets, see https://beets.readthedocs.io/en/stable/reference/query.html. Split on spaces into one query term per argument, which is how beets itself reads argv; a term cannot contain a space.

Verify it before deploying: beet ls -p '<query>' | wc -l.

Type: string

Example: "genre:jazz year:1950..1969"

options.tsunaminoai.media.weatherChannel.ws4channels.music.refresh#

systemd OnCalendar expression for re-running the query. null (the default) means manual only: systemctl start ws4channels-music.service.

A refresh that actually changes the selection restarts podman-ws4channels — the container writes audio_list.txt once, at startup. An unchanged selection leaves it alone, so a timer does not cost a stream interruption per tick.

Type: null or string

Default: null

Example: "weekly"

options.tsunaminoai.media.weatherChannel.ws4channels.music.source#

Query engine. Only beets today (tsunaminoai.media.beets.enable must be on).

An enum rather than a bool because two other backends are plausible without re-plumbing anything downstream — the materializer only needs a list of absolute paths: navidrome (Subsonic API playlists — curation in a UI, from any device, over the same library) and path (plain globs + ffprobe, zero dependencies).

Type: one of "beets"

Default: "beets"

options.tsunaminoai.media.weatherChannel.ws4channels.musicDir#

Host directory bind-mounted read-only over /app/music, replacing the seven bundled tracks. It must contain at least one .mp3: the container’s fallback list names the bundled files by path, which the bind mount has hidden.

Set by ws4channels.music when that is in use — do not set both.

Type: null or path

Default: null

Example: "/mnt/voile/Inaba/weather-music"

options.tsunaminoai.media.weatherChannel.ws4channels.port#

Loopback port serving /playlist.m3u, /guide.xml, /health and the HLS segments. This is what Jellyfin’s tuner points at.

Type: port

Default: 9798

options.tsunaminoai.media.weatherChannel.ws4channels.shuffleMusic#

Randomise the background music order at container start.

Type: boolean

Default: false

Drive ws4kp with a generated PERMALINK_URL (deterministic — no Puppeteer form-filling at all). Set false to fall back to ws4channels typing location.zipCode into the UI and clicking the kiosk/view-mode controls, which is what upstream does by default.

Type: boolean

Default: true

options.tsunaminoai.media.weatherChannel.ws4kp.displays#

Which WeatherStar screens are in the rotation. Attribute names are the literal permalink keys; defaults match upstream.

Type: submodule

Default: {}

options.tsunaminoai.media.weatherChannel.ws4kp.extraQuery#

Raw permalink parameters merged after the typed options — an escape hatch for keys ws4kp gains upstream. Values are percent-encoded for the permalink and passed verbatim as WSQS_*. kiosk cannot be overridden here.

Type: attribute set of string

Default: {}

Example:

{
  mediaPlaying = "false";
}

options.tsunaminoai.media.weatherChannel.ws4kp.image#

WeatherStar 4000+ web app image.

Type: string

Default: "ghcr.io/netbymatt/ws4kp:latest"

options.tsunaminoai.media.weatherChannel.ws4kp.kioskUi#

Also start the browser-facing UI in kiosk mode (no settings toolbar). The permalink handed to ws4channels always forces kiosk regardless.

Type: boolean

Default: false

options.tsunaminoai.media.weatherChannel.ws4kp.port#

Loopback port the ws4kp web UI is published on. HTTPS (tailnet nginx vhost) = port + 1.

Type: port

Default: 12821

options.tsunaminoai.media.weatherChannel.ws4kp.settings#

ws4kp display settings (permalink keys of the same name).

Type: submodule

Default: {}

options.tsunaminoai.media.weatherChannel.ws4kp.settings.customText#

Text for the bottom scroll when customTextEnable is on.

Type: string

Default: ""

Example: "Welcome to the Inaba residence"

options.tsunaminoai.media.weatherChannel.ws4kp.settings.customTextEnable#

Replace the bottom scroll with customText.

Type: boolean

Default: false

options.tsunaminoai.media.weatherChannel.ws4kp.settings.refreshTime#

Weather data refresh interval, in milliseconds.

Type: one of 30000, 300000, 600000, 900000, 1800000

Default: 600000

options.tsunaminoai.media.weatherChannel.ws4kp.settings.scanLineMode#

Scan-line weight. Ignored unless scanLines is on.

Type: one of "auto", "thin", "medium", "thick"

Default: "auto"

options.tsunaminoai.media.weatherChannel.ws4kp.settings.scanLines#

CRT scan-line overlay.

Type: boolean

Default: false

options.tsunaminoai.media.weatherChannel.ws4kp.settings.speed#

Screen dwell multiplier, as a two-decimal string. ws4kp compares the dropdown value with toFixed(2), and Nix float formatting is not stable enough to guarantee that form.

Lower is FASTER (it scales the delay): 0.50 is labelled “Very Fast” and 1.50 “Very Slow”, the opposite of what upstream’s README claims.

Type: one of "0.50", "0.75", "1.00", "1.25", "1.50"

Default: "1.00"

options.tsunaminoai.media.weatherChannel.ws4kp.settings.stickyKiosk#

Persist kiosk mode in localStorage. Has no effect on the capture — Puppeteer launches a fresh profile every time.

Type: boolean

Default: false

options.tsunaminoai.media.weatherChannel.ws4kp.settings.units#

Unit system. The value is si, not metric — “Metric” is only the dropdown label.

Type: one of "us", "si"

Default: "us"

options.tsunaminoai.media.weatherChannel.ws4kp.settings.viewMode#

Aspect/enhancement mode. Also drives the ws4channels capture geometry: standard = 640x480, wide/wide-enhanced = 1280x720, portrait-enhanced = 720x1280.

Type: one of "standard", "wide", "wide-enhanced", "portrait-enhanced"

Default: "wide"

options.tsunaminoai.media.weatherChannel.ws4kp.travelLocations#

Cities on the Travel Forecast screen, replacing the 15 the image ships with. Only visible when displays.travel is also on.

Unlike everything else under ws4kp, this is NOT a permalink parameter — ws4kp has none for travel cities. See the generator notes in weather-channel.nix for how the list actually reaches the app.

Coordinates must fall inside NWS coverage (US and territories). Anywhere else has no gridpoint, and a city without one is dropped from the screen.

Type: list of submodule

Default: []

Example:

[
  {
    name = "Indianapolis";
    lat = 39.7684;
    lon = -86.1581;
  }
]

options.tsunaminoai.media.weatherChannel.ws4kp.travelLocations.<name>.lat#

Latitude in decimal degrees.

Type: number

options.tsunaminoai.media.weatherChannel.ws4kp.travelLocations.<name>.lon#

Longitude in decimal degrees.

Type: number

options.tsunaminoai.media.weatherChannel.ws4kp.travelLocations.<name>.name#

Label on the travel screen. Free text — it is never sent to the NWS, so this is the one place a location can be renamed without patching ws4kp.

Type: string

Example: "Indianapolis"

options.tsunaminoai.monitoring.dataDir#

Directory for Gatus’s sqlite uptime history. Must live under /var/lib (systemd StateDirectory). On ereshkigal point this at the telemetry kurVolumes LV — never the btrfs root.

Type: string

Default: "/var/lib/gatus"

options.tsunaminoai.monitoring.enable#

Whether to enable Gatus synthetic monitoring + status page.

Type: boolean

Default: false

Example: true

options.tsunaminoai.monitoring.endpoints#

Endpoints to monitor, grouped by module/namespace. The namespace will be used as the group name if not explicitly set. Each endpoint follows the Gatus schema (name, url, interval, conditions, …). Endpoints on hosts that are allowed to be down (laptops) should set extra-labels.tier = "intermittent" so they show on the status page but never page.

Type: attribute set of list of attribute set

Default: {}

Example:

{
  webServices = [
    {
      name = "my-api";
      url = "https://api.example.com/health";
      interval = "5m";
      conditions = [ "[STATUS] == 200" ];
      # group will default to "webServices"
    }
  ];
  hosts = [
    {
      name = "some-laptop";
      url = "icmp://laptop.example.ts.net";
      conditions = [ "[CONNECTED] == true" ];
      extra-labels.tier = "intermittent"; # never pages
    }
  ];
}

options.tsunaminoai.monitoring.environmentFile#

EnvironmentFile for the Gatus unit. Gatus substitutes ‘’${VAR} placeholders in its config at load, so endpoint definitions can reference secrets (auth headers) without them landing in the world-readable rendered config in the Nix store. Also passed to every statusPages instance.

Type: null or path

Default: null

Example: "/run/secrets/rendered/gatus-env"

options.tsunaminoai.monitoring.statusPage.acmeChallengePort#

Loopback port for this cert’s lego HTTP-01 listener. Must differ from :8888 (the host cert’s listener — concurrent renewals would race on a shared port).

Type: port

Default: 8889

options.tsunaminoai.monitoring.statusPage.hostname#

Public (LAN/tailnet) name for the status page. Gets its own step-ca ACME cert and an nginx vhost on httpsPort. Null = no vhost at all (Gatus stays on its loopback port, reachable only through a Cloudflare Access origin).

Type: null or string

Default: null

Example: "status.falseblue.com"

options.tsunaminoai.monitoring.statusPage.httpsPort#

HTTPS port for the named status-page vhost.

Type: port

Default: 443

options.tsunaminoai.monitoring.statusPages#

Tenant-scoped read-only status pages: each entry runs an extra Gatus instance serving ONLY the endpoints whose extra-labels.tenant is in tenants. Gatus has no per-user filtering, so audience scoping is done by instance — front each with its own CF Access origin gated on that audience’s Entra group. Pages probe independently but publish NO metrics (the primary instance owns the alerting path), so duplicate probes never double-count in EndpointDown.

Type: attribute set of submodule

Default: {}

Example: { family = { port = 8430; tenants = ["personal"]; }; }

options.tsunaminoai.monitoring.statusPages.<name>.port#

Loopback port for this page’s Gatus instance.

Type: port

options.tsunaminoai.monitoring.statusPages.<name>.tenants#

Endpoint tenant labels this page shows (exact match).

Type: list of string

options.tsunaminoai.monitoring.web.port#

Loopback port Gatus serves its UI + /metrics on (nginx is the only ingress).

Type: port

Default: 8425

options.tsunaminoai.news.autoReload#

Whether to enable Enable auto reload.

Type: boolean

Default: false

Example: true

options.tsunaminoai.news.enable#

Whether to enable Enable newsboat.

Type: boolean

Default: false

Example: true

options.tsunaminoai.news.reloadTime#

Time in minutes to reload feeds

Type: signed integer

Default: 15

options.tsunaminoai.news.urls#

List of feeds to follow

Type: list of submodule

Default: []

options.tsunaminoai.news.urls.<name>.tags#

Tags to add to the feed

Type: list of string

Default: []

options.tsunaminoai.news.urls.<name>.title#

Title of the feed

Type: string

options.tsunaminoai.news.urls.<name>.url#

URL of the feed

Type: string

options.tsunaminoai.nix.isDeployNode#

Whether to enable Set this host as the deploy node. This installs the deployment key for root.

Type: boolean

Default: false

Example: true

options.tsunaminoai.nvidia.enable#

Whether to enable Enable nvidia cards.

Type: boolean

Default: false

Example: true

options.tsunaminoai.nvidia.package#

The NVIDIA driver package to use.

Type: any

Default: config.boot.kernelPackages.nvidiaPackages.stable

Example: "config.boot.kernelPackages.nvidiaPackages.legacy_470"

options.tsunaminoai.ollama.bindAddress#

Address to listen on. Loopback by default; set the host’s Tailscale IP to serve the tailnet. Do not use 0.0.0.0 on machines that leave the home network.

Type: string

Default: "127.0.0.1"

Example: "100.74.80.8"

options.tsunaminoai.ollama.enable#

Whether to enable Ollama LLM server (launchd daemon).

Type: boolean

Default: false

Example: true

options.tsunaminoai.ollama.extraEnvironment#

Extra environment variables for the ollama daemon.

Type: attribute set of string

Default: {}

options.tsunaminoai.ollama.keepAlive#

OLLAMA_KEEP_ALIVE — how long models stay resident after last use.

Type: string

Default: "10m"

options.tsunaminoai.ollama.loadModels#

Models pulled idempotently at load/activation by the ollama-models daemon (the darwin equivalent of NixOS services.ollama.loadModels).

Type: list of string

Default: []

Example: ["qwen2.5:7b-instruct-q4_K_M" "nomic-embed-text"]

options.tsunaminoai.ollama.maxLoadedModels#

OLLAMA_MAX_LOADED_MODELS — e.g. a text model + the embedder.

Type: signed integer

Default: 2

options.tsunaminoai.ollama.maxQueue#

OLLAMA_MAX_QUEUE — queued requests before 503s.

Type: signed integer

Default: 8

options.tsunaminoai.ollama.modelsDir#

Model store (root-owned; the daemon runs as root like borg-backup).

Type: string

Default: "/var/lib/ollama"

options.tsunaminoai.ollama.numParallel#

OLLAMA_NUM_PARALLEL — parallel requests per model.

Type: signed integer

Default: 1

options.tsunaminoai.ollama.package#

Ollama package (aarch64-darwin builds use Metal natively).

Type: package

Default: pkgs.ollama

options.tsunaminoai.ollama.port#

TCP port to listen on.

Type: port

Default: 11434

options.tsunaminoai.ollamaProxy.enable#

Whether to enable nginx failover proxy for Ollama.

Type: boolean

Default: false

Example: true

options.tsunaminoai.ollamaProxy.openFirewall#

Open the proxy port (LAN + tailnet — same posture as a directly exposed Ollama).

Type: boolean

Default: true

options.tsunaminoai.ollamaProxy.port#

Port the proxy listens on (the canonical Ollama port, so consumers need no changes).

Type: port

Default: 11434

options.tsunaminoai.ollamaProxy.upstreams#

Ordered upstream pool. MODEL PARITY REQUIRED: any model referenced by docPipeline/openWebui/rag options must be in every upstream’s loadModels, or failover silently degrades to missing-model errors.

Type: list of submodule

options.tsunaminoai.ollamaProxy.upstreams.<name>.backup#

Only used when all non-backup upstreams are down.

Type: boolean

Default: false

options.tsunaminoai.ollamaProxy.upstreams.<name>.host#

Upstream Ollama host (FQDN or IP).

Type: string

options.tsunaminoai.ollamaProxy.upstreams.<name>.port#

Type: port

Default: 11434

options.tsunaminoai.openWebui.enable#

Whether to enable Open-WebUI LLM chat + RAG interface.

Type: boolean

Default: false

Example: true

options.tsunaminoai.openWebui.externalUrl#

Public URL Open-WebUI is served at (behind Cloudflare Access). Sets WEBUI_URL, which is what the app uses to build absolute links. Null keeps the tailnet https://<host>.<tailnet>:<port+1> vhost URL. Mirrors tsunaminoai.telemetry.server.grafana.externalDomain.

Type: null or string

Default: null

Example: "https://chat.inaba.network"

options.tsunaminoai.openWebui.ollamaHost#

Hostname or IP of the machine running Ollama. Use mokou’s Tailscale FQDN, e.g.: “mokou.’‘${config.tsunaminoai.nix.tailscaleDomain}”

Type: string

Default: "localhost"

options.tsunaminoai.openWebui.paperlessPort#

Port Paperless-NGX is listening on (for the sync timer).

Type: port

Default: 8011

options.tsunaminoai.openWebui.port#

Host port for Open-WebUI (HTTP). HTTPS = port + 1.

Type: port

Default: 3000

options.tsunaminoai.openWebui.trustedEmailHeader#

Header carrying an already-authenticated user’s email address, which Open-WebUI will trust wholesale as the logged-in identity (WEBUI_AUTH_TRUSTED_EMAIL_HEADER — the upstream trusted-header SSO knob; the companion display-name header is trustedNameHeader).

SECURITY: this turns the named header into a full authentication bypass, so it may only be set when EVERY path to port overwrites it. Enabling it forces the container publish onto loopback and closes the firewall for port, and the tailnet vhost below explicitly clears the header — the Cloudflare Access origin vhost (which sets it from the CF-validated Cf-Access-Authenticated-User-Email) is then the only way it can arrive with a value.

Type: null or string

Default: null

Example: "X-Remote-User"

options.tsunaminoai.openWebui.trustedNameHeader#

Optional display-name counterpart to trustedEmailHeader (WEBUI_AUTH_TRUSTED_NAME_HEADER). Same spoofing caveat; it is only cosmetic, the email header is what authenticates.

Type: null or string

Default: null

Example: "X-Remote-Name"

options.tsunaminoai.pki.acme.enable#

Whether to enable step-ca ACME certificate management for this host.

Type: boolean

Default: false

Example: true

options.tsunaminoai.radio.allowedUsers#

List of users to allow on SDR

Type: list of string

Default: []

options.tsunaminoai.radio.enable#

Enable SDR radios

Type: boolean

Default: false

options.tsunaminoai.razer-mouse.enable#

Whether to enable Razer mouse desktop switcher.

Type: boolean

Default: false

Example: true

options.tsunaminoai.razer-mouse.package#

The package to use for mouse button remapping

Type: one of "karabiner-elements"

Default: "karabiner-elements"

options.tsunaminoai.rdp.defaultWindowManager#

The default window manager to use for RDP sessions

Type: string

Default: "${pkgs.icewm}/bin/icewm"

options.tsunaminoai.rdp.enable#

Whether to enable RDP support.

Type: boolean

Default: false

Example: true

options.tsunaminoai.rdp.openFirewall#

Whether to open the firewall for RDP

Type: boolean

Default: true

options.tsunaminoai.samba.enable#

Whether to enable enables samba connectivity with Voile.

Type: boolean

Default: false

Example: true

options.tsunaminoai.security.clamav.enable#

Enable the ClamAV daemon (clamd) and freshclam updater. clamd keeps the full signature database (~1.5GB) resident in RAM and will OOM-kill memory-limited hosts (e.g. Raspberry Pis); set false on those.

Type: boolean

Default: true

options.tsunaminoai.security.keybase.enable#

Whether to enable Keybase and KBFS services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.security.openssh.disable#

Whether to enable Disable SSH.

Type: boolean

Default: false

Example: true

options.tsunaminoai.security.secureDisk.autoBalance.dusage#

Only relocate data block groups up to this % full (low = safe first-pass reclaim on a near-full fs).

Type: lib.types.ints.between 0 100

Default: 10

options.tsunaminoai.security.secureDisk.autoBalance.enable#

Periodically run a filtered btrfs balance on the root filesystem to reclaim mostly-empty chunks back to unallocated space. Prevents the “fully chunk-allocated” state (Device unallocated ~0) that causes metadata ENOSPC on a btrfs fs that still reports free space.

Type: boolean

Default: true

options.tsunaminoai.security.secureDisk.autoBalance.fileSystem#

Mountpoint of the btrfs filesystem to balance.

Type: string

Default: "/"

options.tsunaminoai.security.secureDisk.autoBalance.interval#

systemd OnCalendar for the balance timer (offset from the weekly Sunday scrub).

Type: string

Default: "Wed 03:00"

options.tsunaminoai.security.secureDisk.autoBalance.musage#

Only relocate metadata block groups up to this % full.

Type: lib.types.ints.between 0 100

Default: 5

options.tsunaminoai.security.secureDisk.mainDiskId#

Device path for system disk (by-id, wwn-*, etc).

Type: string

options.tsunaminoai.security.secureDisk.nixDiskId#

Optional device path for dedicated /nix disk.

Type: null or string

Default: null

options.tsunaminoai.servarr-backup.backupPath#

Path where backups will be stored (should be on Synology NAS)

Type: string

Default: "/mnt/voile/Inaba/Yunohost/yunohost.backup/servarr-sqlite"

options.tsunaminoai.servarr-backup.backupTime#

Time of day to run backups (HH:MM:SS in 24-hour format)

Type: string

Default: "02:00:00"

options.tsunaminoai.servarr-backup.compression#

Compression format for archives

Type: one of "gz", "bz2", "xz"

Default: "gz"

options.tsunaminoai.servarr-backup.dependencies#

Services that must be running before backup (stops them during backup)

Type: list of string

Default:

[
  "prowlarr.service"
  "sonarr.service"
  "radarr.service"
  "readarr.service"
  "lidarr.service"
]

options.tsunaminoai.servarr-backup.enable#

Enable automated SQLite database backups for Servarr services

Type: boolean

Default: config.tsunaminoai.servarr.enable

options.tsunaminoai.servarr-backup.enableMonitoring#

Enable monitoring of backup success/failure

Type: boolean

Default: true

options.tsunaminoai.servarr-backup.logPath#

Directory for backup operation logs

Type: string

Default: "/var/log/servarr-backups"

options.tsunaminoai.servarr-backup.onFailure#

Action to take on backup failure (systemd OnFailure directive)

Type: string

Default: "Unit=systemd-logind.service"

options.tsunaminoai.servarr-backup.retentionDays#

Number of days to retain backups

Type: signed integer

Default: 14

options.tsunaminoai.servarr.confineIndexers#

Also confine prowlarr + flaresolverr (indexer/tracker egress) to the exit-node netns, not just qbittorrent. See vpn.nix.

Type: boolean

Default: true

options.tsunaminoai.servarr.enable#

Whether to enable enables media aquisition.

Type: boolean

Default: false

Example: true

options.tsunaminoai.servarr.qbittorrentStateDir#

Local directory holding qBittorrent’s config, resume data (BT_backup) and its active/complete download trees.

Null keeps all of that in the media user’s CIFS home — the arrangement that wedged the kernel on 2026-08-18: torrent I/O is random 4 MB piece writes plus mmap’d reads for hashing, and when the SMB session reconnected, cifs_reopen_file’s flush deadlocked against an in-flight write on the same folio. Five threads went into unkillable D state, the thread-group leader became an unreapable zombie, and the unit spun for 104 restart cycles until the host was rebooted.

Point this at local storage (a kurVolumes LV on ereshkigal) so no torrent I/O ever touches SMB. qBittorrent then downloads and seeds entirely from local disk; the *arrs import from here onto the share. Note this puts downloads and the media library on different filesystems, so imports become copy+delete rather than hardlink/rename — a completed torrent occupies local space for as long as it seeds.

Type: null or path

Default: null

Example: "/var/lib/qbittorrent"

options.tsunaminoai.spotify.enable#

Whether to enable Enable spotify daemon.

Type: boolean

Default: false

Example: true

options.tsunaminoai.tailscale.advertiseExit#

Whether to enable advertise THIS host as an exit node (sets useRoutingFeatures = “server” and passes –advertise-exit-node). For a VPS exit node like myon; mutually exclusive in practice with useExit (a node provides or consumes) .

Type: boolean

Default: false

Example: true

options.tsunaminoai.tailscale.authKeyFile#

The path to the sops-encrypted file containing the Tailscale auth key

Type: string

Default: config.sops.secrets."tailscale/auth-key".path

options.tsunaminoai.tailscale.enable#

Whether to enable Tailscale autoconnect.

Type: boolean

Default: false

Example: true

options.tsunaminoai.tailscale.extraSetFlags#

Extra flags to pass to ‘tailscale set

Type: list of string

Default: []

options.tsunaminoai.tailscale.extraUpFlags#

Extra flags to pass to ‘tailscale up

Type: list of string

Default: []

options.tsunaminoai.tailscale.netnsExit.authKeyFile#

Auth key used for the in-netns node’s first join (must be reusable/pre-approved).

Type: string

Default: config.sops.secrets."tailscale/auth-key".path

options.tsunaminoai.tailscale.netnsExit.confinedUnits#

systemd service names (no .service suffix) to move into the namespace.

Type: list of string

Default: []

Example: ["qbittorrent-nox"]

options.tsunaminoai.tailscale.netnsExit.enable#

Whether to enable netns-confined tailscale exit-node egress for selected services.

Type: boolean

Default: false

Example: true

options.tsunaminoai.tailscale.netnsExit.exitNode#

Tailnet IP (or MagicDNS name) of the exit node to use (myon).

Type: string

Default: "100.70.92.129"

options.tsunaminoai.tailscale.netnsExit.externalInterface#

Host interface the veth subnet is NAT-masqueraded out of.

Type: string

Example: "vmbr0"

options.tsunaminoai.tailscale.netnsExit.hostAddress#

Host side of the veth /30.

Type: string

Default: "10.100.100.1"

options.tsunaminoai.tailscale.netnsExit.hostProxies#

Confined TCP ports republished on the host via systemd-socket-proxyd.

Type: list of port

Default: []

options.tsunaminoai.tailscale.netnsExit.hostname#

Tailnet hostname for the in-netns node.

Type: string

Default: "${config.networking.hostName}-${cfg.namespace}"

options.tsunaminoai.tailscale.netnsExit.namespace#

Name of the network namespace (and suffix for units/interfaces).

Type: string

Default: "vpn"

options.tsunaminoai.tailscale.netnsExit.nsAddress#

Namespace side of the veth /30.

Type: string

Default: "10.100.100.2"

options.tsunaminoai.tailscale.netnsExit.nsProxies#

Host TCP ports republished on the in-namespace loopback via socat.

Type: list of port

Default: []

options.tsunaminoai.tailscale.netnsExit.resolvers#

Nameservers for the namespace. Confined services resolve through the tunnel (DNS dies with the tunnel — consistent with the kill switch); tailscaled bootstraps against them via the veth (uid-0 exemption).

Type: list of string

Default: ["1.1.1.1" "9.9.9.9"]

options.tsunaminoai.tailscale.netnsExit.tunName#

TUN device name for the in-netns tailscaled.

Type: string

Default: "ts${cfg.namespace}0"

options.tsunaminoai.tailscale.useExit#

Whether to enable Use the exit nodes.

Type: boolean

Default: false

Example: true

options.tsunaminoai.telemetry.agent.credentialsEnvFile#

EnvironmentFile (sops-managed) providing TELEMETRY_INGEST_USERNAME and TELEMETRY_INGEST_PASSWORD for basic auth against the ingest edge. Keep it under /run/secrets — never /var/run.

Type: path

Example: "/run/secrets/telemetry/ingest-env"

options.tsunaminoai.telemetry.agent.enable#

Whether to enable the telemetry collection agent (Grafana Alloy + local exporters).

Type: boolean

Default: false

Example: true

options.tsunaminoai.telemetry.agent.exporters.ipmi.enable#

ipmi exporter (fans/temps/PSU). Off until privileges are proven on the live host.

Type: boolean

Default: false

options.tsunaminoai.telemetry.agent.exporters.node.enable#

node_exporter (base host metrics + the textfile collector).

Type: boolean

Default: true

options.tsunaminoai.telemetry.agent.exporters.smartctl.devices#

Devices to monitor (empty = auto-scan). Behind a PERC/megaraid controller the auto-scan misses member disks — verify the needed megaraid,N device args on the live host during rollout.

Type: list of string

Default: []

options.tsunaminoai.telemetry.agent.exporters.smartctl.enable#

smartctl exporter (disk health).

Type: boolean

Default: false

options.tsunaminoai.telemetry.agent.exporters.systemd.enable#

systemd exporter (failed-unit detection — the highest-value signal).

Type: boolean

Default: true

options.tsunaminoai.telemetry.agent.journal.enable#

Ship this host’s journald to VictoriaLogs.

Type: boolean

Default: true

options.tsunaminoai.telemetry.agent.journal.maxAge#

How far back to read journald on first start / after downtime.

Type: string

Default: "12h"

options.tsunaminoai.telemetry.agent.serverUrl#

Base URL of the telemetry ingest edge. Defaults to https://<serverHost>.<tailscaleDomain>:<ingestPort>.

Type: null or string

Default: null

Example: "https://ereshkigal.tailnet.ts.net:8427"

options.tsunaminoai.telemetry.alertRules#

vmalert alerting rules contributed by modules, grouped by module/namespace (one vmalert group per namespace). Rules follow the Prometheus rule schema (alert, expr, for, labels, annotations). Set datasource = "logs" on a rule to evaluate it against VictoriaLogs (LogsQL stats expr) instead of VictoriaMetrics.

Type: attribute set of list of attribute set

Default: {}

Example:

{
  backups = [
    {
      alert = "ServarrBackupStale";
      expr = "time() - servarr_backup_last_timestamp > 86400 * 2";
      "for" = "1h";
      labels.severity = "warning";
      annotations.summary = "servarr backup is more than 2 days old";
    }
  ];
}

options.tsunaminoai.telemetry.ingestPort#

HTTPS port of the ingest edge on the server host (nginx, step-ca cert, basic auth). Agents push metrics to /api/v1/write and logs to /insert/loki/api/v1/push on this port.

Type: port

Default: 8427

options.tsunaminoai.telemetry.logFilters#

Journald drop filters applied at this host’s agent, grouped by module/namespace. Each entry: selector (a Loki stream selector, e.g. matching the unit label) and dropRegex (lines matching are dropped before they ever leave the host).

Type: attribute set of list of attribute set

Default: {}

Example:

{
  paperless = [
    {
      selector = "{unit=\"podman-paperless.service\"}";
      dropRegex = ".*(DEBUG|paperless.tasks).*";
    }
  ];
}

options.tsunaminoai.telemetry.scrapeTargets#

Additional Prometheus scrape targets for this host’s telemetry agent, grouped by module/namespace. Each entry: targets (list of host:port), optional job (defaults to the namespace), optional labels (attrset of extra labels).

Type: attribute set of list of attribute set

Default: {}

Example:

{
  paperless = [
    {
      targets = ["127.0.0.1:9187"];
      labels.role = "database";
      # job defaults to the namespace ("paperless")
    }
  ];
}

options.tsunaminoai.telemetry.server.complianceExceptions#

Risk acceptances (same shape as tsunaminoai.compliance.exceptions) whose monitors are dropped before rule compilation, so an accepted risk stops alerting. Wire it to the compliance option on the host — they are deliberately separate so this module needs no dependency on the compliance module; the compliance side owns the justification and the attestation record.

Type: attribute set of attribute set

Default: {}

Example: config.tsunaminoai.compliance.exceptions

options.tsunaminoai.telemetry.server.complianceMonitors#

Compliance controls (nff lib.mkControl / praxis schema shapes) whose monitors[]/alerts[] are compiled into vmalert rule groups by flake.lib.telemetry.monitorsToRuleGroups. Untranslatable conditions surface as evaluation warnings, not silent gaps.

Type: attribute set of attribute set

Default: {}

Example:

{
  LGO-02 = {
    monitors = [ { name = "lgo-02-auditd-active"; interval = "5m";
                   conditions = ["auditd.service == active"]; } ];
    alerts = [ { severity = "critical"; remediation = "systemctl restart auditd"; } ];
  };
}

options.tsunaminoai.telemetry.server.dataDir#

Data root for VM/VictoriaLogs/Grafana. Must live under /var/lib (systemd StateDirectory). On ereshkigal this should be a tsunaminoai.kurVolumes LV — never the btrfs root.

Type: string

Default: "/var/lib/telemetry"

options.tsunaminoai.telemetry.server.discordMirror.enable#

Whether to enable mirroring paging-worthy alerts to Discord as well as ntfy.

Scope is deliberately narrow (the point is a channel that stays readable): severity="critical" AND no control label — i.e. SystemdUnitFailed / EndpointDown / SmartDeviceUnhealthy, but NOT the compliance-generated control alerts, which are chronic-prone process drift and stay on ntfy + Grafana. Re-notification is daily rather than the root route’s 4h. ntfy keeps receiving everything either way.

Requires DISCORD_WEBHOOK_URL in healthchecksEnvFile (Alertmanager gets one EnvironmentFile; a webhook_url_file pointing at a raw sops secret cannot work — the unit is DynamicUser and the secrets are root-owned 0400) .

Type: boolean

Default: false

Example: true

options.tsunaminoai.telemetry.server.enable#

Whether to enable the telemetry server role (VictoriaMetrics + VictoriaLogs + Grafana + vmalert + Alertmanager + ntfy).

Type: boolean

Default: false

Example: true

options.tsunaminoai.telemetry.server.grafana.adminPasswordFile#

File with the Grafana admin password (sops-managed).

Type: path

Example: "/run/secrets/telemetry/grafana-admin"

options.tsunaminoai.telemetry.server.grafana.externalDomain#

Public hostname Grafana is served at (behind Cloudflare Access). When set: domain/root_url use this name (not the tailnet fqdn:httpsPort), and the tailnet Grafana vhost is NOT created — the loopback backend is reachable only through the CF-tunnel origin defined in host config. Pair with oauthEnvFile for OIDC login/role-mapping. Null keeps the tailnet-only step-ca vhost with password auth.

Type: null or string

Default: null

Example: "grafana.inaba.network"

options.tsunaminoai.telemetry.server.grafana.httpsPort#

HTTPS port for the Grafana vhost.

Type: port

Default: 3443

options.tsunaminoai.telemetry.server.grafana.oauthEnvFile#

sops EnvironmentFile enabling Grafana OIDC (auth.generic_oauth) against the Cloudflare Access SaaS app. Must define GF_AUTH_GENERIC_OAUTH_ CLIENT_ID, _CLIENT_SECRET, _AUTH_URL, _TOKEN_URL, _API_URL — all emitted by nix run .#terraform-cloudflare -- output after the grafana OIDC app is applied (the URLs embed the app’s client_id, so they can’t be hardcoded). Null → password auth only.

Type: null or path

Default: null

Example: "/run/secrets/telemetry/grafana-oidc-env"

options.tsunaminoai.telemetry.server.grafana.oauthRoleAttributePath#

Grafana generic_oauth role_attribute_path (JMESPath over the OIDC claims) mapping group membership to a Grafana role. Verify the claim name against a real token — Cloudflare Access must be configured to include group memberships in the OIDC token for this to resolve.

Type: string

Default: "'Viewer'"

Example: "contains(groups[*].id, '<admin-group-guid>') && 'Admin' || 'Viewer'"

options.tsunaminoai.telemetry.server.grafana.secretKeyFile#

File with Grafana’s security.secret_key (DB secret encryption; the module refuses the old insecure default). Generate once, keep stable — rotating re-encrypts nothing automatically.

Type: path

Example: "/run/secrets/telemetry/grafana-secret-key"

options.tsunaminoai.telemetry.server.healthchecksEnvFile#

Alertmanager’s EnvironmentFile (it takes exactly one), providing HEALTHCHECKS_PING_URL (a hosted healthchecks.io check’s ping URL, sops-managed). The always-firing Watchdog alert pings it; silence beyond the check’s grace period alarms from infrastructure sharing no failure domain with home. Null disables the dead-man’s-switch leg (a warning reminds you). With discordMirror.enable this same file must also define DISCORD_WEBHOOK_URL — merge both with sops.templates (see the ereshkigal alertmanager-env template).

Type: null or path

Default: null

Example: "/run/secrets/telemetry/healthchecks-env"

options.tsunaminoai.telemetry.server.ingestBasicAuthFile#

htpasswd file (sops-managed) for the ingest edge. Multiple entries supported — give each pushing host its own user so credentials can be rotated per-host. Generate entries with echo "user:$(openssl passwd -6 'pass')".

Type: path

Example: "/run/secrets/telemetry/ingest-htpasswd"

options.tsunaminoai.telemetry.server.nonCriticalUnits#

Full unit names whose failures alert at severity=warning — ntfy only, no Discord mirror (the mirror route matches severity=critical) — instead of critical. Housekeeping units whose failure is self-healing, informational or scoped to one service belong here; a unit whose failure means an outage does not.

Names are matched exactly via an anchored regex alternation: listed units are excluded from SystemdUnitFailed and picked up by SystemdUnitFailedNonCritical instead. The rules compile only on the telemetry server, so the list is fleet-wide, not per-host.

Type: list of string

Default: []

Example: ["paperless-openwebui-sync.service" "ws4channels-drift.service"]

options.tsunaminoai.telemetry.server.ntfy.authEnvFile#

sops EnvironmentFile declaratively provisioning ntfy users and tokens (NTFY_AUTH_USERS=user:bcrypt:role,… and NTFY_AUTH_TOKENS=user:tk_…,…). Must provision alertmanager (publisher — declare the SAME token stored in tokenConfigFile) and reader (read-only subscriber for humans/phones); the ACL in settings.auth-access references those names. ntfy upserts these into user.db at startup and upgrades same-named imperative rows to provisioned; entries later removed from the config are deleted. Imperatively-created users NOT named here (e.g. a break-glass admin) are left untouched. Null keeps the imperative-only flow.

Type: null or path

Default: null

Example: "/run/secrets/telemetry/ntfy-auth-env"

options.tsunaminoai.telemetry.server.ntfy.httpsPort#

HTTPS port for the ntfy vhost (phone subscriptions).

Type: port

Default: 2587

options.tsunaminoai.telemetry.server.ntfy.tokenConfigFile#

Extra YAML config for alertmanager-ntfy holding the publish token (ntfy: { auth: { token: … } }), sops-managed. The token value must be the SAME tk_… declared for the alertmanager user in authEnvFile (that file provisions it into ntfy; this file hands it to the bridge). With authEnvFile unset, legacy flow: create the user/token imperatively (ntfy user add alertmanager + ntfy access alertmanager <topic> write-only + ntfy token add alertmanager).

Type: null or path

Default: null

Example: "/run/secrets/telemetry/ntfy-bridge-config"

options.tsunaminoai.telemetry.server.ntfy.topic#

ntfy topic alerts are published to.

Type: string

Default: "alerts"

options.tsunaminoai.telemetry.server.retention.logs#

VictoriaLogs -retentionPeriod. Default tracks praxis MON-10’s event-log-retention knob default (3 months) — the centralized store must meet or exceed the enforced per-host retention.

NB VictoriaLogs’ duration grammar differs from VictoriaMetrics’: the month suffix is a capital M (suffixes s/h/d/w/M/y; a bare number is also months). 3month is NOT accepted — victoria-logs exits with cannot parse duration and the unit crash-loops.

Type: string

Default: "3M"

options.tsunaminoai.telemetry.server.retention.metrics#

VictoriaMetrics -retentionPeriod (bare number = months).

Type: string

Default: "12"

options.tsunaminoai.telemetry.serverHost#

Hostname (tailnet name) of the host running the telemetry server role.

Type: string

Default: "ereshkigal"

options.tsunaminoai.tmpHygiene.cleanOnBoot#

Reboot trigger: empty path on every boot (boot.tmp.cleanOnBoot).

Type: boolean

Default: true

options.tsunaminoai.tmpHygiene.enable#

Whether to enable bounded /tmp cleanup (age OR size OR reboot — whichever is soonest).

Type: boolean

Default: false

Example: true

options.tsunaminoai.tmpHygiene.maxAge#

Age trigger: systemd-tmpfiles removes entries older than this (any of atime/btime/ctime/mtime). Empty string disables the age trigger.

Type: string

Default: "30d"

Example: "14d"

options.tsunaminoai.tmpHygiene.maxDiskPercent#

Size trigger: when path exceeds this percent of its backing filesystem, prune oldest entries until back under. 0 disables it.

Type: lib.types.ints.between 0 100

Default: 10

options.tsunaminoai.tmpHygiene.path#

Directory to keep bounded. Must be its own dir on a real filesystem (not a parent of live mounts).

Type: string

Default: "/tmp"

options.tsunaminoai.tmpHygiene.sizeCheckInterval#

OnCalendar cadence for the size-trigger check.

Type: string

Default: "hourly"

options.tsunaminoai.users.media.enable#

Whether to enable Enable media user.

Type: boolean

Default: false

Example: true

options.tsunaminoai.users.media.gid#

GID for media user

Type: signed integer

Default: 100001

options.tsunaminoai.users.media.group#

group name for media user

Type: string

Default: "nix-media-sops"

options.tsunaminoai.users.media.homeDir#

Path for media’s home dir. Will not be created.

Type: path

Default: "/mnt/voile/Inaba/Yunohost/"

options.tsunaminoai.users.media.uid#

UID for media user

Type: signed integer

Default: 100021

options.tsunaminoai.users.media.username#

user name for media user

Type: string

Default: "nix-media-sops"

options.tsunaminoai.virtualization.enable#

Whether to enable Enable virtualization.

Type: boolean

Default: false

Example: true

originModule.options.accessGroup#

Which Entra security group the CF Access policy for this origin allows. Symbolic (the group Object IDs live in the terraform module, not host config): family = sg-voile-personal (the default for every user-facing service); observability = sg-voile-personal-admins (Grafana/ntfy — logs and alert data restricted to admins).

Type: one of "family", "observability"

Default: "family"

originModule.options.backend#

Upstream URL the origin vhost proxies to (bind your service to loopback).

Type: string

Example: "http://127.0.0.1:4533"

originModule.options.displayName#

Human-readable tile name used by the Cloudflare App Launcher and Terraform Access app resources.

Type: string

Example: "Watch (Jellyfin)"

originModule.options.extraLocationConfig#

Extra nginx config appended to the origin location block.

Type: strings concatenated with "\n"

Default: ""

originModule.options.identityHeader#

Backend header to receive the Cloudflare Access-authenticated email (e.g. “Remote-User” for Navidrome header SSO). Null = don’t map; the backend keeps its own login.

Type: null or string

Default: null

Logo URL shown on this app’s Cloudflare App Launcher tile (terraform logo_url).

Type: string

Default: ""

Example:

"https://raw.githubusercontent.com/loganmarchione/homelab-svg-assets/refs/heads/main/assets/jellyfin.svg"

originModule.options.oidc.enable#

Whether to enable a Cloudflare Access SaaS OIDC app (CF Access as this service’s OIDC IdP).

Type: boolean

Default: false

Example: true

originModule.options.oidc.groupFilterRegex#

Regex selecting which of the user’s CF Access groups are emitted in the OIDC groups claim (id_token + userinfo). Null = emit none. Scope it tightly — every matching group name is exposed to the app (e.g. for Grafana admin role mapping via role_attribute_path).

Type: null or string

Default: null

Example: "^sg-voile-personal-admins$"

originModule.options.oidc.redirectURIs#

OIDC callback URLs the app will redirect to.

Type: list of string

Default: []

Example: ["https://audiobooks.inaba.network/auth/openid/callback"]

originModule.options.oidc.scopes#

OIDC scopes shared with the app.

Type: list of string

Default: ["openid" "email" "profile"]

originModule.options.originPort#

Port for the HTTPS origin vhost cloudflared connects to.

Type: port

originModule.options.publicHostname#

Public hostname served by Cloudflare (e.g. music.inaba.network).

Type: string

Example: "music.inaba.network"

originModule.options.tags#

Cloudflare App Launcher tag names for grouping/filtering this app’s tile.

Type: list of string

Default: []

Example: ["family" "entertainment"]

originModule.options.userHeader#

Header Cloudflare Access injects with the authenticated identity.

Type: string

Default: "Cf-Access-Authenticated-User-Email"

originModule.options.websockets#

Proxy websocket upgrades to the backend.

Type: boolean

Default: true


Generated with nix-options-doc