Skip to content

feat(bootstrap): add phase hooks#10395

Merged
jdx merged 6 commits into
mainfrom
codex/bootstrap-phase-hooks
Jun 13, 2026
Merged

feat(bootstrap): add phase hooks#10395
jdx merged 6 commits into
mainfrom
codex/bootstrap-phase-hooks

Conversation

@jdx

@jdx jdx commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • add [bootstrap.hooks] support for named bootstrap phases such as pre-packages, post-dotfiles, post-tools, and final
  • execute hook commands via the configured default inline shell, with dry-run output and fail-fast behavior
  • document hook syntax and refresh generated CLI usage docs

Validation

  • cargo fmt --all --check
  • cargo test bootstrap
  • cargo test system::hooks
  • cargo check
  • mise run render:usage

This PR was generated by an AI coding assistant.


Note

Medium Risk
Hooks execute arbitrary shell during bootstrap (including after dotfiles change config), so misconfiguration can abort setup or run unintended commands; scope is limited to explicit mise bootstrap and the experimental bootstrap surface.

Overview
Adds [bootstrap.hooks] so mise bootstrap can run imperative shell commands at named phases (pre-packages through post-tools, plus final after the bootstrap task). Hook values support a string, string array, or { run = ... }; they merge global→local, use the default inline shell like tasks, fail fast, and print instead of run under --dry-run.

The bootstrap runner now invokes hooks around packages, dotfiles, defaults, user, and tools, reloads config after dotfiles apply and tool install so hooks from newly applied mise config files take effect, and on dry-run parses templated/dotfile mise config targets so later-phase hooks show up in the preview.

Docs, generated CLI usage/man, config parsing tests, and e2e coverage for dotfile-sourced hooks are updated. The ubi e2e on linux/amd64 switches from an FFmpeg URL to fd as the direct-archive install case.

Reviewed by Cursor Bugbot for commit 1bd40a8. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Configurable bootstrap hooks at named phases (pre/post around packages, dotfiles, defaults, user, tools, plus a final phase); hooks run in the current environment, merge across configs, and respect --dry-run by showing commands.
  • Documentation

    • Updated docs, CLI help, manpage, examples, and tips to document hook syntax, placement, failure/dry-run behavior, idempotency guidance, and sample hooks.
  • Tests

    • Added/extended integration and e2e tests verifying hook parsing, phase ordering, execution, and dry-run semantics.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds configurable phase-based bootstrap hooks to mise: parses [bootstrap.hooks] from TOML across config files, runs named phases during mise bootstrap (pre/post around packages, dotfiles, defaults, user, tools, plus final), supports dry-run, and updates docs and tests.

Changes

Bootstrap Hooks Implementation

Layer / File(s) Summary
Hook Phase Types and Execution Engine
src/system/hooks.rs
BootstrapHookPhase enum defines lifecycle phases; BootstrapHook::from_toml parses string/array/table run forms; run_phase filters by phase, supports --dry-run, and executes commands via CmdLineRunner; includes unit tests.
Configuration Schema and Aggregation
src/system/mod.rs, src/config/config_file/mise_toml.rs
BootstrapTomlConfig gains hooks: IndexMap<String, toml::Value>; hooks_from_config aggregates hook entries across global→local config, parses each into BootstrapHook, and emits per-hook warnings on parse failure; tests updated with [bootstrap.hooks.pre-packages] and [bootstrap.hooks.post-tools].
Bootstrap Command Hook Execution
src/cli/bootstrap.rs
Bootstrap::run derives hooks from config and executes named phases throughout the bootstrap flow (pre/post-packages, pre/post-dotfiles, pre/post-defaults, pre/post-user, pre/post-tools, final); adds run_hooks and dry-run-aware hook re-derivation helpers and preserves dry_run behavior.
E2E and Integration Tests
e2e/cli/test_bootstrap
Adds scenario where dotfiles provide bootstrap.hooks.post-dotfiles and bootstrap.hooks.final which run later in the same mise bootstrap --yes execution; asserts hook outputs.
User Documentation and Help Text
docs/bootstrap.md, docs/cli/bootstrap.md, docs/tips-and-tricks.md, mise.usage.kdl, man/man1/mise.1
Docs and man/help updated to describe [bootstrap.hooks], list supported phase names, show examples (including post-defaults restart Dock example), explain dry-run and failure behavior, and document config merging across global/local files.

