Skip to content

refactor(schema): generate the [env] and [vars] schema from declaration types - #14671

Merged
jdx merged 1 commit into
claude/mise-config-type-toolsfrom
claude/mise-config-type-env
Oct 18, 2026
Merged

jdx merged 1 commit into
claude/mise-config-type-toolsfrom
claude/mise-config-type-env

Conversation

@jdx

@jdx jdx commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

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

The [env] and [vars] parts of schema/mise.json are now generated from declaration types in mise-config, instead of 490 lines of hand-written JSON beside the parser. Nothing changes for users: I compared the old and new schema/mise.json and schema/mise-task.json structurally and they are identical.

[env] accepts a plain value or a table that says what the value is (value, default, required, or an age-encrypted value), plus an _ table of modules (file, path, python, source). The parser reads these with visitors, which a derive can't describe, so the schema comes from types next to it. For example, a variable with an encrypted value:

/// [experimental] age-encrypted environment variable
Age(EnvAgeTable),

where the doc comment is the description editors show on hover.

What changes for maintainers

  • crates/mise-config/src/env/decl.rs holds the types: one per table shape for [env] and [vars] (they differ: [vars] values are strings, integers or true, and a variable may carry a prompt), the _ modules, and the small shared definitions such as env_value and env_required.
  • Nothing parses into them. The parser still reads the options of a variable into EnvDirectiveOptions, so a new test checks that the option keys the types declare (tools, redact, required, expand, find_up, prompt) are exactly that struct's fields. I checked that it fails when a key is declared that the parser does not read.
  • The schema generator closes every typed object with additionalProperties: false, but several [env] shapes deliberately leave their other keys open. A new x-mise-open marker tells it to skip such an object, and it is removed from the output.
  • AGENTS.md says where to change these.

Validation

  • Structural comparison of the old and new schema/mise.json and schema/mise-task.json: no differences. schema/miserc.json is unchanged.
  • cargo +1.95 clippy --workspace --all-features --all-targets -- -D warnings
  • cargo test -p mise-config (schema_files_are_up_to_date and the new test) and cargo test -p mise --lib schema_matches_parser
  • mise run test:e2e config/test_schema_ajv config/test_schema_tombi config/test_config_unknown_key env/test_env_default env/test_env_file env/test_env_path env/test_env_dotenv

Stacked on #14669.

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

🤖 Generated with Claude Code


Note

Low Risk
Schema-generation refactor only; parsing and runtime env behavior are untouched, with conformance tests and structural schema parity checks.

Overview
Refactors how schema/mise.json describes [env] and [vars] — no user-facing config behavior change; the regenerated schema is structurally equivalent to the hand-written version.

The ~490-line hand-written env/schema.rs is removed. [env] / [vars] JSON Schema is now derived from new Env* / Vars* types in crates/mise-config/src/env/decl.rs (doc comments become editor descriptions). The TOML parser is unchanged and still uses custom visitors in env.rs; the decl types only document accepted shapes.

Maintainability: schema.rs emits env, vars, and related $defs via fragment::<…> like other derived sections, instead of chaining hand-written defs. A unit test asserts declaration option keys match EnvDirectiveOptions so schema and parser stay aligned. x-mise-open on a few object shapes prevents the global reject_unknown_keys transform from incorrectly closing tables that must allow extra keys (e.g. env._.path / directives). AGENTS.md documents the new workflow.

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

…on types

The `[env]` and `[vars]` schema was 490 lines of hand-written JSON beside a
visitor parser. It is now generated from declaration types whose doc
comments are the descriptions, and is structurally identical to the old
one. The generator gains an `x-mise-open` marker for typed objects that
deliberately leave their other keys unconstrained, which it would otherwise
close, and strips it from the output.

The parser reads the options of a variable into `EnvDirectiveOptions`, so a
test checks that the option keys the types declare are exactly its fields.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jdx
jdx added this pull request to stack #14664 October 18, 2026 13:02
@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 15 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: 4f2618d7-8a9d-473c-b3ed-4a818aec0d76
📥 Commits

Reviewing files that changed from the base of the PR and between bc8e8e2 and 8a89911.

📒 Files selected for processing: 7
  • AGENTS.md
  • crates/mise-config/src/env.rs
  • crates/mise-config/src/env/decl.rs
  • crates/mise-config/src/env/schema.rs
  • crates/mise-config/src/schema.rs
  • schema/mise-task.json
  • 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.

