Repository navigation
Releases
minimal 0.5.5-dev.49.gcb384e31
docs(specs): add the local box egress proxy spec (BEP) (#1426) * docs(specs): add the local box egress proxy spec (BEP) docs/specs/24-spec-box-egress-proxy, prefix BEP, written from gominimal/inbox#625 with the spec-author workflow (interview, three checkpoints, EARS via spec-ears, tiers via spec-tiers). Binds the un-enrolled, no-Gatehouse Box Egress Proxy: host-side beside gvproxy, TLS terminated only for declared credentialed upstreams under a host-generated name-constrained CA, sealed GitHub members minted by a local device-flow sign-in, Keychain store references set with `min secret`, egress re-check, hash-chained local audit. 54 requirements; the redemption decision at T2 (Kani), expansion validation, name constraints and audit secrecy at T1. Lint clean apart from the expected P004 unresolved-test findings. Architecture of record: gominimal/arch at #67 (Gatehouse v1.19, networking design v0.7). Contradiction filed as gominimal/arch#69; command-tree notes on gominimal/arch#70. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): revise BEP after review, applying the arch#69 and arch#70 rulings Aligns the local Box Egress Proxy spec with gominimal/arch main at 3987a07 (Gatehouse v1.20.1, networking design v0.7.1, command tree after #72). - Sign-in and minting: both flows under the published GitHub App (BEP-001), the sign-in-required creation error (BEP-003), mode and breadth in the member and its context (BEP-005/006), un-enrolled validation (BEP-056, BEP-057 with the client-configuration acknowledgement), members without bounds refused (BEP-058), key and CA lifecycle (BEP-059 to BEP-061), the no-re-mint limit as a non-goal. - Command tree: `min box audit` grammar with `self` refused un-enrolled (BEP-042), `min box stop | rm` (BEP-043), F12 record shape with `kind` (BEP-039), mints and logouts recorded (BEP-067), `min secret --store` and the five-column list (BEP-050 to BEP-053), sections reordered. - Correctness: upstream TLS validation before substitution (BEP-055), hash chain narrowed to what a bare chain detects (BEP-049), BEP-029 on both request forms, BEP-040 record equivalence, store-handle contract (BEP-063, BEP-064), injection form and CR/LF refusal (BEP-065, BEP-066), fail-closed steering while the proxy is down (BEP-062), segment rotation (BEP-068), `proxy_env` boolean (BEP-012), proxy user named (BEP-047). - Design reasoning cites the architecture where it used to argue; crate, field ownership, proxy user, and the set-aside HMAC anchor recorded. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): close BEP's listener, upstream-validation and sign-in gaps BEP-026 refuses every connection that is not a box attachment at the listener, sealed value or not, per Gatehouse §6.10. BEP-055 validates the upstream chain on every flow the proxy terminated before forwarding anything on it, so the foreign-credential passthrough is validated no less than a direct connection. BEP-001 records the un-enrolled sign-in default: the bare verb and --device run the device flow, --browser selects the browser flow, with the divergence from the command tree's prose stated in Design reasoning. BEP-050 refuses an environment-variable flag as well as an argument. Bare issue references are links. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): pin BEP's store-path checks, host set, and the key-custody invariant The GitHub v1 host set is defined by citation to Gatehouse §6.10 in First slice and under BEP-006. BEP-032 names the checks a store reference passes (BEP-019, BEP-020, BEP-022 to BEP-024, BEP-064) so one decision function covers both member kinds. BEP-040's secrecy property is a construction property with a length bound. The sixth invariant states the access-control claim the requirements make: unattended access to the keys and store items is the proxy identity's alone. Design reasoning records why two invariants stay at T0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): define BEP's audit-chain construction, control socket and authority pinning The audit chain is constructed over SHA-256 of the previous line's bytes with the proxy as the log's sole writer, so client mint and revocation records reach it over the control socket rather than a second writer. That control socket is the operator-owned UDS the client also uses to register its store-handle key, separate from the redemption listener. BEP-023 pins an absolute-form request target to the connection authority as well as Host. A box declaring steering off together with proxy_env is refused, since the environment would point at a proxy no injected CA validates. BEP-040's property excludes the chain field and drops the substring clause; BEP-049's property covers records with a successor. BEP-003's sub-bullet and BEP-027 are reworded as the findings asked. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): key BEP-001 to the command tree's sign-in shape The owner ruled the un-enrolled sign-in default the tree's way: the bare verb is the browser flow wherever one exists, --device pins the device flow, and no other flag is added. BEP-001 runs the device flow on --device, or on the bare verb while no browser flow is shipped; the browser sub-bullet takes the bare verb once that flow ships. Design reasoning shrinks to that sentence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): bind BEP's signing CA to the host-wide union and refuse plaintext credentialed legs BEP-013 follows the Gatehouse un-enrolled bullet: one keychain-held signing CA per host, name-constrained to the union of every box's declared credentialed upstream set, with a box's own reach bounded by its egress declaration and its sealed values' host sets. A request to a credentialed host that would ride a non-TLS upstream leg is refused, since port discipline does not see an absolute-form http request inside the proxy_env connection and no chain exists to validate. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
minimal 0.5.5-dev.33.g24dbbfe2
docs(mip): document cache notices subcommand (#1415) Add the missing `cache notices <source_sha256>` section to the mip CLI reference and refresh the generation hash. Co-authored-by: gominimal-aw-bot[bot] <281738952+gominimal-aw-bot[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
minimal 0.5.5-dev.15.gc6cc5fe5
release-c6cc5fe5 fix: nightly smoke races — detached vcs worktrees, dead-host shutdown…
minimal 0.5.5-dev.14.ga514ac9e
docs(specs): refresh TEMPLATE.md; there is no status field (#1368) foundry#89 removed status: from the spec frontmatter. A spec on a branch is a draft, a spec on main is binding, and a spec is shipped when the lint resolves every verify: and proof: line. The copy is refreshed from the squash commit 84fa718 and restamped with it. Claude-Session: https://claude.ai/code/session_018QUk4o4Qarm5SgL7pJxKYW Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
minimal 0.5.5-dev.10.g8e7e72c2
release-8e7e72c2 feat(packaging): CI-owned AUR, Homebrew, and deb/rpm/apk distribution…
minimal 0.5.5-dev.9.g323ae081
release-323ae081 build(deps): bump taiki-e/install-action in the github-actions group …
minimal 0.5.4
62 commits since v0.5.3. Three of them break existing behaviour — read those first if you are upgrading.
Breaking changes
The session detach chord moves to ctrl-] then d
Was ctrl-w. That key is termios-special (VWERASE): the line discipline consumed it before the application ever saw the byte. The daemon no longer intercepts ctrl-w or its CSI encodings anywhere — it is forwarded to the shell like any other key.
The leader is now configurable per client through a [session-keys] section and negotiated per attach channel, so two clients attached to the same session can each use their own chord. Pressing the leader twice forwards it verbatim, which is the primitive for nested sessions. (#1202)
Exec-channel requests are tagged, not string-sniffed
The daemon previously decided what an SSH exec request meant by checking whether the string began with min , conflating three intents in one untagged field. Both failure modes were real: an argv could not be sent, because sh -c 'echo A B C' arrived reshelled and A became $0; and a session's own min --version was unreachable, because the daemon claimed the prefix and refused it.
Requests now carry an explicit tag from a vocabulary both sides share — min://shell, min://argv, min://task/run, min://package/build, min://check. Argv words travel as JSON and are exec'd with no shell in between. Anything untagged now belongs to the session, which is the rule that makes the hijack impossible. Adds min session run <session> <task>. (#1308)
Task env_vars resolve on the client
A task declaring env_vars.X = { inherit = true } resolved against the daemon's own environment — on macOS, not even on the same side of the VM boundary as the shell that typed the command. Your export could never be visible to it, so the task failed at spawn with environment variable not found regardless. [session.vars] used identical syntax and worked, because activation resolves it client-side.
Values are now resolved where they exist and carried over the same channel env mechanism that already carries the session id. A variable declared inherit but unset now fails on the client, naming the task and the variable, instead of surfacing later as a spawn failure. (#1312)
Added
- Diagnostic bundles capture the shutdown cause, host memory, and macOS panic reports. A "my Mac rebooted under Minimal" report could not previously be answered from a bundle: the power collector filtered out exactly the lines that date a restart, nothing recorded host memory to judge a VM allocation against, and the panic report was never read. (#1263)
- Bundles record the terminal they were collected on — per-stream tty status, window size, and tty device. Garbled-TUI, wrong-column-wrap, and resize-does-nothing reports are claims about a terminal the bundle never described. (#1264)
- Bundles are scoped to the project they came from. (#1265)
- New sessions start
fishwhen it is the configured shell and is actually installed, rather than falling back tobash. (#1320) - Loadouts gain a patch source anchor for the loadout root. (#1297)
- Patch files keep their permission bits when copied into a session. (#1302)
- Nickel parse logic for container specs in
decode.
Fixed
Sessions and the daemon
- A version-skewed daemon is refused instead of destroying sessions. A CLI upgraded past its
minimaldfailed mid-activation, not at connect:FinalizeSessionsucceeded on the daemon, its reply would not decode against the newer wire types, and cleanup then tore down the session it had just created. Every session appeared to be created and vanish at once. (#1260) - A stalled host no longer wedges every session RPC. A daemon in the field served
GetVersionin 54µs whileListSessions,GetSessionRecordandCreateSessionhung for fifteen minutes. The split was exact — the RPCs that hang are the ones that round-trip through the sessionsManageractor, which awaitedget_attrsinline. (#1281) - The terminal is unwound when a session process exits, SIGKILL included. Exit notices and the shell-exit prompt were rendered into whatever input modes the dead application had left set. (#1261)
- Package-declared
~/paths expand explicitly, and credentials are dropped. Inside the guestminimaldis pid 1 withHOME=/, so~/.claude.jsonresolved to/.claude.jsonandmin task rundied with EROFS on the read-only rootfs, naming a path nobody had written down. An unsetHOMEpanicked outright. (#1262) execreturns when the child exits, not when its pipes close. (#1342)- The default mfile is scaffolded before composing. (#1339)
- Lifecycle hook stdout and stderr are surfaced during session activation. (#1296)
- Activating a path that already has a session now warns. (#1316)
- A session that cannot be composed names the directory in the error. (#1340)
- The client is told when session hostnames will not route. (#1310)
- The proxy bridge exits when the daemon socket closes. (#1282)
Command-line output
miptrace logs go to stderr, not stdout, where they corrupted piped output. (#1315)min addrenders download progress. (#1213)min initwrites its result line to stdout. (#1285)min addconfirmation drops the array brackets. (#1292)- Host-side
min add --sessionoutput is qualified so it no longer implies a live install. (#1309) - Generated
minimal.tomlheaders name the binarymin. (#1284) min stop --forcehelp matches the live-shell guard it actually applies. (#1294)- The removed-profiles warning names the migration path. (#1300)
--loadoutis validated before the no-config banner prints. (#1153)- Sync runs when a
minimal.tomlis present, before the VCS check. (#1321) - Shells are deduplicated before the completions install loop. (#1283)
command_captureoutput is bounded by size as well as by time. (#1318)
Build graph and determinism
- An unparseable layer-cache entry is a miss, not a fatal error.
LayerCacheDir::getdeleted the file it could not deserialize and propagated the error anyway, so one poisoned entry failed the whole graph load. A session came up with no package environment at all — nobase,git,go,makeorvimon PATH — and nothing to say why. (#1259) min initoutput is deterministic. Stack tables order by name (#1332), the mfile task table is ordered and a redundant sort dropped (#1334),OutputKind::OciImagevars are ordered (#1333), and package-derived setup has a fixed order (#1319).- The R2 read default survives
Config::into_builder(), which rebuiltremote_cache_urlunconditionally from a non-optional field and so treated the default GCS bucket as an explicit user choice. (#1291) decodereturns errors instead of panicking.
Installer and dependencies
install.shwraps its body inmain(), so a short read of the piped script cannot execute a truncated program. (#1276)h20.4.16 → 0.4.18. The 0.4.16 bump taken for RUSTSEC-2026-0258 shipped an empty-DATA-frame flood guard that misfires on legitimate clients multiplexing many streams over one connection. (#1255)wide1.6.0 → 1.6.1; 1.6.0 was yanked. (#1314)
Documentation
- New build reproducibility reference page. (#1254)
- The
architecture.mdcrate map coversminimal-client,minimal-tui, andmlog. (#1336) - Documented where
{ inherit = true }diverges by surface. (#1343) - The
min loadout listexample matches what the command prints. (#1280)
Fourteen further commits in this range are CI regeneration, dependency-group bumps, test coverage, and a README change, and are omitted deliberately. Two decode commits landed without a pull-request reference and so appear unlinked.
Full changelog: v0.5.3...v0.5.4
minimal 0.5.3
feat(dash): add clear-filter hint to the footer (#1226) * feat(dash): show the applied filter in the footer Once Enter leaves the / editing mode a filter stays active invisibly: the footer reverts to the key hints and the user cannot tell the list is narrowed or how to widen it again. When filter input is set, the footer now shows 'filter: <input> · N of M sessions · esc clears ...' instead of the hint line, and Esc outside the editing mode clears the filter (a no-op when nothing is set). While editing, the existing live filter line is unchanged. Fixes #1198 * fix(dash): refresh focus and free footer's right edge on filter clear Address PR #1226 review feedback: - Esc on an applied filter restores rows ahead of the cursor, so the session under it can change; refresh focus (detail fetch, bell ack) after clamping, like every other cursor move. - Reserve the footer's right edge for the transient status so it can't overdraw the filter segment's controls. - Extend the Esc regression test to the row-index-shift case and add a filtered_with_status footer snapshot. * fix: apply CodeRabbit auto-fixes Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai> * feat(dash): keep footer key hints when filtered and note that esc clears it --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
minimal 0.5.2
v0.5.2 feat: lifecycle hooks (#1205)
minimal 0.5.1
build(deps): bump russh from 0.62.4 to 0.62.5 Bumps [russh](https://github.com/warp-tech/russh) from 0.62.4 to 0.62.5. - [Release notes](https://github.com/warp-tech/russh/releases) - [Commits](https://github.com/warp-tech/russh/compare/v0.62.4...v0.62.5) --- updated-dependencies: - dependency-name: russh dependency-version: 0.62.5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>