Skip to content

feat(packslip): shell completions from a tool's packslip - #12779

Merged
jdx merged 15 commits into
feat/packslip-backendfrom
feat/packslip-completions
Sep 5, 2026
Merged

feat(packslip): shell completions from a tool's packslip#12779
jdx merged 15 commits into
feat/packslip-backendfrom
feat/packslip-completions

Conversation

@jdx

@jdx jdx commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Summary

Stacked on #12778. A packslip may list what a release ships besides its executables. This PR reads its completion and cli-spec resources for tools installed with the packslip: backend.

  • mise completion <shell> --tool <name> prints the tool's completion script for whichever of its versions is active in the current directory. <name> is the tool or one of its executables. Sources are tried in the order the specification gives, most verifiable first: a file inside the artifact or a separate signed asset, a file from the source repository at the release's commit, a script derived from the tool's usage spec with the usage command, and only then a command of the tool's own.
  • packslip.exec setting (default off). An exec entry runs a freshly installed binary when the shell first asks for a completion, before the user has run the tool, so it is refused unless this is on; the error says what would have run and how to allow it.
  • --install writes a stub, not the script. Completions are global shell state while the active version depends on the directory, so the stub asks mise for the script at completion time and follows version switches without being rewritten. It goes where the shell loads completions by name, through usage's resolver, the same place mise completion zsh --install puts mise's own, and carries the marker that resolver looks for so re-installing replaces it. The zsh stub only calls the loaded function if the script actually redefined it, so an autoload-style vendor script cannot recurse into the stub.
  • Fetch at install. Files a vendor keeps outside the artifact are fetched when the tool is installed: a separate release asset must match the digest the packslip signed, and a repository file is pinned by the release's commit (github.com and gitlab.com raw URLs).

Test plan

  • clippy, fmt, hk; JSON schema and CLI docs regenerated
  • Unit tests: statement read-back and validation, raw-file URLs, source ordering (shipped files first, unfetched assets skipped, spec before exec), stub content per shell
  • e2e: mise completion zsh --tool packslip reports that the 0.2.0 packslip declares no completion; an unknown tool is refused

🤖 Generated with Claude Code


Note

Medium Risk
New install-time network fetches and completion-time tool execution (when packslip.exec is enabled) touch shell integration and verified packslip data, though paths and digests are constrained and exec is opt-in.

Overview
Adds mise completion <shell> --tool <name> so packslip-installed tools can expose shell completions from their signed manifest resources (completion / cli-spec), using the active version in the current directory. Sources are tried in spec order (shipped files → signed assets → repo files at the release commit → usage-derived scripts → tool exec commands).

Introduces packslip.exec (default off) because exec-based completions run a freshly installed binary at tab time. --install now writes a version-aware stub (via usage’s installer) that calls mise at completion time instead of baking in one script; zsh/bash restore the stub after each completion so directory-based version switches stay correct.

On install, the packslip backend fetches out-of-artifact resources into .mise-packslip/ (digest-checked assets, GitHub/GitLab repo files). Docs, schema, and e2e cover missing completions and unknown tools.

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

Summary by CodeRabbit

  • New Features

    • Added --tool <TOOL> to mise completion to generate shell completions for installed tools.
    • Added --install support for version-aware completion stubs that update automatically when tool versions change.
    • Completions can be sourced from packaged files, CLI specifications, or tool-provided commands.
    • Added optional [packslip] exec configuration, disabled by default, for command-based completion generation.
  • Documentation

    • Updated CLI help, manual pages, and packslip documentation with usage examples and source-selection details.
  • Bug Fixes

    • Added validation for unsupported tools and packslip releases without completion definitions.

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 36f9816a-f1bd-422b-bcdc-53dc3ad1b23f

📥 Commits

Reviewing files that changed from the base of the PR and between e3ce070 and c098baf.

