Skill packs, and the update cycle

What a pack is and why nobody writes one: the inputs, the input manifest, how a compile runs, when a pack goes stale and who recompiles it, what a pinned depth means, how a hub is exported and imported, and the bounds every one of those operations is checked against.

markdownguidev1R4RF-5GZ5area: packsaudience: agentaudience: maintainerskill-packscompilestalenessmanifestexportimportbounds

Updated 2026-10-17

Skill packs, and the update cycle

A pack is an output of the hub, not an input to it. Development teams ship features, fix bugs, publish release notes and update documentation; nobody sits down to write a skill pack, and a platform that asks them to will get stale packs. So the hub compiles one, from documents that already exist, and the compile is repeatable.

This guide covers the pack side of that cycle and the hub side beside it: export and import, which are how a whole hub moves. Every figure is read from the compile artefact or the record named at the figure.

1. What a pack is

Inputs: one workflow document and the documents its steps name, each taken at a depth. Output: the ordered documents, inlined, plus an input manifest listing every document by short id, version, content hash, depth and freshness at compile time, together with the workflow's own version.

A transient bundle and a released pack are the same object at two lifetimes. A search answer or a workflow step composes a bundle on the fly and discards it. A pack is compiled by an explicit call, stored, versioned, and served at the three depth rungs.

Why the manifest is the interesting half: a production agent that loads one pack and never calls back is the intended mode of use, and the manifest is what makes that silent run auditable afterwards. The agent's logs name the pack version, the manifest names every document by id and version, and the documents name their own sources. A pack carries freshness as the minimum tier of its inputs, so one asserted document makes the whole pack asserted — which is the honest answer.

2. The worked example, and the figures it produced

This hub has one compiled pack, from the workflow guides/bootstrap-a-hub.md. Its input manifest is committed at docs/hub/packs/bootstrap-a-hub.manifest.json and the figures below are read from that file rather than from any sentence about it:

figurevalue
documents compiled5
files in the pack6 — the five inputs plus the manifest
rendered bytes8,910
token estimate2,228
pack freshnessasserted, the minimum tier of the inputs
excluded1, as a duplicate: the workflow names one reference document twice
inputs at depth lite4 of 5; the fifth is normal
inputs with a pinned depth5 of 5

Two readings of that table matter more than the numbers.

Four of five inputs are lite because the workflow chose it, not because the compiler economised. A lite input renders the document's front matter and the call that returns the body, which is what the navigate rung is for. The compiler's own depth policy decides the rung only for a step that pins none.

Every input is depth-pinned, so no amount of usage can make this pack stale. Only a change to a named document's bytes, to the set of documents, or to the workflow itself can. That is the rule working as designed for a workflow that makes its own reading decisions, and it is the clearest illustration of what a pinned depth means.

The compile ran as a service call on a developer cluster, not over the MCP surface. Six of the eighteen declared tools are on the wire on the release this hub was tested against, and skills is not one of them; the pack above was compiled by calling the service directly. The pack mechanism is built; the door to it is not open yet.

3. Staleness, and who recompiles

A pack is marked stale when its inputs move by more than the recompile threshold. The default threshold is: any input document version change, or a learned-depth change on two or more inputs.

Crossing the threshold does not recompile the pack. It does three things:

  1. marks the pack stale;
  2. reports that staleness in the envelope of every read, alongside the manifest, naming

the inputs that moved and their new versions or depths;

  1. files a problem entry for the hub's maintainer with the recompile call pre-filled as

the next action.

The compile call remains the only writer of a pack version. That is deliberate: the promise that a pack is correct and current is kept by staleness being *visible on every read*, not by an unnamed background process silently changing what an agent loads. So the answer to "who recompiles" is: a maintainer, or an agent acting as one, on the problem entry the hub filed. Nobody else, and nothing automatically.

A pinned depth edit is a workflow change, not a usage event. If you edit a workflow to pin a step's depth, you have changed the workflow document, which moves its version and marks every pack compiled from it stale. The distinction is worth keeping straight because the two look alike in a manifest and are not alike at all: a learned depth moves because readers behaved differently, and a pinned depth moves because an author decided. The manifest carries a flag per input saying which it was, and that flag was added precisely because a review measured a pinned edit being counted as learned movement.

