Skip to content

refactor(schema): generate the [hooks] schema from declaration types - #14666

Merged
jdx merged 2 commits into
claude/mise-config-type-daemonsfrom
claude/mise-config-type-hooks
Oct 18, 2026
Merged

jdx merged 2 commits into
claude/mise-config-type-daemonsfrom
claude/mise-config-type-hooks

Conversation

@jdx

@jdx jdx commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

https://entire.io/gh/jdx/mise/trails/871

The [hooks] part of schema/mise.json is now generated from declaration types in mise-config, instead of 16 hand-written JSON definitions. Nothing changes for users: I compared the old and new schema/mise.json structurally and they are identical.

A hook can be a command string, { run = ... }, { script = ..., shell = ... }, { scripts = [...], shell = ... } or { task = ... }, and which of those an event accepts differs: enter, leave and cd evaluate a script in the active shell when shell is set, while preinstall and postinstall ignore the shell. The types now say that directly. For example:

// The same keys without a `shell` run in a subprocess, which is deprecated in favor of `run`.
pub struct HookSpawnedScriptTable {
    /// deprecated alias for run when an enter/leave/cd hook has no shell
    pub script: HookScripts,
}

where the doc comment is the description editors show and the deprecation is carried into the schema.

What changes for maintainers

  • crates/mise-config/src/hooks/decl.rs holds the types: one per table shape (HookRunTableDecl, HookCurrentShellScriptTable, HookInstallScriptTable, ...), the unions of them an event accepts (HookDefinitionItem for enter/leave/cd, HookInstallDefinitionItem for the install events), and HooksDecl, which names the five events.
  • The parser still reads one table, HookTable, for every event, and nothing parses into the new types. Two tests keep them from drifting: one checks that the declaration types name exactly the keys HookTable reads, and one checks that HooksDecl has an entry for each hook event. The events test uses an exhaustive match, so adding a Hooks variant fails to compile there until the schema has it.
  • HookScripts now derives its own schema, replacing the hook_script_value definition.
  • AGENTS.md says where to change hook shapes.

Validation

  • Structural comparison of the old and new schema/mise.json: no differences.
  • cargo +1.95 clippy --workspace --all-features --all-targets -- -D warnings
  • cargo test -p mise-config (including schema_files_are_up_to_date and the two new tests) and cargo test -p mise --lib schema_matches_parser
  • mise run test:e2e config/test_schema_ajv config/test_schema_tombi and the config/test_hooks* tests

Stacked on #14663.

AI-assisted — Tool: Claude Code; model: anthropic/claude-sonnet-5-5; version: 2.1.299.

🤖 Generated with Claude Code


Note

Low Risk
Refactor of schema generation and docs/tests only; hook parsing behavior is unchanged and the published schema is intended to be structurally equivalent.

Overview
[hooks] in schema/mise.json is now generated from Hook* declaration types in crates/mise-config/src/hooks/decl.rs, replacing the deleted hand-written hooks/schema.rs. Runtime parsing is unchanged: configs still deserialize through HookTable / HookDefItem.

Schema assembly wires those types through derived_defs in schema.rs (and drops the old schema_defs() chain). HookScripts now derives JsonSchema, and two unit tests keep declaration keys aligned with HookTable and hook events aligned with HooksDecl. AGENTS.md documents the new maintainer workflow.

Regenerated schema/mise.json is structurally the same for users; diffs are mostly key ordering and formatting from schemars.

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

The hook schema was 16 hand-written definitions. They are now declaration
types in `hooks/decl.rs` whose doc comments are the descriptions, and the
shared tables and unions are generated and referenced through `$defs` as
before. The generated schema is structurally identical to the old one.

The parser reads a single `HookTable` for every event, so a test checks
that the declaration types name exactly the keys it reads, and that the
schema has an entry for each hook event.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jdx
jdx added this pull request to stack #14664 October 18, 2026 12:36
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 24 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ed3fcb84-aea4-454f-b42d-d1a4a81ef084
📥 Commits

Reviewing files that changed from the base of the PR and between a719280 and b445620.

📒 Files selected for processing: 6
  • AGENTS.md
  • crates/mise-config/src/hooks.rs
  • crates/mise-config/src/hooks/decl.rs
  • crates/mise-config/src/hooks/schema.rs
  • crates/mise-config/src/schema.rs
  • schema/mise.json
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Low impact] The PR appears safe to merge; no actionable issues were found.

Summary

Replaces hand-written hook schemas with declaration types while leaving the runtime parser unchanged.

  • The [hooks] schema now comes from typed declarations.

Reviews (2) · Last reviewed commit: "Merge branch 'claude/mise-config-type-da..." · Reviewed by Greptile

greptile-apps[bot]
greptile-apps Bot previously approved these changes Oct 18, 2026
@greptile-apps
greptile-apps Bot dismissed their stale review October 18, 2026 12:53

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

@jdx
jdx merged commit c66e3e3 into main Oct 18, 2026
52 checks passed
@jdx
jdx deleted the claude/mise-config-type-hooks branch October 18, 2026 16:06
jdx added a commit that referenced this pull request Oct 18, 2026
…aration types (#14668)

<!-- entire-trail-link-start -->
https://entire.io/gh/jdx/mise/trails/872
<!-- entire-trail-link-end -->

The parts of `[bootstrap]` that stay raw TOML now have their schema
generated from declaration types in `mise-config`, instead of 13
hand-written JSON definitions (about 370 lines). Nothing changes for
users: I compared the old and new `schema/mise.json` structurally and
they are identical.

These are the values mise reads as raw TOML so that a shape from a newer
mise warns and is skipped instead of failing the whole file: the phase
hooks, shell activation, the macOS defaults domains and the curated
Dock, Finder, keyboard and trackpad preferences, and the apt and dnf
repositories. For example, a curated macOS preference is now a field
with a doc comment, which is the description editors show:

```rust
pub struct MacosTrackpad {
    /// enable tap to click for built-in and Bluetooth trackpads
    pub tap_to_click: Option<bool>,
    // ...
}
```

## What changes for maintainers

- `crates/mise-config/src/bootstrap/decl.rs` holds the types. The hook
phases come from one list, `BOOTSTRAP_HOOK_PHASES`, and the schema
offers each phase in both spellings (`pre-packages` and `pre_packages`)
from it.
- Nothing parses into these types, so two tests in mise-system keep them
honest:
- the declared hook phases must equal mise-system's
`BootstrapHookPhase`;
- each declared curated macOS key, set to a sample value of its declared
type, must produce a defaults entry through
`merge_friendly_macos_defaults`. I checked that the test fails when a
key is declared that the code ignores.
- The schema generator now drops the `format: "double"` that schemars
writes for floating-point fields, as it already drops the integer
formats, since neither says anything to an editor.
- mise-system gets `schemars` as a dev-dependency, for the macOS test.
- `AGENTS.md` says where these live.

## Validation

- Structural comparison of the old and new `schema/mise.json`: no
differences.
- `cargo +1.95 clippy --workspace --all-features --all-targets -- -D
warnings`
- `cargo test --workspace --all-features --exclude mise --exclude
mise-system-packages`, `cargo test -p mise --lib schema_matches_parser`
- `mise run test:e2e config/test_schema_ajv config/test_schema_tombi`

Stacked on #14666.

*AI-assisted — Tool: Claude Code; model: anthropic/claude-sonnet-5-5;
version: 2.1.299.*

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Schema-generation refactor with parity checks and new conformance
tests; runtime bootstrap parsing is unchanged.
> 
> **Overview**
> **Refactors how `[bootstrap]` JSON Schema is produced** for fields
that stay raw TOML (phase hooks, shell activation, macOS
defaults/curated prefs, apt/dnf repos). Roughly 370 lines of
hand-written definitions in `bootstrap/schema.rs` are removed and
replaced by `JsonSchema` declaration types in `bootstrap/decl.rs`, wired
through `schema.rs` like other derived sections.
> 
> **Maintainer-facing guardrails:** `BOOTSTRAP_HOOK_PHASES` drives hook
schema (both `-` and `_` spellings); mise-system tests assert hook
phases match `BootstrapHookPhase` and that every curated macOS key in
the declarations is honored by `merge_friendly_macos_defaults`. The
schema generator also strips useless `format` on floating-point fields
(as it already did for integers). `AGENTS.md` documents the new layout.
> 
> **No intended user or config behavior change** — committed
`schema/mise.json` is regenerated with equivalent validation semantics.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
18b9966. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Instruction counts

The comparison never ran — an earlier step failed.

b44562044bce vs `` · measured on the runner, not pushed to the history.

mise-en-dev added a commit that referenced this pull request Oct 19, 2026
<!-- entire-trail-link-start -->
https://entire.io/gh/jdx/mise/trails/879
<!-- entire-trail-link-end -->

### 🚀 Features

- **(backend)** serve every backend's version list from the versions
host by @jdx in [#14700](#14700)
- **(bootstrap)** add --prune-dotfiles to remove orphaned dotfiles by
@jdx in [#14681](#14681)
- **(config)** add read_json, read_yaml and read_toml template functions
by @jdx in [#14705](#14705)
- **(config)** apply the default minimum_release_age to every backend by
@jdx in [#14701](#14701)
- **(dotfiles)** add dotfiles.windows_symlinks to link files instead of
copying on Windows by @jdx in
[#14682](#14682)
- **(dotnet)** add lts and sts version aliases by @jdx in
[#14683](#14683)
- **(http)** read release dates for http versions by @jdx in
[#14696](#14696)
- **(install)** add a PowerShell installer at mise.run/powershell by
@jdx in [#14660](#14660)
- **(task)** add -a as a short alias for tasks --all by @williamsjokvist
in [#14674](#14674)
- **(vfox)** let plugins report release dates for minimum_release_age by
@jdx in [#14695](#14695)

### 🐛 Bug Fixes

- **(aqua)** find binaries in macOS universal archives by @jdx in
[#14665](#14665)
- **(aqua)** date github_tag versions so minimum_release_age applies by
@jdx in [#14691](#14691)
- **(backend)** warn when minimum_release_age cannot check a version's
date by @jdx in [#14694](#14694)
- **(conda)** report release dates so minimum_release_age applies by
@jdx in [#14693](#14693)
- **(core)** date dotnet, deno and erlang versions for
minimum_release_age by @jdx in
[#14692](#14692)
- **(core)** date more ruby, python and rust versions so
minimum_release_age applies by @jdx in
[#14697](#14697)
- **(dotfiles)** report copies instead of symlinks for symlink-each on
Windows by @jdx in [#14654](#14654)
- **(fmt)** keep multiline inline tables intact by @jdx in
[#14670](#14670)
- **(http)** retry the install rename on Windows when antivirus holds
the files by @jdx in [#14703](#14703)
- **(install)** extract 7z archives when the data dir contains `..` by
@jdx in [#14657](#14657)
- **(npm)** run allow_builds scripts despite ignore-scripts in .npmrc by
@jdx in [#14661](#14661)
- **(npm)** pin aube-lock.yaml so a user's lockfile settings don't break
mise lock by @jdx in [#14659](#14659)
- **(rust)** list channels when GitHub is unreachable behind a mirror by
@jdx in [#14662](#14662)
- **(shim)** keep the version tag in the Windows release mise-shim.exe
by @jdx in [#14656](#14656)
- **(task)** keep task commands working when one task's dir template is
broken by @jdx in [#14680](#14680)

### 🚜 Refactor

- **(schema)** generate the [deps] and [secrets] schema from their types
by @jdx in [#14658](#14658)
- **(schema)** generate the [daemons] and [daemon_providers] schema from
types by @jdx in [#14663](#14663)
- **(schema)** generate the [hooks] schema from declaration types by
@jdx in [#14666](#14666)
- **(schema)** generate the [bootstrap] raw-value schema from
declaration types by @jdx in
[#14668](#14668)
- **(schema)** generate the [tools] option schemas from declaration
types by @jdx in [#14669](#14669)
- **(schema)** generate the [env] and [vars] schema from declaration
types by @jdx in [#14671](#14671)
- **(schema)** generate the multi-shape task field schemas from
declaration types by @jdx in
[#14672](#14672)

### 📚 Documentation

- **(config)** add an interactive mise.toml editor and playground by
@jdx in [#14673](#14673)
- **(config)** hover over keys in every mise.toml example by @jdx in
[#14686](#14686)
- **(config)** turn the mise.toml reference into a key explorer by @jdx
in [#14687](#14687)
- **(config)** show a real example for every mise.toml reference key by
@jdx in [#14690](#14690)
- **(dotnet)** explain how private feeds authenticate by @jdx in
[#14679](#14679)
- **(schema)** describe the remaining bootstrap keys by @jdx in
[#14688](#14688)
- **(secrets)** add setup, CI and migration guidance to the fnox page by
@jdx in [#14675](#14675)
- record the landing-page showreel against current mise so its cache
fills by @jdx in [#14685](#14685)

### 📦️ Dependency Updates

- lock file maintenance by @renovate[bot] in
[#14708](#14708)

### 📦 Registry

- add release dates to dart, flutter, nim, julia and other http tools by
@jdx in [#14698](#14698)

### Ci

- **(release)** publish releases staged before install.ps1 existed by
@jdx in [#14684](#14684)
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