Skip to content

fix: decouple mctx from hakoniwa for macOS build-system commands - #721

Merged
0chroma merged 5 commits into
mainfrom
0chroma/feat-mctx-gate-hakoniwa
Jul 14, 2026
Merged

fix: decouple mctx from hakoniwa for macOS build-system commands#721
0chroma merged 5 commits into
mainfrom
0chroma/feat-mctx-gate-hakoniwa

Conversation

@0chroma

@0chroma 0chroma commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

mctx had an unconditional dependency on hakoniwalibcgroupsprocfs (Linux-only), which forced minimal init/add/update to be #[cfg(target_os = "linux")]. This unblocks those commands on macOS.

Background

Per discussion with @norrietaylor / @msample / @twitchyliquid64: the dep chain was accidental. init doesn't use the sandbox — it only needs VCS + graph + mfile parsing. mctx used hakoniwa directly in exactly one place: the return type of Context::command (an execution method init never calls). sandbox2 already gated hakoniwa in its Cargo.toml to Linux, but its source referenced hakoniwa unconditionally.

Options considered

Option A: Gate hakoniwa directly in mctx/Cargo.toml
Move hakoniwa.workspace = true into a target.cfg(target_os = "linux") section, #[cfg] the one hakoniwa::Command return in env.rs. ~5 lines.

Option B: Re-export from sandbox2 (chosen)
Remove mctxhakoniwa dependency entirely. sandbox2 re-exports hakoniwa::Command as sandbox2::Command. Both sandbox2 and mctx gate their hakoniwa-touching code to Linux.

Went with B because sandbox2 is already the single source of truth for the sandbox. Having mctx depend on hakoniwa directly creates two dependency boundaries to maintain; re-exporting through sandbox2 keeps one.

Changes

Crate Change
sandbox2 #[cfg(target_os = "linux")] on Container, execution methods (new_container, command, run, run_with_cancel), bind_mount, locked_mount_flags, SpawnFailed error variant; re-export hakoniwa::Command
mctx Remove direct hakoniwa dep; use sandbox2::Command; #[cfg] the container/command methods and SpawnFailed error conversion
minimal Remove #[cfg(target_os = "linux")] from init/add/update commands and arg structs; make mctx/op unconditional deps

Verification

  • cargo test -p minimal -p sandbox2 — all tests pass
  • cargo clippy -p minimal -p sandbox2 -p mctx --all-targets -- -D warnings — clean
  • cargo fmt -- --check — clean
  • cargo tree -p minimal --target aarch64-apple-darwin — no hakoniwa/libcgroups/procfs in macOS dep tree
  • cargo tree -p mctx --target aarch64-apple-darwin — same, clean

Follow-up to the discussion on gominimal/inbox#159.

Summary by CodeRabbit

  • New Features

    • Build-system CLI subcommands (init, add, update) are now built and available on all supported platforms.
  • Bug Fixes

    • Sandbox/container execution is now enforced as Linux-only; on non-Linux targets, attempts return a clear “sandbox unsupported” error instead of trying to run.
    • Improved cross-platform error handling and sandbox execution flow for spec builds and standalone tests.
    • Updated cache directory replacement to use Linux rename-exchange when available, with safer non-Linux fallbacks.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@0chroma, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: d7c953a1-110d-429f-a5c3-167cd70f1547

📥 Commits

Reviewing files that changed from the base of the PR and between 929e345 and 26d39e9.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • crates/lcache/src/lib.rs
  • crates/mctx/Cargo.toml
  • crates/mctx/src/env.rs
  • crates/mctx/src/error.rs
  • crates/minimal/Cargo.toml
  • crates/minimal/src/lib.rs
  • crates/op/src/lib.rs
  • crates/op/src/specs.rs
  • crates/op/src/standalone_test.rs
  • crates/op/src/task_env.rs
  • crates/sandbox2/src/error.rs
  • crates/sandbox2/src/lib.rs
📝 Walkthrough

Walkthrough

Sandbox2 APIs are gated to Linux, non-Linux sandbox operations return an unsupported error, mctx switches to sandbox2, minimal’s local build commands compile across targets, and lcache adds non-Linux directory finalization.

Changes

Cross-platform sandbox integration

Layer / File(s) Summary
Gate sandbox2 and mctx Linux APIs
crates/sandbox2/src/error.rs, crates/sandbox2/src/lib.rs, crates/mctx/...
Linux-only sandbox types, methods, helpers, and errors are gated, and mctx uses sandbox2 for its Linux sandbox wrappers.
Provide target-specific operation paths
crates/op/..., crates/mctx/src/env.rs
Builds, standalone tests, task command resolution, and environment execution use sandbox helpers on Linux and return sandbox_unsupported() elsewhere.
Compile local commands across targets
crates/minimal/Cargo.toml, crates/minimal/src/lib.rs
Local build-system dependencies, command declarations, dispatch, and helpers are no longer Linux-gated.

