Skip to content

Packaging and distribution

Defined in the packaging contract and the distribution build. Everything on this page runs at developer build time. Users install the prepared output and never run a generator.

flowchart LR
accTitle: Package build pipeline
accDescr: Inputs listed in the closed allowlist feed three host packagers that write dist packages and inventories; the distribution builder produces deterministic ZIPs and a parity inventory; tests and the release rehearsal validate them.
IN[packaging-inputs.json<br/>112 allowlisted inputs] --> PC[package_claude.py]
IN --> PX[package_codex.py]
IN --> PP[package_copilot.py]
PC --> DC[dist/claude/]
PX --> DX[dist/codex/kiyo-axiom-framework/]
PP --> DP[dist/copilot/kiyo-axiom-framework/]
DC --> PD[package_distributions.py]
DX --> PD
DP --> PD
PD --> Z[dist/archives/*.zip<br/>deterministic]
PD --> INV[inventory JSON<br/>hashes + 456 parity rows]
Z --> V[verify_payload.py<br/>+ tests/*]
INV --> V

tools/packaging-inputs.json (format kiyo-packaging-inputs-1) lists exactly 112 inputs:

  • LICENSE;
  • the three platform manifests;
  • the three activation adapters;
  • the 105 canonical src/kiyo/**.md files.

The builder rejects the build if the real src/kiyo tree differs from the allowlist (“Product tree differs from reviewed input allowlist”). It also rejects absolute paths, .., backslashes, symlinks, and reparse points. .git, credentials and .env, actual project Memory, logs, fixtures, node_modules, and developer scripts can never enter a package.

For each of the eight Skills, the host packager:

  1. copies the shared subtrees framework, governance, agent-security, workflows, profiles, and templates, plus KIYO.md, into skills/<name>/references/kiyo/, byte for byte (97 files);
  2. renders SKILL.md, normalizing CRLF to LF and rewriting local entry links from ../../ to ./references/kiyo/;
  3. appends a short “native guidance” link to the host adapter at references/<host>/activation.md;
  4. validates budgets, contained links, anchors, and https-only external URLs.

Worked example, from the contract:

Stage Path or operation
Canonical entry src/kiyo/skills/review/SKILL.md links ../../KIYO.md and ../../workflows/review.md
Shared rule workflows/review.md links ../framework/evidence-contract.md
Build transform Entry links become ./references/kiyo/KIYO.md and ./references/kiyo/workflows/review.md
Shared snapshot The shared layout is preserved, so ../framework/ still resolves inside the snapshot
Native root Claude dist/claude/; Codex and Copilot dist/<ecosystem>/kiyo-axiom-framework/
Host Manifest Fields
Claude Code .claude-plugin/plugin.json Exactly name, description
Codex plugin.json (Agent Plugins 1.0.0 schema) plus derived .codex-plugin/plugin.json $schema, name, description, extensions.com.openai.interface; capabilities: []
Copilot plugin.json (Agent Plugins 1.0.0 schema) $schema, name, description

No version, author, repository, license, or publisher field is set. Those are owner decisions, and the static tests fail if an unapproved release identity appears. The “1.0.0” in $schema is the schema version, not a product version.

tools/package_distributions.py builds all three packages and writes kiyo-axiom-framework-<target>-development.zip with:

  • a single kiyo-axiom-framework/ root;
  • ZIP_STORED (no compression);
  • sorted members;
  • file mode 0644;
  • a fixed 1980-01-01 timestamp, which is serialization metadata, not a build date.

Two builds from identical inputs must produce identical bytes.

Archive Files Size (bytes)
Claude 794 3,850,801
Codex 795 3,857,159
Copilot 794 3,861,873

The inventory (kiyo-distribution-inventory-1) binds input, tool, and output SHA-256 hashes, and includes 456 parity rows: 6 targets × (68 controls + 8 Skills). Each row is marked behavioral evidence NOT_RUN. Hashes are not signatures, certification, or proof of behavior.

tools/verify_payload.py imports no repository modules. It checks an extracted payload for:

  • allowed root entries and case collisions;
  • exactly eight Skills with valid frontmatter;
  • entry budgets;
  • all eight shared copies identical;
  • no absolute or home paths;
  • contained, exact-case links with existing anchors.

It installs a Python audit hook that denies reads outside the payload and any socket or subprocess. The code itself notes that this is not an OS sandbox.

tools/release_candidate.py runs six stages into a fresh dist/releases/<run>/ directory. It never installs, signs, or publishes.

flowchart LR
accTitle: Release rehearsal stages
accDescr: Validate, package twice and compare, inspect extracted payloads, run static, packaging and release tests, write artifact inventories, then write a readiness report that always records publication as blocked.
V[1 · Validate<br/>revision + version consistency] --> P[2 · Package twice<br/>byte-equal]
P --> I[3 · Inspect payload<br/>safe extraction]
I --> T[4 · Run tests<br/>static · packaging · release]
T --> A[5 · Artifact inventory<br/>dependencies · attribution · SHA256SUMS]
A --> R[6 · Readiness report<br/>publication BLOCKED]

Recorded outcome: PACKAGE_VALIDATED_WITH_LIMITATIONS for run p30-run-01, with the Windows symlink probe BLOCKED by OS privilege. The result always records NOT_SIGNED, NOT_ATTESTED, and NOT_PUBLISHED.

Plugin updates replace generated, immutable content. They never modify project policy, Memory, or a managed instruction block, and uninstall never deletes user state. Exact native cache and update behavior per host remains an evidence gate (NOT_TESTED).