8000 feat(mirror): the mirror daemon and its clients, first slice of MIR by msample · Pull Request #2484 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

feat(mirror): the mirror daemon and its clients, first slice of MIR - #2484

Draft
msample wants to merge 11 commits into
mainfrom
feat/mirror
Draft

msample wants to merge 11 commits into
mainfrom
feat/mirror

Conversation

@msample
@msample msample commented Oct 21, 2026
Copy link
Copy Markdown
Member

What

The first slice of the mirror (spec MIR, docs/specs/30-spec-mirror): one copy per laptop of the cache objects and package repositories every client fetches, so min init and min session activate work with no connection once the laptop was online with the mirror running.

Branched from docs/spec-mirror (#2477) so the spec is in the checkout; rebases onto main once that merges.

Shape

  • minmirrord, a new daemon crate. HTTP/1.1 over two Unix sockets: the host socket for every request, the door socket for reads alone. Cache objects fill from the origin a request names under /-/c/<origin>/-/<key>, one fetch per key, sha256-checked artifacts, absence records that answer offline, a root index that revalidates after five minutes and serves stale with Age when the origin is out of reach, eight origin fetches at a time. Repository copies are mirror clones made on the first request and refreshed when older than five minutes, served to a host client as a path and to a guest as a bundle. run --detach, stop, status.
  • mirror-client: the contract clients share, including the [mirror] table of config.toml, the lifecycle file, on-demand start, and a blocking reader for git's copies.
  • common: the path grammar and a third fetch backend (hyper over a Unix socket or a vsock door), so the cache reader only changes its base URL.
  • mctx and checkouts: MINIMAL_MIRROR_SOCKET or ConfigBuilder::with_mirror mounts the read location on the mirror; the checkout manager clones and fetches from the mirror's copy with the original URL as git's remote, falling back to the origin when the mirror holds no copy.
  • min: starts the mirror before every command that reads a project, passes the socket to the native daemon, min mirror status | stop, two new min dirs rows. mip uses a running mirror and starts none.
  • minvmd starts the mirror before a boot, maps vsock port 7354 to the door socket, and puts MINIMALD_MIRROR_DOOR=7354 on the guest's command line as a never-dropped token. minimald in the guest reads its cache and repository copies through the door.

Proven here (Linux sandbox)

  • Against the real public cache and GitHub: the root index, a closure with its companions, a 21 MB artifact (hash equal to its name) and the whole pkgs repository came through the daemon; the door refused the host-only verb.
  • min init -y in a fresh repository started the mirror on demand, read the cache through it, and cloned pkgs from the mirror's copy with the canonical remote URL.
  • With every HTTPS route pointed at a dead proxy, min init -y in a second repository completed in 0.1 s from the copy and pinned the same commit; min mirror status named the failed refresh.

Not proven here: the VM leg (door, guest daemon) needs a Mac or a KVM host. just up now builds minmirrord beside min, and the e2e recipes build it too.

Not in this slice (the spec's later slices)

Project registration and the chain walk, the planner and min mirror prepare, the disk budget and age rules, sealed pins, private sources, the trusted root, door restart of a stopped mirror, installer and dist-build.sh plumbing for the new binary.

Caveats

  • A command that reads a project now fails when minmirrord is neither beside min nor on PATH, with the three lines MIR-020 specifies; [mirror] enabled = false opts out.
  • Unix socket paths must stay under the platform limit; the user's state directory does.
  • Two pre-existing clippy lints surface under a newer rustc than the pinned toolchain (chunks_exact_to_as_chunks in minimald-rpc, result_unit_err in minimald); untouched here.

🤖 Generated with Claude Code

msample and others added 10 commits October 21, 2026 13:50
A daemon on the laptop keeps a copy of the binary cache objects and the
package repositories its clients fetch, plus what the registered projects,
loadouts and an always list need, so `min init` and `min session activate`
work with no connection once `min mirror prepare` reported ready.

Every client reads the mirror over HTTPS and checks its certificate against
one configured authority: the host CLI and native daemon at loopback, the
in-VM daemon at host.min.internal through the switch's host alias, and a
Box Host elsewhere at a shared mirror's name. The laptop's mirror generates
its own authority; a shared one carries an operator's certificate.

Pins follow sealed closures: init and update pin the newest commit within
64 first-parent commits that has a published closure, and the mirror's
absence records let that walk run offline. The closure's sigstore bundle,
the commit map and the Sigstore trusted root are kept for a later verifier.

Draft: the epic and spec number are placeholders, and the Open questions
list the decisions still to make.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…work mirror

Findings from the TLS-round review. Git chooses its certificate authority
once, for the URL it starts with, and keeps it across a redirect, so a 302
from the mirror to an upstream fails the upstream's handshake under the
mirror's authority. The client now asks the mirror for the repository's refs
over its own pinned connection and runs git either against the mirror with no
redirects or against the original URL with the system authorities (MIR-013).

A `[mirror] upstream` setting names what the mirror copies, so a laptop's
mirror can chain to an office mirror, and `MINIMAL_MIRROR_URL` now replaces
the default read location only. A mirror on a network refuses misses once
over budget and runs at most 8 upstream fetches at a time. The slug grammar
admits any path depth, TLS 1.2 stays admitted for the host's git, `mip`
prints a remedy that does not name `min`, the guest token is `MINIMALD_*`,
and multi-clause requirements are folded to one SHALL each.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rewrite MIR as one mirror per user on the laptop, read through a private
Unix socket on the host and a vsock door in each VM, with no TLS on the
client leg. Key cache paths by origin so the client keeps choosing its
cache, cache every hop of each project's upstream chain and its
sideloads, and read private repositories and buckets with the user's own
credentials.

Move the shared office mirror, tiers of mirrors and per-link cache
declaration to Non-goals as follow-up specs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…socket

The mirror (spec MIR) answers HTTP on a Unix socket on the host and on a
vsock door in a guest, neither of which a reqwest client dials. This adds
`common::mirror`, the one parser for cache origins, repository slugs and the
request paths both the daemon and its clients spell, and a third
`FetchBackend` that drives one hyper connection per request over the
endpoint's stream. `AnyUrl::Mirror` joins a cache key under an origin's
mount, so the cache reader needs no second code path; a non-2xx body is kept
on the error so a 502 can name the origin the mirror could not reach.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The directories and sockets the mirror daemon uses, its lifecycle file, the
on-demand start a client performs, the `[mirror]` table of the client
configuration file, and a blocking HTTP reader with which the checkout code
fetches a repository copy's path or bundle without an async runtime.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tory copies

One copy per laptop of what its clients fetch (spec MIR, first slice). The
daemon answers HTTP/1.1 on two Unix sockets, the host socket for every
request and the door socket for reads alone. Cache objects fill from the
origin a request names, with one fetch per key, a sha256 check on artifacts,
absence records that answer offline, a root index that revalidates after
five minutes and serves stale with `Age` when the origin is out of reach,
and a bound of eight origin fetches at a time. Repository copies are mirror
clones made on the first request and refreshed when older than five
minutes, served to a host client as a path and to a guest as a bundle.
`run --detach`, `stop` and `status` carry the lifecycle.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n macOS

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e mirror

`ConfigBuilder::with_mirror`, or `MINIMAL_MIRROR_SOCKET`, mounts the read
location on the mirror when the location is an `https` base in the origin
grammar; a `gs://` bucket and any base outside it stay direct. The checkout
manager asks the mirror for a repository copy before every clone and fetch:
a host client clones from the copy's path, a guest from its bundle, and the
original URL stays git's remote and the registry's key. A copy the mirror
cannot serve falls back to the origin as today. A fetch the mirror does not
answer, or a 502 it relays, renders as the two lines MIR-063 names.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t, open the VM door

`min` starts the mirror daemon before every command that reads a project,
passes its socket to the native daemon it spawns, and gains `min mirror
status` and `min mirror stop` plus two `min dirs` rows. `mip` uses a running
mirror and starts none. The VM host daemon starts the mirror before a boot,
maps vsock port 7354 to the mirror's door socket, and hands the guest a
`MINIMALD_MIRROR_DOOR` token the command line never drops; the guest daemon
reads its cache and repository copies through that door. The `[mirror]`
table joins the client configuration, the status row puts the default
branch first and keeps a copy's refresh time across a restart, and the CLI
reference and the client config reference describe the new surface.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai
coderabbitai Bot commented Oct 21, 2026
Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

A box builds its build context from a fresh config, so the mirror door
the VM host handed the daemon never reached the context `min add`
fetches with: the box read the cache origin directly and the mirror
stayed empty. The box config now takes the daemon's mirror (MIR-024),
so a box's cache objects and repository copies come through the door.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0