Config Overrides

Background and reasoning behind design decisions in splam. This page won’t tell you how to do something. See the How-To Guides for that.

Why admin-task notes and highlight keywords are a code + override pair

SERVICE_INFO in service_info.py and _PATTERNS in highlight.py are plain Python data structures. That keeps the app dependency-free (no database, no migration), makes the shipped defaults reviewable as an ordinary code change, and lets a SERVICE_INFO entry be shared across multiple unit-name aliases (ssh.service / sshd.service) without duplication.

Changes made through the Configure button don’t touch that code. They’re written to two JSON files in the app’s data directory (service_info_overrides.json and highlight_overrides.json), which are merged on top of the built-in data at read time (override wins on a key collision). This gives operators a way to add or correct guidance and highlighting per deployment, without a code change or redeploy, while keeping the reviewed defaults in version control. The tradeoff: overrides live on the instance that made them and aren’t automatically shared across deployments. Promote a useful override into the code (SERVICE_INFO or _PATTERNS) if it should ship by default.

Nothing is merged ahead of time. The two halves stay separate on disk and come together on each read, which is why an override takes effect without a restart.

%%{init: {'theme': 'dark', 'themeVariables': { 'fontFamily': 'monospace', "fontSize":"18px", "darkMode":true}}}%%

flowchart TD
    subgraph Code["<strong>Code</strong>"]
        SI["<strong>SERVICE_INFO</strong><br>service_info.py"]
        PT["<strong>_PATTERNS</strong><br>highlight.py"]
    end

    subgraph Ovr["<strong>Overrides</strong>"]
        SIJ[("service_info_overrides.json")]
        PTJ[("highlight_overrides.json")]
    end

    Btn(["Configure button"])
    Merge{"merge at read time<br>override wins"}
    OutA[\"Tasks tab guidance"\]
    OutB[\"highlighted Status /<br>Logs text"\]

    Btn --> SIJ
    Btn --> PTJ
    SI ==> Merge
    PT ==> Merge
    SIJ ==> Merge
    PTJ ==> Merge
    Merge ==> OutA
    Merge ==> OutB

    style SI fill:#4CBB9D,color:#FFFFFF,rx:5,ry:5,font-family:monospace
    style PT fill:#4CBB9D,color:#FFFFFF,rx:5,ry:5,font-family:monospace
    style Merge fill:#4CBB9D,color:#FFFFFF,rx:5,ry:5
    style OutA fill:#4CBB9D,color:#FFFFFF,rx:5,ry:5
    style OutB fill:#4CBB9D,color:#FFFFFF,rx:5,ry:5
    style SIJ fill:#FFFFFF,color:#000000,stroke:#333,stroke-width:1px,rx:5,ry:5,font-family:monospace
    style PTJ fill:#FFFFFF,color:#000000,stroke:#333,stroke-width:1px,rx:5,ry:5,font-family:monospace
    style Btn fill:#FFFFFF,color:#000000,stroke:#333,stroke-width:1px,rx:5,ry:5
    style Code fill:#FFFFFF,color:#000000,stroke:#333,stroke-width:1px,rx:10,ry:10
    style Ovr fill:#FFFFFF,color:#000000,stroke:#333,stroke-width:1px,rx:10,ry:10

Where the override files live

The data directory resolves from SPLAM_DATA_DIR, else XDG_DATA_HOME, else ~/.local/share/splam (see paths.py). Everything the app writes at runtime lands there:

<data dir>/
├── credentials.json
├── audit_log.jsonl
├── service_info_overrides.json
└── highlight_overrides.json

The two overrides files only exist once Configure has been used at least once. They aren’t created at install time, so a deployment that never opened the dialog has a data directory with two files in it and behaves entirely off the shipped defaults.