📒 Files selected for processing (11)
  • docs/cli/completion.md
  • docs/dev-tools/backends/packslip.md
  • e2e/backend/test_packslip
  • man/man1/mise.1
  • mise.usage.kdl
  • schema/mise.json
  • settings.toml
  • src/backend/packslip.rs
  • src/cli/completion.rs
  • src/main.rs
  • src/packslip.rs

Included review availability: Your plan provides up to 10 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

Changes

The mise completion command now generates completions for installed packslip tools. It selects and fetches verified resources, derives scripts from CLI specifications, optionally runs tool commands, and installs shell-specific dynamic stubs. Documentation, settings, schema, and end-to-end coverage were updated.

Packslip resource acquisition

Layer / File(s) Summary
Resource acquisition and artifact selection
src/packslip.rs, src/backend/packslip.rs, src/main.rs
Packslip statements and external resources are validated, selected for the host artifact, fetched into .mise-packslip, and checked against path and digest rules.

Completion resolution

Layer / File(s) Summary
Completion source resolution and shell loaders
src/packslip.rs
Completion resources are filtered by artifact and platform specificity. File, specification, executable, and specification-executable sources are tried in order. Shell-specific stubs defer loading to mise.

CLI integration and supporting updates

Layer / File(s) Summary
CLI integration, settings, and validation
src/cli/completion.rs, mise.usage.kdl, settings.toml, schema/mise.json, docs/..., man/man1/mise.1, e2e/backend/test_packslip
The CLI accepts --tool, installs dynamic stubs, and reports installation results. The packslip.exec setting, documentation, examples, and failure checks were added.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 9c7f0

No actionable merge-blocking risk is established at the current head.

Sequence Diagram(s)

sequenceDiagram
  participant Shell
  participant MiseCompletion
  participant Packslip
  participant Tool
  Shell->>MiseCompletion: request completion for installed tool
  MiseCompletion->>Packslip: resolve active statement and sources
  Packslip->>Tool: run derivation command when packslip.exec is enabled
  Tool-->>Packslip: return completion script
  Packslip-->>MiseCompletion: provide selected script
  MiseCompletion-->>Shell: print or load completion
Loading

Suggested reviewers: risu729

Poem

