# mestiere documentation > Your team's agent skills, versioned in git and installed into every repository. Source: https://mestiere.io/llms.txt. # mestiere > mestiere installs your team's Agent Skills from a git registry into every repository, pinned and verified, for Claude Code, Kiro and other coding agents. mestiere is a command-line tool for macOS and Linux. Your team keeps its [Agent Skills](https://agentskills.io) in one git repository, a *registry*, organized by namespace. Each project installs the skills it needs, pinned to an exact registry commit, and every agent harness in the repository sees them. *Mestiere* is Italian for craft: the know-how a workshop hands from one person to the next. ## Install ```sh brew install --cask polarity-dev/tap/mestiere ``` Homebrew works on macOS and Linux. Prebuilt archives (amd64, arm64) are on every [GitHub release](https://github.com/polarity-dev/mestiere/releases), and `go install` works too. Full instructions: [Install mestiere](https://mestiere.io/install/index.md). ## Quick start with your agent The Homebrew install also gives Claude Code and Kiro mestiere's own skills globally. If you installed another way, run `mestiere add -g mestiere` once. Then ask your agent, from any repository: ```text Set up mestiere for this repo with our registry git@github.com:polarity-dev/skills.git ``` The agent runs `mestiere init`, shows you what the registry offers, installs the skills that fit the codebase and commits `skills.yaml`. Later prompts work the same way: "Are any of our skills outdated? Update them and summarize what changed", or "I want to tweak frontend-forms for this repo, keep it as our own and commit it". ## Quick start ```sh mestiere init --agents claude,kiro mestiere registry add polarity git@github.com:polarity-dev/skills.git mestiere add frontend backend/db-migrations git add skills.yaml .gitignore && git commit -m "Add team skills" ``` A teammate who clones the repository runs `mestiere sync`. Step by step: [Getting started](https://mestiere.io/docs/index.md). ## How it works 1. A registry is a git repository of skills grouped in namespaces, such as `frontend` or `backend`. 2. `mestiere add` copies skills into `.agents/skills/-/` and locks each one to a registry commit and content hash in `skills.yaml`. 3. Codex, Gemini CLI, Cursor and GitHub Copilot read `.agents/skills/` directly. Claude Code and Kiro get relative symlinks in `.claude/skills/` and `.kiro/skills/`. 4. `mestiere sync` makes any checkout match the lock; `mestiere update` moves skills to the latest registry version. ## Why mestiere - **One source of truth.** Skills live in a git registry, public or private, reviewed like any other code. - **Organized by namespace.** Install a whole namespace or a single skill. New skills in an installed namespace arrive on the next update. - **Reproducible.** Every install is locked to a registry commit and a content hash. Teammates and CI get byte-identical skills. - **Every agent at once.** Files live once in `.agents/skills/`, which Codex, Gemini CLI, Cursor and others read directly. Agents with their own folder, like Claude Code and Kiro, get symlinks to it. - **Out of your way.** Installed skills are ignored by git by default. Your own skills sit next to them untouched, and committing any skill is one command. - **Safe by construction.** mestiere replaces or deletes a folder only when it can prove the folder is an unmodified copy of a published skill. Edited skills are never overwritten silently. - **No lock-in.** Registries are plain git repositories. Installed skills are plain folders that follow the Agent Skills spec. ## Frequently asked questions ### What is mestiere? mestiere is a command-line tool that installs Agent Skills from git repositories into your projects. It works like a package manager for skills: you declare what you want in `skills.yaml`, mestiere resolves it to exact registry commits, and everyone who runs `mestiere sync` gets the same files. ### What are Agent Skills? An Agent Skill is a folder with a `SKILL.md` file, plus any scripts, references and assets it needs. Coding agents such as Claude Code, Kiro, Codex and Cursor read the skill's description and load it when a task matches. The format is described at [agentskills.io](https://agentskills.io). ### Which coding agents does mestiere support? Every agent that reads Agent Skills. Installed files live in `.agents/skills/`, the shared folder that Codex, Gemini CLI, Cursor, GitHub Copilot and others read directly. Claude Code (`.claude/skills/`) and Kiro (`.kiro/skills/`) get links to it. See [Agents](https://mestiere.io/docs/agents/index.md). ### Can I use a private skills repository? Yes. mestiere runs your system `git`, so a registry works wherever `git clone` works: SSH keys, credential helpers and `gh auth` included. In CI, give the job credentials that can read the registry. ### How do I share skills with my whole team? Commit `skills.yaml` and `.gitignore`. Teammates and CI run `mestiere sync`, which installs exactly the locked versions. In CI, `mestiere sync --frozen` fails if the file is inconsistent. See [CI](https://mestiere.io/docs/ci/index.md). ### Do I have to commit the installed skills? No. Installed skills are ignored by git by default, because `skills.yaml` is enough to reproduce them. To commit a skill anyway, run `mestiere track `. ### Will mestiere overwrite a skill I edited? No. Before replacing or deleting a folder, mestiere checks that its content matches a version published in the registry. Edited skills make `sync` stop; keep your changes with `mestiere eject `. See the [safety model](https://mestiere.io/docs/how-it-works/index.md#safety-model). ### Can my agent set up mestiere for me? Yes. mestiere ships its own skills, and the Homebrew install gives them to Claude Code and Kiro for every project. Ask "Set up mestiere for this repo with our registry " and the agent runs `init`, proposes skills and commits `skills.yaml`. See [Agents](https://mestiere.io/docs/agents/index.md#teach-your-agent-to-use-mestiere). ### Can I install skills for every project on my machine? Yes, with `-g`: `mestiere add -g -r polarity frontend` installs into `~/.agents/skills/`, linked for your agents, with the manifest in `~/.config/mestiere/skills.yaml`. Prefer project installs for skills the team relies on, because only a committed `skills.yaml` gives teammates and CI the same versions. See [Global skills](https://mestiere.io/docs/global-skills/index.md). ### How do I update skills? `mestiere outdated` lists skills whose content changed in the registry. `mestiere update` moves all of them to the latest version, or only the targets you name. See [How updates work](https://mestiere.io/docs/how-it-works/index.md#how-updates-work). ### Does mestiere work on Windows? Not yet. macOS and Linux on amd64 and arm64 are supported; Windows support is on the roadmap. --- # Install mestiere > Install the mestiere CLI on macOS or Linux with Homebrew, a prebuilt release or go install, give your agents its skills, and set up completions. mestiere is a single static binary for macOS and Linux, on amd64 and arm64. ## Requirements - macOS or Linux. Windows isn't supported yet. - `git` on your `PATH`. mestiere uses your existing git setup (SSH agent, credential helpers, `gh auth`), so private registries work wherever `git clone` does. ## Install with Homebrew On macOS and Linux: ```sh brew install --cask polarity-dev/tap/mestiere ``` The cask also installs mestiere's own skills globally (`mestiere add -g mestiere`), so Claude Code and Kiro can set mestiere up in any repository: see [Agents](https://mestiere.io/docs/agents/index.md#teach-your-agent-to-use-mestiere). On macOS it clears Gatekeeper's quarantine flag, because the binaries aren't notarized yet. ## Install from a release Prebuilt archives are attached to every [GitHub release](https://github.com/polarity-dev/mestiere/releases). This detects your system, downloads the latest archive and installs the binary in `/usr/local/bin`: ```sh OS=$(uname -s | tr '[:upper:]' '[:lower:]') ARCH=$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/') curl -fsSL "https://github.com/polarity-dev/mestiere/releases/latest/download/mestiere_${OS}_${ARCH}.tar.gz" | tar -xz mestiere sudo mv mestiere /usr/local/bin/ ``` Archives have the same name in every release, so `releases/latest/download/` always serves the newest one: | System | Archive | |---|---| | macOS, Apple silicon | `mestiere_darwin_arm64.tar.gz` | | macOS, Intel | `mestiere_darwin_amd64.tar.gz` | | Linux, x86-64 | `mestiere_linux_amd64.tar.gz` | | Linux, ARM64 | `mestiere_linux_arm64.tar.gz` | For a specific version, replace `releases/latest/download/` with `releases/download/v/`. To install without `sudo`, move the binary to any folder on your `PATH` instead, such as `~/.local/bin`. ### Verify the download Each release has a `checksums.txt` with the SHA-256 of every archive: ```sh BASE="https://github.com/polarity-dev/mestiere/releases/latest/download" FILE="mestiere_${OS}_${ARCH}.tar.gz" curl -fsSLO "$BASE/$FILE" && curl -fsSLO "$BASE/checksums.txt" grep " $FILE\$" checksums.txt | shasum -a 256 -c - ``` ### macOS Gatekeeper Binaries aren't notarized by Apple yet. A download made with `curl` runs as is. If you downloaded the archive with a browser, macOS blocks the binary; clear the flag with: ```sh xattr -d com.apple.quarantine mestiere ``` ## Install with Go With Go 1.27.3 or later: ```sh go install github.com/polarity-dev/mestiere/cmd/mestiere@latest ``` The binary goes to `$(go env GOPATH)/bin`; make sure that folder is on your `PATH`. ## Give your agents mestiere's skills The Homebrew install does this for you. After a release or `go install`, run once: ```sh mestiere add -g mestiere ``` This installs the `mestiere-project` and `mestiere-registry` skills for every project on your machine, in `~/.agents/skills/`, with links for the agents that have a folder in your home directory. See [Global skills](https://mestiere.io/docs/global-skills/index.md). ## Check the installation ```sh mestiere --version ``` ## Shell completions mestiere generates completions for bash, zsh and fish: ```sh # bash echo 'source <(mestiere completion bash)' >> ~/.bashrc # zsh (with compinit enabled) mestiere completion zsh > "${fpath[1]}/_mestiere" # fish mestiere completion fish > ~/.config/fish/completions/mestiere.fish ``` Run `mestiere completion --help` for other setups. ## Upgrade ```sh brew upgrade --cask mestiere ``` The cask also updates mestiere's own global skills. With a release, run the install again: it always downloads the latest version. With Go, run `go install ...@latest`. Then run `mestiere update -g mestiere`. Projects don't depend on the mestiere version: `skills.yaml` stays the same. ## Uninstall ```sh mestiere remove -g mestiere # remove mestiere's global skills first mestiere cache clean # optional: remove the registry cache brew uninstall --cask mestiere # or: sudo rm /usr/local/bin/mestiere ``` The cache lives in `~/Library/Caches/mestiere` on macOS and `~/.cache/mestiere` on Linux. Projects keep their `skills.yaml` and installed skills. ## Next steps - [Getting started](https://mestiere.io/docs/index.md): install your first skills in a project. - [Registries](https://mestiere.io/docs/registries/index.md): publish your team's skills. - [Teach your agent to use mestiere](https://mestiere.io/docs/agents/index.md#teach-your-agent-to-use-mestiere). --- # Getting started > Set up mestiere in a repository, add a skills registry, install namespaces or single skills, and share them with teammates and CI. This guide installs skills from a registry into a project and shares them with your team. It assumes mestiere is [installed](https://mestiere.io/install/index.md) and you can `git clone` the registry. > Prefer to let your agent do it? With mestiere's skills installed (the Homebrew install adds them), ask "Set up mestiere for this repo with our registry ". The agent runs the same steps below and asks you which skills to install. See [Agents](https://mestiere.io/docs/agents/index.md#teach-your-agent-to-use-mestiere). ## 1. Initialize the project In the root of your repository: ```sh mestiere init --agents claude,kiro ``` This creates `skills.yaml` and adds one rule to `.gitignore` so installed skills stay out of git. `--agents` picks the harnesses that receive the skills: `claude`, `kiro`, or both. Without the flag, `init` asks. ## 2. Add a registry A registry is a git repository of skills. Give it a short name and its git URL: ```sh mestiere registry add polarity git@github.com:polarity-dev/skills.git ``` mestiere follows the registry's default branch. Use `--ref` for a branch, tag or commit, e.g. `--ref v2026.10`. Check access first with `git ls-remote ` if you're unsure. ## 3. See what it offers ```sh mestiere registry show polarity ``` This lists every namespace and skill with its description, and marks what's already installed. ## 4. Install skills ```sh mestiere add frontend # a whole namespace mestiere add backend/db-migrations # a single skill ``` - A **namespace** install follows the namespace: skills added to it later arrive with the next `mestiere update`. - A **skill** install brings just that skill. - With several registries configured, pick one with `-r `. - Without arguments, `add` opens an interactive picker. Each skill lands in `.agents/skills/-/`, for example `.agents/skills/frontend-forms/`, and each agent gets a relative link to it: ``` .agents/skills/frontend-forms/ # real files .claude/skills/frontend-forms -> ../../.agents/skills/frontend-forms .kiro/skills/frontend-forms -> ../../.agents/skills/frontend-forms ``` ## 5. Commit and share ```sh git add skills.yaml .gitignore git commit -m "Add team skills" ``` `skills.yaml` now holds both what you asked for and the exact registry commit of every skill. A teammate who clones the repository runs: ```sh mestiere sync ``` Run `mestiere sync` again after a pull or a branch switch. In CI, use `mestiere sync --frozen`: see [CI](https://mestiere.io/docs/ci/index.md). ## Keep skills up to date ```sh mestiere outdated # skills whose content changed in the registry mestiere update # move everything to the latest version mestiere update frontend # or only some targets ``` Commit `skills.yaml` afterwards. A new registry commit that doesn't touch a skill isn't reported. Details: [How updates work](https://mestiere.io/docs/how-it-works/index.md#how-updates-work). ## Remove skills ```sh mestiere remove backend/db-migrations ``` Removing one skill of an installed namespace adds it to `exclude` instead, so the rest of the namespace stays. Skills with local changes are kept and reported. ## Your own skills mestiere manages only the skills listed in the lock. Anything else in a skills folder is yours: it's never modified, moved or deleted. - **Write a skill** directly in `.agents/skills/`, `.claude/skills/` or `.kiro/skills/`, then run `mestiere track ` to commit it. - **Customize a registry skill** with `mestiere eject `. The files stay where they are and mestiere stops updating them. Add `--track` to commit it. - **Find uncommitted local skills** with `mestiere status`. They're ignored by default, so this catches a skill your teammates would never get. ## Skills for every project Add `-g` to install skills for your whole machine instead of one repository, for example `mestiere add -g -r polarity frontend`. Prefer project installs for skills a team relies on. See [Global skills](https://mestiere.io/docs/global-skills/index.md). ## Check the project ```sh mestiere status # installed skills, their links, local and global skills mestiere doctor # everything, without changing anything ``` `status` also works in a folder without `skills.yaml`: it lists the skills already there and the global ones. `doctor` exits with an error on drift, broken links or inconsistent files and says how to fix each problem. ## Next steps - [skills.yaml reference](https://mestiere.io/docs/skills-yaml/index.md): every setting, the lock, and `.gitignore`. - [Command reference](https://mestiere.io/docs/commands/index.md): every command and flag. - [Registries](https://mestiere.io/docs/registries/index.md): publish your own skills. - [Global skills](https://mestiere.io/docs/global-skills/index.md): skills for every project on your machine. --- # skills.yaml reference > Reference for skills.yaml, the mestiere project file that lists agents, registries, installed namespaces and skills, exclusions and the lock. `skills.yaml` sits at the root of the project. One file holds both what you asked for and what got resolved. [Global skills](https://mestiere.io/docs/global-skills/index.md) use the same format in `~/.config/mestiere/skills.yaml`. ## Example ```yaml version: 1 agents: - claude - kiro registries: polarity: url: git@github.com:polarity-dev/skills.git ref: main # branch, tag or commit; defaults to the registry's default branch install: - frontend # whole namespace - backend/db-migrations # single skill exclude: - frontend/legacy-forms # skip one skill of an installed namespace lock: # written by mestiere frontend-forms: path: skills/frontend/forms commit: 3f2a9c1e... tree: 9be1d07a... ``` ## Keys | Key | Edited by | Meaning | |---|---|---| | `version` | mestiere | File format version. Always `1`. | | `agents` | you | Harnesses that get links: `claude`, `kiro`. `.agents/skills/` is always used. | | `registries..url` | you | Git URL of the registry: SSH, HTTPS or a local path. | | `registries..ref` | you | Branch, tag or commit to follow. Defaults to the registry's default branch. | | `registries..install` | you | Namespaces (`frontend`) and skills (`backend/db-migrations`) to install. | | `registries..exclude` | you | Skills of an installed namespace to skip. | | `registries..lock` | mestiere | Resolved skills: registry path, commit and content hash. Never edit it. | | `link` | you | Optional. `copy` gives agent folders copies instead of symlinks. | | `strict` | you | Optional. `true` makes `doctor` fail on local skills that aren't committed. | mestiere preserves your comments and key order when it rewrites the file. After editing `install`, `exclude` or `agents` by hand, run `mestiere sync`. ## The lock Each entry under `lock` is keyed by the installed name, `-`: - `path`: where the skill lives in the registry. - `commit`: the registry commit it was resolved at. - `tree`: the git tree ID of the installed folder. It changes only when that skill's content changes, which is how `outdated` ignores commits that don't touch a skill. `add` and `update` write the lock. `sync` installs exactly what it says. ## Pinning a project Follow a tag or a commit instead of a branch: ```yaml registries: polarity: url: git@github.com:polarity-dev/skills.git ref: v2026.10 ``` Registry authors don't need to tag versions: every install is already locked to a commit. ## Installed layout ``` .agents/skills/frontend-forms/ # real files .claude/skills/frontend-forms -> ../../.agents/skills/frontend-forms .kiro/skills/frontend-forms -> ../../.agents/skills/frontend-forms ``` Links are relative, so they keep working when the repository moves. With `link: copy`, agent folders get copies instead. ## .gitignore `mestiere init` adds one rule, and only if your existing rules don't already cover skill folders: ```gitignore **/.*/skills/* ``` It ignores every skill folder inside any hidden directory, nested packages included, but leaves files like `.claude/settings.json` alone. A single exception line commits a whole skill: ```gitignore !.claude/skills/my-skill ``` `mestiere track ` and `mestiere untrack ` add and remove these lines for every folder the skill appears in. Writing them by hand works just as well. --- # Registries > Create a git registry of Agent Skills with mestiere, organize it in namespaces, share files between skills, and validate it with registry lint. A registry is a git repository of skills that projects install from. It can be public or private, and needs no server: mestiere reads it with `git`. ## Create a registry ```sh mkdir skills && cd skills && git init mestiere registry init --name polarity --description "Polarity's team skills" mestiere registry new-namespace frontend --description "Frontend practices" --owners web-team mestiere registry new-skill frontend/forms --description "Build accessible forms" mestiere registry lint ``` Commit and push. Projects add it with `mestiere registry add polarity `. ## Layout ``` skills/ # registry repository ├── registry.yaml # schemaVersion, name, description └── skills/ ├── frontend/ │ ├── namespace.yaml # description, owners │ ├── _shared/ # files several skills link to │ │ ├── scripts/lint-a11y.sh │ │ └── references/design-tokens.md │ ├── forms/ │ │ ├── SKILL.md # name: frontend-forms │ │ ├── references/ │ │ │ └── design-tokens.md -> ../../_shared/references/design-tokens.md │ │ └── scripts/ │ │ └── lint-a11y.sh -> ../../_shared/scripts/lint-a11y.sh │ └── tables/ │ ├── SKILL.md │ └── scripts -> ../_shared/scripts └── backend/ └── db-migrations/ ├── SKILL.md └── scripts/migrate.sh ``` ## Naming rules - **Namespaces** use lowercase letters and digits only, no hyphens: `frontend`, `payments`, `infra2`. Choose them by domain or team. - **Skills** use lowercase letters, digits and single hyphens: `forms`, `db-migrations`. - The **installed name** is `-`, e.g. `frontend-forms`, at most 64 characters. Because namespaces have no hyphens, the mapping always works both ways. ## Writing SKILL.md `new-skill` generates a `SKILL.md` with frontmatter. Then: - Keep the generated `name`: it must equal the installed name, `-`. - Write a `description` of 1 to 1024 characters. It decides when an agent activates the skill: say what the skill does and when to use it, with the words a user would actually say. - Keep `SKILL.md` focused. Move long material into `references/` and link to it by relative path. - Refer to bundled files by paths relative to the skill folder, e.g. `scripts/check.sh`. - Make scripts executable (`chmod +x`) and give them a shebang. ## Sharing files between skills Put a file in the namespace's `_shared/` folder and link it from each skill with a relative symlink, to a single file or to a whole folder: ```sh cd skills/frontend/forms mkdir -p scripts ln -s ../../_shared/scripts/lint-a11y.sh scripts/lint-a11y.sh # one file ln -s ../_shared/references references # a whole folder ``` On install, mestiere replaces each link with a real copy of its target. Every installed skill is self-contained, and its `SKILL.md` keeps using paths like `scripts/lint-a11y.sh`. When a shared file changes, only the skills that link to it are reported as updated. Links may only point inside the skill or into the same namespace's `_shared/`. Files inside `_shared/` must be real files, not links. ## What lint checks `mestiere registry lint` fails on any `error:` line: - Namespace, skill and installed names follow the naming rules. - `SKILL.md` has frontmatter whose `name` equals the installed name, and a description of 1 to 1024 characters. - Links stay inside the skill or point into the same namespace's `_shared/`, and links into `_shared/` reach a real file. - Skills and `_shared/` contain no hidden files. Hidden files are skipped when installed copies are compared with the registry, so a published hidden file could never match. Shared files that no skill links to produce a warning, which doesn't fail lint. | Error | Fix | |---|---| | `name must be "-"` | Set the frontmatter `name` to the installed name | | `invalid namespace` / `invalid skill name` | Rename the folder to match the naming rules | | `hidden files aren't installed` | Delete the file, or rename it without the leading dot (`.env.example` → `env.example`) | | `links outside the skill and skills//_shared/` | Move the target into `_shared/` and link it from there | | `which is itself a link` / `links aren't allowed inside _shared` | Replace the link in `_shared/` with the real file | ## Test a skill before publishing From a project, add your local checkout as a registry and install from it. Only committed content is installed, so commit on a branch first: ```sh mestiere registry add local /path/to/registry --ref my-branch mestiere add frontend/forms mestiere registry remove local ``` ## Renaming and removing skills - Projects that installed the whole namespace drop a removed skill on their next `mestiere update`. - Projects that installed the skill individually get an error and must remove it, so announce removals. - A rename is a removal plus an addition. ## Run lint in CI ```yaml - uses: actions/setup-go@v7 with: go-version: stable - run: go install github.com/polarity-dev/mestiere/cmd/mestiere@latest - run: mestiere registry lint ``` More CI setups: [CI](https://mestiere.io/docs/ci/index.md). --- # Agents > How mestiere installs Agent Skills for Claude Code, Kiro, Codex, Cursor and other agents, how to use copies, and how to let your agent set it up. An agent, or harness, is a coding tool that reads skills. mestiere stores every installed skill once in `.agents/skills/`, the shared folder that Codex, Gemini CLI, Cursor, GitHub Copilot and other agents read directly. Agents with their own folder, like Claude Code and Kiro, get links to it. ## Supported agents | Agent | ID | Skills folder | |---|---|---| | All (canonical store) | `agents` (always on) | `.agents/skills/` | | Claude Code | `claude` | `.claude/skills/` | | Kiro | `kiro` | `.kiro/skills/` | Codex, Gemini CLI, Cursor, GitHub Copilot and any other harness that reads `.agents/skills/` see installed skills without any extra setting, so they need no entry in `agents`. ## Change the agents of a project Edit `agents` in `skills.yaml`, then sync: ```yaml agents: - claude - kiro ``` ```sh mestiere sync ``` `sync` adds links for new agents and removes them for agents you dropped. To choose at setup time, pass `mestiere init --agents claude,kiro`. ## Symlinks or copies By default each agent folder gets a relative symlink to `.agents/skills/`. If a tool doesn't follow symlinks, give agent folders real copies: ```yaml link: copy ``` Or choose it at setup with `mestiere init --link copy`. ## Teach your agent to use mestiere The mestiere repository is also a registry. It ships two skills that teach coding agents to run mestiere correctly, including setting it up in a new repository: | Skill | For | |---|---| | `mestiere/project` | Repositories that install skills: adding, updating, syncing, ejecting, committing, fixing `doctor` errors | | `mestiere/registry` | Registry repositories: scaffolding, writing `SKILL.md`, sharing files through `_shared/`, fixing lint errors, CI | They're installed globally, for every project on your machine. The Homebrew install already does it; otherwise run once: ```sh mestiere add -g mestiere ``` Teammates whose agent lacks them run the same command. Then ask your agent, from any repository: ```text Set up mestiere for this repo with our registry git@github.com:polarity-dev/skills.git ``` The agent runs `mestiere init`, shows you what the registry offers, installs the skills that fit the codebase and commits `skills.yaml`. Later prompts work the same way: - "Are any of our skills outdated? Update them and summarize what changed." - "I want to tweak frontend-forms for this repo, keep it as our own and commit it." - "Why does mestiere doctor fail?" ## Reading these docs from an agent Every page of this site has a Markdown version at the same URL plus `index.md`, for example [/docs/commands/index.md](https://mestiere.io/docs/commands/index.md). [llms.txt](https://mestiere.io/llms.txt) lists them all, and [llms-full.txt](https://mestiere.io/llms-full.txt) holds the whole documentation in one file. --- # Global skills > Install Agent Skills for every project on your machine with mestiere -g: where files and the manifest go, which commands apply, and when to prefer a project. Global skills are installed once for your whole machine instead of one repository. Agents load them in every project. Add `-g` to a command to act on them: ```sh mestiere add -g mestiere # mestiere's own skills; the Homebrew install runs this mestiere registry add -g polarity git@github.com:polarity-dev/skills.git mestiere add -g -r polarity frontend mestiere status -g ``` ## Where things go | What | Where | |---|---| | Manifest | `~/.config/mestiere/skills.yaml`, or `$XDG_CONFIG_HOME/mestiere/skills.yaml` | | Skill files | `~/.agents/skills/-/` | | Links | `~/.claude/skills/`, `~/.kiro/skills/`, for the agents that have a folder in your home directory | The manifest has the same format as a project's [skills.yaml](https://mestiere.io/docs/skills-yaml/index.md), with its `install`, `exclude` and lock. A new global manifest comes with the `mestiere` registry already configured, so `mestiere add -g mestiere` works without `registry add`. If none of the agents has a folder in your home directory yet, mestiere links all of them. Otherwise it creates no folders for agents you don't use. ## Commands These commands accept `-g`: `add`, `remove`, `update`, `outdated`, `sync`, `status`, `doctor`, `eject` and the `registry` subcommands. They work exactly as in a project, with the same [safety model](https://mestiere.io/docs/how-it-works/index.md#safety-model): a global skill you edited is never overwritten. `init`, `track`, `untrack` and `eject --track` don't apply, because nothing global is in git. ## mestiere's own skills `mestiere add -g mestiere` installs `mestiere-project` and `mestiere-registry`, which teach your agent to set up and run mestiere in any repository. The Homebrew install does it for you and keeps them updated on `brew upgrade`. See [Agents](https://mestiere.io/docs/agents/index.md#teach-your-agent-to-use-mestiere). To remove them, for example before uninstalling: ```sh mestiere remove -g mestiere ``` ## Seeing global skills from a project `mestiere status` in a project also lists the skills in `~/.agents/skills`, `~/.claude/skills` and `~/.kiro/skills`, global or not, because agents load them there too. It works in folders without a `skills.yaml` as well. ## Global or project? Prefer project installs for skills a team relies on. They're locked in a committed `skills.yaml`, so teammates and CI get the same versions. Global skills are per machine: use them for personal skills and for tools like mestiere's own skills. --- # Command reference > Every mestiere command with its arguments, flags and examples: init, registry, add, remove, sync, update, outdated, status, track, eject, doctor and cache. Run `mestiere --help` for the same information in your terminal. ## Global flags | Flag | Effect | |---|---| | `-C, --dir ` | Run as if started in `` | | `-q, --quiet` | Only print warnings and errors | | `-g, --global` | Act on the skills installed for every project, in your home directory. See [Global skills](https://mestiere.io/docs/global-skills/index.md). | | `--version` | Print the mestiere version | | `-h, --help` | Help for any command | ## Targets Commands that take skills accept several forms: | Form | Means | |---|---| | `frontend` | The `frontend` namespace | | `frontend/forms` | The `forms` skill of `frontend` | | `frontend-forms` | The same skill, by installed name | | `polarity:frontend` | `frontend` from the `polarity` registry | ## Exit status Commands exit non-zero on any `error:` line. `warning:` and `hint:` lines don't fail the command. ## Project setup ### mestiere init Create `skills.yaml` and the `.gitignore` rule in the current project. ```sh mestiere init --agents claude,kiro ``` | Flag | Effect | |---|---| | `--agents ` | Comma-separated agents: `claude`, `kiro`. Asks when omitted in a terminal. | | `--link ` | How agents get skills: `symlink` (default) or `copy` | ## Registries ### mestiere registry add Add a registry to the project. ```sh mestiere registry add [--ref ] mestiere registry add polarity git@github.com:polarity-dev/skills.git --ref main ``` `--ref` defaults to the registry's default branch. ### mestiere registry remove Uninstall the registry's skills and drop it from `skills.yaml`. ```sh mestiere registry remove [--force] ``` `--force` also deletes skills with local changes. ### mestiere registry list List the project's registries. ### mestiere registry show List the namespaces and skills a registry offers, with descriptions and install state. ```sh mestiere registry show [name] ``` ## Installing and removing ### mestiere add Install namespaces or skills. ```sh mestiere add ... [-r ] [--force] mestiere add frontend mestiere add backend/db-migrations -r polarity ``` | Flag | Effect | |---|---| | `-r, --registry ` | Registry to install from; required when several are configured | | `--force` | Overwrite existing folders with the same name | Without arguments, `add` opens an interactive picker. ### mestiere remove Uninstall namespaces or skills. ```sh mestiere remove ... [--force] ``` Removing one skill of an installed namespace adds it to `exclude` instead. Modified skills are kept and reported as local skills unless you pass `--force`. ## Syncing and updating ### mestiere sync Make the skill folders match the lock in `skills.yaml`. Run it after a clone, a pull, a branch switch or a hand edit. ```sh mestiere sync [--frozen] [--force] [--dry-run] ``` | Flag | Effect | |---|---| | `--frozen` | Fail if `install` and `lock` disagree instead of re-resolving. Use in CI. | | `--force` | Overwrite local changes | | `--dry-run` | Print what would change | ### mestiere update Move locked skills to the latest version of their ref. Without targets, everything is updated. Updating a namespace also picks up skills added to it and drops skills deleted from it. ```sh mestiere update [target]... [--force] mestiere update frontend polarity:backend ``` ### mestiere outdated Show skills whose content changed in their registry. A commit that doesn't touch a skill isn't reported. ## Inspecting ### mestiere status Show installed skills, their links, local skills (including the ones that aren't committed) and global skills from `~/.agents/skills`, `~/.claude/skills` and `~/.kiro/skills`. In a folder without `skills.yaml` it lists the skills already there. ### mestiere doctor Check the project without changing anything: lock consistency, local changes, links, `.gitignore` and registry access. ```sh mestiere doctor [--strict] [--offline] ``` | Flag | Effect | |---|---| | `--strict` | Also fail on local skills that aren't committed | | `--offline` | Skip network checks | Common errors and their fixes: | Message | Fix | |---|---| | `has local changes` | Keep them with `mestiere eject `, or discard them with `mestiere sync --force` | | `install and lock disagree` | Run `mestiere sync` and commit `skills.yaml` | | `already exists and isn't a published version` | A local skill has the same name: rename it, or overwrite it with `--force` | | `comes from both and ` | Add the skill to `exclude` in one of the registries | | `isn't reachable` | A git access problem: check your credentials for that URL | | `is committed but ignored` | `git rm -r --cached `, or `mestiere track ` to keep committing it | ## Your own skills ### mestiere track Commit a skill by adding `.gitignore` exceptions for every folder it appears in. ```sh mestiere track ... ``` ### mestiere untrack Remove a skill's `.gitignore` exceptions. ```sh mestiere untrack ... ``` ### mestiere eject Keep an installed skill as your own. The files stay; mestiere stops managing them and excludes the skill from future installs of its namespace. ```sh mestiere eject ... [--track] ``` `--track` also commits the ejected skills. It doesn't apply with `-g`. ## Global skills With `-g`, these commands act on the skills for every project on your machine instead of the current repository: `add`, `remove`, `update`, `outdated`, `sync`, `status`, `doctor`, `eject` and the `registry` subcommands. ```sh mestiere add -g mestiere mestiere registry add -g polarity git@github.com:polarity-dev/skills.git mestiere add -g -r polarity frontend mestiere status -g ``` `init`, `track` and `untrack` don't apply: nothing global is in git. Where files and the manifest go: [Global skills](https://mestiere.io/docs/global-skills/index.md). ## Cache ### mestiere cache Inspect or clear the registry cache: one bare git mirror per registry. ```sh mestiere cache dir # print the cache directory mestiere cache info # show the directory and its size mestiere cache clean # delete all mirrors; they are re-fetched when needed ``` The location is configurable: see [Configuration](https://mestiere.io/docs/ci/index.md#configuration). ## Registry authoring ### mestiere registry init Scaffold a new registry repository. ```sh mestiere registry init [dir] [--name ] [--description ] ``` `--name` defaults to the directory name. ### mestiere registry new-namespace ```sh mestiere registry new-namespace [--description ] [--owners ] ``` ### mestiere registry new-skill Create a skill with a `SKILL.md` template. ```sh mestiere registry new-skill / [--description ] ``` ### mestiere registry lint Check a registry against the naming and `SKILL.md` rules. Run it in the registry's CI. ```sh mestiere registry lint [dir] ``` See [what lint checks](https://mestiere.io/docs/registries/index.md#what-lint-checks). ## Shell completions ```sh mestiere completion bash|zsh|fish ``` Setup instructions: [Install](https://mestiere.io/install/index.md#shell-completions). --- # How it works > How mestiere locks skills to registry commits, detects updates per skill with git tree hashes, and never overwrites a skill you edited. ## How updates work mestiere locks each skill to a registry commit, the same way package lockfiles do. Registry authors don't need to tag versions. - `add` resolves the registry's `ref` and locks the new skills at that commit. - `outdated` fetches the registry and lists skills whose content changed. A new commit that doesn't touch a skill isn't reported. - `update` moves the lock forward, for everything or only for the targets you name. Updating a namespace also picks up skills added to it and drops skills deleted from it. - `sync` installs exactly what the lock says. `sync --frozen` fails if `install` and `lock` disagree, which is what CI should run. Pin a whole project with `ref: v2026.10` (a tag) or a commit ID. ## Safety model The lock is the only state mestiere keeps. There's no hidden database or marker file to get out of sync. Before replacing or deleting a folder, mestiere checks the folder itself: 1. It computes the git tree hash of the folder on disk, skipping hidden files such as `.DS_Store` and editor swap files. 2. It looks up the registry skill that matches the folder's name, and every version that skill has had in the registry's history. 3. Only if the hash matches one of those versions is the folder an untouched install, and only then is it safe to replace or remove. For each folder in a skills directory: - **Listed in the lock, hash matches the locked version:** nothing to do. - **Listed in the lock, hash matches an older published version:** upgraded to the locked version. - **Listed in the lock, hash matches no published version:** `sync` stops. The folder has local changes; use `--force` or `eject`. - **Not in the lock, name and content match a published skill:** removed, because it was dropped from `skills.yaml`. - **Not in the lock, anything else:** left alone. It's your skill. `--force` is always an explicit choice. The same check makes routine team workflows work without extra steps: | Situation | Result | |---|---| | A teammate updates a skill; you pull and run `sync` | Your older, unmodified copy is upgraded | | A teammate removes a skill; you pull and run `sync` | The leftover folder is removed | | You edited an installed skill | `sync` stops and suggests `--force` or `eject` | | You copied a skill to make your own | The copy is never touched | | Offline, with a cached registry | `sync` installs from the cache | ## Architecture - **Registry (git):** `skills///SKILL.md` and `skills//_shared/`. - **Local cache:** one bare git mirror per registry, filled with `git fetch`. - **Project:** `skills.yaml` (install and lock), `.agents/skills/-/` with the real files, and symlinks from `.claude/skills/` and `.kiro/skills/`. `add` and `update` resolve `install` against the registry mirror and write `lock`. `sync` compares the lock with the skill folders on disk and applies only the steps it can prove are safe: install, upgrade, link, unlink, remove. ## Design decisions - **The system `git` binary, not a Go git library,** so authentication works exactly as it does for your own `git`. - **Git tree hashes as content identity.** A skill's identity is the tree ID of its installed folder, so changes are detected per skill. For skills without shared links it's the registry's own tree ID. - **History as proof of ownership.** Ownership is never recorded in a state file. It's decided by whether a folder's content was ever published. - **Flat installs, namespaced registries.** Harnesses discover skills one level deep, so namespaces exist in the registry and in the installed names, not as folders. - **Writes go through a temporary sibling folder,** which is then renamed into place, so an interrupted run never leaves a half-written skill. --- # CI and configuration > Check agent skills in CI with mestiere sync --frozen and doctor --strict, give CI access to private registries, and configure the registry cache. ## Check a project in CI Two commands catch every inconsistency: ```yaml - run: mestiere sync --frozen # fail if skills.yaml is inconsistent - run: mestiere doctor --strict # fail on drift, broken links or uncommitted local skills ``` ## GitHub Actions example ```yaml name: skills on: pull_request: push: branches: [main] jobs: skills: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: actions/setup-go@v7 with: go-version: stable - run: go install github.com/polarity-dev/mestiere/cmd/mestiere@latest - run: mestiere sync --frozen - run: mestiere doctor --strict ``` To skip the Go toolchain, download a release archive instead: see [Install](https://mestiere.io/install/index.md#install-from-a-release). ## Private registries mestiere uses whatever git is configured with. Give the CI job credentials that can read each registry, for example: - an SSH deploy key loaded into `ssh-agent`, for `git@` URLs; - a token in a git credential helper, or a URL rewrite such as `git config --global url."https://x-access-token:${TOKEN}@github.com/".insteadOf "https://github.com/"`, for HTTPS URLs. Check access with `git ls-remote ` in the same job. `mestiere doctor` reports a registry it can't reach as `isn't reachable`. ## Check a registry in CI In a registry repository, run lint on every pull request: ```yaml - run: mestiere registry lint ``` See [what lint checks](https://mestiere.io/docs/registries/index.md#what-lint-checks). ## Configuration mestiere has no config file of its own: a project is configured in [skills.yaml](https://mestiere.io/docs/skills-yaml/index.md), global skills in `~/.config/mestiere/skills.yaml`. Environment variables control where files go: | Variable | Effect | |---|---| | `MESTIERE_CACHE_DIR` | Cache location (highest precedence) | | `XDG_CACHE_HOME` | Cache goes to `$XDG_CACHE_HOME/mestiere`, honored on macOS too | | `XDG_CONFIG_HOME` | The [global](https://mestiere.io/docs/global-skills/index.md) manifest goes to `$XDG_CONFIG_HOME/mestiere/skills.yaml` instead of `~/.config/mestiere/skills.yaml` | By default the cache is `~/Library/Caches/mestiere` on macOS and `~/.cache/mestiere` on Linux. It holds one bare mirror per registry and is safe to delete: `mestiere cache clean` removes it, and the next command re-fetches what it needs. In CI, cache that folder between runs to save fetches.