Repository navigation
Description
Summary
computedHash in skills-lock.json is close to being a portable identity for an installed skill: a value any tool can recompute from the files an agent actually loads. Two gaps are not reported yet, and together with the open items below they would make one small, specified algorithm.
Two new findings (main at 13e4063)
1. The file order depends on the machine's locale. computeSkillFolderHash sorts with localeCompare, so the same folder hashes differently on machines with different locales, and skills update can see a change where there is none.
LC_ALL=de_DE.UTF-8 node -e "console.log(['z.md','ä.md'].sort((a,b)=>a.localeCompare(b)))" # [ 'ä.md', 'z.md' ]
LC_ALL=sv_SE.UTF-8 node -e "console.log(['z.md','ä.md'].sort((a,b)=>a.localeCompare(b)))" # [ 'z.md', 'ä.md' ]With the function copied verbatim, a folder with SKILL.md, z.md and ä.md hashes to 602e8c40… under C, en_US and de_DE, and to eac7de40… under sv_SE (Node 22.23).
2. Symlinked files are left out of the hash, but installed. collectFiles keeps only entry.isFile(), which is false for a symlink, while copyDirectory copies the target with dereference: true. For sources hashed before install (git, local, sync), the installed skill then contains bytes that no lock entry covers. If the target changes, the hash stays the same and the installed content does not. Reproduced: a skill with notes.md -> ../../outside.txt keeps the same hash after outside.txt changes.
Related open items
- [Bug]: Folder hash misses a filename and content change #2427 / fix(update): prevent collisions in project skill hashes #2438: path and content are not framed (
a+bcequalsab+c). fix(update): prevent collisions in project skill hashes #2438 fixes this. - [Bug]: computedHash in skills-lock.json cannot be verified against installed files #806: the hash cannot be recomputed from the installed files, because the installer excludes files the hash includes.
- [Bug]:
skills-lock.jsonhash differs between Windows and Linux for the same skill due to line endings #781: line endings make the hash differ between Windows and Linux.
Proposal: one specified identity
- Order files by the UTF-8 bytes of the relative path (
Buffer.compare), not by locale. - Frame each file (path, NUL, byte length, NUL, content), as in fix(update): prevent collisions in project skill hashes #2438.
- Hash exactly the file set the installer writes: the same exclusions as
copyDirectory, symlinks resolved the same way (or rejected when they point outside the skill folder). - Decide line endings once and document it ([Bug]:
skills-lock.jsonhash differs between Windows and Linux for the same skill due to line endings #781). - Mark the algorithm version in the value or the lock version, so old values are recognised instead of silently differing.
- Document it in the README so other tools compute the same value.
Why we care
We (inblock.io) want to bind signed review records to this hash, so that any agent's installed skill can be checked against the exact version someone reviewed. #806 asks for the same thing for security assessments. One documented identity would let tools agree on it instead of each inventing its own.
Happy to send a PR with the spec text and test vectors for all five points, building on #2438, if this direction works for you.
Activity