A rabbit hops through packslip files,
Finds shell scripts in tidy piles.
It checks each path and signed degree,
Then grows a stub beside the tree.
Version switches make it spring,
And fresh completions softly sing.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 80.56% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 36 functions across 4 files. (7 skipped: 7 …
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.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding shell completion support sourced from a tool's packslip.

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 Sep 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds packslip-provided, active-version-aware tool completions and install-time fetching of completion resources.

  • Adds mise completion <shell> --tool <name> and version-aware completion stubs.
  • Restores Bash and Zsh stubs after vendor completion scripts run.
  • Adds opt-in execution for command-generated completions and verifies fetched release assets.
  • Updates generated CLI documentation, configuration schema, and packslip tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/packslip.rs Implements resource fetching, completion source selection, script generation, and Bash/Zsh restoration; the previously reported stale-state and return-handling issues are fixed.
src/cli/completion.rs Adds tool-specific completion output and installation through usage’s shell completion resolver.
src/backend/packslip.rs Fetches external packslip resources after installation and exposes selected-artifact resolution.
settings.toml Adds the default-off packslip execution setting used to gate tool-provided completion commands.
e2e/backend/test_packslip Covers missing packslip completion declarations and unknown active tools.

Reviews (20): Last reviewed commit: "fix(packslip): say when a completion was..." | Re-trigger Greptile

Comment thread src/packslip.rs Outdated
Comment thread src/packslip.rs
@jdx
jdx force-pushed the feat/packslip-completions branch from 77168be to 5dfd6d4 Compare September 4, 2026 15:05
Comment thread src/packslip.rs Outdated
Comment thread src/packslip.rs
Comment thread src/packslip.rs Outdated
Comment thread src/packslip.rs Outdated
Comment thread src/packslip.rs Outdated
Comment thread src/packslip.rs Outdated
Comment thread src/packslip.rs
@jdx
jdx force-pushed the feat/packslip-completions branch from 72f539d to 476f317 Compare September 4, 2026 16:02
Comment thread src/packslip.rs
functions[_{tool}]="$__mise_stub"
compdef _{tool} '{tool}'
return $__mise_ret
"#

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Zsh stub double-runs vendor scripts

Medium Severity

The zsh stub evals the vendor script inside _{tool}, so usage-style scripts whose funcstack[1] check self-invokes already complete once. The stub then sees the redefined body and calls that function again, producing duplicate candidates and a second generator run on every tab.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 476f317. Configure here.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed: the stub reads compstate[nmatches] before and after the eval. A script that completes on its own, as a usage or clap script does when it finds itself inside _tool, changes it, and the stub then does not call the function again.

Comment thread src/packslip.rs
} else {
Ok(HeaderMap::new())
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Asset fetch omits GitHub API headers

Medium Severity

headers_for only treats github.com and raw.githubusercontent.com as GitHub, so a resource url on api.github.com (or GHE) is downloaded with no bearer token and no Accept: application/octet-stream. The artifact installer already uses is_github_api_url for those URLs; without it the response is metadata JSON, the signed digest does not match, and the whole install is aborted.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 476f317. Configure here.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed: headers_for treats api.github.com like the backend does, so an asset URL on the API host is fetched with the bearer token and the octet-stream media type.

Comment thread src/packslip.rs
Comment thread src/packslip.rs
Comment thread src/packslip.rs
@jdx
jdx force-pushed the feat/packslip-completions branch from 6254d61 to 5bb4f90 Compare September 4, 2026 16:25
Comment thread src/packslip.rs Outdated
@jdx
jdx force-pushed the feat/packslip-completions branch from 22048ae to 76e38ab Compare September 4, 2026 17:43
Comment thread src/cli/completion.rs
@jdx
jdx force-pushed the feat/packslip-completions branch from 76e38ab to a533620 Compare September 4, 2026 18:39
Comment thread src/packslip.rs
@jdx
jdx force-pushed the feat/packslip-completions branch from a533620 to 126dc89 Compare September 4, 2026 18:47
Comment thread src/packslip.rs
Comment thread src/packslip.rs
@jdx
jdx force-pushed the feat/packslip-completions branch 2 times, most recently from 7b54d2f to b56ad8f Compare September 4, 2026 19:08
Comment thread src/packslip.rs Outdated
Comment thread src/packslip.rs
Comment thread src/packslip.rs
Comment thread src/packslip.rs Outdated
@jdx
jdx force-pushed the feat/packslip-completions branch from c173151 to 0be41a6 Compare September 4, 2026 21:54

@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.

Stale Bugbot comment from a previous run.

Comment thread src/packslip.rs
Comment thread src/packslip.rs
jdx and others added 15 commits September 5, 2026 01:16
A packslip may list what a release ships besides its executables. For
tools installed with the `packslip:` backend, `mise completion <shell>
--tool <name>` prints the tool's completion script for whichever of its
versions is active here, from the most verifiable source the vendor
offered, in the order the specification gives: a file inside the
artifact or a separate signed asset, a file from the source repository
at the release's commit, a script derived from the tool's usage spec
with the `usage` command, and only then a command of the tool's own.
That last kind runs a freshly installed binary before the user has run
it, so it is refused unless the new `packslip.exec` setting is on.

Completions are global shell state while the active version depends on
the directory, so `--install` writes a stub, not the script: it asks
mise for the script when the shell first completes the tool, and needs
no rewrite on a version switch. The stub goes where the shell loads
completions by name, through usage's resolver, like mise's own.

Files a vendor keeps outside the artifact are fetched at install time:
a separate release asset must match the digest the packslip signed, and
a repository file is pinned by the release's commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e the install

- The zsh and bash stubs let the vendor's script take over for one
  completion and then put themselves back (function and compdef binding
  in zsh, the `complete -F` registration in bash), so the next tab asks
  mise again and a version switch in another directory is followed.
  fish and PowerShell load the script once per session, which the docs
  now say.
- An asset name must be a plain file name and a repository path a safe
  relative one before either is joined onto the install directory, both
  when fetching and when reading back, so a statement on disk cannot
  point mise outside the install.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A vendor script may register with complete -C or -W rather than -F. The
stub now only invokes a function when one is registered; otherwise it
leaves the vendor's registration in place and returns 124, which makes
bash retry the completion with it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…g after a spec exec fails

- Repository files are fetched through the contents API with the raw
  media type, so a token applies to a private repository and a missing
  file is an error, not a login page mistaken for a script.
- A failing spec-generating command is one more skipped source, not the
  end of the search.
- The PowerShell stub joins the script's lines itself instead of going
  through Out-String, which wraps long lines at the buffer width.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…eter

When the vendor registers with complete -C, -W or -A, the stub hands
that completion over by returning 124 and reinstalls itself from
PROMPT_COMMAND at the next prompt (string or array form), so later
completions ask mise again and a version switch is still followed.
The PowerShell stub forces an array before joining, so a one-line
script is not split into characters.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… now requires

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…y paths in URLs

- A completion derived from a spec the tool generated names the spec
  file at completion time, so the spec now lives under the install's
  .mise-packslip/specs instead of a temp dir that is gone by then, and
  the bin and format names are checked before they form a file name.
- Repository paths are percent-encoded per segment before they go into
  a URL, so a name with ? or # cannot rewrite the query or fragment and
  reach past the pinned commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Calling the vendor's function directly dropped the options its own
complete call carried (-o nospace and the like). The stub now hands
every completion to the vendor's registration by returning 124 and
puts itself back at the next prompt, so options apply and version
switches are still followed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A resource may carry os, arch, or libc when layouts differ by platform.
Completion lookup keeps the entries that apply to the artifact this
host installed, and the most specific of them, before the source order.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ers; --install takes a plain name

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sh script runs in its own function; the spec for the completed executable wins

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…xe too; rustfmt

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A declared completion file that is not in the install drops out of the
source list, and an empty list was reported as "the packslip declares no
completion" — which is the vendor's doing, not what happened. What happened
is that the resource fetch failed or was skipped, and saying the other
thing hides it.

Ask the statement whether it offers this shell anything at all, and report
the two cases apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jdx
jdx force-pushed the feat/packslip-completions branch from 0be41a6 to c098baf Compare September 5, 2026 01:28

@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 3 total unresolved issues (including 2 from previous reviews).

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 c098baf. Configure here.

Comment thread src/packslip.rs
spec_entries.into_iter().filter(|r| describes(r)).collect()
} else {
spec_entries
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Multi-bin completions pick wrong source

Medium Severity

completion_sources selects among every completion and cli-spec together instead of isolating the executable being completed. Entries for other bins stay in play, and applicable can drop another executable's only entry when one bin is more specifically scoped. Completing a second binary can then load the first binary's script or spec.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c098baf. Configure here.

@jdx
jdx force-pushed the feat/packslip-completions branch from c098baf to 9c7f00a Compare September 5, 2026 01:53
@jdx
jdx force-pushed the feat/packslip-completions branch from 9c7f00a to c098baf Compare September 5, 2026 03:07
@jdx
jdx merged commit 1ec5239 into main Sep 5, 2026
84 of 104 checks passed
@jdx
jdx deleted the feat/packslip-completions branch September 5, 2026 03:41
jdx added a commit that referenced this pull request Sep 5, 2026
## Summary

Stacked on #12779. A packslip may declare an agent skill: a directory
holding `SKILL.md` and whatever it references, in the Agent Skills
format. This PR fetches them and hands them to agents at the version a
project pins.

- **Fetched at install**, like completions: from inside the artifact,
from a separate signed asset (verified against the statement, then
unpacked), or from the source repository at the release's commit through
the GitHub contents API. A skill offered only as a command of the tool's
own is generated at install when `packslip.exec` is on.
- **`mise skills ls`** lists the skills of the tools active in the
current directory, with the version each belongs to and its path
(`--json` for agents and scripts).
- **`mise skills sync`** writes one symlink per skill into the project's
`.claude/skills` (`--dir` for another agent's location, `--global` for
`~/.claude/skills`), pointing at the installed version's directory.
Since the project pins its tool versions, an agent working there sees
the skill for exactly that version; running sync again after `mise use`
moves the links. Only links mise made, which point into its installs
directory, are ever replaced or, with `--prune`, removed. A real
directory or a link of your own at a skill's name is left alone and
reported, as is a name two tools both claim.

## Settings

Four settings under `skills` shape what the commands do, all with
`MISE_SKILLS_*` env forms:

- **`skills.dir`** (`.claude/skills`): where `mise skills sync` links,
relative to the project root, or to the home directory with `--global`;
an absolute path is used as is. `--dir` still overrides it for one run.
Set `.agents/skills` for agents that look there.
- **`skills.auto_sync`** (off): after every `mise install` and `mise
use`, link the active tools' skills into `skills.dir`, so the links
never lag `mise.toml`. Nothing is written outside a project root, and a
problem is reported without failing the install.
- **`skills.prune`** (off): remove links mise made for skills that are
no longer active, as the default for the command and for auto sync.
- **`skills.fetch`** (on): turned off, tools install without their
skills.

## Test plan

- [x] clippy, fmt, hk; CLI docs and sidebar regenerated
- [x] Unit tests: skill discovery per source (including a stripped
top-level directory and an ungenerated exec skill), and sync semantics:
link, unchanged, version switch, foreign directory and link left alone,
duplicate name skipped, prune of a stale mise-made link, nothing created
when there is nothing to link
- [x] e2e: `mise skills ls` and `sync` on a tool whose packslip declares
no skill

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> New symlink writes under project dirs and install-time fetching/exec
of tool binaries; sync logic is careful about not touching user paths,
but filesystem side effects and `packslip.exec` semantics changed for
completions.
> 
> **Overview**
> Adds **`mise skills`** so packslip-installed tools can expose **Agent
Skills** (`SKILL.md` directories) at the versions pinned in the project.
> 
> **`mise skills ls`** lists skills for active tools (table or
`--json`). **`mise skills sync`** symlinks them into `skills.dir`
(default `.claude/skills`), with `--dir`, `--global`, and `--prune`.
Sync only replaces or removes links mise recorded in `.mise-skills.json`
that point into the installs tree; user dirs or foreign links are
skipped.
> 
> Skills are **fetched at install** (archive, signed asset + unpack,
GitHub repo tree at release commit, or tool `exec` when `packslip.exec`
is on). New **`skills.*`** settings control fetch, link target,
auto-sync after `mise install` / `mise use`, and default pruning.
> 
> **`packslip.exec` is narrowed**: it applies to install-time exec
resources (e.g. generated skills), not shell completions. **Exec
completions** run on first tab, cache under
`.mise-packslip/completions/`, and no longer require `packslip.exec`.
> 
> Docs, CLI usage/man output, schema, unit tests for discovery/sync, and
packslip e2e for tools with no skills are updated.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3ad64ce. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added `mise skills` support for discovering agent skills provided by
installed tools.
- Use `mise skills ls` to view available skills, including JSON output.
- Use `mise skills sync` to link skills into project or global agent
directories, with custom directory and pruning options.
- Skills can be fetched during installation and synchronized
automatically after installs or tool changes.

- **Documentation**
- Added CLI, configuration, man-page, and packslip documentation for
agent skills and related settings.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

Instruction counts

The comparison never ran — an earlier step failed.

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

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