sysupdate: update the box, and reach it from the pit as /update - #37
Merged
Conversation
Updating a machine was three commands nobody could quite remember the order of: apt update, apt upgrade, snap refresh. This makes it one, and the pit gets it as `/update`. Deliberately not called `update`. `cli-tools update` already means "move this checkout to the current commit", `update` is a dispatcher verb, and a verb wins over the passthrough -- so a `bin/update.ts` would have been unreachable through `cli-tools` and would have failed the test that says a command may never share a name with a verb. `/names -> free-names` is the same precedent. The alias is safe because nothing on PATH answers to `update`. Three decisions worth keeping: `apt`, not `apt-get`. They are not the same command: `apt upgrade` installs a package that needs a new dependency, `apt-get upgrade` holds it back. That difference is how kernels and security updates quietly never land on a box everybody believes is current, and it is the same trap root-ubuntu.sh works around with --with-new-pkgs. sudo only when it is not already root. A minimal image may have no sudo on it at all, and asking for it there fails for a reason that has nothing to do with updating anything. Stop at the first failure, which is the && the one-liner had. Upgrading against package lists that failed to refresh is pointless, and a snap refresh afterwards only buries the real error further up the scrollback. A box with no snapd skips that step and says so, rather than reporting a failure for something that was never going to run; a box with no apt is refused outright rather than half-updated. When the upgrade lands a kernel or a libc it names the packages and says a reboot is required -- that being exactly the moment people stop thinking about it. The plan is built separately from running it, so the decisions are tested by asserting on the argv rather than by upgrading anything. The one path that cannot be faked, the stdio-inheriting spawner, is stdio: 'inherit' because both halves need a terminal: sudo prompts for a password on one and apt draws progress on the other. Also fixes the alias table in the tools plugin, which had drifted -- it was missing /names. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013TerE4nvNU3jvS51nRR6Pd
ThreatCrush Security Scan16 finding(s) HIGH/CRITICAL: 5 | MEDIUM: 2 | LOW: 9
Snippets are redacted; ThreatCrush never prints matched credential material. |
ralyodio
added a commit
that referenced
this pull request
Aug 30, 2026
Eight commits since 0.15.0, one of them a new command, so the minor moves. - sysupdate: apt lists, apt packages and snaps in one command, reachable from the pit as /update (#37) - root-ubuntu.sh: a 2G swapfile on a box with no swap at all, plus vm.swappiness=10 (#36) - root-ubuntu.sh: one ssh-agent per user under systemd (#35) - root-ubuntu.sh: lm-sensors, smartmontools and the rest of the hardware inventory set, with sensor detection on bare metal - companions: diskpush, and installers that are not npm (#34) - porkbun: Porkbun's own pre-flight, structured refusals, and the fact that registration spends prepaid credit rather than a card (#32, #33) Claude-Session: https://claude.ai/code/session_013TerE4nvNU3jvS51nRR6Pd Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
One command for the three nobody remembers the order of, and
/updatein the pit.Why it is not called
updateupdatewas not available, and not only by convention:cli-tools updatealready means "move this checkout to the current commit"updateis inKNOWN_VERBS, and a verb wins over the passthrough — sobin/update.tswould have been unreachable through the dispatchertest/dispatcher.test.tsasserts no command may share a name with a verb, so it would have failed the suite outrightSo the command is
sysupdateand the pit alias is/update— the same precedent as/names → free-names, and safe because nothing onPATHanswers toupdate.Three decisions worth reviewing
apt, notapt-get. They are not the same command:apt upgradeinstalls a package that needs a new dependency,apt-get upgradeholds it back. That difference is how kernels and security updates quietly never land on a box everybody believes is current — the same traproot-ubuntu.shworks around with--with-new-pkgs.sudo only when not already root. A minimal image may have no
sudoat all; asking for it there fails for a reason that has nothing to do with updating anything.Stop at the first failure — the
&&the one-liner had. Upgrading against package lists that failed to refresh is pointless, and a snap refresh afterwards only buries the real error further up the scrollback.Beyond that: a box with no snapd skips that step and says so rather than reporting a failure for something that was never going to run; a box with no
aptis refused outright rather than left two-thirds updated; and when the upgrade lands a kernel or libc it names the packages and says a reboot is required, that being exactly the moment people stop thinking about it.Testing
16 new tests, 576 across the suite, all passing. The plan is built separately from running it, so every decision is tested by asserting on the built argv — nothing is upgraded and nothing is spawned, matching how
faviconis tested.The one path injection cannot cover is the real stdio-inheriting spawner, so I smoke-tested that directly:
stdio: 'inherit'rather than captured because both halves need a terminal — sudo prompts for a password on one, apt draws progress on the other. Capturing would hang at the password prompt with nothing on screen to explain why.Typecheck clean for the new files (the two pre-existing
src/free-names.tserrors onmasterare untouched).Also
Fixes the alias table in
plugins/tools/commands/install.md, which had drifted — it was missing/names.🤖 Generated with Claude Code
https://claude.ai/code/session_013TerE4nvNU3jvS51nRR6Pd