Skip to content

feat(edit): add interactive config editor (mise edit)#7930

Merged
jdx merged 26 commits intomainfrom
feat/config-generate-interactive
Feb 1, 2026
Merged

feat(edit): add interactive config editor (mise edit)#7930
jdx merged 26 commits intomainfrom
feat/config-generate-interactive

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Jan 31, 2026

Summary

Adds a new mise edit command that provides an interactive TUI for editing mise configuration files. The editor treats the TOML config as a navigable menu where users can:

  • Navigate sections and entries with arrow keys or vim bindings (j/k/h/l)
  • Add tools via fuzzy-searchable picker with ~500+ tools from the registry
  • Select versions with smart version cycling (latest → major → minor → full)
  • Edit values inline with cursor navigation
  • Undo changes with u key
  • Auto-detect tools from project files (.nvmrc, pyproject.toml, etc.)

Key Features

  • Schema-aware editing: Uses JSON schema to provide appropriate defaults and pickers for settings, hooks, task_config, and monorepo sections
  • Type-aware inputs: Boolean settings show true/false picker, arrays start empty, numbers prompt for input
  • Section-specific add buttons: [tools] shows "Add tool from registry" and "Add tool from backend", [env] shows "Add PATH", "Load .env", "Add variable"
  • Dotted key support: Properly handles _.path and _.source notation for env section
  • Dry-run mode: Preview changes without writing to disk

Architecture

The editor is implemented in a separate mise-interactive-config crate with clear module separation:

mise-interactive-config/
├── cursor.rs      - Navigation state and position tracking
├── document.rs    - TOML document model and serialization
├── editor/
│   ├── mod.rs     - Main editor struct and run loop
│   ├── handlers.rs - Key handlers for each mode
│   ├── actions.rs  - Business logic for mutations
│   └── undo.rs     - Undo system
├── picker.rs      - Fuzzy search picker
├── render.rs      - Terminal rendering
├── schema.rs      - Build-time schema extraction
└── providers.rs   - Trait interfaces for tool/version data

Test plan

  • cargo build compiles successfully
  • cargo test -p mise-interactive-config - 37 tests pass
  • Manual testing of interactive editor
  • Test tool picker with registry tools
  • Test version selector cycling
  • Test undo/redo functionality
  • Test dry-run mode

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk due to introducing a large new TUI/editor codepath that reads/writes config files and adds new schema/registry build-time codegen (detect), which could affect tooling detection and config serialization behavior.

Overview
Introduces a new workspace crate, mise-interactive-config, implementing an interactive terminal editor for mise.toml (navigation, inline edits, fuzzy pickers, undo, type-aware defaults, and schema-driven key pickers).

Adds the mise edit CLI command wired to this editor, including registry-backed tool and backend pickers, async version lookup, dry-run support, and automatic tool/prepare detection based on registry detect files.

Updates build/codegen and dependencies to support this: registry codegen now emits a detect field for tools, the workspace and root crate depend on the new crate, and Cargo.lock is updated accordingly.

Written by Cursor Bugbot for commit 0c42b63. This will update automatically on new commits. Configure here.

Copilot AI review requested due to automatic review settings January 31, 2026 15:48
@gemini-code-assist
Copy link
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an interactive wizard to mise config generate that auto-detects tools from project files and provides a user-friendly configuration experience. The command now defaults to interactive mode when TTY is detected and writes directly to mise.toml.

Changes:

  • Interactive wizard with tool detection from package.json, go.mod, pyproject.toml, and version files
  • Multi-select interface for adding tools from the registry with searchable filtering
  • New flags: -n/--dry-run for preview mode and -y/--yes to skip interactive mode
  • Changed default output from stdout to mise.toml file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +370 to +373
