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.
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/<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
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://
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
“speakerID
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
options.tsunaminoai.haosVm.iotLeg.uplink#
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"
options.tsunaminoai.homer.links#
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
options.tsunaminoai.media.weatherChannel.ws4channels.usePermalink#
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
originModule.options.logo#
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