Release notes for a pack are the diff of two manifests: which documents changed, which were added or dropped, which moved depth, and why. Nobody writes them.

4. Export and import: moving a hub

The same two commands serve an agent and an operator. Export produces a bundle from the whole hub, a folder or one document. Import reads a bundle into a hub at a path, in merge or replace mode, with a dry run that writes nothing.

The import is bounded, because it is a multiple of a bounded operation: one import is N document writes in one transaction with N chosen by the caller. So it carries two bounds of its own — a file count (2,000 by default, bounds 1 to 20,000) and a byte total (50 MiB by default, bounds 1 MiB to 500 MiB) — and both are checked before any file is read, on the directory walk's own counters. An oversized bundle costs one directory pass and no file reads, and the refusal names both the bound and the measured value. A hub may tighten either bound and may never exceed the platform ceiling.

The dry run is the whole safety net. It performs every write the real run would and rolls the transaction back, so its report is the real answer discarded rather than a prediction. It returns one verdict per entry — created, changed, unchanged or refused — and it refuses an oversized _boot/ entry with the measured tokens and the budget named, exactly as an authored write does. Fix every refusal, then run for real.

Two properties a reader should know before trusting a dry run's output. The counts and the per-entry verdicts are real. The catalog digest is not comparable with the real run's, because the dry run mints the short ids the catalog names and then rolls them back; the runner prints that caveat beside the digest.

The import requires maintainer on the hub, one rung above the contributor floor a document write needs. That rung is named in this hub's own bootstrap runbook, in the runner's header and in the runner's output, because it was named in no document at all until a first end-to-end run was refused by it.

Front matter is derived from structure, never from content, and only where it is absent. Derivation is per field: a file with partial front matter keeps every field it declares, and every derived field is reported per entry so nothing silently acquires a role. role comes from the first path segment, shape is always markdown, summary is the first real body line, status is draft, and covers, facets and depends_on are left empty rather than invented. Freshness is asserted and is never raised by an import.

One consequence worth planning for: a document left to the derivation is in the hub and in no pack, because a compile never inlines a draft. That is the right default for an unreviewed file and the wrong one for a curated corpus, which is why this hub's own import manifest declares status: published on every mapped file.

5. The bounds, and what is honestly not there

operationboundwhere it is checked
importfile count and byte totalthe directory walk, before any file is read
importarchive limitsthe zip guard, on an archive source
any _boot/ entrythe whole-file and hand-written token budgetsthe shape validator, identically on a write and on an import
a document bodythe ingest split capat ingest: a body above the embed cap is split into parts, and a split that would exceed the part cap is refused with both numbers named
folder pulla token cap, and an explicit per-call budgetthe pull path; the per-call budget is the only truncation and it is reported

Three gaps, each recorded rather than smoothed over:

  • The export pays one of its four promises. The content tree is produced; the

version history and change log for a narrowed path, the signed expiring bundle, and the federated effective-scope format are named in the bundle's own manifest under what is not included, so a reader of the artefact is told rather than misled (tracking/backlog/hub.md item 27).

  • An archive source, a URL source and replace mode are not served. The import

answers a typed not-implemented refusal for each, before it touches the hub.

  • **The generated folder card and source manifest can be neither generated nor

authored** today: nothing writes them, and the path rule refuses an underscore-prefixed file name, so a bundle cannot carry them either.

6. The cycle, in order

  1. Write or edit the documents. Front matter per

reference/standard/hub-standard.md; status: published on anything you want a pack to inline.

  1. Write or edit the workflow document: ordered steps, each naming its documents and

pinning a depth where the step knows what it needs.

  1. Compile. Read the manifest the compile returns, and keep it — it is the audit record

of every silent run that follows.

  1. Watch for staleness on read. The envelope names the inputs that moved.
  2. Recompile when a maintainer acts on the problem entry, and read the diff of the two

manifests as the release note.

  1. Export when the hub has to move; import with a dry run first, always.

Next reads

  • guides/bootstrap-a-hub.md — the workflow this hub's one pack was compiled from.
  • reference/standard/hub-standard.md — the front-matter contract a compile depends on.
  • guides/sdk-and-transport.md — which of these calls are on the wire today.
  • guides/runbooks/register-in-commander.md — the publisher side of a hub's content.

Read this document as markdown — the same bytes an agent receives.