Skip to content

fix(artifact-delivery): run Skills that ship media or doc keys - #487

Merged
harlan-zw merged 2 commits into
mainfrom
fix/check-classes
Oct 6, 2026
Merged

harlan-zw merged 2 commits into
mainfrom
fix/check-classes

Conversation

@harlan-zw

Copy link
Copy Markdown
Collaborator

🔗 Linked issue

Related to #481

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • 🧹 Chore
  • ⚠️ Breaking change

📚 Description

An offline sweep of registry Skills found three classes that npx skilld run refused after #481. None of them makes a Skill unsafe or unusable.

Size limits. Before this change, one file over 2 MiB or a folder over 10 MiB blocked the whole Skill. latent-spaces/brag, the first demo on the homepage, ships four music files of 2.01 to 3.76 MiB and packs to 16.04 MiB.

The limits stay. A file the Skill does not read is now left out when it is over a limit, and the rest of the Skill is delivered:

  • Files the Skill does not read: media, binaries, and files in example or test folders.
  • First, each such file over 2 MiB is left out. Then the largest go until the folder fits in 10 MiB.
  • Only the files a Skill reads can still block it. tt-a1i/archify is 10.36 MiB of text, so it needed the example folder rule: five rendered examples/*.html files of about 760 KB each.

Each omitted file is listed in a new omitted-files check result with its path, size, and GitHub URL at the commit. The check is not required, so the Skill still runs. The list sits in a check result because skilld 3.6.1 parses the attestation and the Resolution answer with deny_unknown_fields. A new omittedFiles field in either one would fail every released skilld run with unknown field `omittedFiles` .

Credential material. Version 1 matched a -----BEGIN PRIVATE KEY----- line alone. All nine Skills it blocked were false positives: a secret scanner's pattern table, "-----BEGIN PRIVATE KEY-----\n..." placeholders, and a test fixture whose body is TEST-NOT-A-REAL-KEY. Version 2 needs a whole key block with a base64 body of at least 64 characters, the size of an Ed25519 key. A real key still blocks, including one with escaped line breaks inside a JSON service account file, one indented in YAML, and a legacy encrypted key with PEM headers.

Names. The registry lists a Skill under its folder name made into a slug. The resolver compared the raw folder name, so better-auth/emailAndPassword could not run as emailandpassword. The same mismatch hit 07.1-…, Skill Development, and ib_0dte. Since #481, a registry name resolves its admitted folder first. The tree search is the fallback, and it now matches the registry slug. slugifySkillName moves to shared/skill-path.ts so that both sides read one function.

The policy version moves to 2026-10-07.2.

Merge order with #485. #485 lets the signer sign the previous policy during a deploy. If #485 lands first, its previous entry should become 2026-10-07.1 with the check set from #481. This change loosens checks and closes no safety gap, so the signer can keep signing .1.

Still blocked, by design. austintgriffith/ethskills is a root Skill with a symbolic link (AGENTS.md), which an Artifact cannot carry. The finding names the file.

Architecture after this change: the registry and the resolver share one slug function, the loader passes omitted files to the checks, and the signed omitted-files result reaches the skilld CLI

🤖 AI disclosure: Harlan Agent Kit modified this description. My AI open-source policy.

The 2026-10-07 sweep found registry Skills that skilld run refused for
reasons that do not make the Skill unsafe or unusable:

- A file over 2 MiB or a folder over 10 MiB blocked the whole Skill,
  even when the bytes were music, images or sample renders the Skill
  never reads (latent-spaces/brag, tt-a1i/archify). Such files are now
  left out and listed in a signed omitted-files check. Only the files a
  Skill reads can still block it. The check is a result, not a new
  field, because skilld 3.6.1 refuses unknown fields.
- The credential check matched a key header alone, so a secret
  scanner's pattern table or a "BEGIN PRIVATE KEY\n..." placeholder
  blocked nine Skills. It now needs a whole key block.
- The registry names a Skill by its folder name made into a slug, but
  the resolver compared the raw folder name, so emailAndPassword could
  not run as emailandpassword. slugifySkillName moves to shared so both
  read one function.

The policy version moves to 2026-10-07.2.
@harlan-zw harlan-zw added the harlan-agent-review Pull request triage requires an adversarial Review. Adding this label manually always forces one. label Oct 6, 2026
#485 merged first. The signer's previous policy entry moves from
2026-08-20.1 to 2026-10-07.1, the policy this branch bumps from. The
bump only loosens checks, so the signer keeps signing .1 through a
deploy.
@harlan-github-agent harlan-github-agent Bot added harlan-agent-review-required Pull request triage requires an adversarial Review for this head commit. harlan-agent-running An Agent holds a Task on this issue or pull request right now. and removed harlan-agent-review Pull request triage requires an adversarial Review. Adding this label manually always forces one. labels Oct 6, 2026
@harlan-github-agent

harlan-github-agent Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

🤖 MERGED

Harlan Agent Kit posted this automated review. It is not Harlan's personal review or approval. AI open source policy. Last updated: 2026-10-06 15:59 UTC.

GitHub merged this pull request.

  • Logged (45/100): A real private key inside JSON that escapes slashes as \/ ships undetected. View code
    • Ask an agent to verify and fix this finding
  • Logged (30/100): Real PGP private key material is never blocked by the credential check. View code
    • Ask an agent to verify and fix this finding
  • Logged (10/100): The PR's embedded architecture diagram is inaccessible, leaving the described data flow undocumented by pixels. View code
    • Ask an agent to verify and fix this finding

Review completed. No finding above 80/100.

Selected findings run after merge and open separate pull requests.

@harlan-zw
harlan-zw merged commit 4eec940 into main Oct 6, 2026
4 of 7 checks passed
harlan-zw added a commit that referenced this pull request Oct 6, 2026
Keeps #487's slug match and omitted files on top of the split tree
listing. A truncated tree is now split, so the reject test truncates
the single level read too.
harlan-zw added a commit that referenced this pull request Oct 6, 2026
#487 moved slugifySkillName to shared/skill-path. This branch keeps
registrySkillName and imports the shared slug.
harlan-zw added a commit that referenced this pull request Oct 6, 2026
…eft out

#487 leaves large media out of a folder. R2 holds only the packed files, so a stored build that left a file out loads from GitHub. Every folder 2026-10-07.1 accepted packs the same files, so that policy joins the byte-compatible set.
@harlan-github-agent harlan-github-agent Bot removed harlan-agent-running An Agent holds a Task on this issue or pull request right now. harlan-agent-review-required Pull request triage requires an adversarial Review for this head commit. labels Oct 6, 2026
harlan-zw added a commit that referenced this pull request Oct 7, 2026
* feat(artifact-delivery): stream Skill archives up to 64 MiB

A build read every Skill file into memory, then packed a second copy,
so the limits had to stay at 10 MiB, 2 MiB a file and 900 files.
#487 worked around that by leaving media out, which dropped the music
latent-spaces/brag needs for its films.

The build now streams the codeload archive, keeps only the Skill
folder, hashes as it goes, and streams the archive into R2 with the
digest R2 checks. Files the archive lacks come from
raw.githubusercontent.com. Every file still matches its Git blob.
Public limits rise to the CLI's 64 MiB and 2,000 files. A CLI that
sends Skilld-Capabilities: linked-files gets larger files as linked
files instead of omitted ones.

* fix(artifact-delivery): bound check findings, paths and inflate writes

A sweep of the largest Skills found three limits the old 900 file
ceiling hid: a check result with over 100 findings fails the schema,
a path USTAR cannot hold failed while packing instead of blocking, and
one compressed chunk of zeros can inflate to many megabytes at once.
The signer also needs Node types now that it hashes as it streams.

* docs(adr): write the linked files example as valid JSON
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant