feat(task): add task templates for reusable task definitions#7873
Conversation
Add support for task templates that can be extended by tasks via the `extends` field. This enables DRY task definitions in monorepos and projects with similar task patterns. Templates are defined in [task_templates.*] sections and can provide default values for run, tools, env, depends, and other task fields. Tasks can extend templates and override specific fields as needed. Merge semantics: - run, depends, sources, outputs: local overrides completely - tools, env: deep merge (local values override template) - Other fields: local overrides if set Requires experimental = true to use. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds support for task templates, allowing users to define reusable task definitions that can be extended by tasks via the extends field. This feature enables DRY (Don't Repeat Yourself) principles in task definitions, particularly useful in monorepos and projects with similar task patterns.
Changes:
- Introduces
TaskTemplatestruct with same fields asTaskfor defining reusable configurations - Implements template resolution with smart merge semantics (deep merge for tools/env, complete override for run/depends/sources/outputs)
- Adds experimental flag requirement for using the
extendsfeature - Templates support colon-namespacing (e.g.,
python:build,rust:test)
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/task/task_template.rs | New file containing TaskTemplate struct and merge_template implementation with comprehensive unit tests |
| src/task/mod.rs | Adds extends field to Task struct and exports TaskTemplate |
| src/config/mod.rs | Implements template collection, resolution, and integration into task loading pipeline |
| src/config/config_file/mod.rs | Adds task_templates() trait method to ConfigFile |
| src/config/config_file/mise_toml.rs | Implements TaskTemplates type and deserialization logic |
| src/cli/generate/task_docs.rs | Updates task documentation generation to handle templates |
| e2e/tasks/test_task_templates | Comprehensive E2E tests covering all template features and edge cases |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| redactions: self.redactions.clone(), | ||
| plugins: self.plugins.clone(), | ||
| tasks: self.tasks.clone(), | ||
| task_templates: self.task_templates.clone(), |
There was a problem hiding this comment.
The task_templates field in the Clone implementation lacks test coverage. Consider adding a test that verifies cloning a MiseToml instance with task templates preserves the templates correctly.
| // Iterate in reverse order (global -> local) so child directories override parent configs | ||
| for cf in config_files.values().rev() { |
There was a problem hiding this comment.
The comment states 'Iterate in reverse order (global -> local) so child directories override parent configs', but .rev() on values() actually iterates from local to global (since values() already returns an iterator in insertion order, which is global->local in ConfigMap). Either the comment is incorrect or the iteration order is backwards. Consider clarifying or fixing this.
| // Iterate in reverse order (global -> local) so child directories override parent configs | |
| for cf in config_files.values().rev() { | |
| // Iterate from global to local so later (child) configs overwrite earlier (parent) templates | |
| for cf in config_files.values() { |
|
|
||
| assert "mise run build" "cargo build" | ||
|
|
||
| echo '' >mise.toml |
There was a problem hiding this comment.
The test cleanup at the end uses echo '' >mise.toml which creates a file with a newline. Consider using rm -f mise.toml or true >mise.toml for cleaner test isolation, as the empty file with a newline could affect subsequent tests.
| echo '' >mise.toml | |
| rm -f mise.toml |
- Add new docs/tasks/templates.md with comprehensive documentation - Update docs/tasks/index.md to reference templates - Update docs/tasks/monorepo.md to show template usage in monorepos - Add Task Templates to sidebar navigation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use <code v-pre> to escape Tera template syntax that was being interpreted as Vue template syntax by VitePress. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Boolean fields (quiet, hide, raw) in Task use `bool` not `Option<bool>`, so we cannot distinguish between "not set" (defaults to false) and "explicitly set to false". Remove merge logic for these fields to avoid overriding a task's explicit `false` value with a template's `true`. Users must explicitly set these fields in their task if needed. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 x -- echo |
19.1 ± 0.2 | 18.6 | 21.7 | 1.00 |
mise x -- echo |
19.3 ± 0.2 | 18.9 | 20.5 | 1.01 ± 0.02 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 env |
18.5 ± 0.5 | 18.0 | 23.5 | 1.00 |
mise env |
18.8 ± 0.3 | 18.2 | 22.3 | 1.02 ± 0.03 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 hook-env |
18.8 ± 0.3 | 18.4 | 24.6 | 1.00 |
mise hook-env |
19.1 ± 0.2 | 18.6 | 20.3 | 1.01 ± 0.02 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.8 ls |
16.7 ± 0.2 | 16.2 | 17.4 | 1.00 |
mise ls |
17.0 ± 0.2 | 16.5 | 19.0 | 1.02 ± 0.02 |
xtasks/test/perf
| Command | mise-2026.1.8 | mise | Variance |
|---|---|---|---|
| install (cached) | 108ms | 108ms | +0% |
| ls (cached) | 65ms | 65ms | +0% |
| bin-paths (cached) | 69ms | 69ms | +0% |
| task-ls (cached) | 278ms | -87% |
### 🚀 Features - **(doctor)** add backend mismatch warnings by @jdx in [#7847](#7847) - **(http)** add rename_exe support for archive extraction by @jdx in [#7874](#7874) - **(http)** send x-mise-ci header for CI environment tracking by @jdx in [#7875](#7875) - **(install)** auto-install plugins from [plugins] config section by @jdx in [#7856](#7856) - **(registry)** add vercel by @mikecurtis in [#7844](#7844) - **(task)** support glob patterns in task_config.includes by @jdx in [#7870](#7870) - **(task)** add task templates for reusable task definitions by @jdx in [#7873](#7873) ### 🐛 Bug Fixes - **(backend)** change registry mismatch log from info to debug by @jdx in [#7858](#7858) - **(ci)** use squash merge for auto-merge-release workflow by @jdx in [7e5e71e](7e5e71e) - **(ci)** remove --auto flag to merge immediately when CI passes by @jdx in [23ed2ed](23ed2ed) - **(github)** select platform-matching provenance file for SLSA verification by @jdx in [#7853](#7853) - **(go)** filter out version "1" from available versions by @jdx in [#7871](#7871) - **(install)** skip CurDir components when detecting archive structure by @jdx in [#7868](#7868) - **(pipx)** ensure Python minor version symlink exists for postinstall hooks by @jdx in [#7869](#7869) - **(registry)** prevent duplicate -stable suffix in Flutter download URLs by @jdx in [#7872](#7872) - **(task)** pass env to usage parser for env-backed arguments by @jdx in [#7848](#7848) - **(task)** propagate MISE_ENV to child tasks when using -E flag by @jdx in [06ee776](06ee776) - **(vfox-dotnet)** use os.execute() to fix Windows installation by @prodrigues1912 in [#7843](#7843) ### 📚 Documentation - update cache-behavior with env_cache information by @jdx in [#7849](#7849) ###◀️ Revert - remove task inheritance from parent configs in monorepos by @jdx in [#7851](#7851) - Revert "fix(ci): remove --auto flag to merge immediately when CI passes" by @jdx in [0606187](0606187) ### 📦 Registry - add mago ([aqua:carthage-software/mago](https://github.com/carthage-software/mago)) by @scop in [#7845](#7845) ### Chore - **(ci)** auto-merge release branch into main daily at 4am CST by @jdx in [#7852](#7852) ### New Contributors - @mikecurtis made their first contribution in [#7844](#7844) - @prodrigues1912 made their first contribution in [#7843](#7843)
Summary
This PR adds support for task templates that allow defining reusable task definitions which can be extended by tasks via the
extendsfield. This enables DRY task definitions in monorepos and projects with similar task patterns.Key features:
[task_templates.*]sections of mise.tomlextends = "template-name"python:build,rust:test, etc.run,depends,sources,outputs: local overrides completelytools,env: deep merge (local values override template values)experimental = truein settingsExample usage:
Test plan
run🤖 Generated with Claude Code
Note
Adds experimental task templates to enable DRY task definitions and inheritance.
task_templatesinmise.tomlwithextendssupport and defined merge semantics; implementsTaskTemplateandTask::merge_templateexperimentalis offgenerate task-docsupdated to include template resolutiondocs/tasks/templates.md, sidebar/nav entries, and monorepo referencesWritten by Cursor Bugbot for commit d2a9296. This will update automatically on new commits. Configure here.