Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

mind is a manager for agent tooling: skills, agents, rules, and tools. It melds arbitrary git repos and links the items they offer into one or more agent homes (default ~/.claude).

  • A source is a melded git repo (mind meld). It offers items: skills, agents, rules, and tools, found by convention or declared in a mind.toml.
  • mind learn <item> copies an item into the store (~/.mind/store) and symlinks it into each lobe (agent home). A tool is the exception: store-only helper tooling reached by reference, not linked into a lobe by default. Lobes can be non-Claude homes (Gemini CLI, Codex CLI, Antigravity) with a per-kind filter so only the compatible item types link in; see Configuration.
  • mind recall and mind probe inspect what is installed and what is available; mind sync and mind upgrade keep sources and installed items current.
  • For authoring, mind init-source and mind review scaffold and validate a source for publishing.

This site is the reference for installing, using, and authoring mind. Start with Install and the Quickstart; Commands is the full verb reference. For authoring a source, see Source layout and Authoring a source. The normative behavior is the spec.

Install

Requirements

mind runs git to clone and sync sources, so git must be installed and on your PATH. The methods below fetch the mind binary itself; they do not install git. Without git, meld and sync fail with a clear “git executable not found” error.

Linux (install script)

curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/jaemk/mind/main/resources/install.sh | sh

Downloads the release binary for your platform (x86_64 / aarch64) and installs it to ~/.local/bin. Override the target dir with MIND_INSTALL_DIR or pin a version with MIND_VERSION:

curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/jaemk/mind/main/resources/install.sh \
  | MIND_INSTALL_DIR=/usr/local/bin MIND_VERSION=0.2.0 sh

If ~/.local/bin is not on your PATH, the script prints the line to add. The same script also serves Apple Silicon macOS; Intel macOS should use the tap below.

Homebrew (macOS / Linux)

brew tap jaemk/mind https://github.com/jaemk/mind
brew trust jaemk/mind
brew install mind

The repo is not named homebrew-mind, so the tap needs its clone URL.

Updating

mind evolve updates the binary itself to the latest release. It reports the target version and prompts before downloading, unless --yes is given (--check reports without changing anything, --version <v> pins a target). It uses the same download path as the install script.

Quickstart

Meld a source, install an item, and see it linked into ~/.claude:

mind meld owner/repo        # clone and register a source repo
mind probe                  # browse and search available items (interactive)
mind learn <item>           # install one into each agent home
mind recall                 # list what's installed

Agent homes can be Claude Code, Gemini CLI, Codex CLI, or Antigravity – not just ~/.claude. See Configuration for the per-harness path table and preset commands.

For a self-contained first run with no remote, use the bundled starter source (a plain convention layout, see examples/starter/):

cp -r examples/starter /tmp/starter
cd /tmp/starter && git init -q && git add -A && git commit -qm init
mind meld /tmp/starter
mind probe
mind learn greet

Commands is the full verb reference. Source layout covers how a source repo exposes items.

Examples

The examples/ directory in the repo holds runnable sources, each a small but valid mind source with its own README.md and a test that melds it so it cannot rot. This page maps each use case, consumer and maintainer, to the example that demonstrates it.

Every example is a directory inside the mind repo, not its own git repo, so copy it out and init a repo before melding (each README shows the exact commands):

cp -r examples/<name> /tmp/<name>-demo
cd /tmp/<name>-demo && git init -q && git add -A && git commit -qm init
mind meld /tmp/<name>-demo
mind probe

Example catalog

ExampleShowsKey spec
starterConvention discovery: a repo with no mind.toml, items found by skills/<n>/SKILL.md, agents/<n>.md, rules/<n>.mddiscovery.md
toolingThe tool kind plus path tokens {{self}}, {{tools:name}}, {{path:ref}}tooling.md
hooksSource [[hooks]]: build/install tooling at meld, tear down at unmeld, with the disclosure promptinstall-hooks.md
explicitAuthoritative [[items]] inventory: export control, custom path/link, per-item install/uninstall hooksdiscovery.md
monorepo[source].roots: convention discovery rooted at per-package subtreesdiscovery.md
namespacingA prefix plus {{ns:name}} reference tokens that survive a renamenamespacing.md
super-source[discover].sources: a curated registry that melds other repos, optionally namespaced or auto-installeddiscovery.md
marketplace-pluginA Claude .claude-plugin/plugin.json: skills and agents mapped to items, unsupported components reportedmarketplace.md
marketplace-catalogA Claude .claude-plugin/marketplace.json: a catalog of in-repo plugins, each a namespaced sub-sourcemarketplace.md
policyAn enterprise managed policy: trusted-source allowlist, require-pinned, lobe lockpolicy.md

Consumer use cases

You are installing and managing tooling that other people authored.

  • Install an item from a source. Meld a repo, then learn an item. See the Quickstart and the starter example (mind meld, mind learn).
  • Browse and search what is available. mind probe opens an interactive browser, or prints a listing when piped. See Commands.
  • Resolve a name collision between two sources. Namespace one on install with mind meld <repo> --namespace <prefix>, so its items install as <prefix>:<name>. See namespacing and Troubleshooting.
  • Pull from a curated registry. Meld a super-source to register a whole chain of repos at once; meld --recursive offers every nested source for install. See super-source.
  • Meld a Claude plugin or marketplace. A repo with a .claude-plugin/plugin.json or .claude-plugin/marketplace.json melds with no re-packaging; its skills and agents show up as items. See Claude plugin marketplaces and the marketplace-plugin / marketplace-catalog examples.
  • Install into more than one agent home. Configure lobes in ~/.mind/config.toml. See Configuration.
  • Stay up to date. mind sync refreshes every source; mind upgrade upgrades installed items and reports deltas first. See Commands.
  • Run under an enterprise policy. A fixed-path managed policy restricts a client to trusted sources and locks related settings. See policy.

Maintainer use cases

You are authoring a source repo for others to meld.

  • Ship items with zero config. Use the convention layout; no mind.toml needed. See Source layout and starter.
  • Declare an explicit inventory, or control what is exported. List items with [[items]] to turn convention off, set custom path/link, and omit files you do not want offered. See explicit.
  • Lay out a monorepo or subtree. Point [source].roots at the package subtrees, or use [discover] kind globs for layouts roots cannot express. See monorepo.
  • Share helper tooling across items. Ship a tool item and reference it with {{tools:name}} / {{path:ref}}, or bundle a script with one skill and address it with {{self}}. See tooling and Source layout.
  • Build or install tooling at meld. Declare a source [[hooks]] install entry (and an uninstall entry for teardown). See Install hooks and hooks.
  • Run a host side effect per item. Declare per-item install/uninstall hooks (or [[items.hooks]]). See explicit.
  • Make intra-source references survive a prefix. Write sibling references as {{ns:name}} tokens. See namespacing and Authoring a source.
  • Curate other repos into a registry. List them in [discover].sources; a bare list keeps your own convention items too. See super-source.
  • Validate and scaffold before publishing. mind init-source scaffolds a mind.toml and reports references; mind review validates a source. See Authoring a source.

Commands

Mental model

mind connects sources (git repos full of agent tooling) and lobes (your agent homes, like ~/.claude/~/.agents).

Source. A melded git repo. mind meld <repo> clones the repo into ~/.mind/sources/<host>/<owner>/<repo> and records it in ~/.mind/sources.json. This initializes the source and makes its items available to mind learn. mind sync (or re-melding, re-running mind meld <repo>) refreshes the clone.

Item. A unit offered by a source, one of four kinds:

  • skill - a skills/<name>/ directory containing a SKILL.md and any associated resources (scripts, templates, etc).
  • agent - an agents/<name>.md file.
  • rule - a rules/<name>.md file.
  • tool - a tools/<name>/ directory containing a TOOL.md, a script/executable, any associated resources. Tools are an optional feature to assist with managing and referencing shared scripts/executables utilized by multiple skills.

Items are discovered by convention (the paths above) or declared in a mind.toml.

Lobe. An agent home mind links items into: the directory holding skills/, agents/, and rules/. The default lobe is ~/.claude; you can add Gemini, Codex, Antigravity, or any directory, each with an optional per-kind filter (see Configuration). The gemini preset (path ~/.gemini/config) covers both Gemini CLI and the Antigravity IDE. Users of the Antigravity CLI who previously used an antigravity-cli preset should configure a custom lobe path manually.

Learn. mind learn <item> copies the item out of the source clone into the store (~/.mind/store/<kind>/<name>) and symlinks that store copy into every lobe. The store copy is the stable thing your agent homes point at, so a later sync cannot change an installed item under you until you choose to upgrade. forget reverses it.

What each step puts on disk

mind meld jaemk/mind clones the source. Nothing is linked yet:

$ mind meld jaemk/mind

~/.mind/
  sources.json                              # registry: `mind` is now melded
  sources/
    github.com/jaemk/mind/                  # the clone (a staging area)
      examples/hello/skills/hello-mind/     # the offered skill
        SKILL.md
      ...                                   # the rest of the repo
  store/                                    # empty - nothing learned yet

mind probe browses what the melded sources offer before you learn anything (kind:name, source, content hash, description):

$ mind probe

  skill:hello-mind  github.com/jaemk/mind  c62e88cc  A hello-world skill; confirms mind melded this repo

mind learn jaemk/mind#skill:hello-mind copies that one item into the store and symlinks it into the lobe:

$ mind learn jaemk/mind#skill:hello-mind

~/.mind/
  manifest.json                                  # registry: `hello-mind` installed
  store/
    skill/hello-mind/SKILL.md                    # the copy, taken from the clone
  sources/
    github.com/jaemk/mind/ ...                   # clone untouched

~/.claude/                                       # a lobe (agent home)
  skills/
    hello-mind -> ~/.mind/store/skill/hello-mind # symlink the harness discovers

The harness now resolves /hello-mind through that symlink. A tool the skill referenced would instead land in ~/.mind/store/tool/<name> with no symlink under ~/.claude, present for the skill to call but invisible to the harness.

Stay current. sync refreshes every source clone; upgrade moves installed items to the refreshed version, reporting hash and commit deltas before changing anything; evolve updates the mind binary itself.

Inspect. recall and probe show what is installed and what is available; introspect reports drift and broken links.

Verbs