Sequence Diagram

sequenceDiagram
  participant BootstrapCLI as Bootstrap::run
  participant ConfigLoader as hooks_from_config
  participant HookParser as hooks::from_toml
  participant PhaseRunner as hooks::run_phase
  participant CmdLineRunner
  BootstrapCLI->>ConfigLoader: request aggregated hooks (global→local)
  ConfigLoader->>HookParser: parse per-entry into BootstrapHook
  BootstrapCLI->>PhaseRunner: run_phase(phase, dry_run)
  PhaseRunner->>CmdLineRunner: execute command (or print in dry_run)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • jdx/mise#10365: Related bootstrap execution changes that overlap with hook insertion points.
  • jdx/mise#10376: Overlapping changes around dotfiles/bootstrap orchestration and stages.

Poem

🐰 I found a hook beneath the log,

It prints and runs, then skips a clog,
Pre, post, and final hops in line,
Dock restarts, tools install, all fine,
The rabbit cheers — the bootstrap's prime!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.37% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(bootstrap): add phase hooks' directly and accurately summarizes the main change—adding support for named bootstrap hook phases.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@jdx jdx changed the title [codex] feat(bootstrap): add phase hooks feat(bootstrap): add phase hooks Jun 13, 2026
@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds [bootstrap.hooks] to mise bootstrap, letting users run arbitrary shell commands at named phases (pre-packages, post-dotfiles, post-tools, final, etc.) before and after each bootstrap step. Hooks merge additively from global to local config, respect --dry-run, fail fast on error, and the config is reloaded after the dotfiles and tools steps so hooks defined in dotfile-managed configs are visible to later phases.

  • src/system/hooks.rs implements the BootstrapHookPhase enum, TOML parsing (string / array / table-with-run), and the async run_phase executor using the configured default inline shell.
  • src/cli/bootstrap.rs threads hook calls through the bootstrap sequence with a hooks_after_dotfiles_dry_run helper that simulates config reload in dry-run by parsing dotfile config targets ahead of time.
  • Docs, manpage, CLI help, and e2e tests are all updated to cover hook syntax, phase ordering, and dry-run behavior.

Confidence Score: 5/5

Safe to merge; the feature is experimental and explicit opt-in, and the one discrepancy found only affects dry-run preview output ordering, not actual hook execution.

The hook execution path, fail-fast behavior, config reload after dotfiles and tools, and forward-compatible raw-TOML parsing all look correct. The dry-run simulation in hooks_after_dotfiles_dry_run appends dotfile-config entries at the end of the IndexMap, which inverts their position relative to real execution after Config::reset(). This is a preview-ordering discrepancy only — no hooks are silently dropped and real execution is unaffected.

src/cli/bootstrap.rs — specifically the hooks_after_dotfiles_dry_run helper and where it inserts dotfile config entries into the config_files map.

Important Files Changed

Filename Overview
src/system/hooks.rs New file implementing BootstrapHookPhase enum, BootstrapHook parsing from TOML, and async run_phase executor; well-structured with tests covering phase parsing and error messages.
src/cli/bootstrap.rs Orchestration layer wiring hook phases into the bootstrap sequence; contains hooks_after_dotfiles_dry_run for dry-run simulation that appends dotfile configs at the end of config_files, potentially mis-ordering their hooks in dry-run output vs real execution.
src/system/mod.rs Adds hooks field to BootstrapTomlConfig and hooks_from_config/hooks_from_config_files aggregation helpers; ordering via .rev() is consistent with all other config aggregation functions in this file.
e2e/cli/test_bootstrap Adds e2e tests for hook execution, dry-run preview, and templated dotfile config targets; tests verify presence of hook output but not execution order.
src/config/config_file/mise_toml.rs Adds test coverage for hooks TOML parsing; no logic changes to production code.
e2e/backend/test_ubi Swaps ffmpeg (broken tarball URL) for fd as the Linux/amd64 ubi tarball test target.
docs/bootstrap.md Documents hook syntax, phase list, merge/ordering semantics, dry-run behavior, and idempotency caveats; accurate and complete.