Cache portability

Layer / File(s) Summary
Handle cache replacement by target
crates/lcache/src/lib.rs
Linux uses renameat2 exchange semantics, while non-Linux removes the destination and renames the temporary directory into place.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Poem

I’m a rabbit with a patch in my paws,
Linux bounds now follow clearer laws.
Sandbox tools hop where they belong,
Cache paths settle safely along.
Carrots and cfgs—both neatly aligned!


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

@twitchyliquid64 twitchyliquid64 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! CI shows theres a couple more to flag but then this should be g2g!

0chroma added 5 commits July 14, 2026 00:54
mctx had an unconditional dependency on hakoniwa, which pulls in
libcgroups → procfs (Linux-only). This forced minimal's init/add/update
commands to be gated behind #[cfg(target_os = "linux")], blocking
macOS users from initializing projects.

The dep was accidental: mctx only used hakoniwa directly for the
Command return type in Context::command (an execution method init
never calls). sandbox2 already gated hakoniwa to Linux in its
Cargo.toml but its source referenced hakoniwa unconditionally.

Changes:
- sandbox2: #[cfg(target_os = "linux")] the Container struct, execution
  methods (new_container, command, run, run_with_cancel), bind_mount,
  locked_mount_flags, and the SpawnFailed error variant; re-export
  hakoniwa::Command as sandbox2::Command
- mctx: remove direct hakoniwa dependency; use sandbox2::Command
  instead; #[cfg] the container/command methods and SpawnFailed error
  conversion arm
- minimal: remove #[cfg(target_os = "linux")] gates from init/add/update
  commands and their arg structs; make mctx/op unconditional dependencies

Went with Option B (re-export from sandbox2) over Option A (gate
hakoniwa directly in mctx) because sandbox2 is already the single source
of truth for the sandbox — mctx shouldn't reach through to hakoniwa
directly. This keeps one dependency boundary instead of two.
The renameat2 module in common was gated behind #[cfg(target_os = "linux")]
but lcache imported it unconditionally, causing a compile failure on macOS.
Gate the import and provide a std::fs::rename fallback for non-Linux platforms,
matching the pattern already used in sessions/src/store.rs.
… build

After gating hakoniwa in sandbox2 (f144854), the op and mctx crates still
called Sandbox::run / run_with_cancel unconditionally. These methods are
#[cfg(target_os = "linux")] in sandbox2 because they depend on hakoniwa.

Extracted sandbox execution into cfg-gated helper methods that return a
runtime error on non-Linux platforms, keeping the trait impls and public
APIs compilable on macOS. The prebuilt/collection fast paths in SpecBuild
that don't touch the sandbox remain available on all platforms.
… macOS

Gate the sandbox2::Container import in mctx (it is #[cfg(target_os = "linux")]
in sandbox2) and the BufRead/Shlex imports in op/task_env.rs that are only
used by the Linux sandbox execution path. Also gate the invocations methods
in SpecBuild and StandaloneTest which are only called from the Linux-only
execute_in_sandbox helpers.
…nvocations

- Extract the repeated "sandbox execution is only supported on Linux"
  error string into a shared op::sandbox_unsupported() helper
- Replace #[cfg(target_os = "linux")] on the invocations() methods with
  #[cfg_attr(not(target_os = "linux"), allow(dead_code))] so the parsing
  logic remains available on all platforms
@0chroma
0chroma force-pushed the 0chroma/feat-mctx-gate-hakoniwa branch from 929e345 to 26d39e9 Compare July 14, 2026 07:54
@0chroma
0chroma merged commit b27c498 into main Jul 14, 2026
28 checks passed
@0chroma
0chroma deleted the 0chroma/feat-mctx-gate-hakoniwa branch July 14, 2026 08:13
norrietaylor added a commit that referenced this pull request Jul 14, 2026
Resolve the conflicts from the commits that landed on main since this
branch's merge-base (#721, #732, #734, #735, #722), keeping main's
content and re-applying the `min` binary-target rename on top.

- justfile: main folded `up` into `dm1` (#722), so the branch's older
  `up` recipe is dropped rather than resurrected. Main's `dm1` invoked
  the `{{minimal}}` variable this branch renames, which would have left
  `just` unable to resolve it; it now invokes `{{min-bin}}`.
- CI lanes: keep main's rewritten jobs and steps, renaming only the CLI
  build flags and built-binary paths (`--bin min`, `target/debug/min`).

Also point the sessions example project at `./target/debug/min`; the
binary path it documented no longer exists after the rename.

Published release asset names (`minimal-linux-amd64`, ...), the macOS
`minimal` shim, and the `minimal` crate and lib target are deliberately
left alone.
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.

2 participants