fix(ansible): install btop with saved config and a launcher that fits phone panes - #31
Merged
Merged
Conversation
added 3 commits
October 1, 2026 18:03
Byte-for-byte copy of the btop.conf btop 1.4.7 wrote on a clean quit (sha256 9d48d3c289346e4e9f55bc9e8888369ed155268448857de5bb4a7f8326ec49e0).
btop shows only "Terminal size too small" in a pane smaller than its shown boxes need: 80x24 for all four boxes in btop 1.4 (cpu 60 columns wide, proc 44 beside the 36 of mem and net). A Herdr phone pane is about 50 columns, so btop never loaded there. Channel: btop comes from the latest upstream GitHub release (aristocratos/btop), not the snap. scripts/install_tools.py installs the static musl build as a core tool, verified against the GitHub release-asset SHA-256, the same path herdr, gh and treehouse use (docs/architecture.md rule 1). The snap is a third-party repack (publisher kz6fittycent, not upstream) with no published checksum the installer can verify, and snapd is not available in the container image. The installer links the binary as ~/.local/bin/btop-bin. It reads ~/.config/btop/btop.conf, so the config is installed there instead of at the snap path. Config change against the capture (sha256 9d48d3c2...): the previous commit is the capture byte-for-byte. This commit changes one line: line 26, presets, gains " proc:0:default", which defines preset 4 (processes only). btop 1.4.7 does not know the captured proc_tree_auto_collapse = 0 line (the snap was built from a newer upstream commit), so it ignores the line and drops it when it rewrites the file on exit. Every apply restores it. Mechanism: maintenance/btop.sh (plain sh, about 20 lines), installed as ~/.local/bin/btop, reads stty size. It starts btop with preset 0 (all boxes) in a pane of at least 80x24, and with preset 4 otherwise. The threshold is btop's real minimum for all four boxes, measured on real btop; at 50 columns only proc alone (44x16) or mem+net fits, and preset 4 keeps the saved proc_sorting = "cpu direct". A preset in btop.conf is the only way to choose boxes from the command line (-p). The launcher runs btop in the background and traps WINCH. When a live resize crosses 80x24, it sends TERM (btop exits cleanly) and starts btop again with the other preset. When btop quits, the launcher exits with btop's status. It always passes -p, because btop saves the last preset's shown_boxes on exit; without -p, a phone session would leave the desktop pane showing only proc. btop's stdin is a copy of the original stdin, not /dev/tty: with a /dev/tty stdin btop assumes a Linux console and drops to 16-color tty mode. ansible/tasks/herdr.yml installs the launcher and config on every apply; verify.yml checks they exist. Proof, real btop 1.4.7 in throwaway tmux sessions: 50x40 shows preset 4; a live resize to 177x66 shows the full layout; back to 50x40 and wide again switch correctly; quitting exits 0. 80x24 shows the full layout, 79x30 and 120x23 show preset 4. Quitting in phone mode and then starting wide shows the full layout. Five rapid resize cycles end on the correct preset with no leftover processes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
save the current btop config and fix the fact that it cannot load on my mobile screen
Context: btop (snap
btop1.4.7, launched as~/.local/bin/btop->/snap/bin/btop) runs in a Herdr pane on the fleet host. Its "current config" is the btop.conf it wrote on a clean quit on 2026-10-01 (it had never been written to disk before). Its notable non-default values:update_ms = 100,shown_boxes = "cpu mem net proc",proc_sorting = "cpu direct",color_theme = "Default". The snap keeps config at~/snap/btop/current/.config/btop/btop.conf. Code-Factory does not install or configure btop today.The mobile problem: on a phone, Herdr switches at or below
mobile_width_threshold(64 columns by default) to its single-column mobile layout, where the pane is the full screen width, about 50 columns in portrait over SSH or mosh (Code-Factory docs/herdr.md "On a phone"). btop refuses to draw a layout smaller than the shown boxes need and shows "Terminal size too small" instead. With all four boxes it needs about 80x24: in btop 1.4 the cpu box needs 60 columns, mem 36, net 36, proc 44, and mem/net sit beside proc. So on the phone btop never loads, while the desktop pane (177x66 today) needs the full layout.What Changed
scripts/install_tools.py,factory_core_tools,--toolsdefaults, and container smoke commands). It installs the static musl release as~/.local/bin/btop-bin, andtests/test_install_tools.pyresolves it. Addsconfig/btop.conf, the saved btop config (update_ms = 100,shown_boxes = "cpu mem net proc",proc_sorting = "cpu direct",color_theme = "Default"). Its preset 4 is processes only.maintenance/btop.sh, installed as~/.local/bin/btop. It startsbtop-binwith preset 0 (all boxes) in a pane of at least 80x24 and with preset 4 (processes only, 44x16) in a smaller pane. A resize that crosses 80x24 restarts btop with the other preset. This stops btop showing "Terminal size too small" in Herdr's ~50-column phone pane.ansible/tasks/herdr.ymlnow installs the launcher and the config at~/.config/btop/btop.confon every apply.ansible/tasks/verify.ymlchecks that the launcher,btop-binand the config exist.docs/herdr.mdgains a btop section.docs/dependencies.mdlists btop and raises the GitHub lookup maximum from eight to nine.Channel and mechanism
scripts/install_tools.pyuses for herdr, gh and treehouse: always latest, never pinned, checksum-verified (docs/architecture.md rule 1). The snap is not upstream. It is a third-party repack by publisher kz6fittycent, has no published checksum the installer can verify, and snapd is not available in the container image. The upstream binary reads~/.config/btop/btop.conf, so the config is installed there instead of at the snap path. The snap stays installed on this host but is no longer used.presets, which gainsproc:0:defaultto define preset 4 (processes only). btop 1.4.7 does not know the capturedproc_tree_auto_collapse = 0line, because the snap was built from newer upstream code. btop drops that line when it rewrites the file on exit, and every apply puts it back.-p. The threshold is btop's own minimum for all four boxes, 80x24, measured on real btop, not Herdr's 64. At 50 columns only proc alone (44x16) or mem+net fits. Preset 4 keeps the savedproc_sorting = "cpu direct".clean_quit, so it restores the terminal. The launcher always passes-p, because btop saves the last preset'sshown_boxeson exit.Risk Assessment
Testing
The config-fidelity scenario passed live: the repo config matches the operator's saved btop config except for the added 4th preset, and btop accepts it without errors. The installer tests passed through uv (54 passed) but are unit tests, so that scenario is untested live. All earlier live launcher scenarios pass: phone, desktop, resize, boundary, tiny pane and tty restore after quit.
proc:0:defaultpreset-p 4 --debugruns and exits 0 with no warn or error in the btop loguv run --with pytest python -m pytest tests/test_install_tools.py -q: 54 passed). It did not run the installer against the live product, s…Evidence: Config comparison: saved snap config vs config/btop.conf
Evidence: Installer tests
Evidence: Phone 50x40 pane
Evidence: Desktop 177x66 pane
Evidence: Live resize wide to phone
Evidence: Live resize phone to wide
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
maintenance/btop.sh:19- The resize-triggered restart stops btop withkill "$pid", which sends SIGTERM. btop 1.4.7 has no SIGTERM handler. Its src/btop.cpp_signal_handlerhandles only SIGINT, TSTP, CONT, WINCH, USR1 and USR2. The default action kills it withoutclean_quitorTerm::restore. So the first instance never restores the tty (echo off, non-canonical mode) and never leaves the alternate screen. The relaunched btop then runstcgetattrinTerm::init, which stores that already-raw state as itsinitial_settings. When the user later quits,Term::restorewrites the raw state back instead of the real original. Any phone/desktop resize that crosses 80x24 therefore leaves the pane's tty with echo off and line buffering off after the final quit. The first instance also skips itsConfig::write. Smallest fix:kill -INT "$pid". btop installs a SIGINT handler that doesshould_quitthenclean_quit, which restores the terminal and saves the config. This is the only restart path in the changed code.ansible/group_vars/all.yml:180- The intent asks to save the current btop config and make btop load on the phone. Its btop is the snap, launched via~/.local/bin/btop->/snap/bin/btop, with config under~/snap/btop/current/.config/btop. The change goes further. It adds btop tofactory_core_tools, so every host gets the upstream musl release downloaded and linked asbtop-bin. It also overwrites~/.local/bin/btopwith a launcher and rewrites~/.config/btop/btop.confon every apply (herdr.yml, installer entry at scripts/install_tools.py:68, plus docs and verify checks). No intent line requires fleet-wide installation of a second btop binary that replaces the snap one. A narrower form would ship onlyconfig/btop.confandmaintenance/btop.sh, with the launcher running the btop already on the host. Confirm that the fleet-wide release install is wanted; removing it is the remedy, not hardening it. Verified in btop 1.4.7 source: the min sizes (cpu 60, mem/net 36, proc 44x16, all boxes 80x24) and the preset indexing (the added 4th custom preset is index 4) are correct.🔧 Fix applied.
1 warning still open:
ansible/group_vars/all.yml:180- The intent asks to save the current btop config and make btop load on the phone. Its btop is the snap, launched via~/.local/bin/btop->/snap/bin/btop, with config under~/snap/btop/current/.config/btop. The change goes further. It adds btop tofactory_core_tools, so every host gets the upstream musl release downloaded and linked asbtop-bin. It also overwrites~/.local/bin/btopwith a launcher and rewrites~/.config/btop/btop.confon every apply (herdr.yml, installer entry at scripts/install_tools.py:68, plus docs and verify checks). No intent line requires fleet-wide installation of a second btop binary that replaces the snap one. A narrower form would ship onlyconfig/btop.confandmaintenance/btop.sh, with the launcher running the btop already on the host. Confirm that the fleet-wide release install is wanted; removing it is the remedy, not hardening it. Verified in btop 1.4.7 source: the min sizes (cpu 60, mem/net 36, proc 44x16, all boxes 80x24) and the preset indexing (the added 4th custom preset is index 4) are correct.-p 4) and quitting rewrites the live btop.conf with shown_boxes = "proc", because save_config_on_exit = true. The launcher passes -p on every start, so layout selection is unaffected. The saved all-boxes config only comes back when the Ansible herdr.yml task re-copies config/btop.conf on the next apply, which is the documented behavior.proc:0:defaultpreset-p 4 --debugruns and exits 0 with no warn or error in the btop loguv run --with pytest python -m pytest tests/test_install_tools.py -q: 54 passed). It did not run the installer against the live product, s…Read-only compare of ~/snap/btop/current/.config/btop/btop.conf against config/btop.conf: update_ms, shown_boxes, proc_sorting and color_theme are identical. The only diff is thepresetsline, which gains the 4th custom presetproc:0:default.Isolated tmux run of real btop 1.4.7 with--debug,-p 4and the repo config: exit code 0, and the btop log has no warn or error linesuv run --with pytest python -m pytest tests/test_install_tools.py -q: 54 passed (unit test, not live)tmux runs of the launcher at 50x40, 177x66, 80x24, 80x23 and 30x10, a resize of a running pane in both directions, and a tty-restore check after quitRemoved .venv, .pytest_cache and __pycache__ from the worktree afterwards✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.