feat: link agent skills into environments on activation - #597
Conversation
Environments can now declare agent skills — SKILL.md directories used by
AI coding agents — in bin/hermit.hcl, and Hermit provides them to the
project the same way it provides toolchains:
skill-repo "https://github.com/org/repo.git" {
path = "skills"
skills = ["my-skill"]
# ref = "<full commit sha>" # optional security pin
}
On activation (both the activate command and 'hermit env --activate')
each repository is resolved to a commit — the pinned SHA, or the remote
HEAD re-checked at most every 15 minutes — and each declared skill is
materialised as an immutable, content-addressed snapshot under the
Hermit state directory, then symlinked into .agents/skills/<name> and
.claude/skills/<name>.
Skill content never enters the project's version control: only the
hermit.hcl declaration is committed, and Hermit warns when the link
directories are not gitignored. Reconciliation is self-healing and
conservative: links for undeclared skills are removed via a per-env
ownership ledger, repo-committed skill directories and foreign symlinks
are never touched, and an unreachable remote degrades to the last good
snapshot instead of blocking activation or tearing down working links.
Buzz-Message: buzz://message?channel=573ff355-6c19-422d-b425-112853d0ec7e&id=39bb545df8409daa9df623a016f92a1da98bac803d0e370417a65235c208f327
Amp-Thread-ID: https://ampcode.com/threads/T-019fce44-560f-770d-bacb-fba12dd9ae31
Co-authored-by: Amp <amp@ampcode.com>
The skill source path is repository-controlled and was checked with os.Stat, which follows symlinks: a repository could commit its skills directory (or a skill entry) as a symlink to a local path outside the checkout, and the snapshot would materialise that local content. The OnSymlink skip policy only covers symlinks inside the copied tree, not a symlinked source path. Resolve the selected skill path and require it to remain within the checkout before snapshotting. Buzz-Message: buzz://message?channel=573ff355-6c19-422d-b425-112853d0ec7e&id=b5be8f34bb7e24316b8be6171fcb3089eeb8f9c8e0240cd7e0d5441cb503c8a7 Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019fce27-e59e-727c-b6d3-cdeeba894a4e
|
This is definitely too specific to be in Hermit, but I'm interested in generalised solutions for the same pattern. I think you could do the same by using on activate. You'd create an agent-skills package pointing at a git repo (already supported), with an on activate {...} block that copies/symlinks the skills into the repo. So I think all the pieces are already there, but give it a shot and see how it goes. |
|
Gave the composition a shot with stock Hermit built from master — it works end to end: an env-local Five rough edges surfaced, all generic rather than skills-specific:
Sending these as separate small PRs. |
|
🤖 Sent by Joah's AI agent: Follow-up PRs from the composition experiment above, each a small generic fix rather than anything skills-specific:
With those five, the agent-skills pattern works as a pure manifest convention on stock Hermit: a content-only package with a git channel source ( |
|
🤖 Sent by Joah's AI agent: @alecthomas the five PRs above (#598–#602) are ready for your review whenever you have a chance — each is small, independent, and generic (no skills-specific behavior). |
What
Environments can declare agent skills —
SKILL.mddirectories used by AI coding agents (the.agents/skills/.claude/skillsecosystem conventions) — inbin/hermit.hcl, and Hermit provides them to the project the same way it provides toolchains:On activation (both the
activatecommand andhermit env --activate) each repository is resolved to a commit — the pinned SHA, or the remote HEAD re-checked at most every 15 minutes — and each declared skill is materialised as an immutable, content-addressed snapshot under the Hermit state directory, then symlinked into.agents/skills/<name>and.claude/skills/<name>.Why
Today skills must be copied into every repository that wants them, and they drift. Declaring them in the environment gives every workflow that enters the project — humans, CI, coding agents — the same skills, with one committed line of provenance and no vendored content.
Design notes
<state>/agent-skills/snapshots/<name>@<sha12>/directories, never at a mutable checkout, so an update can never swap content under a running agent. Snapshot creation is atomic (temp dir + rename) and serialized by a file lock.bin/toolchain links, skill links persist; discovery is cwd-scoped so leaving the project "unloads" them. Reconciliation uses a per-environment ownership ledger: links Hermit created are updated/removed to match the declaration; repo-committed skill directories and foreign symlinks are never touched.^[a-z0-9][a-z0-9-]{0,63}$),pathcannot escape the repository, symlinked skill paths that resolve outside the checkout are rejected, symlinks inside skill content are not copied, andrefpins must be full commit SHAs. Skill content never enters the project's version control; Hermit warns when the link directories are not gitignored.Testing
go test ./...green; newagentskillspackage has unit coverage for linking, reconciliation, precedence (repo-committed skills win), pinned refs, HEAD updates, freshness window, offline fallback, failed-repo link preservation, and symlink-escape rejection.