mind-cli 0.48.0

A manager for agent tooling (skills, agents, rules, tools) that melds arbitrary git repos and links items into your agent directories.
# Resource and helper tooling

Status: done. Some agent libraries ship helper tooling -- shell or Python
scripts, or a compiled binary -- that their skills and agents invoke at runtime.
This document specifies how a source ships that tooling, how `mind` installs it
(including an optional build step for compiled tooling), and how an item
references it by a stable, namespace-safe path.

## Overview

A skill or agent often calls a helper script it ships next to itself
(`skills/voice/resources/mine-commits.sh`) or a shared helper used by several
items (`resources/detect-project.sh`). Copying the files is already handled --
`learn` copies a skill's whole directory -- so the unsolved parts are two others:

- **Reference.** The item must name the tooling's installed path. A hardcoded
  `~/.claude/skills/voice/resources/...` breaks the moment a prefix renames the
  item to `jk:voice`, and is ambiguous when more than one agent home is
  configured (which home?). This is the same fragility `{{ns:name}}` already
  fixes for sibling *names* (namespacing.md), one level down: a path, not a name.

- **Standalone and compiled tooling.** A helper shared across items is neither a
  skill, an agent, nor a rule, so no kind installs and tracks it. And compiled
  tooling must be built, with the output landing somewhere stable to reference.

`mind` answers these with: a `tool` item kind (a store-only installable that
exists to be referenced), path-reference tokens (`{{self}}`, `{{tools:name}}`,
`{{path:ref}}`, expanded at install like `{{ns:}}`), and an optional per-item
build hook (install-hooks.md, HOOK-70..73) for tooling that must be compiled.
Tokens expand to the store path (`~/.mind/store/...`), which is single and
home-independent, so a reference resolves the same regardless of how many agent
homes are configured or what prefix is in force.

The rest of this document states the rules normatively.

## The `tool` kind

- `TOOL-1` `tool` is a fourth item kind alongside skill, agent, and rule. By
  convention, every immediate subdirectory of a `tools/` directory (under each
  scan root) is a tool; the whole directory is the item. Unlike a skill
  (`skills/<name>/SKILL.md`), a tool needs no anchor file: a bare `tools/<name>/`
  directory is a tool, and its contents are the final tool state as installed (no
  build is implied). An authoritative `mind.toml` overrides convention scanning
  as for any kind (discovery.md).
- `TOOL-2` A tool's metadata comes from an optional `TOOL.md` in its directory:
  frontmatter `description`, `bin`, and `build`. A `mind.toml` `[[items]]` entry
  overrides those fields. With neither a `TOOL.md` nor a `mind.toml` entry, a tool
  has no description and `bin`/`build` come only from convention (TOOL-5).
- `TOOL-3` A tool installs to the store (`~/.mind/store/tool/<effective_name>/`)
  like any item, but by default is NOT linked into any agent home: it carries no
  symlink and the Claude harness does not discover it. Its manifest entry records
  the store path with an empty `links` set. `forget` removes the store copy;
  `recall` reports it installed. A tool is reached only by reference (TOOL-10..12).
- `TOOL-4` A tool MAY declare an explicit `link` (`mind.toml` `[[items]].link`)
  to also surface it under each agent home, for the rare tool that should be
  discoverable in place; absent a `link`, a tool is store-only (TOOL-3).
- `TOOL-5` A tool's entrypoint -- what `{{tools:name}}` resolves to -- is the
  `bin` resolved in order: an explicit `mind.toml` `[[items]].bin`, else `TOOL.md`
  frontmatter `bin:`, else the convention default `<name>` (a file named after
  the tool at the tool dir root, e.g. `tools/shard-plan/shard-plan`) when that
  file is present in the source. A tool that nothing invokes as an executable
  need not resolve a `bin`.
- `TOOL-6` Namespacing applies to tools as to any kind: a prefix gives the
  effective name `<prefix>-<name>`, and a tool's stable identity is
  `(source, kind, bare_name)` (namespacing.md), so a prefix change is a rename
  matched on identity by `upgrade`/`introspect` (lifecycle.md).
