Share helper scripts
Some agent libraries ship helper scripts or compiled binaries that their skills
and agents call at runtime. mind handles this with two mechanisms:
- The
toolkind: a store-only installable for helpers that are shared across items or do not belong inside a single skill directory. - Path-reference tokens:
{{self}},{{tools:name}}, and{{path:ref}}, expanded at install to stable store paths.
See the worked example for a complete source you can browse.
The tool kind
A tool is an item kind whose purpose is to be referenced by other items; unlike a skill, by default it is not linked into
an agent home and the Claude harness does not discover it directly. A
tool can opt in to a link with an explicit link field (below).
Convention discovery: every immediate subdirectory of a tools/
directory under a scan root is a tool. The whole directory is the item; no anchor
file is required. A bare tools/detect/ is a tool named detect.
Store path: ~/.mind/store/tool/<effective-name>/. The manifest records the
store path with an empty links set. forget removes the store copy; recall
reports it as installed.
Optional link: a tool can declare an explicit link field in mind.toml
[[items]] to also surface it under an agent home, but the default is
store-only.
Namespacing: a prefix gives a tool the effective name
<prefix>:<name>, the same as a skill or rule (agents are the exception and keep
their bare link name). Stable identity is (source, kind, bare_name), so a
prefix change is a rename matched by upgrade/introspect.
When to use a tool
A helper that is bundled with a single skill (a resources/ script) does not
need to be a tool. Put it in the skill directory and address it with {{self}}
(see source layout). Use the tool kind when:
- The helper is shared across two or more items.
- The helper stands alone and is not logically part of any one skill.
- The helper must be compiled and the build belongs to the item rather than to a source-level install hook.
For a data file items read rather than run (a JSON allowlist, a prompt template), use a resource instead.
mind review treats a byte-identical helper copied into several items as a
duplicate-tooling advisory (informational), suggesting it as a tool
candidate. Keeping per-item copies is equally valid.
TOOL.md frontmatter
Place a TOOL.md in the tool directory to declare metadata:
---
description: Detect the project type from files in the current directory.
bin: detect.sh
build: make
---
| key | meaning |
|---|---|
description | shown in recall / probe |
bin | the entrypoint; what {{tools:name}} resolves to |
build | per-item build command run in staging at install |
The entrypoint resolution order is:
mind.toml[[items]].binTOOL.mdfrontmatterbin:- Convention: a file named after the tool at the tool dir root (e.g.
tools/detect/detect) when it is present in the source
A tool that nothing invokes as an executable need not resolve a bin.
A mind.toml [[items]] entry overrides TOOL.md fields. With neither, a tool
has no description and no explicit bin or build. For the [[items]] form and
[discover].tools globs (which match the tool directory, not an anchor file) see
The mind.toml file.
The bin and build fields are valid only on a tool; on any other kind they
are a mind.toml schema error.
Build hooks for compiled tooling
The common case is a source-level install hook ([[hooks]] in mind.toml) that
builds all tooling once at meld, producing artifacts in the working tree; the
tool directory is then copied as its final state at learn. Use a
per-item build when you want an isolated, rollback-safe build that runs in
staging before the store swap. See Run setup with hooks for the full
hook model.
Path-reference tokens
Tokens expand at install to stable store paths. Expansion runs in the same
staging pass that expands {{ns:}} (see
spec/namespacing.md),
so a bad reference fails before the live install is touched. The recorded content
hash is of the token (source) form, so drift detection compares source with
source.
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 expand: list.
“Markdown extension” means md, markdown, mdown, or
mkd, case-insensitively. A token in an ordinary non-markdown bundled file –
a script, data – is left exactly as written unless the item is a workflow or
the file is expand:-listed; the designed use of a path token is prose, e.g. a
skill telling Claude to run {{tools:detect}}. Inner whitespace is trimmed
({{ path:x }} works); an unterminated token (no closing }}) is left
verbatim; non-UTF-8 files are not scanned. To expand tokens in a specific
script, list it in expand: (below).
References resolve within the same source only: ship a tool in the same source as the items that use it.
Every path token except {{self}} is also a dependency: mind learn of an item
that writes {{tools:detect}} installs the detect tool with it, showing the
dependency tree and asking first (see Dependencies).
Expanding tokens in a script: expand:
A bundled script that must call a sibling tool or reach an adjacent file can opt
that file into expansion, so its tokens resolve at install instead of being left
literal. Add an expand: key to the item’s frontmatter, listing item-relative
paths (whitespace-separated, the same form as requires:):
---
name: review
description: Review code changes.
expand: resources/pr.py
---
Now resources/pr.py is expanded exactly like markdown. A token in it renders
as an absolute store path (/home/you/.mind/store/tool/detect/detect.sh),
not the ~ form markdown uses, because the file is read by a program that does
not expand a leading ~ (a Python pathlib.Path, say). So a script locates its
tooling without a language-specific self-locate:
# resources/pr.py -- {{tools:detect}} is rewritten to an absolute path at install
det = Path("{{tools:detect}}")
The key lives on the item, so declaring it keeps convention discovery on and
says nothing about other items (it does not make a source authoritative). An
entry naming a file the item does not ship, an absolute path, or a .. segment
fails the install (BadReference) and is reported by review as a hard
bad-expand finding, so a typo surfaces before a meld. An unresolved token in a
listed file is a hard failure, exactly as in markdown.
Cross-source tooling is still out of scope: expand: bakes an install-time path
that works because the tool ships in the same source. A script needing a tool
from a different source has no token mechanism; ship the tool alongside its
callers.
{{self}}
Expands to the item’s own store directory. Available in every kind.
{{self}}/resources/helper.sh
A skill addresses its bundled resources with {{self}} without hardcoding its
installed name. Without {{self}}, a prefix rename (e.g. voice to jk:voice)
would silently point at the wrong path.
{{tools:name}}
Expands to a sibling tool’s entrypoint: the tool’s store directory joined with
its resolved bin. The plural tools: is distinct from the tool:
kind-qualifier used in {{path:}}.
{{tools:detect}}
A name that is not a sibling tool, or a tool with no resolvable bin, is a
BadReference error.
{{path:ref}}
Expands to a sibling item’s store directory, for reaching non-entrypoint files.
ref is a bare sibling name, optionally kind-qualified:
{{path:tool:detect}}/lib.sh
{{path:skill:review}}/resources/pr.py
An unqualified ref that matches items of more than one kind is a BadReference
error. A ref matching no sibling is also a BadReference error.
{{tools:name}} is shorthand for {{path:tool:name}}/<bin>: use {{tools:name}}
when you want the entrypoint, {{path:tool:name}} when you want the directory.
Tilde rendering
A token renders the store root with a leading ~ when the store is under the
user’s home directory (the default ~/.mind/store). This keeps the expansion
matchable by a Claude settings.json permission glob:
"Bash(~/.mind/store/**)"
An absolute path would not match that glob. When MIND_HOME points outside
home, or when the home directory cannot be determined, the token expands to the
absolute path.
Worked example
Source tree (see examples/tooling):
tools/detect/
TOOL.md # bin: detect.sh
detect.sh # the entrypoint
lib.sh # a library sourced by callers
skills/scan/
SKILL.md
resources/notes.md
tools/detect/TOOL.md:
---
description: Detect the project type from files in the current directory.
bin: detect.sh
---
skills/scan/SKILL.md (excerpt):
1. Run the shared tool: `{{tools:detect}} .`
2. Source its library: `. {{path:tool:detect}}/lib.sh`
3. Record the result: `{{self}}/resources/notes.md`
mind learn scan --yes installs the skill and, because the skill’s tokens
name it, the detect tool. Afterwards:
{{tools:detect}}expands to~/.mind/store/tool/detect/detect.sh– the entrypoint frombin:.{{path:tool:detect}}expands to~/.mind/store/tool/detect– the store directory, for non-entrypoint files.{{self}}expands to~/.mind/store/skill/scan– the skill’s own store directory.
All three use tilde syntax so a Bash(~/.mind/store/**) permission rule covers
them.
Under a prefix (meld --namespace jk), {{tools:detect}} expands to
~/.mind/store/tool/jk:detect/detect.sh – no edits to the skill needed.