commanddoes
mind meld [<repo>] [--link-only] [--yes] [-f|--force] [-r|--recursive] [-n|--namespace <prefix>] [--root <dir>] [--follow-branch <branch> | --pin-tag <tag> | --pin-ref <commit>] [--install-hook <cmd>] [--dangerously-skip-install-hook-check]clone and register a source (default .), then prompt to install its items (--link-only registers only; --yes installs without prompting; -f/--force overwrites conflicting non-mind link targets; -r/--recursive offers to install items from every nested source a super-source curates). Re-melding an already-melded source installs any missing items, else shows each item’s install state and commit
mind init-source [<path>] [--template]scaffold mind.toml + report references; --template rewrites bare refs as {{ns:}} (maintainer)
mind unmeld <name> [--unlink-only] [--yes] [--uninstall-hook <cmd>] [--dangerously-skip-install-hook-check] (alias detach)drop a source and forget its items (--unlink-only keeps them)
mind learn [--yes] [-f|--force] [-n|--dry-run] [--all] <item>install a skill/agent/rule/tool (glob installs many); a partial selection also pulls in the source siblings it references. --force overwrites a conflicting non-mind link target (without it, a conflict prompts on a TTY); --all installs every item of the named source (shorthand for <source>#*); -n/--dry-run previews the dependency closure without installing anything
mind forget [--yes] [-f|--force] [--unmanaged] [--dangerously-skip-install-hook-check] [<item>] (alias unlearn)remove an installed item (glob removes many; a multi-match glob confirms first, --yes skips). --unmanaged scopes removal to unmanaged lobe items only; with no <item>, removes every unmanaged item across all lobes. -f/--force skips the dependents confirmation when the item being removed has dependents. --dangerously-skip-install-hook-check runs uninstall hooks without the safety prompt
mind sync [--upgrade] [--dangerously-skip-install-hook-check]refresh every source (optionally upgrade after; flag allows unattended hook re-runs)
mind upgrade [--yes] [--dangerously-skip-install-hook-check] [item]upgrade installed items to their latest source version (re-runs install hooks on sources that advance)
mind evolve [--check] [--yes] [--version <v>]update the mind binary itself to the latest release (or –version)
mind recall [item] [--sources] [--kind K] [--source S] [--tree] [--json] (alias status)status: each source with its items, marked installed or available; --sources narrows to sources; <item> shows one item’s details; --tree renders installed items as a dependency forest (with an item ref, scopes to that item’s subtree)
mind probe [query] [--kind K] [--source S] [--json] [--no-tui]browse and search items (interactive TUI on a terminal)
mind review <target> [-n|--namespace <prefix>] / mind review --policy <path>validate a source for publishing, or validate a managed policy file (read-only)
mind introspect [--fix] [--json]report drift and broken links (optionally repair)
mind config show / mind config lobes add [<path> | --preset <name>]|list|remove <path>|detect [--yes] [--json] (alias config target)view config and manage agent homes (lobes). add --preset <name> adds a preset lobe with a preconfigured path and kinds filter (presets: gemini, codex, universal). detect reports which known harness homes exist on the machine and offers to add their presets; adds only with --yes or an interactive TTY confirm; --json emits detection results as structured JSON. config lobes list and config show include the kinds filter for each lobe, e.g. ~/.gemini/config [skill]. See Configuration for the preset table and per-harness path details.
mind dump [--output <path>] [--whole-sources]write a super-source mind.toml reproducing the current melded and installed state (to stdout or --output <path>); each source is pinned to its recorded commit; item-filtered by default (--whole-sources emits install = true for every source regardless of install count)
mind absorb <ref> [--to <path>] [-f|--force]claim a single unmanaged lobe item into a version-controlled source and install it as a managed item; --to sets the destination (see absorb for full destination precedence); --force overwrites a kind:name collision at the destination
mind completions <shell> / mind manshell completions / man page

A source repo exposes items by convention (skills/<n>/SKILL.md, agents/<n>.md, rules/<n>.md, tools/<n>/), via a mind.toml, or via a Claude .claude-plugin/ manifest (see Claude plugin marketplaces). See Source layout and the examples/: starter for the plain convention layout, namespacing for {{ns:}} reference tokens under a prefix, and policy for an enterprise managed policy. The full behavioral spec is at spec/.

probe

mind probe with no flags opens an interactive browser of melded sources and items (search, install, remove, meld, unmeld, sync, upgrade) when stdout is a terminal. -n / --no-tui or --json, or a piped or redirected stdout, prints the listing instead.

Selecting items (globs)

learn, forget, upgrade, unmeld, probe, and recall all accept a glob in place of an exact item ref. The kind prefix, source qualifier, and glob compose:

patternselects
'*'every item across all sources
'skill:*'all skills
'owner/repo#*'all items of one source
'review*'items whose name starts with review

The glob is matched against the effective (installed) name. A glob matching nothing is ItemNotFound (for items) or SourceNotFound (for sources). The exception is upgrade: a glob (or exact ref) that matches no installed item reports up-to-date rather than erroring, since upgrading nothing is a no-op.

Shell-quoting caveat: quote the glob so the shell does not expand it before mind sees it:

mind learn 'skill:*'
mind forget 'owner/repo#*'

Spec: CLI-31, CLI-41, CLI-65.

Filtering with –kind and –source

recall and probe accept two composable filters:

  • --kind <skill|agent|rule|tool> narrows to one item kind.
  • --source <selector> narrows to items from a matching source. The selector is an exact name, an unambiguous trailing suffix (repo or owner/repo), or a glob matched against the full host/owner/repo identity (so * spans /):
mind recall --kind skill
mind probe --source '*agents'
mind recall --source my-repo --kind rule

For recall, these filters apply to the installed-items listing only, not to --sources or a single-item lookup. Spec: CLI-83, CLI-86.

Global flags and output

--json, --yes (-y), and --ascii are global flags accepted before or after any verb. Position does not matter: mind --json recall and mind recall --json are equivalent (CLI-150).

Color and Unicode. Output uses ANSI color and Unicode glyphs when all of the following hold: stdout is a TTY, the locale is UTF-8, NO_COLOR is unset, and neither --json nor --ascii is in effect. Any one of those conditions being false forces plain ASCII output with no color escapes. The ASCII fallback substitutes visually equivalent characters (+ installed, ! warning, x error, - available) so no information is lost (CLI-151, CLI-152, CLI-154).

NO_COLOR set to any value (including empty), a non-UTF-8 or unset locale, or --ascii each independently force plain ASCII regardless of the others.

--json output. Read-only verbs (recall, probe, introspect) emit their existing JSON shapes. Every mutating verb (meld, learn, forget, sync, upgrade, unmeld, config lobes add/remove) emits a structured result object with at minimum action, target, and outcome fields (CLI-153).

Exit status

Exit 0 on success. Any MindError is printed to stderr and exits non-zero (CLI-100).

sync exits non-zero (SyncFailed) when any per-source fetch fails, even if other sources succeeded; successfully fetched commits are persisted and reported (CLI-54).

review distinguishes hard errors (malformed mind.toml, unknown item kind, unresolved {{ns:}} token) from advisory findings (unguarded references, missing descriptions). Hard errors exit non-zero; advisory-only exits zero. Neither mode writes to disk, except review --fix on a local-path target (CLI-132).

Running unattended / in CI

Pass --yes (-y) to skip confirmation prompts. Without it, any command that would prompt on a TTY instead exits non-zero with ConfirmationRequired when stdin is not a TTY (CLI-23, CLI-42).

Install and uninstall hooks are skipped in non-TTY contexts and a note is printed. To run them unattended, pass --dangerously-skip-install-hook-check. This executes arbitrary code from the source; only use it for sources you trust (HOOK-22).

dump

mind dump writes a super-source mind.toml to stdout (or --output <path>) that reproduces the current melded and installed state. Melding the output recreates the same source set at the same revisions. It is the inverse of melding a curated super-source.

mind dump                        # write to stdout
mind dump --output snapshot.toml # write to a file
mind dump --whole-sources        # include all items, not just installed ones

Each entry in the emitted [discover].sources references a melded source and pins it to its currently recorded commit as a pin-ref, overriding any pin the source itself declares (DUMP-1). The meld-time settings are carried through: prefix (as), scan roots, and the resolved commit pin (DUMP-4).

Item filtering. By default each source entry is stamped with the install directive that reproduces exactly which items are installed (DUMP-2):

  • Every offered item installed: install = true
  • No items installed: install = false
  • A subset installed: install_items = [...] listing those items by kind:name

--whole-sources disables this filtering and emits install = true for every source, offering the full catalog instead of the recorded subset (DUMP-3).

With no melded sources, dump emits a valid super-source with an empty [discover].sources and exits 0 (DUMP-8).

Interactive TUI

mind probe opens an interactive terminal UI: a browsable, searchable view of every source and item, and the interactive front end for the rest of the CLI (meld, learn, sync, upgrade, config). For the probe verb and its flags, see Commands.

Opening it

  • mind probe with no opt-out launches the TUI. It requires a TTY on stdout.
  • It falls back to the non-interactive catalog listing when --no-tui (short -n) is given, when --json is given, or when stdout is not a terminal (piped or redirected).
  • The query, --kind, and --source arguments apply in both modes. In the listing they filter it; in the TUI they seed the initial search and filter state.

The browse tree

Two top-level groups, each an independently collapsible tree:

  • Installed: the manifest. Installed items grouped source -> kind -> item, each showing effective name, source, and short commit, matching what recall reports.
  • Available: catalog items of melded sources that are not installed, not-yet-melded sources suggested by the registry, and ad-hoc sources you enter, de-duplicated.

A third Unmanaged group appears below them when the agent home holds items mind did not install. See Unmanaged items.

Under each group the hierarchy is source -> kind (skills, agents, rules) -> item -> detail. Expanding an item shows its description and frontmatter, and for a skill its file tree.

  • Up / Down: move the highlight.
  • Left / Right: collapse / expand a structural node (source and kind buckets).
  • Space: also collapses / expands a structural node.
  • Enter: open the details dialog on a source or item; on a group header or kind bucket it toggles instead.

As the selection moves, the view scrolls to keep the highlighted row away from the top and bottom edges while there are more rows to scroll. Near the start or end of the list the highlight may sit at the edge.

A search box filters the visible tree by case-insensitive substring over item name and description, across both groups, and composes with the active kind and source filters. Clearing the search restores the full tree.

Live refresh

The TUI polls the on-disk registry (sources.json) and manifest (manifest.json) about once a second, so changes made by another mind process or a direct edit appear without a manual reload. A refresh preserves the current selection, expansion, and search state, and is skipped while a mutating action is running.

Actions

Each action invokes the same verb the CLI exposes, against the same registry, manifest, and store. Every mutating action confirms before applying; destructive actions (forget, unmeld --forget) require an explicit confirmation. Results and errors are shown inline.

  • Install / learn: install the selected Available item. On a higher node it installs in bulk: a source installs every available item from it, a kind bucket every item of that kind, and the Available group everything. Already-installed items are skipped.
  • Forget: uninstall the selected Installed item.
  • Meld / unmeld: meld the selected or entered source; unmeld a melded source. The TUI’s unmeld uninstalls the source’s installed items by default and confirms first.
  • Sync / upgrade: sync all or the selected source; upgrade pending or the selected items, showing the same deltas and confirming before applying.
  • Config lobes: view and manage agent homes (list / add / remove).

An install preview arms the same dependency closure as the direct install action. See Dependencies.

Details dialog

Pressing Enter on a source or item opens a centered details dialog describing the node and listing the actions valid for it as a selectable list, each run through the normal confirm-and-execute path.

  • For an item: its kind, source, the commit when installed, and the description. It offers Install when the item is not installed, else Forget.
  • For a source: its name and installed/available item counts, and Install all available items, Uninstall all installed items, and Unmeld. An action is omitted when it would do nothing.

In the dialog, j / k move the highlight, Enter or y runs the highlighted action, and Esc, q, or n dismisses without acting. On a group header, kind bucket, or suggested source there is no dialog: Enter keeps its toggle/preview.

Registry preview

The Available group lists suggested, not-yet-melded sources: the union of the [discover].sources entries declared by all melded sources, de-duplicated by URL and excluding sources already melded. Expanding a registry entry shallow-clones it to a temporary preview area and shows its catalog tree under Available without registering it. Confirming promotes the preview to a real meld; declining discards the temp clone.

Terminal handling

  • Actions whose verbs may prompt interactively run with the TUI suspended: mind leaves raw mode and the alternate screen, runs the verb on the normal terminal so its prompts read stdin and write stdout exactly as the CLI does, then restores the alternate screen and redraws. After the verb you press Enter to return. The verbs that suspend are meld and unmeld.
  • While the TUI holds the terminal, every git child runs non-interactively (GIT_TERMINAL_PROMPT=0 and an ssh BatchMode=yes wrapper), so an auth-required remote fails fast with an error surfaced inline instead of hanging the UI on a hidden prompt. The suspended interactive meld restores interactive git for its duration, so a passphrase or host-key prompt works on the normal terminal.

Exit

  • q quits from the main view.
  • Ctrl-C is a force-exit from every mode. One Ctrl-C arms and shows a hint; a second consecutive Ctrl-C exits, so a single accidental Ctrl-C while typing does not quit. Any other key disarms.

Configuration

Agent homes (lobes)

learn links items into every configured agent home (a lobe). Each item is linked under its kind subdirectory: skills/, agents/, rules/. The default lobe is ~/.claude. Configure more in ~/.mind/config.toml:

lobes = ["~/.claude", "~/.config/some-other-agent"]

The file is created with the default lobe (~/.claude) on first use. For a single invocation, set MIND_AGENT_HOMES to a :-separated path list instead.

Lobe precedence (STO-14): MIND_AGENT_HOMES wins over lobes in config.toml, which wins over the default ~/.claude. An unknown key in config.toml is a hard error.

Use mind config lobes add <path> and mind config lobes remove <path> to manage lobes without hand-editing the file; see Commands for the full verb list.

Kinds filter

A lobe may carry a kinds list so only items of the listed kinds link into it. A lobe without a kinds field receives all kinds (existing behavior; a bare string is equivalent):

lobes = ["~/.claude", { path = "~/.gemini/config", kinds = ["skill"] }]

Linking an item into a lobe whose kinds excludes its kind is a no-op for that lobe, not an error. The manifest records only the lobes that actually received a link, so forget, upgrade, and introspect never expect a link a filtered lobe was never given (HARN-1, HARN-2).

Cross-harness lobes

Skills (skills/<n>/SKILL.md) and agents (agents/<n>.md) use layouts that are now cross-harness conventions. mind links them verbatim – no content transform is needed. Rules (rules/<name>.md) have no cross-harness directory equivalent (the analog in other harnesses is a single concatenated context file like AGENTS.md or GEMINI.md, not a directory of per-rule files), so rules are Claude-only and are never linked into a lobe added via a non-Claude preset (HARN-3).

Per-harness path table:

HarnessSkills dirAgents dirmind lobe (parent)
Claude Code~/.claude/skills/<n>/SKILL.md~/.claude/agents/<n>.md~/.claude
Gemini CLI / Antigravity~/.gemini/config/skills/-~/.gemini/config
Codex CLI~/.agents/skills/(subagents)~/.agents

~/.agents is a vendor-neutral alias: Codex reads it as its user skills path, so one ~/.agents lobe serves Codex and any harness that follows the same convention.

Presets

mind config lobes add --preset <name> adds a lobe with the preset’s path and kinds in one step. Presets:

presetpathkinds
gemini~/.gemini/configskill
codex~/.agentsskill
universal~/.agentsskill

Example:

mind config lobes add --preset gemini
# + added gemini lobe ~/.gemini/config [skill]

Note (migration): The gemini preset path changed from ~/.gemini to ~/.gemini/config in a previous release. If you added this preset earlier, your ~/.mind/config.toml may still have the old path. Update it by running:

mind config lobes remove ~/.gemini && mind config lobes add --preset gemini

Or hand-edit ~/.mind/config.toml and replace ~/.gemini with ~/.gemini/config.

mind config lobes detect detects which known harness homes exist on the machine and reports the matching presets it could add. It never mutates config on its own: it only adds a lobe with --yes or an interactive TTY confirm. --json emits the detection result as structured JSON (HARN-5).

mind config lobes list shows the kinds filter for each lobe (e.g. ~/.gemini/config [skill]); a lobe with no filter shows just the path. mind config show uses the same format.

Frontmatter portability

mind links skill and agent files verbatim. Frontmatter portability across harnesses – for example, Gemini’s mcp_* tool-permission wildcards vs Claude’s tools: schema – is the author’s responsibility; mind does not rewrite frontmatter to fit a target harness (HARN-6). An item whose frontmatter uses Claude-specific keys will link into a Gemini or Codex lobe correctly, but those keys may be ignored or produce a warning in the target harness.

Absorb destination

mind absorb moves an unmanaged item into a version-controlled source you own. The destination source is resolved from three places, in order – the first one set wins:

  1. --to <path> flag on the command line.
  2. MIND_ABSORB_TO environment variable.
  3. absorb_to key in ~/.mind/config.toml.

When none of the three is set and the run is interactive, absorb prompts and offers ~/.mind/personal as the default. That directory is created and git init-ed on demand if it does not exist. After an interactive resolution, absorb offers to save the chosen path as absorb_to in config.toml so future runs skip the prompt. A --to flag, MIND_ABSORB_TO, or an existing absorb_to value is used as-is and never triggers a save.

A non-TTY run with no destination configured (none of the three sources set) is an error; there is no silent default to assume.

Set the persistent default in ~/.mind/config.toml:

absorb_to = "~/dev/my-agent-library"

~ is expanded at use. The destination must be a git repository; a path that is not a git repo is an error.

SSH cloning

To authenticate with an SSH key instead of an https username/password, meld the git@host:owner/repo form, or set ssh = true in ~/.mind/config.toml so the owner/repo shorthand clones over SSH. An https remote still prompts (or uses a credential helper) as git normally does.

Config example

A single ~/.mind/config.toml may contain any combination of the keys:

lobes = ["~/.claude", { path = "~/.gemini/config", kinds = ["skill"] }]
ssh = true
absorb_to = "~/dev/my-agent-library"

Paths

~/.mind/
  config.toml                   persistent settings (lobes, ssh, absorb_to)
  sources.json                  source registry (melded repos)
  manifest.json                 installed-item manifest and file registry
  sources/<host>/<owner>/<repo> clone of each melded repo
  store/<kind>/<name>/          installed copy of each item (name is effective)
  personal/                     built-in absorb destination, created on demand
  .tmp/staging/                 scratch for new copies during transactional installs
  .tmp/backup/                  previous copy held during a swap, for rollback
  .lock                         global advisory lock

Override the roots with MIND_HOME (the ~/.mind tree) and CLAUDE_HOME (the default lobe).

Concurrency

A global advisory lock (~/.mind/.lock) is held by every mutating command (meld, unmeld, learn, forget, sync, upgrade, introspect --fix, config lobes add|remove). A second concurrent mind invocation blocks until the first finishes. The lock is released when the holding process exits, even on crash, so an aborted run never wedges the next one. Read-only commands (recall, probe, introspect, config show) take a shared lock and proceed concurrently with each other, but never observe a writer mid-update (STO-40..43).

Install and upgrade are transactional

A failed learn or upgrade never leaves you worse off. The new copy is built in a staging directory first; the previous version is moved to a backup and only dropped after the swap succeeds. A failure at any point restores the previous version from backup (LIFE-1..4).

A prefix change (adding or removing --namespace <prefix> on a source) causes upgrade to report rename old -> new and is handled the same way: the new name is installed before the old one is removed (LIFE-14). This is normal, not an error.

For diagnosing a failed install or broken links, see Troubleshooting.

Unmanaged items

An agent home (lobe) often holds skills, agents, and rules that mind did not install: files written by hand or placed by another tool. mind surfaces these as unmanaged items so the listing reflects everything the agent actually sees, and lets forget remove one after a distinct confirmation.

Tools are store-only (not linked into a lobe by default), so unmanaged detection covers skills, agents, and rules only (spec UNM-1).

What counts as unmanaged

A lobe entry is unmanaged when its path is not recorded in any manifest item’s links (spec UNM-1). A managed symlink and an unmanaged file cannot occupy the same path simultaneously; a given path is always one or the other.

mind scans every configured lobe. An item present in more than one lobe is one logical item that records each occupied path.

Listing unmanaged items

recall

mind recall (no arguments) lists unmanaged items after the melded sources, in a group labeled “unmanaged: not installed by mind”, one row per item showing kind:name and the lobe path(s) it occupies (spec UNM-2). No flag is needed to see them; --kind filters them the same way it filters managed items; --source excludes them because they have no source.

recall --json covers managed sources only (its schema is unchanged); unmanaged items are exposed machine-readably through probe --json (spec UNM-2, UNM-3).

probe

mind probe includes unmanaged items in its listing and substring search (spec UNM-3). In the non-interactive listing each unmanaged row is labeled. In --json output each carries "unmanaged": true with no source or hash field. --kind filters; --source excludes them.

In the interactive TUI, unmanaged items appear under an Unmanaged group node, browsable and searchable like a source’s items (spec UNM-6). See Interactive TUI.

Forgetting an unmanaged item

mind forget <kind:name>

When the ref resolves to an unmanaged item, forget removes the lobe entry itself (the file or directory the user owns) and leaves the manifest unchanged (spec UNM-4).

Exact ref only. An unmanaged item is matched only by its exact kind:name. A glob such as forget '*' removes managed items only and never deletes a user’s own files (spec UNM-4).

Confirmation required. Every unmanaged removal prompts first, regardless of count. The prompt states explicitly that the item is not managed by mind and that removal deletes the user’s own file or directory, not a symlink (spec UNM-5).

  • --yes proceeds after displaying that statement.
  • A non-TTY run without --yes refuses with ConfirmationRequired and removes nothing (spec UNM-5).

The --force / clobber flags do not apply here; nothing is being overwritten.

When a bare name matches both a managed and an unmanaged item, add a kind prefix to disambiguate (for example skill:review vs agent:review). See Commands for the full forget verb reference.

Bulk removal of unmanaged items

mind forget --unmanaged [<ref>]

--unmanaged scopes removal to unmanaged lobe items only – the deliberate opt-in inverse of the default, where a glob matches managed items only. Managed (mind-installed) items are never matched in this mode; it cannot delete a mind-installed link or store copy.

Ref forms.

  • With a glob <ref> (e.g. 'skill:*'), every matching unmanaged item is removed. A kind prefix composes with the glob.
  • With an exact kind:name, that single item is removed.
  • With no <ref>, every unmanaged item across all configured lobes is removed.

A <ref> that matches no unmanaged item is an error.

Confirmation. Before removing anything, mind lists all matched items and asks once to confirm, making clear these are not managed by mind and that removal deletes the user’s own files or directories (not symlinks). --yes (-y) skips the prompt. A non-TTY run without --yes refuses with ConfirmationRequired and removes nothing.

The manifest is not touched; these items were never in it. The --force / clobber flags do not apply.

absorb

mind absorb <ref> claims a single unmanaged lobe item (skill, agent, or rule) into a version-controlled source and installs it as a managed item. It is the constructive inverse of forget --unmanaged: instead of deleting an unmanaged file, absorb moves it into a source you own, commits it there, and replaces the lobe entry with a managed symlink. After absorb the item participates in sync, upgrade, and forget like any installed item.

See Unmanaged items for how unmanaged items are detected and listed.

Basic usage

mind absorb skill:my-skill
mind absorb agent:my-agent
mind absorb rule:my-rule
mind absorb my-item --to /path/to/my-source

The ref must resolve to exactly one unmanaged item. A glob ref is an error; bulk absorb is not supported. A kind prefix disambiguates when the same name appears in more than one kind.

Tools are never absorbed: they are store-only and never appear as unmanaged lobe items (spec ABS-1).

Choosing the destination

The destination source is resolved in this precedence order:

  1. --to <path> – the explicit destination flag.
  2. MIND_ABSORB_TO environment variable.
  3. absorb_to key in ~/.mind/config.toml.

The first one set wins; later sources are not consulted (spec ABS-2).

When none of the three is set and the run is interactive, absorb prompts for a destination and offers ~/.mind/personal as the built-in default. That directory is created and git init-ed on demand if it does not already exist. After a prompted choice, absorb offers to save it as absorb_to in config.toml so future invocations skip the prompt (spec ABS-3, ABS-4).

A non-interactive (non-TTY) run with no destination configured is an error (ConfirmationRequired) and changes nothing (spec ABS-3).

When --yes is given on a TTY and no destination is configured, absorb automatically uses (and persists) ~/.mind/personal. On a non-TTY this does not apply: with no destination configured the run errors regardless of --yes (see Running unattended below).

Flags

flageffect
--to <path>Destination source directory (highest precedence).
-f / --forceOverwrite the destination convention path if a kind:name collision already exists there. Without --force, a collision is an error and nothing is changed (spec ABS-6).

The global -y / --yes flag skips the [y/N] confirmation described below.

Confirmation and multi-lobe cleanup

An unmanaged item may occupy more than one lobe. absorb takes the content from one occupied path; because learn relinks the item into every configured lobe (spec STO-14), the other unmanaged copies must be removed so the managed link can take their place.

Before acting, absorb lists what it will move and which stray copies it will delete and prompts [y/N] once. This covers deleting files the user owns, so the prompt runs even when only one lobe is affected (spec ABS-7).

  • --yes (-y) skips the prompt and proceeds.
  • A non-TTY run without --yes refuses with ConfirmationRequired and changes nothing.
  • Declining the prompt leaves the original lobe entry in place and the manifest unchanged.

What absorb does internally

  1. Resolves <ref> to a single unmanaged item (ABS-1).
  2. Confirms the destination source is a git repository. The --to / MIND_ABSORB_TO / absorb_to path must already be a git repo; a non-repo path is an error. ~/.mind/personal is the one path absorb will create and git init on demand (spec ABS-5).
  3. Lists the move and any stray copies to delete; prompts [y/N] (skipped with --yes).
  4. Moves the item into the destination source at its convention path (skills/<name>/, agents/<name>.md, rules/<name>.md). Melds the source first if it is not yet registered.
  5. Stages and commits the moved item in the destination repo with the message absorb <kind>:<name> (spec ABS-5).
  6. Runs learn on the item; the lobe path is now a managed symlink.
  7. Records the item in the manifest keyed kind:effective-name with the destination source as its source (spec ABS-8).

A failure at any step before learn completes leaves the original lobe entry in place and the manifest unchanged. A failed absorb never loses the user’s file (spec ABS-10).

After absorb

The item’s effective name follows the destination source’s prefix when one is in effect (--namespace or [source].prefix in mind.toml). It then appears in mind recall, participates in mind upgrade and mind sync, and can be removed with mind forget <kind:name> like any managed item (spec ABS-8).

Running unattended

Pass --yes (-y) to skip all prompts. In a non-TTY context without --yes, absorb refuses at any point that would normally prompt (destination resolution or the multi-lobe confirmation). You must also supply a destination via --to or MIND_ABSORB_TO or absorb_to in config, because a missing destination in a non-TTY context is itself an error (spec ABS-3).

Install hooks

A source can declare install hooks in mind.toml: shell commands that build or install the tooling its items rely on. A user can supply or override them with meld --install-hook <cmd>.

The full form is a [[hooks]] array-of-tables. Each entry has a required run field (the shell command), an optional name label shown in the disclosure, an optional bool (default false), and an event field ("install" for meld, "uninstall" for unmeld; default "install"). The legacy [source].install string is shorthand for one required install hook:

# mind.toml in a source repo

[[hooks]]
run = "make build"
name = "build tooling"
event = "install"

[[hooks]]
run = "pip install -r requirements.txt"
name = "python deps"
optional = true
event = "install"

[[hooks]]
run = "make clean"
name = "cleanup"
event = "uninstall"

The safety prompt

Because a hook is arbitrary code, mind discloses the source identity, pin, commit, clone path, and exact command before running anything, and prompts [Y/n/a] with three choices: run the hook (the default, a bare Enter), skip it but still install the source and its items, or abort and install nothing. In a non-TTY context (CI, scripts) the hook is skipped and a note is printed; --dangerously-skip-install-hook-check runs it unattended. Overriding a source’s declared install hook with --install-hook is announced in the prompt, which shows both the declared and the overriding command.

Re-runs

A skipped hook is recorded and re-offered by mind upgrade, so you can run it later without the source needing to advance first. On an upgrade re-run the source is already installed, so abort is treated as skip. upgrade also re-runs the hook when a source advances to a new commit. sync --upgrade accepts --dangerously-skip-install-hook-check so a CI pipeline can run hook re-runs unattended. Without the flag, a non-TTY sync --upgrade skips hook re-runs (the same as upgrade).

Uninstall hooks

Uninstall hooks (event = "uninstall") run at unmeld, in the source’s clone, before the clone is removed. They use the same safety-prompt model as install hooks: required hooks prompt run / skip / abort-the-unmeld; optional hooks prompt run / skip; a non-TTY unmeld skips them and notes it. unmeld --uninstall-hook <cmd> supplies or overrides the source’s declared uninstall hooks. unmeld --dangerously-skip-install-hook-check runs them unattended (the flag name is reused deliberately). A required uninstall hook that fails or is aborted leaves the source melded.

Visibility

recall --sources marks a source that carries hooks with a count-aware token in its status bracket (e.g. 1 hook or 3 hooks). mind review <repo> lists every declared hook (install and uninstall), showing each hook’s command, event, and whether it is required or optional.

[source].install is deprecated in favor of the [[hooks]] form. See The mind.toml file for the schema and spec/install-hooks.md for the full behavior.

Managed policy (enterprise)

A managed policy file lets an administrator constrain mind machine-wide. It restricts the client to a trusted set of sources and locks related settings, modeled on Claude Code’s managed settings: a file at a fixed system path takes precedence over user configuration and the user cannot override it.

This is a compliance guardrail, not a security sandbox. mind runs with the user’s own privileges, so a user can still place agent files under an agent home by hand without invoking mind; the policy cannot prevent that. What it provides is a policy the user cannot edit (enforced by file permissions), refusal of disallowed operations through mind, and auditability.

The policy file

mind reads a managed policy file on every invocation from a fixed per-OS system path (POL-1):

OSPath
Linux/etc/mind/policy.toml
macOS/Library/Application Support/mind/policy.toml
Windows%PROGRAMDATA%\mind\policy.toml

The path is owned by an administrator and world-readable but not user-writable. It is not relocatable by MIND_HOME or other user environment (POL-2).

MIND_POLICY_FILE overrides the path only when no file exists at the system path (for tests and non-managed use). When the system file exists it is authoritative and MIND_POLICY_FILE is ignored. The env path is honored only when the file it names exists; a set-but-missing MIND_POLICY_FILE is treated as no policy, not a hard error (POL-2).

When a policy is in effect it is authoritative over user configuration (~/.mind/config.toml) and the user’s registry: a user cannot widen what the policy restricts (POL-3).

With no policy file present, mind is unmanaged and behaves exactly as it does without this feature. Every control below is opt-in and absent unless the policy sets it, so the feature is inert by default (POL-4).

A policy file that does not parse, has unknown keys, or violates an internal rule is a hard error on every command (fail closed), naming the problem; mind does not silently fall back to unmanaged (POL-5). Validate a policy with mind review --policy before deploying it.

Schema

[sources]
# Allowlist matched against a source's host/owner/repo identity. `*` matches
# within one path segment.
allow = ["github.com/acme/*", "github.example.com/platform/*"]

# Refuse to meld any source whose identity is not in `allow`. Without lock, the
# allowlist is advisory (a non-matching meld warns but proceeds).
lock = true

# Every meld must resolve to a tag or ref; floating branches are refused. When
# pinned, every auto_meld entry below must declare a tag or ref.
pinned = true

# Sources mind provisions automatically (melds if not already present), during
# `sync`. `repo` is a repo spec as `meld` accepts (owner/repo, a URL, git@, or a
# path); its derived host/owner/repo identity must satisfy `allow` under lock.
[[sources.auto_meld]]
repo = "acme/agent-baseline"
tag = "v1.4.0"

[[sources.auto_meld]]
repo = "https://github.example.com/platform/security-rules"
ref = "9f3a1c2e7b1d0a4c5e6f8a9b0c1d2e3f40516273"

[lobes]
# Lock the agent homes: `config lobes` edits and $MIND_AGENT_HOMES are refused,
# and the effective homes are exactly `targets`. With lock off, `targets` is a
# base set the user's configured lobes are unioned onto.
lock = true
targets = ["~/.claude"]

The scalar [sources] keys precede the [[sources.auto_meld]] tables, per TOML ordering. Source identity is host/owner/repo.

Trusted-source allowlist

[sources].allow is a list of patterns matched against a source’s host/owner/repo identity, where * matches within a path segment, so github.com/acme/* matches every repo under acme (POL-10).

[sources].lock is the enforcement switch:

  • With lock = true, meld refuses any repo whose identity does not match allow (SourceNotAllowed); nothing is cloned or registered (POL-11). learn, sync, and upgrade operate only on allow-matching sources. A registered source that is no longer allowed is reported and skipped, not updated or installed from (POL-12).
  • With lock absent or false, allow is advisory: a non-matching meld is warned about but not refused, and the verbs above are not restricted (POL-13).

Require pinned

With [sources].pinned = true, every meld must resolve to a tag or ref pin (--pin-tag / --pin-ref, or a [source] pin directive that resolves to a tag or ref); a floating branch (--follow-branch or the default branch) is refused (UnpinnedSourceForbidden) (POL-20).

With pinned = true, every [sources].auto_meld entry must declare a tag or ref. A policy whose auto_meld contains an unpinned entry or a follow_branch entry is invalid and is reported by mind review --policy (POL-21).

Auto-meld (org provisioning)

[sources].auto_meld is a list of tables, each with repo (a repo spec as meld accepts: owner/repo, a URL, git@..., or a path) and an optional pin: tag, ref, or follow_branch. mind provisions these by melding any that are not already melded (POL-30). It is a base set, not an exclusive one: with lock off the user may meld additional sources beyond it; when locked, only allow-matching sources are permitted.

Every auto_meld entry must satisfy allow when lock is true, matched on the host/owner/repo identity derived from its repo spec. An entry outside the allowlist, or whose repo does not parse, is an invalid policy (POL-31).

Auto-meld provisioning runs during sync, using each entry’s declared pin. It is idempotent: an entry already melded at the declared pin is left unchanged (POL-32).

Lobe lock

With [lobes].lock = true, the effective agent homes are exactly [lobes].targets; config lobes add / config lobes remove are refused and the user’s lobes (from ~/.mind/config.toml) and MIND_AGENT_HOMES are ignored. With targets absent under a lock, the lock pins the default ~/.claude (POL-40).

With [lobes].lock absent or false, [lobes].targets is a base set the user extends: the effective agent homes are targets unioned with the user’s configured lobes (POL-41).

Validation

mind review --policy <path> statically validates a managed policy file without cloning: it parses the TOML, rejects unknown keys, checks that allow patterns are well formed and auto_meld repo specs parse, enforces that every auto_meld entry is pinned when pinned = true (POL-21), and that every auto_meld entry satisfies allow when locked (POL-31). It reports hard errors and advisories and exits non-zero on a hard error (POL-50).

Caveat: install hooks are not gated

The policy does not currently gate install-hook execution. A source’s build command is arbitrary code, and it still runs under the normal hook safety prompt rather than under any policy control. How a policy should govern install hooks is an open research item, not yet specified. See Install hooks for the disclosure and prompt model that applies.

Example

A worked example is at examples/policy.

Troubleshooting

  • An item didn’t show up in ~/.claude. Run mind introspect; it reports missing links and drift, and mind introspect --fix recreates missing symlinks.
  • learn refused to overwrite a path. mind will not clobber a file or link it did not create (the clobber guard). Move the existing one aside, then learn again.
  • Two sources ship an item with the same name. Namespace one with mind meld <repo> --namespace <prefix>, so its items install as <prefix>:<name>. See examples/namespacing/.
  • Where things live: see Configuration. Override the roots with MIND_HOME and CLAUDE_HOME.
  • Before publishing a source, run mind review <path> to check its mind.toml, item kinds, {{ns:}} references, and pin directive. See Authoring a source.
  • To authenticate with an SSH key, see Configuration.
  • Stuck in the TUI. Press q in the main view, or Ctrl-C twice from anywhere (search box, dialogs) to force exit.
  • A mind.toml change is rejected as a parse error. The file is strict (deny_unknown_fields), so a misspelled key is a hard error, not silently ignored (DSC-30). Common near-misses: pin keys are hyphenated (follow-branch, pin-tag, pin-ref), not underscored; min-mind-version likewise uses a hyphen; and entry keys under [discover].sources are exact (DSC-31). Run mind review <path> to check the file before melding.
  • A source’s items are not discovered after setting roots in mind.toml. roots = [] (an explicit empty list) is distinct from omitting the key: it scans zero roots and finds nothing. Omitting roots (or removing the key) keeps the default behavior of scanning the repo root (DSC-50). Set the actual subdirectory paths, or remove roots entirely.
  • learn reports LinkOccupied and refuses to overwrite. The clobber guard will not replace a path that mind did not create (LIFE-41). Move the existing file aside, then learn again, or pass learn --force (CLI-35) to replace it unconditionally. Note: on non-unix platforms mind cannot always recognize its own copies (symlink ownership is not detectable), so a reinstall or upgrade may report LinkOccupied for items mind did install; this is a documented platform limitation (see the lifecycle.md platform note).
  • An item shows as out of date in recall/probe without an upstream change. Editing a store or source file by hand changes its content hash; mind compares source-content hashes and reports the delta as drift (LIFE-33, CLI-75). Either re-sync and then upgrade the item, or restore the edited file to its original content. See Configuration for where store and source files live.
  • meld or sync fails with “git executable not found”. mind shells out to git for all clone and fetch operations; put git on your PATH first. See the Install page.
  • A skill links to a Gemini or Codex lobe but a rule does not. Rules have no cross-harness directory equivalent and are Claude-only (HARN-3). Only skills and agents are linked into non-Claude lobes. If the lobe was added via a preset, this is expected; rules remain in ~/.claude only.
  • An agent’s tool permissions don’t work in Gemini or Codex after linking. mind links files verbatim and does not rewrite frontmatter. A skill or agent whose frontmatter uses Claude-specific keys (e.g. the tools: allow-list schema) will link correctly but those keys may be ignored or produce a warning in the target harness. Adapt the frontmatter for the target harness by hand (HARN-6). See Configuration.

Source layout

A source is a git repo mind melds. It offers items, discovered by convention or declared in a mind.toml. The convention layout, which works on any repo with no config:

<repo>/
  skills/<name>/SKILL.md     a skill (the whole directory is the item)
  agents/<name>.md           an agent
  rules/<name>.md            a rule
  tools/<name>/              a tool (the whole directory; no anchor file)
  mind.toml                  optional: metadata, export control, odd layouts

The kinds:

  • skill: a directory with a SKILL.md anchor. Bundled files (a resources/ dir, scripts) ship with it.
  • agent / rule: a single markdown file.
  • tool: a directory of helper scripts or a compiled binary. A tool is store-only: other items reference it, and by default it is not linked into an agent home (a tool can opt in with an explicit link, see Tooling).

A mind.toml is optional enrichment, never a gate. It carries source metadata, a namespace prefix, and (when you need it) explicit [[items]] or [discover] globs for non-standard or monorepo layouts. See examples/.

A repo published for Claude Code’s plugin system needs no changes either: a .claude-plugin/plugin.json or .claude-plugin/marketplace.json is read as a discovery input, mapping the plugin’s skills and agents to mind items. See Claude plugin marketplaces.

Where shared helpers belong

A helper used by a single skill lives in that skill’s own directory and is addressed with {{self}}:

skills/review/
  SKILL.md           # ... run {{self}}/resources/pr.py ...
  resources/pr.py

A helper used by more than one item has two good homes. Either:

  • An install hook puts it in a known location. Declare a [[hooks]] install entry to run your install script, which installs the shared tooling wherever you want, and have your items call it there. This suits anything with a build step or a dependency to fetch, and a source onboards its build once.
  • A tool item shares it through the store. Put it once under tools/<name>/ and reference it by token ({{tools:name}}). mind carries it in the store and expands the token at install.
tools/detect/detect          # the shared script, shipped once
skills/a/SKILL.md            # ... {{tools:detect}} ...
skills/b/SKILL.md            # ... {{tools:detect}} ...

Copying a byte-identical helper into several items works too; mind review and mind init-source note it as a duplicate-tooling advisory (informational, not a defect) in case you would rather share it once.

Referencing items and resources

To reference one item from another, mind provides tokens it expands at install. They are useful mainly under a namespace prefix (which renames items) or across multiple agent homes; an unprefixed single-home source can often just use the name or a bundled path.

tokenexpands to
{{ns:name}}a sibling item’s effective name (use in prose, e.g. “hand off to {{ns:dev}}”)
{{self}}the item’s own store directory (its bundled resources)
{{tools:name}}a sibling tool’s entrypoint
{{path:ref}}a sibling item’s store directory, for a non-entrypoint file ({{path:tool:detect}}/lib.sh)

References resolve within the same source only: ship a tool in the same source as the items that use it.

Hardcoded paths

mind learn copies an item into the store (~/.mind/store/<kind>/<name>) and symlinks it into each agent home (~/.claude/skills/<name>, agents/<name>.md, rules/<name>.md). A tool is the exception: it is store-only and, by default, not linked into an agent home.

A path you control is fine: pointing at a location your install hook populates works as long as your hook and your items agree on it. What is fragile is hardcoding mind’s OWN install layout, since that layout shifts under you. mind review classifies those as the advisory hardcoded-path finding:

  • A skill referencing its own resources by an agent-home path (~/.claude/skills/<self>/resources/x) resolves through the skill’s symlink today, but breaks the moment a prefix renames the item (<prefix>:<self>) or a second agent home is configured. {{self}} generalizes it. Fragile, not broken.
  • A reference to a tool item by an agent-home path never resolves: a tool is not linked there. Use {{tools:name}} (or install it elsewhere via a hook).
  • Any reference under a prefix points at the wrong effective name, since a literal path does not track the rename.

A token keeps a leading ~ when the store is under your home, so a Claude settings.json permission glob such as Bash(~/.mind/store/**) matches the expansion.

mind review recognizes these install paths written with ~, $HOME, ${HOME}, or an absolute /home/<user> / /Users/<user> root, and mind review --fix rewrites the ones that map confidently to a token. The finding is advisory, so a deliberate fixed-location-via-install-hook layout is your call.

The mind.toml file

A source repo may place a mind.toml at its root to declare what it offers and how mind should treat it. It is always optional: a repo with no mind.toml is discovered by convention. mind.toml is enrichment, never a gate.

There are four discovery layers, in precedence order:

  1. Convention (default, no file): the scanner finds skills/<name>/SKILL.md, agents/<name>.md, rules/<name>.md, and tools/<name>/.
  2. Frontmatter (always read): each item’s description (and a tool’s bin / build) come from the frontmatter it already carries.
  3. Claude plugin manifest (optional): a .claude-plugin/plugin.json or .claude-plugin/marketplace.json in the repo is read as a discovery input. It is authoritative for the items it declares (convention scanning is skipped for the paths it covers) but an authoritative mind.toml overrides it. See Claude plugin marketplaces.
  4. mind.toml (optional): [source] metadata is read regardless. Declaring [[items]] or [discover] item globs makes the file authoritative: convention scanning and the plugin-manifest layer are both turned off and only what the file lists is offered.

When does mind.toml take over discovery?

mind.toml containsconvention scanresult
nothing / no fileonitems found by convention (or by a .claude-plugin/ manifest, if present)
[source] onlyonconvention items, plus metadata (prefix, pin, …)
[discover].sources onlyonconvention items, plus a curated chain
[[items]]offexactly the declared items
[discover] with kind globsoffexactly the glob matches

The last two are authoritative. A bare [discover].sources list (curating other repos) does not turn off convention scanning, so a repo can ship its own items by convention and curate others at the same time (see Regular plus super-source).

When a repo has no authoritative mind.toml but does carry a Claude .claude-plugin/plugin.json or .claude-plugin/marketplace.json, that manifest supplies the items instead of convention scanning. An authoritative mind.toml overrides it (and meld notes the manifest was ignored). See Claude plugin marketplaces.

[source] - repo metadata

All keys are optional.

[source]
description = "James's agent library"   # shown in recall/probe
prefix = "jk"                            # namespace: items install as jk:<name>
min-mind-version = "0.5"                 # refuse to scan under an older mind
follow-branch = "main"                   # pin: track a branch ...
# pin-tag = "v2"                          # ... or fix to a tag ...
# pin-ref = "a1b2c3d"                     # ... or to an exact commit (pick one)
roots = ["packages"]                     # scan under these dirs, not the repo root
  • prefix: every item installs as <prefix>:<name> (identity, store path, symlink, and ref), except an agent’s harness link, which stays bare. A consumer’s meld --namespace <prefix> overrides it; meld --namespace '' removes it. See namespacing.
  • install (deprecated): a shell command run once on meld, after checkout, to build or install the tooling the source’s items rely on. It is disclosed and prompted before it runs (--dangerously-skip-install-hook-check runs it unattended). Deprecated in favor of a [[hooks]] install entry below; still parsed, but new sources should use [[hooks]].
  • follow-branch / pin-tag / pin-ref: how sync tracks upstream. Declare at most one; two is an error. A consumer meld --follow-branch|--pin-tag|--pin-ref overrides it.
  • roots: convention discovery scans under each listed directory instead of the repo root, for a monorepo or subtree layout. Ignored when the file is authoritative ([[items]]/[discover] paths are always repo-root-relative).

[[hooks]] - lifecycle hooks

Zero or more named hooks the maintainer declares. Each runs on the host (gated by a disclosure prompt) at the bound lifecycle event.

[[hooks]]
run = "make build"          # the shell command (required)
name = "build tooling"      # label shown in the disclosure (else the command)
optional = false            # required (run/skip/abort) vs optional (run/skip)
event = "install"           # "install" (on meld, default) or "uninstall" (on unmeld)

[[hooks]]
run = "make clean"
event = "uninstall"
optional = true

[[hooks]] is the canonical form. The legacy [source].install is a deprecated shorthand for one required install hook (still parsed); use [[hooks]] instead.

[[items]] - explicit inventory (authoritative)

List items explicitly when convention does not fit (a non-standard layout, export control, custom link targets). Declaring any [[items]] turns off convention scanning for the source.

[[items]]
kind = "rule"                    # skill | agent | rule | tool (required)
name = "style"                   # the bare name (required)
path = "guidelines/style.md"     # path relative to the repo root; a dir for skills/tools (required)
link = "rules/house-style.md"    # optional: link target relative to the agent home
description = "House style"       # optional: overrides frontmatter

[[items]]
kind = "tool"
name = "detect"
path = "tools/detect"
bin = "detect.sh"                # tool only: what {{tools:detect}} resolves to
build = "make"                   # tool only: per-item build, run in staging at install
install = "./setup.sh"           # any kind: host side effect run after install
uninstall = "./teardown.sh"      # any kind: host cleanup run before removal
  • bin and build are valid only on a tool; on any other kind they are a schema error.
  • install / uninstall are per-item lifecycle hooks (valid on any kind), distinct from build (which produces the item’s content) and from the source-level [[hooks]].

[discover] - glob-based discovery

For odd or monorepo layouts where the items exist but not at the convention paths. Declaring any kind globs makes the file authoritative.

[discover]
skills = { include = ["packages/*/skill"], exclude = ["packages/internal/*"] }
agents = { include = ["agents/**/*.md"] }
rules  = { include = ["rules/*.md"] }
tools  = { include = ["packages/*/tool"] }   # globs match the tool DIRECTORY

Within a kind, include globs are matched first, then anything also matched by an exclude glob is dropped. Tool globs match the tool directory (its TOOL.md, if present, supplies metadata), not an anchor file.

[discover].sources - curated super-source

A repo can list other repos to meld, acting as a curated registry. Melding it recursively melds each listed source (skipping any already registered; cycles terminate). Each nested source is registered independently and tracks its own upstream commit. mind dump generates exactly this shape of mind.toml from your installed state, so you can author a super-source automatically rather than by hand (see dump).

[discover]
sources = [
  { source = "owner/repo" },                        # melded, items left available
  { source = "github:foo/bar", as = "fb" },         # imposed namespace (like meld --namespace)
  { source = "owner/recommended", install = true }, # offered for install on meld
]

The equivalent table-array form is also valid:

[[discover.sources]]
source = "owner/recommended"
install = true
  • source: any repo spec meld accepts (owner/repo, a host-qualified spec, or a local path).
  • as: impose a namespace prefix on that nested source.
  • install (default false): when true, melding the super-source offers that nested source’s items for install (the same preview-and-prompt as the top-level source), instead of leaving them registered but not installed.
  • install-items: a list of bare kind:name refs selecting only a subset of the nested source’s items to offer for install, e.g. install-items = ["skill:review", "agent:dev"]. install = true and a non-empty install-items are mutually exclusive (declaring both is an error). The empty-list form (install-items = []) is never used in practice; that case is install = false.

By default a melded super-source registers the whole chain but installs only its own items plus the install = true (or install-items) entries. meld --recursive (-r) offers every nested source for install.

Adopting un-onboarded sources (DSC-59/60/61)

A [[discover.sources]] entry may supply configuration for a nested source that has no mind.toml of its own:

  • follow-branch / pin-tag / pin-ref: curator-supplied pin directive for the nested source. Declare at most one; two is an error. sync uses whichever is set, the same as if the source had declared it in its own [source] table (DSC-41). A consumer’s explicit meld --follow-branch, --pin-tag, or --pin-ref still overrides this.
  • roots: convention scan roots for the nested source, for a monorepo or subtree layout (DSC-50).
  • [[discover.sources.hooks]]: one or more hooks to run for the nested source. Each entry has the same shape as a source’s own [[hooks]] entry: a required run field, and optional name, optional, and event fields. They run under the same disclosure and safety prompt as the source’s own hooks (including the non-TTY skip and --dangerously-skip-install-hook-check).

These fields apply ONLY when the nested source ships no mind.toml. If the nested source has a mind.toml, that file is authoritative for its pin, roots, and hooks, and the curator-supplied values are ignored (a warning is emitted). The gate is whole-file: a nested mind.toml, even one that does not declare a pin/roots/hooks, suppresses all three. as and install are unaffected; they always apply.

# Adopt a source that has no mind.toml: supply config it lacks.
# follow-branch, roots, and [[discover.sources.hooks]] apply only because
# this source ships no mind.toml of its own (DSC-60).
[[discover.sources]]
source = "owner/unonboarded"
follow-branch = "main"           # track this branch (DSC-41)
roots = ["packages/agents"]      # scan under this subdir, not the repo root (DSC-50)

[[discover.sources.hooks]]       # build hook, same shape as [[hooks]] (HOOK-50)
run = "make build"
name = "build tooling"
event = "install"

Scenarios

A regular source

A repo that ships its own skills, agents, rules, and tools. The simplest form is no mind.toml at all (pure convention). Add a mind.toml to attach metadata or a prefix:

[source]
description = "James's agent library"
prefix = "jk"

Convention scanning still finds skills/<name>/SKILL.md, agents/<name>.md, etc., and each installs as jk:<name>. Use [[items]] or [discover] instead only when the layout is non-standard (those turn convention off).

A super-source

A curated registry that ships no items of its own, only a list of other repos:

[source]
description = "Curated agent registry"

[discover]
sources = [
  { source = "acme/agents" },
  { source = "acme/skills", as = "acme", install = true },
]

Melding it registers acme/agents and acme/skills (the latter namespaced acme: and offered for install). It has no items of its own, so without install = true (or meld --recursive) nothing installs; mind probe browses what the chain offers.

Regular plus super-source

A repo that both ships its own items and curates others. Because a bare [discover].sources is not authoritative, convention scanning still runs for this repo’s own items:

[source]
description = "James's library and registry"
prefix = "jk"

# This repo's own items are still found by convention (skills/, agents/, ...)
# because only [discover].sources is declared, not [[items]] or kind globs.

[discover]
sources = [
  { source = "acme/skills", as = "acme", install = true },
]

Melding installs this repo’s own jk:<name> items (per the default install prompt) and registers acme/skills (offered for install via its install = true flag). If you instead need to declare this repo’s items explicitly while also curating, add [[items]] or [discover] kind globs alongside sources; that turns convention off, so list every item the repo offers.

Authoring a source

A source is a git repo. Publishing one is mostly “lay the items out and push”; mind melds arbitrary repos with no config, so there is no manifest to write and nothing to register.

Publish in two minutes

A repo with a skills/ directory is already a source. Nothing else is required.

myrepo/
  skills/greet/SKILL.md      # a skill (the directory is the item)
  agents/reviewer.md         # optional: an agent
  rules/style.md             # optional: a rule

Push it, and anyone can meld it:

mind meld owner/myrepo       # discovers the items by convention
mind probe                   # they show up, ready to learn

See examples/starter for a minimal repo of this shape and Source layout for the full convention.

Flat skill layout

If your repo keeps skill directories at the root with no skills/ container (<repo>/greet/SKILL.md), set [source].flat-skills so convention discovery finds them:

[source]
flat-skills = true

A consumer can also force it at meld time with mind meld owner/repo --flat-skills (useful for adopting a flat-layout repo that has not set the flag itself). It applies to skills only; agents, rules, and tools keep their agents/ / rules/ / tools/ directories. See DSC-74..77.

A Claude plugin or marketplace

A repo published for Claude Code’s plugin system is meldable as-is: a .claude-plugin/plugin.json or .claude-plugin/marketplace.json is read as a discovery source, no mind.toml needed. See Authoring a plugin or marketplace.

Preparing a source

Two commands help a maintainer prepare a repo for melding: init-source scaffolds and reports, review validates.

init-source

Run mind init-source in the repo. It discovers the items the repo offers (exactly as melding would), reports the references among them, scaffolds a mind.toml if none exists, and surfaces advisories:

mind init-source                 # report + scaffold
mind init-source --template      # also rewrite bare sibling refs to {{ns:}}

It is read-only except for creating an absent mind.toml and, with --template, editing item files. It registers nothing and touches no agent home.

review

mind review <target> validates a source for publishing without changing anything (--fix is the one exception). <target> is a melded source name, a local path, or a repo spec; with no target it reviews the current directory.

Findings are hard (non-zero exit) or advisory:

  • hard: a malformed mind.toml, an unknown item kind, a min-mind-version the running mind does not meet, or an unresolved {{ns:}} / {{self}} / {{tools:}} / {{path:}} token.
  • advisory: a missing description, a hardcoded install path (hardcoded-path, classified by what it resolves to), a sibling tool named in prose without a token, a misplaced {{ns:}} token, a helper script duplicated across items (duplicate-tooling), a deprecated [source].install field (deprecated-field, pointing to the [[hooks]] form), and each declared install/uninstall hook (so a consumer sees the source will run code).
mind review                      # review the current dir
mind review owner/repo           # review a melded source or repo spec
mind review . --fix              # rewrite confidently-mapped findings in place

--fix rewrites a local working tree only: recognized hardcoded paths become tokens, misplaced {{ns:}} tokens are un-wrapped, and bare sibling names are templatized. Structural advisories like duplicate-tooling are left for you to resolve by hand.

Resources and tooling

Where an item’s resources and shared tooling belong (bundled with {{self}}, put in a known location by an install hook, or shared through the store as a tool item) is covered in Source layout. mind review’s duplicate-tooling, bare-tool-reference, and hardcoded-path findings are advisory: each of those layouts is valid.

Namespacing

Most sources give their items unique, descriptive names and are never prefixed, so this does not come up. A prefix exists only for the collision case: two sources that both ship a review would land at the same path, so a prefix namespaces one (<prefix>:<name>). The effective prefix is, in order: the consumer’s meld --namespace <prefix>, the repo’s [source].prefix, else none.

A prefix renames items, so if a prefixed source’s items reference each other by name, those references must be tokens: {{ns:name}} in prose, and the path tokens ({{self}} / {{tools:name}} / {{path:ref}}) for code and paths. mind expands each at install. review and init-source warn (advisory) when a source that is being prefixed references a sibling in bare prose. An unprefixed source, or one with no intra-source references, needs none of this. Agents are the exception: they link under their bare name even under a prefix, so a reference to a sibling agent is not renamed and does not warn.

See the spec for the normative rules and examples/namespacing for a worked source.

Namespacing

Two melded sources can each ship an item of the same name (both a review). Without a prefix they would land at the same install path. A prefix namespaces a source so every item from it installs as <prefix>:<name>: the effective name, store path, symlink, and the name mind uses in the ref all carry the prefix. Agents are the one exception, because the harness keys them by frontmatter name rather than by their link path; see Agents are not namespaced. Most sources give their items unique, descriptive names and never need a prefix; this page covers the case where a prefix is needed.

Setting a prefix (NS-1, NS-2)

Two ways, in precedence order:

  1. Consumer-side: meld --namespace <prefix> (short -n). Stored as the source alias and takes priority over anything the repo declares. meld --namespace '' removes a prefix. (--as <prefix> is a deprecated alias for --namespace.)
  2. Repo-side: [source].prefix in mind.toml.
[source]
prefix = "jk"

With prefix jk, every item in the source installs as jk:<bare-name>. The catalog and the item’s stable identity keep the bare name; the prefix is applied at install time (NS-3). To change a prefix after items are installed, forget the installed items first (mind forget) and then re-meld with the new prefix.

Agents are not namespaced

A prefix reaches skills, rules, and tools but not an agent’s harness identity (NS-40, NS-41, NS-42). A skill is keyed by its directory name, so prefixing its directory and link changes the name the harness resolves. An agent is keyed by the name field in its frontmatter, not its filename, so renaming the link to <prefix>:<name> would not change the resolved name. mind therefore links an agent under its bare frontmatter name in each lobe even when the source has a prefix in effect (NS-40). The prefix still applies to the agent’s store path and manifest key, so its stable identity stays collision-free and a prefix change is still a rename; only the harness-visible link is bare.

Because agents link under their bare name, two melded sources that each ship an agent with the same frontmatter name resolve to the same lobe link. mind detects this instead of silently repointing: learning an agent whose bare name already maps to an installed agent from a different source fails with an AgentCollision error telling you to mind forget the existing one first, and meld surfaces it as an advisory warning (NS-41). A prefix does not avert the collision, since it does not reach the agent link.

Because a prefix cannot disambiguate agents for you, give a custom agent profile a distinctive frontmatter name so it does not clash with agents from other sources. If a generic name (dev, review, lead) is unavoidable, bake the namespace into the name itself (acme-dev, acme-review), since that is the identity the harness resolves and the only part you control.

A sibling agent’s name is the same bare name with or without a prefix, so a bare prose reference to it resolves either way and the unguarded-reference warning does not fire for it (NS-42). A {{ns:}} token naming a sibling agent still expands (to the bare name) and is not an error, so tokenizing an agent reference is harmless.

Why {{ns:name}} tokens exist (NS-10, NS-11)

The Claude harness resolves a skill at runtime by the name in the text, and a prefix changes that name. A plain-prose reference like “run the review skill” breaks once review installs as jk:review. Authors write intra-source references as {{ns:name}} instead, where name is the sibling’s bare name.

At install time, mind expands each token to the referent’s effective name:

source installed as{{ns:review}} expands to
unprefixedreview
--namespace jkjk:review

Expansion runs whether or not a prefix is in effect (NS-14), so a token-using source installs correctly in both cases. A token whose referent is an agent expands to the bare name in both cases, since agents are not namespaced (Agents are not namespaced).

Minimal example

A source with an agent lead that references a skill review:

<!-- agents/lead.md -->
When implementing, run the {{ns:review}} skill.

Installed unprefixed:

When implementing, run the review skill.

Installed with meld --namespace jk:

When implementing, run the jk:review skill.

A worked multi-item source is at examples/namespacing.

Validation at install time (NS-12, NS-13)

A token whose name is not a sibling in the same source is a BadReference error at install time, naming the referencing item and the bad referent. Expansion runs in a staging copy during the transactional install, so a bad reference fails before the live install is touched.

Content with no {{ns: tokens is copied unchanged. Non-UTF-8 files are not scanned (NS-13).

Whitespace inside a token ({{ns: name }}) is trimmed before the sibling lookup. An unterminated token ({{ns: with no closing }}) is left verbatim rather than treated as a reference or an error (NS-15).

Scope: prose only (NS-24)

{{ns:name}} is a prose name reference. It is misplaced in a fenced code block, an inline code span, adjacent to a path separator (/ or ~), or in a frontmatter structured field like name:, where name-substitution would yield broken code, a broken path, or (under a prefix) a wrong identity. For code and paths, use the path tokens ({{self}}, {{tools:name}}, {{path:ref}} described in Tooling) instead of {{ns:}}.

mind review flags misplaced {{ns:}} tokens (CLI-139); init-source --template does not create them (INIT-5).

Unguarded-reference warning (NS-20 to NS-23)

A source whose items reference siblings in bare prose (no token) breaks at runtime under a prefix. mind does not guess and rewrite prose, because sibling names are often common words. Instead, when melding a source with a prefix in effect, meld scans each item’s text files for sibling names that appear outside any {{ns:}} token and warns for each item where it finds one (NS-20).

Matching is whole-word (alphanumeric, _, and - are word characters); an item’s own name is not reported against itself (NS-21). A reference whose referent is a sibling agent is not reported either, since agents keep their bare name under a prefix and so the reference does not break (NS-42). The warning is advisory and does not fail meld; it does not rewrite anything (NS-22). No warning is emitted when no prefix is in effect (NS-23).

Authoring tools

mind init-source --template rewrites bare sibling references to {{ns:}} tokens. mind review . --fix does the same for a working tree. Both are covered in Authoring a source, which also describes how init-source and review surface advisories when a prefixed source’s items reference each other in bare prose.

Claude plugin marketplaces

Claude Code ships its own plugin system: a repo can carry a .claude-plugin/plugin.json (a single plugin) or a .claude-plugin/marketplace.json (a catalog of plugins). mind reads these manifests as a discovery input, so a repo published for Claude’s plugin system melds like any other source, with no re-packaging by its author.

mind meld owner/claude-plugin-repo   # a repo with .claude-plugin/plugin.json
mind probe                           # its skills and agents show up as items
mind learn <plugin-name>:<skill>     # install one, same as any source

A marketplace is a source, not a sink

mind treats a plugin manifest strictly as a way to discover items. Discovered items go to ~/.mind/store and are symlinked into each lobe exactly like a convention- or mind.toml-discovered item. mind never writes into Claude’s plugin cache (~/.claude/plugins/cache/...), its settings.json enabledPlugins, or known_marketplaces.json. Consuming a marketplace does not turn mind into a plugin publisher: it does not emit .claude-plugin/ manifests or register anything with Claude.

This keeps everything mind gives a source: namespacing, {{ns:}} reference expansion, the broader rule/tool taxonomy, and the source-hash drift model that sync, upgrade, and introspect use.

A single plugin (plugin.json)

A plugin is a directory with .claude-plugin/plugin.json whose component directories sit at the plugin root. Claude’s layout for skills and agents is byte-for-byte mind’s convention layout, so the mapping is direct:

Plugin componentmind item
skills/<name>/SKILL.mda skill
agents/<name>.mdan agent
commands/, hooks/, .mcp.json, LSP, monitors, themes, output-stylesnot installed (no mind equivalent)

A plugin has no rules or tools component, so nothing maps to those kinds.

The projection is lossy and says so: when a plugin declares components mind cannot represent, meld prints a count of what it skipped, for example 2 hooks, 1 mcp server not installed (no mind equivalent). You are never left believing the plugin installed in full when part of it was dropped.

Naming: the plugin name is the default prefix

A plugin’s name becomes the default namespace prefix for its items, mirroring Claude’s mandatory plugin:skill naming. So a plugin named acme-tools shipping a greet skill installs as acme-tools:greet. Unlike the native system the prefix stays optional and consumer-overridable: meld --namespace <p> overrides it and meld --namespace '' clears it.

The prefix does not reach agents. An agent links under its bare frontmatter name regardless of the prefix (the harness keys agents by that name, not by the plugin scope), so two sources shipping a same-named agent collide and mind surfaces the collision rather than silently resolving it. See namespacing.

A plugin’s version and description are read as metadata (the description overrides frontmatter; the version is recorded for display). Drift and upgrade still compare source content, not the declared version, so bumping version alone is not what triggers an upgrade.

A marketplace catalog (marketplace.json)

A marketplace.json lists several plugins, each either in-repo (a path inside the catalog repo) or an external git source. This is the native analog of a mind curated super-source, so it reuses that machinery: each listed plugin becomes a sub-source.

  • An in-repo plugin is a scan root inside the catalog repo, read per the single-plugin rules above. Like a normal source’s own items, in-repo plugins are offered for install on meld.
  • An external plugin is a nested git source, melded and registered like any [discover].sources entry, tracking its own upstream commit. Like other nested sources it is registered and left available; meld --recursive extends install to the whole chain.

Each entry’s name namespaces that plugin’s items, and an entry may carry a version read as metadata. Where a marketplace entry and an in-repo plugin.json supply the same field, the entry wins (mirroring Claude’s non-strict mode, where the marketplace overrides the plugin manifest).

The post-meld probe hint and the sync re-walk apply to a marketplace exactly as they do to any super-source.

Precedence: when a plugin manifest is used

The plugin-manifest layer slots alongside the other discovery layers. A source’s own mind.toml still wins:

  • A mind.toml that declares [[items]] or [discover] kind globs is authoritative and suppresses the plugin-manifest layer, the same way it suppresses convention scanning. meld prints a note that a .claude-plugin/ manifest was found and ignored.
  • A [source]-only mind.toml (metadata, no item globs) composes: its metadata is read and the plugin manifest supplies the items.
  • With no authoritative mind.toml, a plugin manifest (if present) is authoritative for the items it declares, and convention scanning is skipped for the paths it covers.

Safety

Manifests are attacker-controlled content shipped by a melded repo and are held to the same guards as mind.toml:

  • They are parsed strictly; a malformed manifest is rejected rather than partially trusted.
  • Every path a manifest contributes (a plugin root, an in-repo plugin path, a component path, a link target) is validated by the same safe-relative-path rule as [[items]] path/link: an absolute path, a leading ~, a .. component, or a NUL byte is rejected. A melded marketplace cannot read files outside its clone or place a symlink outside a lobe.
  • An external plugin source is pinned and validated through the same path as a [discover].sources spec.
  • Names and descriptions taken from a manifest have ANSI escapes and control characters stripped before display, so catalog-controlled text cannot inject terminal sequences.

Provenance

recall --sources and the probe source view label a source whose items came from a plugin manifest with its origin (claude-plugin or claude-marketplace), so you can tell a native-plugin source from a convention or mind.toml source at a glance.

Authoring a plugin or marketplace

You don’t need a mind.toml to make a Claude plugin repo meldable: the manifest layer is enough on its own, and everything below is Claude’s own format, not something mind adds.

A single plugin. Put .claude-plugin/plugin.json at the repo root (or at a scan root) with name, and optionally version and description:

{
  "name": "acme-tools",
  "version": "1.0.0",
  "description": "Acme developer tools plugin"
}

Lay out skills/<name>/SKILL.md and agents/<name>.md next to it, same as any mind source (Source layout). commands/, hooks/, .mcp.json, and the other Claude-only component kinds are fine to keep in the repo for Claude users; mind just skips them (with a printed count) rather than erroring, so one repo layout serves both consumers. There is no plugin-level place for a rule or a tool - if you want mind users to get those, add a mind.toml with [[items]] for them; it composes with the plugin manifest as long as it stays metadata-only or covers different items (Precedence).

Pick name deliberately: it becomes every consumer’s default namespace prefix (acme-tools:greet), so treat it like a package name - short, unique enough to avoid colliding with other plugins someone might meld, and stable across releases (renaming it renames every item for existing consumers).

A marketplace catalog. Put .claude-plugin/marketplace.json at the repo root listing each plugin by name and source (a repo-relative path for an in-repo plugin, or a git URL for an external one), plus optional version / description:

{
  "name": "Acme Marketplace",
  "plugins": [
    { "name": "alpha", "source": "./plugins/alpha", "description": "Alpha plugin" },
    { "name": "beta", "source": "./plugins/beta", "description": "Beta plugin" }
  ]
}

Each in-repo entry’s source must resolve inside the repo (no .., no absolute path, no ~) or mind rejects it (Safety). An entry’s version/description override the same fields in that plugin’s own plugin.json if it has one, so a curator can relabel a plugin without editing its manifest.

Validate either shape the same way you’d validate any mind source: run mind meld <path-or-repo> against a local clone and mind probe to confirm the items and namespacing came out as expected.

Try it

Two runnable fixtures live in the repo:

The normative behavior is spec/marketplace.md (MKT-1..11).

Tools and path tokens

Some agent libraries ship helper scripts or compiled binaries that their skills and agents call at runtime. mind handles this with two mechanisms:

  • The tool kind: 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 (TOOL-1..7)

A tool is a fourth item kind alongside skill, agent, and rule. Its 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 (TOOL-3). A tool can opt in to a link with an explicit link field (TOOL-4, below).

Convention discovery (TOOL-1): 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 (TOOL-3).

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 (TOOL-4).

Namespacing (TOOL-6): 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 evolve/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.

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 (TOOL-2, TOOL-5)

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
---
keymeaning
descriptionshown in recall / probe
binthe entrypoint; what {{tools:name}} resolves to (TOOL-5)
buildper-item build command run in staging at install (HOOK-70..73)

The entrypoint resolution order is (TOOL-5):

  1. mind.toml [[items]].bin
  2. TOOL.md frontmatter bin:
  3. 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 (TOOL-7).

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 (TOOL-1). Use a per-item build when you want an isolated, rollback-safe build that runs in staging before the store swap. See Install hooks for the full hook model (HOOK-70..73).


Path-reference tokens (TOOL-10..16)

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 (TOOL-13).

Tokens expand in every text file of every item kind, including tool directories and bundled scripts (TOOL-14). Inner whitespace is trimmed ({{ path:x }} works); an unterminated token (no closing }}) is left verbatim; non-UTF-8 files are not scanned.

References resolve within the same source only: ship a tool in the same source as the items that use it (TOOL-15).

{{self}} (TOOL-10)

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}} (TOOL-12)

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:}}.