- `TOOL-7` `mind.toml` accepts `kind = "tool"` wherever a kind is named
  (`[[items]]`, and `[discover].tools` globs, which match the tool DIRECTORY
  rather than an anchor file). The `bin` and `build` item fields are valid only on
  a tool; on any other kind they are a `mind.toml` schema error.

## Path-reference tokens

An item references tooling by a token that expands, at install, to the tooling's
store path. Expansion runs in the same staging pass that expands `{{ns:}}`
(namespacing.md), so a bad reference fails before the live install is touched and
the recorded content hash is of the source (token) form.

- `TOOL-10` `{{self}}` in an item's text expands to that item's own store
  directory (a path under the store root, `~/.mind/store` honoring `MIND_HOME`,
  rendered with a leading `~` per TOOL-16). It is available in every kind, so a
  skill addresses its own bundled resources as `{{self}}/resources/<script>`
  without hardcoding its installed name.
- `TOOL-11` `{{path:ref}}` expands to a sibling item's store directory, for
  reaching non-entrypoint files in a tool (`{{path:tool:x}}/lib/helper.sh`).
  `ref` is a sibling's bare name, optionally kind-qualified
  (`{{path:tool:detect}}`, `{{path:skill:review}}`). An unqualified `ref`
  matching items of more than one kind is an error (`BadReference`); a `ref`
  matching no sibling is an error (`BadReference`), as for `{{ns:}}` (NS-12).
- `TOOL-12` `{{tools:name}}` expands to a sibling tool's entrypoint: the tool's
  store directory joined with its resolved `bin` (TOOL-5). The plural `tools:` is
  distinct from the `tool:` kind-qualifier used in `{{path:}}`. A `name` that is
  not a sibling tool, or a tool with no resolvable `bin`, is an error
  (`BadReference`).
- `TOOL-13` Path tokens expand in the staging copy during the transactional
  install, alongside `{{ns:}}` (NS-11). The recorded content hash is of the token
  (source) form, not the expanded copy, so drift detection compares source with
  source (NS-13). Both prefixed and unprefixed installs expand tokens (NS-14): a
  store path is prefix-aware via the referent's effective name.
- `TOOL-14` Path tokens follow the same gate `{{ns:}}` does (NS-53, TOOL-19). A
  token expands in a file when the file has a markdown extension, or the item
  is of the `workflow` kind, or the file is on the item's NS-57 `expand:` list.
  For a markdown item file, whatever the item kind, that covers the anchor file
  of a skill or tool (`SKILL.md`, `TOOL.md`), an agent or rule's own file, or a
  bundled markdown reference doc. Outside that gate -- a non-markdown bundled
  file (a script, data) that belongs to a non-workflow item and is not
  `expand:`-listed -- `{{tools:shard-plan}}` written in a bundled `pr.py` is left
  exactly as written. The designed use of a
  path token is prose (a skill telling Claude to run `{{tools:detect}}`), which
  is why the narrowing costs nothing in practice for the ordinary case. Token
  edge cases mirror `{{ns:}}` (NS-15): inner whitespace is trimmed
  (`{{ path:x }}`); an unterminated token (no closing `}}`) is left verbatim; a
  non-UTF-8 file is not scanned; text with no `{{` token is copied unchanged.
- `TOOL-15` Path tokens resolve within the source only (sibling scope), as
  `{{ns:}}` does, so tool-to-tool and bundled-script-to-tool references resolve
  when both items ship in the same source. Cross-source tooling references are out
  of scope: ship a tool in the same source as the items that use it.
- `TOOL-19` Path tokens follow NS-53's gate: `{{self}}`, `{{tools:name}}`, and
  `{{path:ref}}` all expand in a file when the file has a markdown extension (an
  extension of `md`, `markdown`, `mdown`, or `mkd`, case-insensitively), or the
  item is of the `workflow` kind, or the file is on the item's NS-57 `expand:`
  list -- the same rule and the same chokepoint
  (`namespace::item_expands_tokens`) `{{ns:}}` expansion uses. Combined with
  TOOL-14, this is
  the complete statement of where every token family expands.
