Repository navigation
feat(artifact-delivery): follow symbolic links in a Skill folder - #512
Merged
Merged
Conversation
108 Skills failed every run with INVALID_SOURCE because their folder held a symbolic link. 103 are simota/agent-skills, whose Skills link the shared _common and _templates folders at the Repository root. A build now resolves each link at the same commit by POSIX rules and packs the files it names at the link path, each checked against its own Git blob SHA. Links that leave the Repository, dangle, loop, chain past 8, or point into .git still refuse the Skill. A link inside a followed folder, and a link to a folder inside the Skill that holds it, are left out: tar --dereference recursed 5,800 folders deep on simota/agent-skills. The non-required symbolic-links check lists every link. Policy 2026-10-07.4 keeps 2026-10-07.3 signable, since that policy refused every link.
Names symbolic link in the glossary, apart from ADR-0013's linked file.
harlan-zw
added this pull request to stack #513
October 6, 2026 17:22
Contributor
🤖 MERGED
GitHub merged this pull request.
8ef7794b-32d7-4859-a4f5-1205c08502af |
Contributor
There was a problem hiding this comment.
Harlan Agent Kit posted this automated review. AI open source policy.
Automated Review: READY.
harlan-zw
added a commit
that referenced
this pull request
Oct 7, 2026
* feat(registry): move Repositories that GitHub renamed or transferred ADR-0002 kept a moved Repository under its old name, so pages, sitemaps and run commands named Repositories GitHub no longer serves, and two renames left duplicate Repositories in the registry. Sync now follows GitHub: it stores the Repository ID, moves every row to the new name in one batch, and keeps the old name as an alias that answers 301. ADR-0013 replaces ADR-0002. * chore(scripts): add the moved Repository backfill Sync moves a Repository the next time it reads it. The script runs the same statements now for the 13 moves the 2026-10-07 run sweep found, with a read-only dry run as the default. * fix(registry): renumber the moves migration and parse the ID once Main gained its own 0144 migration, and two migrations may not share a number. The batched summary read narrowed the Repository ID with a check TypeScript could not carry into the parser, so the parser now owns it. * fix(registry): queue moved Repositories past the sync prefetch The hourly prefetch records an unchanged Repository in place without a sync job. A moved Repository with an unchanged tree never reached syncRepo, so its rows would never move. * fix(registry): refuse a move into a name another Repository holds * fix(scripts): refuse a backfill merge into another Repository's row The backfill now runs the held-row check sync runs, so it never merges into a row stored for a different Repository ID. It also stops with a clear message when the D1 lacks the moves migration. * chore: renumber the repository move migration and ADR #510 adds migration 0145 and ADR-0013, and #512 adds ADR-0014. This branch moves to 0146 and ADR-0015 so all three merge without a clash. * fix(scripts): reserve migration 0145 for pull request 510 --------- Co-authored-by: Harlan GitHub Agent <harlan-github-agent[bot]@users.noreply.github.com>
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.
Stacked on #510.
🔗 Linked issue
Related to #510.
❓ Type of change
📚 Description
108 Skills failed every run with
INVALID_SOURCE: The Skill source layout was rejected., because their Skill folder holds a symbolic link. 103 of them aresimota/agent-skills/*, where each Skill links the shared_commonfolder at the Repository root.A build now resolves each link at the same commit and packs the files it names at the link path, as regular files. Each file keeps its own Git blob SHA from the tree, so the build checks its bytes like any other file. The signed statement stays a plain file list, so released CLIs need no change.
The rules, recorded in ADR-0014:
.git, missing, into a submodule, looping, or through more than 8 linksescape -> ../../../outside: the target is outside the Repositoryatlas/reference/atlas -> ../../atlasFollowing every link the way
tar --dereferencedoes cannot work here. Onsimota/agent-skills, tar recursed 5,800 folders deep and crashed, because_commonlinks every Skill folder back. Refusing the self links instead of leaving them out would keep 22 simota Skills refused.A new
symbolic-linkscheck result lists each link, as_common -> ../_commonor with the reason it was left out. It is not required, so released CLIs accept it, as they didomitted-filesin #487. A file a link put in the Skill never becomes a linked file: the CLI would read it at the link path, where GitHub serves no file.The archive lists a link target at its own path, so files no longer arrive in Artifact order. The reader holds entries that pass before their turn, up to 8 MiB a pass. A link file waits for a later target when the files it holds back fit, and reads it from
raw.githubusercontent.comotherwise. A Skill without links streams as before.Private builds follow links by the same rules. The reads the links cost come out of the 900-file limit, so a private build stays inside its subrequest budget.
The sweep harness built the 108 Skills on this branch, with the archives cached locally:
raw.githubusercontent.comThe one still refused is
oaustegard/claude-skills/agent-routing. Its only link,agent-routing -> ../../agent-routing, leaves the Repository.garrytan/gstackbuilds with 1,134 files left out under the 2,000-file limit from #510.The policy moves to
2026-10-07.4. The signer still signs2026-10-07.3, which refused every link, so a ready build under it is checked again from its stored bytes. A stored build that followed a link always loads from GitHub, because its bytes do not show which files a link put there.GLOSSARY.mdgainssymbolic link, kept apart from ADR-0013's linked file.skilld updatereads an installed copy back as a local Skill and refuses one over 512 files.simota/agent-skills/honepacks 527 files andgarrytan/gstack2,000. A run is unaffected.