Sources
A source is a git repository, optionally a folder inside it at a ref, or a directory inside your project’s git worktree.
palm installs entities from sources, and every source is declared in palm.yaml, so it is a dependency of the project and never a per-user setting.
$ palm install mattpocock/skills tddi ref ^1.2 saved to palm.yaml (latest tag v1.2.3); edit ref: to track main+ skill tdd .claude/skills/tdd/ 2 files from mattpocock/skills v1.2.31 installed. Commit palm.yaml, palm.lock.yaml and .claude/ together.$ palm get sourcessource alias kind ref sha/tree entries───────────────── ───── ──── ───────────── ──────── ───────mattpocock/skills git ^1.2 → v1.2.3 2c0db90 1$ cat palm.yamltargets: [claude]sources: mattpocock/skills: ref: ^1.2 skills: [tdd]The first install from mattpocock/skills declared it in palm.yaml with a version range.
palm get sources shows each source with its range, the commit it resolved to and the number of entries taken from it.
Forms a source takes
Section titled “Forms a source takes”The first word after palm install is the source.
| You type | palm declares | Example |
|---|---|---|
owner/repo |
a GitHub repository, keyed owner/repo |
palm install mattpocock/skills tdd |
owner/repo/sub/dir |
the same repository with root: sub/dir |
palm install cursor/plugins/pstack comment-sicko |
github:owner/repo |
the same as owner/repo |
palm install github:obra/superpowers --all |
an https://, ssh:// or user@host:path URL |
a named source with url: |
palm install https://gitlab.acme.com/platform/agent-kit.git reviewer |
any of these plus #ref |
the source with that ref: |
palm install mattpocock/skills#v1.2.3 tdd |
./dir or ../dir |
an in-repo source, rendered from the working tree | palm install ./agent-kit review |
a name already in palm.yaml, or its alias |
that source | palm install kit reviewer |
palm also accepts file:// URLs, and http:// and git:// with a warning.
It refuses every other scheme, ext:: style transports and a leading -.
A directory may sit anywhere in the same git worktree, so a nested project can use the root’s kit as ../../agent-kit.
A local path outside the worktree is refused, because a teammate’s clone would not have it.
A bare word is a source only when palm.yaml declares it.
For any other word, the error suggests a command you can paste: ./<word> for a folder in the project, a declared source that offers that name, or the repository form.
A repository that git ls-remote cannot reach prints repository not found or private, with the command to try yourself.
Declared on first use
Section titled “Declared on first use”palm writes a source to palm.yaml the first time you install something from it.
A repository you only list is fetched and indexed, and nothing is saved.
- GitHub shorthand is keyed by
owner/repo. - A URL is keyed by the repository name, or
owner-repowhen that name is taken.--as <name>picks the key yourself. - A directory is keyed by its project-relative path, such as
./agent-kit. --layout <kind>=<glob>, repeatable, writes a layout descriptor with the new source.
Until a source is declared, every hint palm prints uses the form you typed, such as the URL or owner/repo, never a key that does not exist yet.
A listing’s paste lines keep the #ref you typed.
palm always writes the ref: it used, so the intent is visible in review.
A source you wrote into palm.yaml by hand without a ref: gets one on its first install, with the same line.
| The repository has | palm writes | and prints |
|---|---|---|
a #ref you typed |
that ref | nothing extra |
| semver tags | a caret range on the newest tag | i ref ^1.2 saved to palm.yaml (latest tag v1.2.3) |
| no tags | the default branch, by name | i ref main saved to palm.yaml; edit ref: to pin a tag |
Declaring the same URL and ref under another name prints ~ source acme → kit (renamed).
The rename happens only after the install succeeds.
--as <name> with a different #ref declares a second source for the same repository, so two skills can follow two refs.
A different ref for a declared source prints ~ source acme: ref ^1.2 → main and needs a confirmation or --yes.
Refs and ranges
Section titled “Refs and ranges”ref: is the one place a version lives. It is a tag, a branch, a commit or a semver range.
ref: |
Resolves to |
|---|---|
v1.2.3 |
that tag |
main |
the head of that branch when the source is first resolved or updated |
3f2a1c9 |
that commit |
^1.2 |
the highest tag from 1.2.0 up to, not including, 2.0.0 |
~1.2 |
the highest 1.2.x tag |
1.x, v1 |
the highest 1.x tag, unless a branch or tag has exactly that name |
">=1.2 <2" |
any range the semver package accepts |
A branch or tag named exactly like the range wins, such as a 2.x maintenance branch or a moving v1 tag.
Tags may carry a v prefix. Prereleases match only when the range names one.
The lock records the range, the tag it resolved to and the commit.
A listing, a first install and palm update ask the remote for its current tags, so they never show a stale version.
A bare palm install uses the locked commit.
palm update moves the commit within the range, and palm update --to <ref> changes the range itself.
A ref: you edit by hand is an update too.
The next bare palm install prints the update plan, asks for consent when a program changes, and needs --yes without a terminal.
In-repo sources
Section titled “In-repo sources”A directory inside the project, such as ./agent-kit, is a source like any other.
palm renders it from the working tree, so the directory is the truth.
- The lock stores no commit for it. Each entry’s content hash covers that entry’s own files, so two pull requests that change two skills do not conflict in the lock.
- A bare
palm installre-renders every entry whose files changed and reports~ re-rendered. palm checkfails for each entry whose files changed since the lock was written, and for a directory that is missing or renamed.- Hook scripts run in place, from the directory, so a script edit is live at once. palm hashes them, so after an edit the next install asks for consent again.
- An in-repo source has no
ref:. For a tagged checkout, use afile://URL instead.
palm create writes templates into ./agent-kit and declares it for you. See Publish your own source.
Aliases
Section titled “Aliases”The key is the source’s name everywhere: in palm.yaml, in the lock, in --allow-exec keys and in messages.
A source may add an alias: to save typing.
sources: acme-kit: url: https://gitlab.acme.com/platform/agent-kit.git alias: kit agents: [reviewer]palm install kit tester then installs from acme-kit.
Names and aliases are unique within one palm.yaml, ignoring case.
What palm refuses
Section titled “What palm refuses”- A source that overlaps an output directory, such as
./.claude. The error names both paths and suggests./agent-kit. - An output directory that is a symlink into a declared source, such as
.claude/skills -> ../skill. palm checks real paths on both sides, at listing and at install. - A source missing on disk, or a renamed in-repo directory, on every command until you fix
palm.yaml. - A project source under
-g. The error saysacme is a project source; -g uses ~/.palm/palm.yaml sources only. - A second source for an entity of the same kind and name in one scope.
E_CONFLICTnames the owner and thepalm removecommand.
Any other symlinked output directory prints one notice per run, such as i .claude/skills is a symlink to ../shared; palm writes through it.
A marketplace or plugin manifest inside a source is only a hint for finding entities. It never registers anything, and palm never fetches another repository on its own. Scanning explains what palm reads.