- `TOOL-20` A path token in a file listed in an item's `expand:` frontmatter
  (NS-57) does expand, overriding TOOL-19 for that file, and renders as an
  absolute store path rather than the `~` form of TOOL-16. A `{{tools:name}}` in
  a bundled `pr.py` listed under `expand:` expands to
  `/home/user/.mind/store/tool/name/...`, not `~/.mind/store/tool/name/...`,
  because the file is read by a program (here Python's `pathlib`) that does not
  itself expand a leading `~`. The permission-glob rationale for TOOL-16 does not
  apply: an `expand:` file is program input, not a command line a Claude
  `settings.json` rule matches.
- `TOOL-16` A path token renders the store root with a leading `~` when the store
  lies under the user's home directory (the default `~/.mind/store`): the home
  prefix is written as a literal `~`, not spelled out absolutely. This keeps the
  expansion matchable by a Claude `settings.json` permission glob, which uses
  tilde syntax (`Bash(~/.mind/store/**)`) that an absolute path would not match.
  When the store root is not under home (a `MIND_HOME` pointing elsewhere) or the
  home directory cannot be determined, the token expands to the absolute path.
- `TOOL-17` A `{{tools:name}}` `BadReference` (TOOL-12) names its specific cause,
  so a maintainer can tell a typo from a tool whose entrypoint failed to resolve.
  A referent that matches no sibling tool -- a miss, or a name that is a non-tool
  sibling -- reports "does not match any item", the wording every other reference
  miss uses. A referent that names a real sibling tool with no resolvable `bin`
  (TOOL-5) instead reports that the tool has no resolvable entrypoint. The cause
  rides on both the install-time error and the `review` `bad-reference` finding
  (CLI-135). The common trigger for the entrypoint case is a `TOOL.md` that
  declares the `bin` but is gitignored or unadded, so it resolves in the author's
  working tree yet is absent from a clone; `review` catches that ahead of time as
  a distinct advisory (CLI-190).
- `TOOL-18` A `{{path:ref}}` (TOOL-11) `BadReference` likewise names its cause. A
  bare `{{path:name}}` that matches more than one sibling across kinds with no
  `kind:` qualifier reports "is ambiguous across kinds; add a kind qualifier"
  rather than "does not match any item" -- the referent does match, it is just
  under-qualified, so the miss wording would send a maintainer looking for a
  missing item that exists. A referent that matches nothing keeps the miss
  wording. The cause rides on both the install-time error and the `review`
  `bad-reference` finding (CLI-135), the same threading as TOOL-17.

Because every token expands under `~/.mind/store`, an item's invocations of its
tooling share one stable path prefix regardless of agent home or prefix, so a
permission allowlist can target that prefix (a `Bash(~/.mind/store/**)` rule,
matched by the `~` rendering of TOOL-16) rather than chase per-item installed
paths.

## Build hooks for compiled tooling

Tooling that must be compiled or fetched before it runs uses a build step. The
expected default is the maintainer's project-level build (a Makefile or build
script) run via a source-level install hook (install-hooks.md, HOOK-50) at meld,
which produces the artifacts in the working tree; the tool directory is then
copied as the final state at `learn` (TOOL-1), no per-tool config needed. A tool
that wants its own isolated, rollback-safe build instead declares a per-item
`build` (install-hooks.md, HOOK-70..73), run in staging before the store swap;
`{{tools:name}}` (TOOL-12) then resolves to the built artifact.

## Relationship to existing mechanisms

- A skill's bundled helpers install as part of the skill directory: the whole
  directory is the item, copied and linked into each agent home as one symlink, so
  every file under it comes along. They may live anywhere within it (`resources/`
  is a convention, not a requirement); `{{self}}` is what makes them addressable
  under a prefix. Siloing a helper with the single skill that uses it is a
  supported choice, distinct from the `tool` kind, which is for tooling
  deliberately shared across items or shipped on its own. `review` may note a
  helper duplicated across items as a `tool` candidate, but treats keeping the
  per-item copy as equally valid (CLI-144).
- The executable bit on scripts is preserved by the copy into the store (the
  install copies file permissions), so a `+x` helper stays executable without a
  hook.