Sweep every machine for config worth tracking

Reactive capture missed wallust entirely, so this is a systematic pass over
~/.config on all four machines: every entry that is not already a symlink,
judged on whether it is hand-authored config or app-generated state.

Shared and identical everywhere -> common/: lazygit, ncmpcpp, neofetch,
matplotlib. Everything else differs per machine and goes in
hosts/<host>/config/: gtk-2.0/3.0/4.0, mimeapps.list, user-dirs.dirs,
mpv, swaync, swayimg, bob, pavucontrol.ini, zoom; plus beets, bottom,
glow and mpd on system76; fastfetch, gh, uv, traggo, tiling-assistant and
xdg-desktop-portal on the work laptop; inbox-tidy and llmfit on mainframe.

Deliberately excluded, all verified to hold live credentials: the work
laptop's Claude OAuth tokens (~/.config/anthropic/credentials), the NAS
restic repo password and hetzner.env, subsonic passwords in subtui, stmp
and termsonic, mopidy, supersonic, the Proton bridge env and the LiteLLM
virtual keys. The ignore list now names those shapes directly — a bare
`password` file would not have been caught before.

Also excluded as generated state or too large to be meaningful: GIMP,
kicad, BambuStudio, OrcaSlicer, calibre, LightBurn, obs-studio, feishin,
libreoffice, VirtualBox, FortiClient; and mainframe's dead X11-era
leftovers (i3, openbox, lxpanel, lxsession, pcmanfm).
This commit is contained in:
2026-09-14 14:54:17 -04:00
parent 45e76f375f
commit 29bcf615e6
56 changed files with 5188 additions and 1 deletions
@@ -0,0 +1,99 @@
# inbox_tidy -- archive stale unread mail out of the Proton inbox.
#
# Nothing here deletes anything. The only operation is an IMAP MOVE from INBOX
# to Archive, recorded in ~/.local/share/inbox-tidy/archived.jsonl so any run
# can be reversed with `inbox_tidy --undo <run-id>`.
# ARMED? Left false until `--check` has been compared against the Proton web
# UI and `--dry-run` has been read. --check and --dry-run work regardless.
enabled = true
# Unread for longer than this many days is a candidate.
age_days = 3
# Most that will be archived in one run. A backlog drains over several days
# rather than in one sweep, which also caps how much a bad guard list can move
# before you notice. `--max` overrides.
max_per_run = 250
# ---------------------------------------------------------------------------
# Interlocks. Both abort the run rather than archiving; both exist because of
# something actually observed, not as theoretical caution.
# ---------------------------------------------------------------------------
# Bridge reported 1249 unread in INBOX while the Proton UI showed 646. Resolved
# 2026-09-09: NOT a flag problem. The initial sync finished at 100% and the
# count did not move, and the messages were spot-checked in the web UI as
# genuinely unread and genuinely in the Inbox. Threading was also ruled out
# (1249 messages -> 1247 RFC thread roots, 1026 distinct subjects; no grouping
# scheme reaches 648). Most likely Proton's inbox categories showing a subset
# in the badge. Unresolved, but no longer load-bearing.
#
# Backlog drained 2026-09-09 (1180 archived over 5 runs; INBOX went to 14
# messages / 0 unread). Lowered back from the temporary 1400 now that steady
# state is one day's mail -- at 1400 this interlock could never fire, and an
# interlock that cannot fire is not one. 200 is roughly a week of arrivals, so
# it tolerates a holiday without tripping while still catching a runaway.
expected_unread_max = 200
# The correspondent allowlist is derived from the Sent mailbox. If Sent is
# nearly empty (as it was mid-sync, at 11 messages) that guard silently does
# nothing. Refuse to run rather than sweep up mail from people you write to.
min_correspondents = 25
# ---------------------------------------------------------------------------
# Guards. Evaluated in this order, before the archive decision, so anything
# uncertain resolves to leaving the message where it is.
#
# 1. \Flagged or \Answered (no config; always protected)
# 2. protect_senders
# 3. anyone in the Sent-derived correspondent list
# 4. protect_subjects
# 5. no Message-ID (could not be undone, so is not moved)
# ---------------------------------------------------------------------------
# An entry containing @ matches that address exactly. An entry without one
# matches the domain AND its subdomains, so "chase.com" also covers
# "fraudalert.chase.com" -- which is the case that actually matters.
protect_senders = [
# Deliberately empty to start. Add whatever gets archived that you wanted
# kept; the log names the sender for every move, so this list can be grown
# from evidence rather than guessed at up front.
]
# Case-insensitive regexes tested against the Subject. These are the mails
# where not noticing has a real cost, so they are held back across every
# sender rather than relying on protect_senders being complete.
protect_subjects = [
'fraud',
'security alert',
'suspicious',
'unauthori[sz]ed',
'action (needed|required)',
'verify your',
'past due',
'overdue',
'final notice',
'court|subpoena|jury',
'\bIRS\b',
]
[ntfy]
url = "https://ntfy.rcjohnstone.com"
# Its own topic, NOT rent-utilities -- that one is a monthly message worth
# reading, and burying it under a daily archive summary would train you to
# swipe both away. `ntfy access bot inbox-tidy rw` was granted so delivery can
# be verified by polling, not just inferred from a 200 (the `bot` user is
# write-only on `*`, so polling with its token otherwise returns an empty list
# even when messages are sitting there).
topic = "inbox-tidy"
[imap]
host = "127.0.0.1"
port = 1143
starttls = true
user = "c@rcjohnstone.com"
password_env = "PROTON_BRIDGE_PASSWORD"
sent_mailbox = "Sent"
# Cap on how much of Sent is read to build the allowlist.
sent_scan_limit = 3000