Add a custom skill

Extend Cantrip's knowledge with your own charm-building skills — no recompile, no config edits, just a Markdown file in the right place.

What a skill is

A skill is a focused Markdown document that teaches Cantrip how to accomplish one charm-building task — how to write Scenario tests, how to set up ingress, how to migrate from Harness. The bundled set ships with Cantrip; the body loads on demand when the agent needs it.

The same directory format is used by Claude Code, gh skill, Cursor, Codex, Gemini CLI, and Windsurf — so a skill authored for any of those tools works with Cantrip without translation.

Where Cantrip looks

Cantrip discovers skills at startup from these places, in order of most-sharedmost-specific. Later directories override earlier ones on name conflict, so the most specific copy wins. Missing directories are silently skipped — every external directory is optional.

User scope:

  1. Bundled skills inside the Cantrip package. You don't touch these.
  2. ~/.config/agents/skills/ — the "universal" user-scope bucket gh skill install --scope user writes into when no agent is named; also shared by several individual agents (opencode, kimi-cli, warp, replit).
  3. ~/.claude/skills/ — shared with Claude Code. Also the Claude Code user-scope dir for gh skill install --agent claude-code --scope user.
  4. ~/.config/cantrip/skills/ — Cantrip-specific. Use this when you want a skill that only Cantrip should see.

Project scope (when Cantrip runs inside a charm directory — it uses the charm path as the project root):

  1. <charm>/.agents/skills/ — the shared project-scope bucket gh skill install writes into by default (no --scope).
  2. <charm>/.claude/skills/ — Claude Code's project-scope dir.

Project-scope skills win over every user-scope skill with the same name, so a repo-local copy always trumps a shared one. Cantrip logs an overrides message at INFO level when a later directory shadows an earlier one so the precedence is auditable.

Installing skills with gh skill install

Cantrip automatically picks up skills installed via GitHub CLI's gh skill install (released in gh v2.90). The command writes to whichever directory the target agent reads from — there is no separate "gh skill" directory. The two recommended combinations for Cantrip users:

# Project-scope (default) — installs into <charm>/.agents/skills/
cd ~/charms/my-charm
gh skill install microsoft/skills/harness-migration

# User-scope — installs into ~/.claude/skills/
gh skill install microsoft/skills/harness-migration \
  --agent claude-code --scope user

Restart Cantrip. The installed skill appears in index.format_for_prompt() and can be loaded with load_skill("<name>") the next time the agent needs it.

Use gh skill list to see what's installed and where; use gh skill update to pull new versions.

Skill format

Two layouts are accepted:

Both start with YAML frontmatter:

---
name: my-skill
description: A one-line summary shown in the skill index.
tools:
  - juju_status
  - read_file
---

# My skill

The body is Markdown. Cantrip loads it on demand when the
agent decides this skill is relevant to the task at hand.

Example: a reminder about your team's charm conventions

mkdir -p ~/.config/cantrip/skills
cat > ~/.config/cantrip/skills/team-conventions.md <<'EOF'
---
name: team-conventions
description: Coding and review conventions for charms owned by the platform team.
---

# Team conventions

- All charms use `ops[testing]` (Scenario) for unit tests,
  never Harness.
- Integration tests live in `tests/integration/` and use
  Jubilant.
- New charms must include `ops-tracing` from the start.
- Pull requests need a reviewer from the platform team
  before merging to `main`.
EOF

Restart Cantrip. The new skill appears in index.format_for_prompt() and the agent can load_skill("team-conventions") the next time it's relevant.

MCP dependencies

A skill that relies on tools from an MCP serverfilesystem, github, a custom server someone on your team set up — can declare that dependency in its frontmatter:

---
name: deploy-via-github
description: Deploys the charm by opening a PR against the
  operations repository.
mcp_servers:
  - github
---

# Deploy via GitHub

Use `mcp__github__create_pr` to…

When the agent calls load_skill("deploy-via-github"), Cantrip looks at the current session's configured MCP servers (loaded from ~/.config/cantrip/mcp.yaml and cantrip.mcp.yaml per How to use MCP servers) and, if any declared server is missing, prepends a warning banner to the returned content:

> ⚠️  This skill declares MCP server dependencies that are NOT
>    configured in the current session: github.
>    The content below may reference tools from those servers
>    that won't be available.  Configure the servers via
>    `~/.config/cantrip/mcp.yaml` or `cantrip.mcp.yaml`, or
>    adapt the workflow to skip those steps.

# Deploy via GitHub

Use `mcp__github__create_pr` to…

The skill body still loads — silently hiding a skill because a declared MCP server is missing would be worse than a visible warning the agent can reason about. The skill index the agent reads on every turn (<available_skills>…) also lists the requirement:

<skill>
  <name>deploy-via-github</name>
  <description>Deploys the charm by opening a PR…</description>
  <required_mcp_servers>github</required_mcp_servers>
</skill>

so the agent can pick a different skill when the missing server would block it.

Exporting a skill

cantrip skill export NAME PATH writes any discovered skill to a standalone SKILL.md file in the same vendor-neutral format Cantrip imports from. It works on the bundled skills as well as your own — so you can start from a bundled skill, tweak it locally under ~/.config/cantrip/skills/, and then export the modified copy to share with a teammate.

# Export to a skills tree (creates <dir>/<name>/SKILL.md)
cantrip skill export scenario-tests ~/my-skills-bundle

# Export to an explicit .md file (single-file layout)
cantrip skill export scenario-tests ~/scratch/scenario-tests.md

# Overwrite an existing file
cantrip skill export scenario-tests ~/scratch/scenario-tests.md --force

# Scrub occurrences of your current charm path to <CHARM_PATH>
cantrip skill export my-skill ~/share --charm-path ~/work/my-charm

Export is symmetric with import — dropping the resulting file into ~/.claude/skills/ or ~/.config/cantrip/skills/ and restarting Cantrip picks it up again.

Sanitisation

The body is passed through the same scrubber used by /memory export:

The command prints the number of secret-pattern matches replaced so you can see at a glance whether anything was scrubbed before you share the file.

Troubleshooting

"My skill isn't being picked up"

Cantrip logs skipped skills at warning level. Start Cantrip with --log-level=DEBUG and look for lines like:

Skipping malformed skill file: /home/you/.claude/skills/bad/SKILL.md

The usual causes:

"My skill overrides the bundled one — is that a mistake?"

Cantrip logs this explicitly at INFO level:

Skill 'scenario-tests' from /home/you/.config/cantrip/skills/scenario-tests/SKILL.md
overrides bundled at /path/to/cantrip/skills/scenario-tests/SKILL.md

If that's what you want, no action is needed. If you'd rather keep the bundled skill, rename your file or move it to a different directory.