{{tools:detect}}

A name that is not a sibling tool, or a tool with no resolvable bin, is a BadReference error.

{{path:ref}} (TOOL-11)

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 (TOOL-16)

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`

After mind learn scan:

  • {{tools:detect}} expands to ~/.mind/store/tool/detect/detect.sh – the entrypoint from bin: (TOOL-5, TOOL-12).
  • {{path:tool:detect}} expands to ~/.mind/store/tool/detect – the store directory, for non-entrypoint files (TOOL-11).
  • {{self}} expands to ~/.mind/store/skill/scan – the skill’s own store directory (TOOL-10).

All three use tilde syntax so a Bash(~/.mind/store/**) permission rule covers them (TOOL-16).

Under a prefix (meld --namespace jk), {{tools:detect}} expands to ~/.mind/store/tool/jk:detect/detect.sh – no edits to the skill needed.

Within-source dependency resolution

Items in a source can reference siblings via {{ns:name}} tokens (see Namespacing). Those tokens are dependency edges. When you install a partial selection, mind follows those edges to the full transitive closure so you get a working set, not a dangling one.

What counts as a dependency

A dependency is an intra-source reference. There are two ways to declare one, and the closure that learn installs is their union.

{{ns:name}} tokens – a token appearing in the item’s text files (the whole skill directory, or the agent/rule file) names a sibling as a dependency. This is the inline form: the reference lives in the prose and is also rewritten to the effective name on install. See Namespacing for token expansion rules.

requires: frontmatter key – a top-level scalar in the item’s frontmatter (SKILL.md for a skill, the .md for an agent or rule), listing whitespace-separated intra-source refs:

---
description: My skill
requires: skill:plan agent:test
---

This is the pure-metadata form: it adds a dependency edge without any prose reference. Use it when an item needs a sibling at runtime but does not mention it in its text.

Each entry is either a qualified ref (kind:name, e.g. skill:plan) or a bare name. A bare name matches across kinds; if more than one sibling shares that bare name across different kinds, the ref is ambiguous and must be qualified. A source-qualified ref (owner/repo#name) is rejected – requires is intra-source only. An entry that resolves to no sibling (typo, unknown item, ambiguous bare name, or source-qualified ref) is a hard error at install.

Dependencies never cross sources; both {{ns:}} tokens and requires: entries are always resolved within the one source.

Partial learn pulls in the closure

When learn selects every item in a source (e.g. learn owner/repo#*), resolution is a no-op: every referent installs anyway (DEP-10). The work is for a partial selection.

Example: a source ships skill:review, agent:dev, and agent:test. review references dev via {{ns:dev}}, and dev references test via {{ns:test}}.

mind learn skill:review

mind resolves the closure – review -> dev -> test – and installs all three, dependencies first (DEP-11, DEP-21, DEP-30).

What you see before install

When the closure adds items beyond your explicit selection, mind prints the dependency tree and prompts before changing anything (DEP-31):

skill:review  [selected]
  agent:dev   [dependency]
    agent:test  [dependency]

Install these 3 items? [y/N]

Nodes already in the manifest are marked [installed] and are not re-installed (DEP-23). Cycles are shown as marked back-edges rather than expanded again (DEP-22).

--yes (or answering y) confirms without prompting. See Commands - learn for the full flag reference.

--dry-run preview

--dry-run renders the same dependency tree and lists the full closure that would be installed, then exits without installing anything (DEP-32):

mind learn --dry-run skill:review

Interactive TUI (probe)

Choosing to install an available item in mind probe shows the same dependency tree in the confirm step before applying, with the same selected / dependency / already-installed distinction. Confirming installs the whole closure in dependency-first order; declining installs nothing (DEP-40, DEP-41).

forget does not cascade

forget removes exactly the one named item. It does not automatically remove its dependencies, because a dependency may be shared by another installed item. Uninstall is always a per-item operation (DEP-50).

init-source

mind init-source [path] helps a source author prepare a repo for melding. It scaffolds a mind.toml, reports the intra-source reference graph it detects, and optionally rewrites bare sibling references into {{ns:}} tokens. It is the setup counterpart to review (which validates without changing anything).

What it does

Run mind init-source in the repo (or pass a path):

mind init-source                 # report + scaffold
mind init-source --template      # also rewrite bare sibling refs to {{ns:}}
mind init-source path/to/repo

On each run it:

  1. Discovers items exactly as melding would: convention scanning (skills/<n>/SKILL.md, agents/<n>.md, rules/<n>.md, tools/<n>/), then an authoritative mind.toml if one is present. What it reports is what melding would install.
  2. Scaffolds a mind.toml when none exists (INIT-3). The scaffold contains a [source] table with a description placeholder and a commented-out prefix. An existing mind.toml is never overwritten.
  3. Reports the intra-source dependency graph (INIT-4): for each item, the siblings it references via existing {{ns:name}} tokens, and the siblings it mentions in bare prose. Bare-prose mentions are emitted as unguarded-reference advisories in the same advisory [kind]: message format that review uses, and only when a prefix is in effect (see below).
  4. Reports duplicate-tooling advisories for any non-markdown helper file that is byte-identical across two or more items (INIT-7), in the same finding format as review. These are advisory only; --template does not fix them. Extracting a shared tool into tools/<name>/ is a structural change made by hand.

--template: rewriting bare references

With --template, init-source rewrites each bare whole-word sibling mention in item text to its {{ns:name}} token (INIT-5), writes the changed files, and reports each rewrite.

What is rewritten:

  • Bare whole-word occurrences of a sibling item’s name in prose.

What is left alone:

  • Text already inside a {{ns:}} token.
  • Names inside a fenced code block, an inline code span, a path, or a frontmatter structured field. A keyword or path component is never wrapped.

The rewrite is heuristic: a sibling’s name can be an ordinary English word, so the result should be reviewed (e.g. with git diff) before committing.

See Namespacing for how {{ns:name}} tokens work and when they are needed.

Bare-reference advisories

init-source emits unguarded-reference advisories only when an effective prefix is in force for the repo ([source].prefix in mind.toml) (INIT-9). Without a prefix, bare sibling references resolve as written at runtime, so flagging them would be noise. This matches meld and review, which also suppress this advisory on unprefixed sources.

{{ns:}}-token edges in the dependency graph and the --template rewrite are unaffected by this gate; only the advisory is gated.

Safety contract

init-source makes no network calls and does not read or write the store or any agent home (INIT-6). Without --template it is read-only except for creating an absent mind.toml. With --template it edits item files in the target repo only.

Broader workflow

init-source sets up the repo; review validates it before publishing. The full authoring workflow is in Authoring a source.