Repository navigation
Conversation
A skill is a directory with a SKILL.md: instructions a coding agent loads and follows, often with scripts next to them. internal/skills pins every file of a skill in an RFC 6962-shaped Merkle tree, derives a label of what the skill can do (shell, network, secrets, file writes outside the project, package installs, remote content, hooks, pre-approved tools, ...), runs 40 deterministic rules for the tricks poisoned skills use - hidden Unicode, look-alike hosts, encoded payloads, curl | sh, conditional triggers, exfiltration, persistence - and compares all of it with a lockfile. Every rule has a fixture and a golden file; ordinary skills must trip none.
skills.lock sits next to the project's skills. lock pins what is not pinned yet, verify fails on any change nobody approved, diff shows a changed SKILL.md sentence by sentence with new imperatives and the rules each added sentence trips, approve accepts a skill as it is, label shows what a skill can do and where it says so, and scan vets a skill before it is installed. verify and diff write Markdown for a pull request or a job summary; label writes a badge.
A new skills input names a project directory; the step writes the skills report to the job summary, hands it out as the skills-report output for a pull request comment, and fails on any change nobody approved unless skills-fail is false. Without the input nothing changes. make golden re-approves the fixture project CI checks the Action against.
Also catches curl -F field=@file as exfiltration: the form field name sat between the flag and the @.
tabwriter counts the bytes of colour codes, so a coloured status pushed every column after it out of line. The table is plain, as lock's is; the details below it carry the colour.
… bytes From review: - A skill whose SKILL.md is a symlink was not a skill at all; it is now found, pinned and scanned. A symlink to a file is pinned by its target and its content, and the content is scanned. - Only a real repository (HEAD, objects, refs) at the root of a skill is left out, and its presence is pinned with a git-repository finding. A .git directory anywhere else, .DS_Store and Thumbs.db are hashed. - A text file with one NUL or invalid UTF-8 byte was treated as binary and skipped every rule. It is now scanned with the bad bytes replaced, and flagged by malformed-text. - A repository that is itself one skill (--path .) gets the key '.', and the lockfile inside it is not hashed as part of it.
- An HTML comment that starts a line runs to its -->, so a fenced block inside one is read as the hidden comment it is. - Variation selectors, the grapheme joiner and soft hyphens are folded out before matching, curly quotes are straightened and runs of spaces are one; a selector after an ASCII character is itself a finding. - Keyword windows start a line before the keyword, for wrapped prose. - curl | /bin/bash, | /usr/bin/env bash and | tee f | sh are pipe-to-shell. - An added sentence is read as prose and its inline code as code, and every sentence of the diff carries the line it starts on. - Line numbers are counted once per pass, and one rule is reported at most 50 times per stretch of a file. - A skill is matched by its directory, never by the name it gives itself.
verify needs a lockfile (or --missing-ok), --dir has to be a directory and an explicit --path has to name something. A name that matches more than one skill is refused. Everything printed from a skill stays on its line, lock --json prints [] for nothing pinned, and the lockfile is never hashed as part of a skill it sits in.
A skills check that cannot run - an agentgate without skills, a missing or
broken lockfile - fails the step instead of passing as drift or as nothing
at all, and skill text in the log cannot issue workflow commands.
gendocs put generated text into a regexp replacement template, where a $
is a submatch reference: ${IFS} vanished from the rule table.
The status section listed what comes next for the proxy only. It now also names the next steps for skills - signed approvals, a SessionStart hook and SARIF output - and links the full roadmap in the design notes.
…ty label, prose diff and approval gate agentgate skills pins Agent Skills in skills.lock, labels what each skill can do, shows changed instructions sentence by sentence and fails CI on any change nobody approved. 42 deterministic rules, no network, no model.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Brings
developtomain. The only content is the skills lockfile from #10:agentgate skillswithlock,verify,diff,approve,labelandscan, plus the new Action inputs.How
developwas even withmainbefore #10, so this PR carries exactly that change. It does not tag a release, because the release workflow only runs onv*tags. The CHANGELOG keeps the entry under Unreleased.Effect on enforcement and the audit log
None. See #10.
Checklist
make fmt vet lint testpassesmake e2epasses, if the proxy, CLI or audit store changedmake goldenwas run and the diff reviewed, if policy evaluation changed (not affected)make docswas run, if a command, flag, matcher or redaction pattern changeddocs/and the README reflect any user-visible changeGenerated by Claude Code