detected.push(DetectedTool {
name: "bun".to_string(),
version: None,
source: "bun.lock".to_string(),
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The source is always set to 'bun.lock' even when 'bun.lockb' is detected. This should reflect the actual file found (either 'bun.lockb' or 'bun.lock').

Suggested change
detected.push(DetectedTool {
name: "bun".to_string(),
version: None,
source: "bun.lock".to_string(),
let source = if cwd.join("bun.lockb").exists() {
"bun.lockb"
} else {
"bun.lock"
};
detected.push(DetectedTool {
name: "bun".to_string(),
version: None,
source: source.to_string(),

Copilot uses AI. Check for mistakes.
if !env_vars.is_empty() || load_dotenv {
config.push_str("[env]\n");
if load_dotenv {
config.push_str("mise.file = \".env\"\n");
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The key 'mise.file' is inconsistent with TOML convention. Consider using an underscore separator like 'mise_file' or a nested structure to follow common TOML naming patterns.

Suggested change
config.push_str("mise.file = \".env\"\n");
config.push_str("[env.mise]\n");
config.push_str("file = \".env\"\n");

Copilot uses AI. Check for mistakes.
Comment on lines +496 to +498
fn quote_toml_value(s: &str) -> String {
format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

This function manually escapes TOML values, which is error-prone. Consider using the toml crate's serialization functionality to properly escape values according to the TOML specification.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

github-actions bot commented Jan 31, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.1.12 x -- echo 19.7 ± 0.2 19.2 20.9 1.01 ± 0.02
mise x -- echo 19.6 ± 0.4 19.0 24.2 1.00

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.1.12 env 19.2 ± 0.6 18.5 24.7 1.00 ± 0.04
mise env 19.1 ± 0.3 18.4 21.2 1.00

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.1.12 hook-env 19.8 ± 0.3 19.3 21.2 1.00 ± 0.02
mise hook-env 19.8 ± 0.3 19.2 21.1 1.00

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.1.12 ls 17.7 ± 0.3 17.2 19.3 1.00
mise ls 17.8 ± 0.4 17.1 20.7 1.00 ± 0.03

xtasks/test/perf

Command mise-2026.1.12 mise Variance
install (cached) 109ms 110ms +0%
ls (cached) 69ms 69ms +0%
bin-paths (cached) 73ms 73ms +0%
task-ls (cached) 529ms 530ms +0%

@jdx jdx changed the title feat(config): add interactive wizard to mise config generate feat(config): add interactive config editor (mise edit) Jan 31, 2026
@jdx jdx force-pushed the feat/config-generate-interactive branch from 27849d1 to ec8a68e Compare January 31, 2026 22:26
@jdx jdx changed the title feat(config): add interactive config editor (mise edit) feat(edit): add interactive config editor (mise edit) Jan 31, 2026
self.mode = Mode::RenameKey(section_idx, entry_idx, InlineEdit::new(&key));
// Note: We'll need to track the field_idx somehow
// For now, we only support entry rename
}
Copy link

Choose a reason for hiding this comment

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

Rename inline table field modifies wrong key

Medium Severity

When renaming an inline table field (e.g., version in node = { version = "20" }), the field_idx is not stored in Mode::RenameKey. The edit box misleadingly shows the field's key name, but when confirmed, handle_rename_key renames entry.key (the parent entry) instead of the field. A comment acknowledges this: "We'll need to track the field_idx somehow. For now, we only support entry rename" — but the UI still shows "r rename" for inline table fields, misleading users.

Additional Locations (1)

Fix in Cursor Fix in Web

}
}
}
Ok(None)
Copy link

Choose a reason for hiding this comment

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

Text editing key handlers duplicate cursor navigation logic

Low Severity

handle_backend_tool_name_key and handle_rename_key (lines 673-737) duplicate nearly identical key handling patterns for ArrowLeft, ArrowRight, Home, End, Backspace, Del, and Char(c). Both methods call the same InlineEdit methods and only differ in how they restore the mode. This pattern could be extracted into a helper method or macro.

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

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.

Bugbot Autofix is ON, but a Cloud Agent failed to start.

jdx and others added 17 commits January 31, 2026 17:46
- Interactive by default when TTY detected, skipped with `-y`
- Auto-detects tools from project files:
  - Node.js from package.json, .nvmrc, .node-version
  - Python from .python-version, pyproject.toml
  - Go from go.mod
  - Ruby from .ruby-version, Gemfile
  - Package managers (pnpm, yarn, bun, uv, poetry) from lockfiles
- Searchable multi-select to add tools from registry
- Prompts for environment variables and .env file loading
- Writes to mise.toml by default (not stdout)
- Add `-n`/`--dry-run` flag to preview without writing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `detect` field to registry schema for tool detection
- Add detect patterns for node, python, go, ruby, bun, pnpm, yarn, uv, poetry
- Replace hardcoded detection with registry-driven detection
- Use menu-driven interface instead of linear wizard flow
- Add mise.lock prompt to wizard

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add config preview displayed above menu each iteration
- Separate add/edit tool operations for better UX with large registry
- Truncate tool descriptions to 60 chars to prevent UI overflow
- Use FOO=bar format for env vars (KEY= to remove)
- Add min_version option to wizard state and menu
- Document config generate in walkthrough guide

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Detects useful settings based on project context:
- idiomatic_version_file when .nvmrc/.python-version etc. exist
- _.path for node_modules/.bin, .venv/bin, or ./bin
- python.uv_venv_auto when Python + uv detected

Shows "Suggested settings" menu option with context-aware
recommendations that users can select.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace deprecated idiomatic_version_file boolean with the
per-tool idiomatic_version_file_enable_tools list setting.

Now suggests per-tool settings like:
  idiomatic_version_file_enable_tools = ["node", "python"]

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove confirmation prompt - detected tools are now automatically
added to the config. Users can remove unwanted tools via the
"Edit/remove tools" menu option.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive undo system covering all actions (add/edit/delete/rename)
- Extract schema info from mise.json at build time for validation
- Classify top-level properties as sections vs entries (min_version is entry, not section)
- Generate settings keys with dot notation for nested settings
- Add common hook names for autocomplete
- Rename command from `mise config generate` to `mise edit`

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add picker for [settings] section with all valid settings from schema
- Add picker for [hooks] section with common hook names
- Filter out already-existing keys in pickers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add picker for [task_config] section with dir, includes keys
- Add picker for [monorepo] section with config_roots key
- Add missing descriptions to schema for env, hooks, vars, watch_files, etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for top-level TOML entries (like min_version,
experimental_monorepo_root) that are not part of a section:

- Parse top-level entries into a root section with empty name
- Serialize root section entries directly to document root
- Display root section as "(root)" in the UI
- Allow adding entries from schema's SCHEMA_ENTRIES via section picker
- Section picker now shows both sections and top-level entries
- Selected items are correctly added as sections or entries based on type

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract type information from JSON schema at build time for settings,
  entries, task_config, monorepo (boolean, integer, number, array, object)
- Add type-appropriate defaults: booleans default to true, arrays to [],
  objects to empty inline tables, numbers prompt for input
- Fix _.path serialization: use dotted key notation in env section
  instead of quoted key "_.path" (creates nested _.path structure)
- Add Prepare section support: prepare providers default to inline tables
- Handle redactions as array type, experimental_monorepo_root as boolean
- Add tests for dotted key serialization and type detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
jdx and others added 8 commits January 31, 2026 17:46
- Split 1867-line editor.rs into focused modules:
  - editor/mod.rs (265 lines) - Main struct, construction, run loop
  - editor/handlers.rs (715 lines) - Key handlers for each mode
  - editor/actions.rs (890 lines) - Business logic for mutations
  - editor/undo.rs (34 lines) - UndoAction enum
- Add boolean true/false picker for boolean schema types
- Box PickerState in Mode enum to reduce variant size
- Update docs/walkthrough.md to reference `mise edit` with tip callout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Shows a spinner with status messages while:
- Loading existing config file
- Detecting tools from project files
- Detecting prepare providers

The spinner clears with "Ready" before the TUI starts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show loading indicator in TUI while fetching version info for tools
- Add Mode::Loading variant for transient loading states
- Store path_display in InteractiveConfig for handlers to trigger renders
- Fix single-character quote causing slice panic in env variables
- Fix undo tracking for duplicate sections (no-op add_section)
- Clear undo stack when creating root section to prevent index corruption

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Detect boolean settings by schema type when editing entries
- Use left/right arrow keys to toggle true/false instead of text input
- Support boolean editing for inline table fields (e.g., compile = true)
- Display boolean values without quotes in the TUI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Sort failed installations alphabetically for deterministic output (from #7936)
- Add cargo-machete ignore for serde_json build dependency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix nested TOML tables silently ignored in document.rs parse_entry
- Add undo tracking for version selection edits
- Fix generate config test to use -n flag for stdout output

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@jdx jdx force-pushed the feat/config-generate-interactive branch from cf03f94 to 2290440 Compare January 31, 2026 23:46
When all predefined items exist in these sections, the add button falls
back to manual text entry. Previously, apply_new_key had no handlers for
Hook, TaskConfig, or Monorepo - they fell through to _ => {} and silently
discarded user input.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@jdx jdx enabled auto-merge (squash) January 31, 2026 23:58
@jdx jdx merged commit adedd15 into main Feb 1, 2026
36 checks passed
@jdx jdx deleted the feat/config-generate-interactive branch February 1, 2026 00:04
mise-en-dev added a commit that referenced this pull request Feb 1, 2026
### 🚀 Features

- **(edit)** add interactive config editor (`mise edit`) by @jdx in
[#7930](#7930)
- **(lockfile)** graduate lockfiles from experimental by @jdx in
[#7929](#7929)
- **(task)** add support for usage values in task confirm dialog by
@roele in [#7924](#7924)
- **(task)** improve source freshness checking with edge case handling
by @jdx in [#7932](#7932)

### 🐛 Bug Fixes

- **(activate)** preserve ordering of paths appended after mise activate
by @jdx in [#7919](#7919)
- **(install)** sort failed installations for deterministic error output
by @jdx in [#7936](#7936)
- **(lockfile)** preserve URL and prefer sha256 when merging platform
info by @jdx in [#7923](#7923)
- **(lockfile)** add atomic writes and cache invalidation by @jdx in
[#7927](#7927)
- **(templates)** use sha256 for hash filter instead of blake3 by @jdx
in [#7925](#7925)
- **(upgrade)** respect tracked configs when pruning old versions by
@jdx in [#7926](#7926)

### 🚜 Refactor

- **(progress)** migrate from indicatif to clx by @jdx in
[#7928](#7928)

### 📚 Documentation

- improve clarity on uvx and pipx dependencies by @ygormutti in
[#7878](#7878)

### ⚡ Performance

- **(install)** use Kahn's algorithm for dependency scheduling by @jdx
in [#7933](#7933)
- use Aho-Corasick for efficient redaction by @jdx in
[#7931](#7931)

### 🧪 Testing

- remove flaky test_http_version_list test by @jdx in
[#7934](#7934)

### Chore

- use github backend instead of ubi in mise.lock by @jdx in
[#7922](#7922)

### New Contributors

- @ygormutti made their first contribution in
[#7878](#7878)
lucasew pushed a commit to lucasew/CONTRIB-mise that referenced this pull request Feb 18, 2026
## Summary

Adds a new `mise edit` command that provides an interactive TUI for
editing mise configuration files. The editor treats the TOML config as a
navigable menu where users can:

- **Navigate** sections and entries with arrow keys or vim bindings
(j/k/h/l)
- **Add tools** via fuzzy-searchable picker with ~500+ tools from the
registry
- **Select versions** with smart version cycling (latest → major → minor
→ full)
- **Edit values** inline with cursor navigation
- **Undo changes** with `u` key
- **Auto-detect tools** from project files (.nvmrc, pyproject.toml,
etc.)

### Key Features

- **Schema-aware editing**: Uses JSON schema to provide appropriate
defaults and pickers for settings, hooks, task_config, and monorepo
sections
- **Type-aware inputs**: Boolean settings show true/false picker, arrays
start empty, numbers prompt for input
- **Section-specific add buttons**: [tools] shows "Add tool from
registry" and "Add tool from backend", [env] shows "Add PATH", "Load
.env", "Add variable"
- **Dotted key support**: Properly handles `_.path` and `_.source`
notation for env section
- **Dry-run mode**: Preview changes without writing to disk

### Architecture

The editor is implemented in a separate `mise-interactive-config` crate
with clear module separation:

```
mise-interactive-config/
├── cursor.rs      - Navigation state and position tracking
├── document.rs    - TOML document model and serialization
├── editor/
│   ├── mod.rs     - Main editor struct and run loop
│   ├── handlers.rs - Key handlers for each mode
│   ├── actions.rs  - Business logic for mutations
│   └── undo.rs     - Undo system
├── picker.rs      - Fuzzy search picker
├── render.rs      - Terminal rendering
├── schema.rs      - Build-time schema extraction
└── providers.rs   - Trait interfaces for tool/version data
```

## Test plan

- [x] `cargo build` compiles successfully
- [x] `cargo test -p mise-interactive-config` - 37 tests pass
- [x] Manual testing of interactive editor
- [ ] Test tool picker with registry tools
- [ ] Test version selector cycling
- [ ] Test undo/redo functionality
- [ ] Test dry-run mode

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk due to introducing a large new TUI/editor codepath that
reads/writes config files and adds new schema/registry build-time
codegen (`detect`), which could affect tooling detection and config
serialization behavior.
> 
> **Overview**
> Introduces a new workspace crate, `mise-interactive-config`,
implementing an interactive terminal editor for `mise.toml` (navigation,
inline edits, fuzzy pickers, undo, type-aware defaults, and
schema-driven key pickers).
> 
> Adds the `mise edit` CLI command wired to this editor, including
registry-backed tool and backend pickers, async version lookup, dry-run
support, and automatic tool/prepare detection based on registry `detect`
files.
> 
> Updates build/codegen and dependencies to support this: registry
codegen now emits a `detect` field for tools, the workspace and root
crate depend on the new crate, and `Cargo.lock` is updated accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0c42b63. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
lucasew pushed a commit to lucasew/CONTRIB-mise that referenced this pull request Feb 18, 2026
### 🚀 Features

- **(edit)** add interactive config editor (`mise edit`) by @jdx in
[jdx#7930](jdx#7930)
- **(lockfile)** graduate lockfiles from experimental by @jdx in
[jdx#7929](jdx#7929)
- **(task)** add support for usage values in task confirm dialog by
@roele in [jdx#7924](jdx#7924)
- **(task)** improve source freshness checking with edge case handling
by @jdx in [jdx#7932](jdx#7932)

### 🐛 Bug Fixes

- **(activate)** preserve ordering of paths appended after mise activate
by @jdx in [jdx#7919](jdx#7919)
- **(install)** sort failed installations for deterministic error output
by @jdx in [jdx#7936](jdx#7936)
- **(lockfile)** preserve URL and prefer sha256 when merging platform
info by @jdx in [jdx#7923](jdx#7923)
- **(lockfile)** add atomic writes and cache invalidation by @jdx in
[jdx#7927](jdx#7927)
- **(templates)** use sha256 for hash filter instead of blake3 by @jdx
in [jdx#7925](jdx#7925)
- **(upgrade)** respect tracked configs when pruning old versions by
@jdx in [jdx#7926](jdx#7926)

### 🚜 Refactor

- **(progress)** migrate from indicatif to clx by @jdx in
[jdx#7928](jdx#7928)

### 📚 Documentation

- improve clarity on uvx and pipx dependencies by @ygormutti in
[jdx#7878](jdx#7878)

### ⚡ Performance

- **(install)** use Kahn's algorithm for dependency scheduling by @jdx
in [jdx#7933](jdx#7933)
- use Aho-Corasick for efficient redaction by @jdx in
[jdx#7931](jdx#7931)

### 🧪 Testing

- remove flaky test_http_version_list test by @jdx in
[jdx#7934](jdx#7934)

### Chore

- use github backend instead of ubi in mise.lock by @jdx in
[jdx#7922](jdx#7922)

### New Contributors

- @ygormutti made their first contribution in
[jdx#7878](jdx#7878)
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