ivar skill
Authored, external, and materialised across harnesses — how hall and personal skill roots work, how to install from external URLs, and how to keep them in sync.
A skill is a folder with a SKILL.md that teaches an agent how to do
something in your codebase. ivar installs them, tracks where they came from,
and materialises them into each harness's native location — so the same set
follows you across harnesses instead of being re-installed per tool.
Two roots: hall and personal
Skills live in one of two roots:
- Hall skills (
.ivar/skills/) are committed and shared. The hall's.gitignoreexplicitly un-ignores this directory, so everyone who clones the hall inherits these skills. - Personal skills (
.ivar/skills-local/) are gitignored and private to your machine.
Personal is the write default. Both ivar skill create and ivar skill add place skills in .ivar/skills-local/ unless you pass --hall. The committed root is shared across the team: writing there is a commit, visible in review, and inherited by all collaborators. Publishing is the consequential act, so it gets a flag; a skill written by reflex stays private, and promoting it is a deliberate second step.
A skill's id is simply its folder basename. ivar skill list annotates personal skills with (local) and leaves hall skills unannotated.
One root per ID
A harness skills directory has exactly one slot per id. An id claimed by both roots is dropped from both with a warning naming both paths, because picking a winner would let one root silently shadow the other. Both create and add refuse an id that already exists in either root.
Install a skill from a URL
ivar skill add downloads a repository tarball from GitHub, scans for folders containing a SKILL.md, and installs the chosen skill into your personal root (or .ivar/skills/ with --hall).
# Default branch, scans repo for skills
ivar skill add mattpocock/skills
# Explicit GitHub repository URL
ivar skill add https://github.com/mattpocock/skills
# Explicit git ref and subpath
ivar skill add https://github.com/mattpocock/skills/tree/main/skills/engineering/prototype
# Filter by path or ref, or install to hall root
ivar skill add mattpocock/skills --path skills/engineering/prototype --ref main --hall
### Rejected sources
`ivar skill add` accepts only GitHub HTTPS URLs and `owner/repo` shorthands. The following are rejected:
- Non-GitHub hosts (GitLab, Bitbucket, self-hosted git instances).
- SSH URLs (`git@github.com:...`).
- Bare local paths.
- `owner/repo@ref` syntax (use `--ref <ref>` instead).
- Combining `--path` with a URL that already contains a subpath (`/tree/<ref>/<path>`).
When multiple skills exist in a target repository without `--path`:
- An **interactive terminal** receives a multi-selection prompt to choose which skills to install.
- A **non-interactive context** (pipe, script, or agent) refuses with error code `skill.add.multiple_choices`, listing every candidate alongside its `--path` argument.
On install, `ivar` rewrites the `SKILL.md` frontmatter to record a `source` (repo, path, and git ref). For example, installing `prototype` from `mattpocock/skills` produces:
```yaml
---
name: prototype
description: >-
Build a throwaway prototype to answer a design question. Use when the user
wants to sanity-check whether a state model or logic feels right, or explore what a
UI should look like.
source:
repo: mattpocock/skills
path: skills/engineering/prototype
ref: ""
---An empty ref (ref: "") indicates that no ref was pinned at install time, so ivar skill update tracks the repository's default branch. Pinning a specific git ref with --ref makes the installed skill reproducible. This recorded source marks the skill as external and makes it updatable.
Add failure codes and fixes
skill.add.path_not_found: NoSKILL.mdexists at the specified--path. Fix: Runivar skill add <repo>without--pathto discover available candidate skills.skill.add.no_skills: NoSKILL.mdfound anywhere in the target repository. Fix: Verify that the target repository contains valid skill directories.skill.add.duplicate_id: Two candidate skill folders in the repository share the same folder name. Fix: Specify--pathto select the exact candidate to install.skill.add.already_exists: A skill with this id is already installed in either.ivar/skills/or.ivar/skills-local/. Fix: Remove the existing skill first withivar skill remove <id>.skill.add.multiple_choices: Multiple skills were found in the repository, but the command was run non-interactively without--path. Fix: Re-run with--path <candidate-path>using one of the candidate paths listed in the error message.skill.add.none_selected: The multi-select prompt was dismissed without choosing any candidate. Fix: Re-run the command and select at least one skill.
Authored and external
Every skill has a source type that dictates how it behaves during sync and update:
- Authored (no
sourcein frontmatter): Created locally or detached. During sync, authored skills are symlinked to their source directory. - External (
sourcein frontmatter): Installed from a URL. During sync, external skills are copied to the target directories.
Update external skills
# Update all external skills across both roots
ivar skill update
# Update specific skills
ivar skill update prototypeivar skill update re-downloads external skills from their tracked ref and replaces their contents. Running update on an authored skill is a safe no-op that emits a warning explaining why. A network failure on one skill does not abort the entire batch; remaining skills continue updating.
Detach a skill
ivar skill detach prototypeivar skill detach converts an external skill into an authored skill by stripping the source field from its SKILL.md frontmatter. The body remains byte-for-byte identical, and no network requests are made. Detaching an already-authored skill is a silent no-op.
Use detach when you want to customize a vendored skill locally and prevent subsequent ivar skill update calls from overwriting your edits.
Create one
ivar skill create doc-probe --description "probe"Pass --hall to create a committed hall skill instead of a private local one.
--json returns the created path and id:
{
"root": "/home/mnzs/personal/valhalla-hall",
"id": "doc-probe",
"skill_file": "/home/mnzs/personal/valhalla-hall/.ivar/skills-local/doc-probe/SKILL.md"
}Materialise them
ivar skill syncivar skill sync materialises all skills from .ivar/skills/ and .ivar/skills-local/ into three harness target directories:
.claude/skills.opencode/skills.omp/skills
Every target directory is gitignored wholesale because its entries are derived, machine-local artifacts. The source of truth remains .ivar/skills/ and .ivar/skills-local/.
Sync is offline-only, idempotent, and best-effort per target: an error materialising into one harness emits a warning without aborting the others.
Skill state is persisted in two separate state files:
.ivar/skills/state.json(committed).ivar/skills-local/state.json(gitignored)
They are split so that private personal skill identifiers are never written to a committed file.
Inspect and diagnose
ivar skill list # list skills in both roots
ivar skill status # show authored [A] vs external [E] status and target materialisations
ivar skill doctor # health diagnostics: missing materialisation targets, duplicates, broken links
ivar skill remove <id> # remove skill directory, unmaterialise targets, and purge stateivar skill doctor identifies configuration issues and provides runnable fix actions:
11 problems found:
1. materialised target for `brandkit` at `/home/mnzs/personal/valhalla-hall/.omp/skills/brandkit` is missing (skill.target_missing)
fix: Run `ivar skill sync` to repair.
$ ivar skill sync