Reviews (7): Last reviewed commit: "test(ubi): replace stale direct url fixt..." | Re-trigger Greptile

Comment thread src/system/hooks.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/bootstrap.md`:
- Around line 115-120: The docs currently say hooks are "command strings" which
is too narrow; update the wording in the bootstrap hooks docs to state that
[bootstrap.hooks] accepts command strings, arrays of strings, or table forms
with a run key (i.e., the same shorthand and expanded forms parsed by
src/system/hooks.rs), and keep the existing notes about default inline shell
behavior, failure stopping bootstrap, dry-run printing, and running in the
current process environment intact; simply replace phrases that imply only plain
strings with language like "hooks may be specified as a command string, an array
of command strings, or a table with a run field" so readers are aware of the
alternate forms.

In `@docs/tips-and-tricks.md`:
- Around line 101-102: Update the surrounding doc text that currently implies
the bootstrap flow is purely declarative/idempotent to explicitly scope that
claim: state that hooks (example block [bootstrap.hooks.post-defaults] with run
= "killall Dock || true") and entries under [tasks.bootstrap] are imperative
commands executed during mise bootstrap and may have side effects, and add a
short caution recommending reviewers treat hook commands as non-idempotent; keep
the example hook but prepend or follow it with a one-sentence note clarifying
hooks and tasks.bootstrap are the non-declarative pieces.

In `@src/system/hooks.rs`:
- Around line 121-129: run_phase currently assumes
Settings::get().default_inline_shell() returns at least one token and indexes
shell[0], which panics if the vec is empty; fix by validating the returned shell
Vec immediately after let shell = Settings::get().default_inline_shell()? so if
shell.is_empty() return an Err (or otherwise propagate a meaningful error)
explaining the misconfiguration before entering the phase_hooks loop, and then
use safe indexing (e.g. use shell[0] only after the emptiness check) when
constructing crate::cmd::CmdLineRunner::new(&shell[0]) and calling
.cmd_body_args(&shell[1..], &hook.run).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c238c6e9-b03b-4e0a-9d41-9cb7de054450

📥 Commits

Reviewing files that changed from the base of the PR and between e420ad4 and 5b8544c.

📒 Files selected for processing (8)
  • docs/bootstrap.md
  • docs/cli/bootstrap.md
  • docs/tips-and-tricks.md
  • mise.usage.kdl
  • src/cli/bootstrap.rs
  • src/config/config_file/mise_toml.rs
  • src/system/hooks.rs
  • src/system/mod.rs

Comment thread docs/bootstrap.md Outdated
Comment thread docs/tips-and-tricks.md
Comment thread src/system/hooks.rs Outdated
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.6 x -- echo 19.6 ± 0.8 17.8 23.6 1.00
mise x -- echo 20.2 ± 1.3 18.3 42.0 1.03 ± 0.08

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.6 env 19.0 ± 0.8 17.2 22.7 1.00
mise env 19.7 ± 0.9 17.8 25.5 1.04 ± 0.07

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.6 hook-env 19.7 ± 0.8 18.1 23.0 1.00
mise hook-env 20.2 ± 0.8 18.7 23.1 1.02 ± 0.06

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.6 ls 16.3 ± 0.8 14.4 19.6 1.00
mise ls 16.7 ± 0.7 15.2 19.9 1.02 ± 0.07

xtasks/test/perf

Command mise-2026.6.6 mise Variance
install (cached) 132ms 133ms +0%
ls (cached) 59ms 59ms +0%
bin-paths (cached) 64ms 65ms -1%
task-ls (cached) 125ms 125ms +0%

Comment thread src/cli/bootstrap.rs
Comment thread src/cli/bootstrap.rs
Comment thread src/cli/bootstrap.rs Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3b29b13. Configure here.

Comment thread src/cli/bootstrap.rs
@jdx jdx force-pushed the codex/bootstrap-phase-hooks branch from 2304310 to 1bd40a8 Compare June 13, 2026 14:58
@jdx jdx merged commit e532297 into main Jun 13, 2026
35 checks passed
@jdx jdx deleted the codex/bootstrap-phase-hooks branch June 13, 2026 15:13
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