Skip to content

feat(artifact-delivery): stream Skill builds up to 64 MiB - #510

Merged
harlan-zw merged 5 commits into
mainfrom
fix/artifact-size
Oct 7, 2026
Merged

harlan-zw merged 5 commits into
mainfrom
fix/artifact-size

Conversation

@harlan-zw

Copy link
Copy Markdown
Collaborator

🔗 Linked issue

Related to #487. The CLI side of linked files is skilld-dev/skilld#209.

❓ Type of change

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

📚 Description

A public build held every Skill file in memory, then packed a second copy. Its limits stayed at 10 MiB, 2 MiB a file and 900 files, and only the 900 had a recorded reason. #487 kept larger Skills running by leaving files out, so latent-spaces/brag lost the music its films use.

A build now streams the Repository archive from codeload.github.com at the exact commit. It keeps the Skill folder's entries, hashes them as they pass, and stops after the last one. Each file must still match the Git blob SHA from the tree. A file the archive lacks comes from raw.githubusercontent.com at the same commit. An archive over 16 MiB is read a second time and streams into R2, and R2 refuses it unless it matches the digest of the first read. The signer hashes the object as it streams.

Architecture: the build streams the codeload archive through the packer into R2, and the CLI reads linked files from raw.githubusercontent.com

ADR-0013 measures the constraint behind each limit. Public limits rise to what the skilld CLI accepts:

Limit Before After
Artifact 10 MiB 64 MiB
One file 2 MiB none of its own
Files 900 2,000

Private builds keep the old limits, because they still read one blob per request and encrypt the archive in memory.

Over 64 MiB, a CLI that sends Skilld-Capabilities: linked-files gets the largest files as linked files. The signed statement lists each one by path, mode, size and Git blob SHA, and the CLI reads it from GitHub at that commit. Other CLIs keep the #487 rule at the new limits, and never see the field.

A local sweep of the registry, with main at #487 on the left:

Skill Before After
latent-spaces/brag 4 music files left out all 289 files, 16.03 MiB
tt-a1i/archify 1 example left out all 314 files, 10.36 MiB
oaustegard/claude-skills/tree-sitting 8 parsers left out all 38 files, 27.60 MiB
careerhackeralex/visualize/eval 256 files left out all 563 files, 43.95 MiB
thedivergentai/gd-agentic-skills/godot-master refused at 1,728 files all 1,728 files
thvroyal/kimi-skills/kimi-xlsx 73 MiB binary left out linked, for a CLI that reads linked files

Across all 5,949 registry Skills, none that built in the 2026-10-07 sweep of main fails on this branch.

Changes the larger limits needed:

  • A check result keeps at most 100 findings of 500 characters, as the CLI requires.
  • A path a USTAR header cannot hold is refused before any byte is read.
  • The inflater takes 16 KiB writes, so a file of zeros cannot inflate a whole network chunk at once.
  • load takes its options as a required argument. feat(artifact-delivery): fall back to the requester's GitHub token #495's requester fallback forwarded load without them.

The policy moves to 2026-10-07.3. The signer still signs 2026-10-07.2. A ready build under it that left nothing out, up to 16 MiB, is checked again from its stored bytes. The deploy workflow applies migration 0145 and deploys the signer before the site, which this order needs: the old signer refuses an Artifact over 10 MiB.

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

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.
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.
Renumbers the linked files migration to 0145 after main took 0144, and
makes the load options required: #495's requester fallback forwarded a
load without them, so no CLI would have received a linked file.
@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
@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-07 01:37 UTC.

GitHub merged this pull request.

  • Logged (20/100): The PR's architecture diagram is unreachable, so its visual claim about the streaming flow is unverified. View code
    • Ask an agent to verify and fix this finding
  • Logged (55/100): The spec check buffers the whole SKILL.md in memory with no file cap, so an oversized file OOMs the isolate and the queue burns retries. 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-github-agent harlan-github-agent Bot added harlan-agent-ready The automated Review passed every gate on this head commit. and 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-github-agent harlan-github-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Harlan Agent Kit posted this automated review. AI open source policy.

Automated Review: READY.

Read the Review results

@harlan-zw
harlan-zw added this pull request to stack #513 October 6, 2026 17:22
harlan-zw added a commit that referenced this pull request Oct 6, 2026
#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.
@harlan-github-agent harlan-github-agent Bot added the harlan-agent-running An Agent holds a Task on this issue or pull request right now. label Oct 7, 2026
#508 builds a Resolution in its own request. Keep its after-response
build beside the linked-files header, and give its tests the
linked_files column.
@harlan-github-agent harlan-github-agent Bot removed the harlan-agent-ready The automated Review passed every gate on this head commit. label Oct 7, 2026
@harlan-zw
harlan-zw merged commit cbf825a into main Oct 7, 2026
6 checks passed
@harlan-github-agent harlan-github-agent Bot removed the harlan-agent-running An Agent holds a Task on this issue or pull request right now. label Oct 7, 2026
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>
harlan-zw added a commit that referenced this pull request Oct 7, 2026
#510 lets a ready build serve only a CLI that reads what it holds, so
the warm run passes the CLI's linked-files capability to
findReusableBuild.
harlan-zw added a commit that referenced this pull request Oct 7, 2026
#510 loads a Skill through a streaming read and the signer hashes the
stored object as a stream.
harlan-zw added a commit that referenced this pull request Oct 7, 2026
* perf(artifact-delivery): serve a warm run from its ready build

A warm run requested a new Resolution, waited for the queue, then waited
again while the build re-signed the same bytes: 5.6 to 9.2 s in 14
production runs on 2026-10-07. When a ready public build of the same
Repository, commit, Skill folder and policy passes every reuse check,
the POST now answers with that ready Resolution, as GET would, and
queues nothing.

A request that names no commit resolves on GitHub first, within 2.5 s,
using the cached commit and tree reads. When no ready build fits, the
build gets the request pinned to that commit and folder, as a registry
name already is. The run sweep keeps building every check.

* fix(artifact-delivery): emit the served event without an object spread

* test: give the warm run tests the streamed build shape

#510 loads a Skill through a streaming read and the signer hashes the
stored object as a stream.

---------

Co-authored-by: Harlan GitHub Agent <harlan-github-agent[bot]@users.noreply.github.com>
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