Summary

Moves the [env] and [vars] schemas from hand-written JSON into Rust declaration types.

  • The [env] and [vars] schemas now come from declaration types.

No actionable issues found. Tests were not run during this review.

Reviews (1) · Last reviewed commit: "refactor(schema): generate the [env] and..." · Reviewed by Greptile

@jdx
jdx merged commit 5c19b56 into main Oct 18, 2026
56 of 58 checks passed
@jdx
jdx deleted the claude/mise-config-type-env branch October 18, 2026 16:06
jdx added a commit that referenced this pull request Oct 18, 2026
…claration types (#14672)

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

The tasks part of `schema/mise.json` is now generated from declaration
types in `mise-config`. Seventeen task fields that accept several shapes
(a string or a list, a name or a table) took their schema from
hand-written JSON functions; each is now a type with doc comments, and
`task/schema.rs` goes from 516 to 96 lines. Nothing changes for users: I
compared the old and new `schema/mise.json` and `schema/mise-task.json`
structurally and they are identical.

For example, `depends`, `depends_post` and `wait_for` take the same
shapes and differ only in what they say they do, so they come from one
macro:

```rust
task_dependencies!(TaskDepends, "task with args to run before this task");
task_dependencies!(TaskDependsPost, "task with args to run after this task");
task_dependencies!(TaskWaitFor, "task with args to wait for completion first");
```

## What changes for maintainers

- `crates/mise-config/src/task/shapes.rs` holds the types: `alias`,
`confirm`, the three dependency fields, `daemons`, `outputs`, `sources`,
the task and `[task_config]` caches, `rust_cache`, `output`, `silent`,
`run` and `run_windows`, `secrets`, `watch` and the shared `$defs` for
dependency items and run entries.
- `TaskDecl` and `TaskConfig` attach them with `schemars(with = ..)`, so
the runtime types of the fields (`Vec<TaskDep>`, `Option<TaskConfirm>`,
...) are untouched and nothing parses into the new ones.
- A task's `tools` repeated the key patterns of `[tools]`; they now come
from the backend table added in #14669, so a new backend is one row in
one place.
- Where a parser has a typed struct, two tests compare its fields with
the declared keys: `TaskWatchOptions`, `TaskCacheConfig` (for the task
and `[task_config]` caches) and `TaskRustCacheOptions`, and the keys a
dependency table reads through `TaskDep`. I checked that both fail when
a key is declared that the parser does not read.
- `AGENTS.md` says where each of these lives.

## Validation

- Structural comparison of the old and new `schema/mise.json` and
`schema/mise-task.json`: no differences. `schema/miserc.json` is
unchanged.
- `cargo +1.95 clippy --workspace --all-features --all-targets -- -D
warnings`
- `cargo test -p mise-config` (`schema_files_are_up_to_date` and the two
new tests), `cargo test -p mise --lib schema_matches_parser` and `cargo
test -p mise --lib task::` (555 tests)
- `mise run test:e2e config/test_schema_ajv config/test_schema_tombi`
and a sample of the `tasks/test_task_*` tests covering depends,
includes, aliases and `task_config`

Stacked on #14671.

*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 only; parsers unchanged and conformance
tests guard schema/parser alignment. No runtime task behavior change
intended.
> 
> **Overview**
> **Maintainer-only refactor:** task-related JSON schema for multi-shape
fields (`depends`, `run`, `outputs`, `cache`, and similar) is now driven
by `JsonSchema` declaration types in
`crates/mise-config/src/task/shapes.rs` instead of large hand-written
`schema_with` helpers in `task/schema.rs`.
> 
> `TaskDecl` and `TaskConfig` wire those types with `schemars(with =
..)` so **runtime parsers and field types are unchanged**; the new types
exist only for schema generation. Shared `$defs` (`task_dependency_*`,
`task_run_entry`, `task_watch`) are registered from `shapes.rs` in
`schema.rs`, and task `tools` backend key patterns are reused via
`tools::task_tool_patterns()` so they stay in sync with `[tools]`.
> 
> `task/schema.rs` shrinks to composition (`task`, `task_template`,
`task_props_tools`). **AGENTS.md** documents the new layout. New unit
tests assert declared schema keys match what parsers accept (including
dependency tables). Regenerated `schema/mise.json` is intended to be
structurally equivalent for users.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8849ea4. 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.

8a89911d86f1 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