Home Design Record

Compilation Pipeline

How typed Mold references become target-specific cast artifacts with provenance.

reviewed meta
Revised
2026-08-02
Rev
30

How Molds become cast artifacts. Anchored to the file layout in architecture (molds/<name>/ -> casts/<target>/<name>/). Working premise: deterministic assembly first, LLM second, reproducible enough to diff. In this Foundry the deterministic half reaches all the way — there is no LLM phase, every reference is copied or built mechanically, and a re-cast of an unchanged Mold is byte-identical. That is what makes --check a gate rather than a diff review.

What casting is

Casting takes a Mold (a typed reference manifest plus a procedural body), its artifact IO contracts, and its declared references — pattern pages, CLI manual pages, IO schemas, prompt fragments, examples, and operational research notes — and produces a target-specific cast artifact. mold-spec owns the source-layout and manifest contract; this document describes how casting consumes that contract. The cast is isolated — no links back to the Foundry, no runtime dependency on it.

For the Claude target, SKILL.md is always rendered from Mold source. The renderer combines the Mold summary, input_artifacts[], output_artifacts[], inherited producer/schema metadata, resolved references[], and the procedural body of index.md. Generated skill bodies are not hand-maintained; if a cast looks under-instructed, improve the Mold body or referenced notes and re-cast.

Casting operates as per-kind dispatch over the manifest, not a single resolve-and-inline pass. Different reference kinds get different transformations:

Reference kindSource locationCasting transformationLands atStatus
patterncontent/patterns/*.mdVerbatim copy; may carry per-note companionsreferences/patterns/<slug>.mdv1
cli-commandcontent/cli/<tool>/<cmd>.md framing note plus registered upstream CLI metadataDeterministic JSON sidecar sourced from registry metadata + framing markdownreferences/cli/<slug>.json (flat — <slug> is the source basename)v1
schema[[wiki-link]] to a type: schema note in content/schemas/. The note declares package + package_export; cast imports the named runtime export at build time and serializes it. Foundry-authored: schemas in packages/<name>-schema/src/<name>.schema.json (e.g. summary-nextflow, galaxy-tool-discovery). Vendored: schemas synced from upstream packages into packages/<name>-schema/src/ (e.g. tests-format from @galaxy-tool-util/schema).Verbatim copy of the imported export, JSON-serializedreferences/schemas/<note-slug>.schema.jsonv1
researchcontent/research/<slug>/index.md plus any companion files in that directoryVerbatim copyreferences/notes/<slug>.md for the note; each companion keeps its own filenamev1
promptcontent/prompts/<area>/<slug>/index.md wrapper note plus its upstream.prompt companionRaw prompt sidecar copied verbatimreferences/prompts/<slug>.mdv1
examplecontent/molds/<slug>/examples/, shared content/examples/Verbatim copyreferences/examples/Contracted; caster rejects until a real Mold needs it
evalcontent/molds/<slug>/eval.mdNever packaged— (Foundry-only)n/a
mold (smell)another MoldDiscouraged; factor shared content into other reference kindsn/a

Every path above is deterministic. Which one a kind takes is not knowledge the caster holds: each kind’s cast: block in reference_contract.yml declares its resolve strategy (note, package-export, payload-companion), its default_mode, an optional slug_field, and whether its notes may carry companions. A kind with no cast: block is not castable, which is how example is refused — stated where the kinds live rather than in a second list inside the caster.

The inherited mode vocabulary is verbatim and sidecar, and this Foundry renders both — the copies above and the cli-command JSON. So it narrows nothing: every mode an author may spell here is one the caster can perform.

example is declared in the contract but no Mold uses it yet, so the caster fails fast rather than guessing dst conventions. prompt is active for wrapper notes; the raw text is the upstream.prompt file beside index.md, named by convention rather than declared in frontmatter.

Typed reference manifest

Molds declare operational dependencies through the object-shaped references manifest. mold-spec is canonical for field requirements and authoring rules; the reference contract is canonical for vocabulary labels and descriptions — reference_contract.yml for kind, @galaxy-foundry/reference-contract for the four inherited vocabularies. Casting reads the manifest, resolves each reference by kind, and writes the target-specific reference layout described below.

Mold IO contracts live on input_artifacts[] / output_artifacts[]. Producer-owned output_artifacts[].schema wiki-links point at schema notes that casting packages; consumers inherit those contracts by binding to the same artifact id.

Agent-facing vs. human-facing vendored artifacts

When an upstream project ships both a structured source (YAML, JSON Schema, IDL) and a derived human-rendered form (LaTeX-heavy Markdown, generated HTML), cast from the structured source, not the rendered form. The structured source is denser per token, schema-regular, and preserves identifiers (labels, test pin names) that the renderer typically discards.

Canonical examples: galaxy-collection-semantics and galaxy-xsd. Upstream (galaxyproject/galaxy) keeps the formal collection type-rule spec in lib/galaxy/model/dataset_collections/types/collection_semantics.yml, runs semantics.py to generate doc/source/dev/collection_semantics.md (MyST admonitions + LaTeX math), and keeps the Galaxy tool wrapper XML contract in lib/galaxy/tool_util/xsd/galaxy.xsd. The Foundry vendors these artifacts at the same SHA:

  • content/research/galaxy-collection-semantics/galaxy-collection-semantics.yml — canonical for casting and for any agent reasoning about collection mapping/reduction. Carries tests: blocks pinning concrete Galaxy test names that the rendered MD drops.
  • content/research/galaxy-collection-semantics/galaxy-collection-semantics.upstream.myst — vendored solely so the site can render the upstream view for human readers. Not consumed by casting.
  • content/research/galaxy-xsd/galaxy.xsd — canonical for casting and agent reasoning about Galaxy tool wrapper XML. Framed by galaxy-xsd and synced through the same vendored-upstream manifest as the collection-semantics artifacts.

Casting policy: a cast that needs collection-semantics knowledge resolves the .yml and inlines from there; a cast that needs Galaxy wrapper syntax resolves galaxy.xsd; the rendered MyST is a site-rendering concern only. Pattern generalizes — when both forms exist, agents read structure, humans read prose.

The casting process is itself expected to evolve. Today: deterministic SKILL.md assembly, deterministic file copies and sidecars, no LLM phase at all. Tomorrow: maybe additional target renderers, or a condensation phase if some kind ever earns one — the vocabulary for that is still in the shared contract, declined rather than deleted, so re-admitting it is a one-line narrowing change plus the machinery. The Foundry does not lock in every implementation detail; it locks in a contract (input shape, output shape, provenance).

When casting runs

Three triggers, in increasing automation:

  1. Manual. npm run cast -- <mold-name> --target=<target>. That is the whole cast — there is no follow-up phase, and SKILL.md is never hand-maintained.
  2. CI on Mold change. When a PR touches molds/<name>/, CI re-casts that Mold against all configured targets and surfaces the diff in review.
  3. Watch-on-change for development convenience.

Drift surfaces via foundry-build cast <mold> --check (per-Mold) and cast-skill-verify.ts <mold> (verifier rejects hash drift, missing dst, schema violations, and missing or stale SKILL.md). make check-casts and make check-verify run each over every Mold — the first as foundry-build cast-all --check, which sweeps in one process and says nothing when nothing moved. The sweep is @galaxy-foundry/cast; the list of Molds it sweeps is this Foundry’s, because every Mold here is expected to be cast.

Input contract

To cast a Mold, the casting process consumes:

  • The Mold directoryindex.md (frontmatter manifest + procedural body) plus, if the schema permits, casting hints. The cast renders the procedural body of index.md into SKILL.md. Which sibling files travel is not decided here: the mold kind declares a disposition per companion (packages/note-schema/src/types/mold/schema.ts), and the cast verifier refuses a bundle carrying one that is not bundled. eval.md and the other Foundry-only companions never leave the Foundry; casting.md and cast-skill-verification.md are read while casting but not shipped. Author-facing meta-content (changelog entries, casting open-questions) belongs in those sibling files, not in the body of index.md — anything in the body is runtime instruction.
  • Artifact IO contractsinput_artifacts[] and output_artifacts[] define what a skill consumes and produces. Producer-owned schemas declared on output_artifacts[].schema are surfaced to consumers by shared artifact id; cast provenance records the producer list and inherited schema hints for harnesses.
  • All typed references declared in the manifest, resolved by kind:
    • references — object-shaped typed references with kind, ref, used_at, load, and mode; this is the preferred manifest for new operational references.
    • patterns — legacy wiki links into content/patterns/.
    • cli_commands — legacy wiki links into content/cli/<tool>/<cmd>.md.
    • output_artifacts[].schema (and inherited consumer-side schemas via input_artifacts[].id) — wiki-links into content/schemas/<name>.md; resolved at cast time via the schema note’s package + package_export to a runtime import from packages/<name>-schema/.
    • prompts — legacy wiki links into content/prompts/ (when the Mold needs them).
    • examples — legacy paths into content/molds/<slug>/examples/ or shared content/examples/.
    • IWC exemplar URLs cited in pattern bodies are resolved by the pattern transformation, not by the casting top-level (URLs stay URLs in pattern bodies; pinning to a SHA is at the pattern author’s discretion).
    • Other Molds (related_molds) — flagged as a smell; shared operational content should move to a pattern page, CLI manual page, schema, prompt, example, or research note.
  • The cast bundle spec — the deterministic Agent Skills assembly and reference layout declared in casts/claude/_target.yml. The historical target name remains for provenance compatibility; Claude Code and Codex package the resulting tree through separate thin manifests.

Resolution policy is per-kind, not a single rule:

  • pattern — verbatim copy, and one of the two kinds whose notes may declare companions.
  • cli-command — always cast to JSON sidecar from registered upstream metadata plus the Foundry framing note; no token-budget condensation needed because the sidecar is loaded only when the agent needs that command.
  • schema, example, prompt — always verbatim copy unless the typed reference declares a future supported transformation.
  • research — operational background; copied verbatim, loaded according to used_at / load, and the other kind that may carry companions.
  • eval — never packaged.

Output contract

Per cast: casts/claude/skills/<mold-name>/. The directory uses the portable Agent Skills core shared by Claude Code and Codex:

casts/claude/skills/<mold-name>/
├── SKILL.md                  # deterministic render of Mold body + artifacts + refs
├── references/               # supporting content, organized by kind
│   ├── schemas/              # verbatim *.schema.json
│   ├── cli/                  # deterministic JSON sidecars (flat, <slug>.json)
│   ├── patterns/             # verbatim pattern excerpts
│   ├── notes/                # research notes, verbatim
│   ├── prompts/              # raw prompt sidecars copied from prompt wrapper notes
│   └── examples/             # populated when example refs exist
└── _provenance.json          # required, not part of the skill (schema v4 — see below)

Per-kind dst conventions are declared in casts/claude/_target.yml (kinds.<kind>.dst_dir + dst_extension + allowed modes). For verbatim modes the dst basename matches the source 1:1; for sidecars it’s <source-slug><dst_extension>.

Per-kind subdirectories under references/ mirror the casting dispatch and let the generated skill’s runtime locate any artifact deterministically.

SKILL.md contains deterministic sections for when to use the skill, upstream artifact inputs, produced artifacts, upfront references, on-demand references and triggers, validation hints, the Mold procedure, and runtime notes. Raw Foundry wiki-links are stripped or resolved to packaged reference paths so the skill is self-contained. Its frontmatter stays in the shared name/description core; runtime-specific invocation syntax belongs in manifests and usage documentation.

The plugin root carries both .claude-plugin/plugin.json and .codex-plugin/plugin.json, each pointing to the same skills/ directory. Repo marketplace metadata is likewise thin: Claude reads .claude-plugin/marketplace.json, while Codex reads .agents/plugins/marketplace.json. Neither duplicates skill bodies, references, schemas, provenance, or Pipeline assemblies.

Claude is the only target. A target becomes real by acquiring a casts/<target>/_target.yml — that file’s existence is what the caster and the site each read, so there is no list of targets anywhere to keep in step with the directories.

_provenance.json is required for every cast. The contract of record is the cast-provenance schema note (rendered field-by-field from scripts/lib/schemas/cast-provenance.schema.json, schema version 4); the JSON below is an illustrative sketch, not the authority. Shape:

{
  "provenance_schema_version": 4,
  "cast_target": "claude",
  "mold": {
    "name": "summarize-nextflow",
    "path": "content/molds/summarize-nextflow/index.md",
    "revision": 7,
    "content_hash": "<sha256 of index.md>",
    "commit": "<git SHA at cast time>"
  },
  "cast_at": "2026-05-02T22:44:00.546Z",
  "cast_history": [
    { "rev": 1, "date": "2026-05-01", "note": "initial deterministic cast" }
  ],
  "refs": [
    {
      "kind": "research",
      "mode": "verbatim",
      "ref": "[[component-nextflow-testing]]",
      "src": "content/research/component-nextflow-testing/index.md",
      "dst": "references/notes/component-nextflow-testing.md",
      "used_at": "runtime",
      "load": "on-demand",
      "evidence": "hypothesis",
      "src_hash": "<sha256>",
      "dst_hash": "<sha256>",
      "source": "deterministic"
    },
    {
      "kind": "cli-command",
      "mode": "sidecar",
      "ref": "[[planemo-test]]",
      "src": "content/cli/planemo/test.md",
      "dst": "references/cli/test.json",
      "used_at": "runtime",
      "load": "on-demand",
      "trigger": "before running a tool test",
      "src_hash": "<sha256>",
      "dst_hash": "<sha256 of the built sidecar>",
      "source": "deterministic"
    }
  ],
  "artifacts": {
    "produces": [
      { "id": "summary-nextflow", "kind": "json", "default_filename": "summary-nextflow.json", "schema": "[[summary-nextflow]]", "description": "..." }
    ],
    "consumes": [
      { "id": "nextflow-galaxy-interface", "description": "...", "producers": ["nextflow-summary-to-galaxy-interface"] }
    ]
  }
}

refs[] is sorted by (kind, src) for stable diffs. Each entry’s source records how the dst was produced; it is deterministic and nothing else, kept as a positive claim rather than dropped so a reader never has to infer determinism from a missing field. A verbatim entry proves itself with src_hash == dst_hash. artifacts records the runtime handoff contract after producer inheritance.

Provenance is the foundation for drift detection, reproducibility audits, and “why does this cast contain X” forensics. See cast-provenance for the per-field contract and stable anchors.

Schema artifacts in casts

The test-format schema is the canonical case. @galaxy-tool-util/schema ships tests.schema.json (generated from galaxy.tool_util_models.Tests Pydantic models — see galaxyproject/galaxy#22566 and jmchilton/galaxy-tool-util-ts#75 for the source-of-truth chain). It carries every assertion’s parameters, types, defaults, required fields, the that discriminator constant, and the original Python docstring as description. An agent equipped with that JSON Schema can author syntactically valid <workflow>-tests.yml and look up what each assertion does — no prose vocabulary catalog required.

Casting policy for upstream-package schemas:

  • Source of truth lives upstream. The Foundry pins a version (in its toolchain package.json for npm, etc.) but does not edit the schema.
  • Casting copies the schema verbatim into references/schemas/. The generated skill’s runtime loads it for AJV / equivalent validation; no Foundry round-trip needed.
  • Bundle helper functions when applicable. For test-format specifically, @galaxy-tool-util/schema also exports validateTestsFile and checkTestsAgainstWorkflow (label/type cross-check between a .ga and a tests file). When a cast’s runtime is Node-capable, depending on the package directly is cleaner than vendoring just the JSON; the dependency is also recorded in _provenance.json so reviewers can see the version pin.
  • Schema-page rendering in the Foundry uses the same vendored copy. The Foundry syncs the vendored test schema to packages/foundry/src/schemas/tests-format/tests.schema.json and renders it via site/src/lib/schema-registry.ts as a navigable schema note, so research notes and Mold bodies can deep-link individual $defs (e.g. [[tests-format#has_text]]). The vendored JSON is the single source for both casting output and site rendering.

Other schemas that fall under this policy as they land:

  • gxformat2 — workflow source format. Schema-Salad-derived; vendored similarly.
  • Mold IO summary schemas (summarize-nextflow, summarize-cwl, and future structured summaries) — Foundry-authored under packages/<name>-schema/src/, paired with a <name>.md schema note in content/schemas/; cast and site-rendered through the same machinery so consumers see one consistent surface. Narrative starts (summarize-paper, interview-to-freeform-summary) currently emit Markdown freeform-summary rather than a rigid schema.

The reference-kind schema does not distinguish between Foundry-authored and upstream-vendored at cast time — both are verbatim copies. The distinction matters only for sync/update flow: upstream schemas update via package bumps, Foundry-authored schemas update via direct edits.

Process steps (per cast)

cast_mold(mold_name, target):
  mold     <- read molds/<mold_name>/index.md
  validate mold against frontmatter schema (incl. typed-reference manifest)
  refs     <- resolve_manifest(mold)               # by kind: references plus legacy fields
  validate every ref exists and conforms to its kind's contract
  target   <- load_target_adapter(target)

  # Per-kind dispatch:
  for ref in refs:
    case ref.kind:
      pattern      -> verbatim copy (plus any declared companions)
                      write to references/patterns/<source-basename>
      cli-command  -> deterministic JSON sidecar from registry metadata + framing body
                      write to references/cli/<source-slug>.json
      schema       -> copy verbatim to references/schemas/<source-basename>
      research     -> copy verbatim (plus any declared companions)
                      write to references/notes/<source-basename>
      prompt       -> copy sibling `upstream.prompt` verbatim to references/prompts/<slug>.md
      example      -> reject until first example ref establishes target convention
      eval         -> skip (never packaged)

  artifacts <- read_artifact_contracts(mold.meta, producer_index)
  skill_md  <- target.assemble_skill(mold.summary, mold.body, artifacts, refs)
  write SKILL.md to casts/<target>/<mold_name>/
  write _provenance.json (schema v4: mold object, refs[] sorted by kind+src,
                          per-ref src_hash/dst_hash, source=deterministic,
                          per-ref license lineage for redistributed bytes)

foundry-build cast handles verbatim copies, sidecars, SKILL.md rendering, orphan pruning, and provenance — the whole cast. Nothing hand-edits a bundle; skill-body changes flow from Mold source changes, and a hand edit is reported as drift by --check and overwritten by the next cast. The deterministic verifier (scripts/cast-skill-verify.ts) enforces the contract on the result.

Drift detection

A cast is stale when any of:

  • The Mold’s index.md content hash differs from _provenance.mold.content_hash.
  • Any resolved ref’s source hash differs from the recorded refs[*].src_hash, or its dst hash drifts from refs[*].dst_hash.
  • The deterministic SKILL.md render differs from the committed SKILL.md.
  • The target adapter has changed.

foundry status enumerates stale casts; foundry cast --all re-casts every stale entry. Re-casting an unchanged Mold with unchanged refs produces the same SKILL.md, sidecars, copied refs, and provenance except for cast timestamps, commit, and history — which is exactly what make check-casts asserts over all 47 Molds.

Versioning

No semver on Molds, no semver on casts. Identity is content hash + commit SHA. Re-casting is the migration path. If a generated skill needs to be “frozen” (e.g., a published skill on a marketplace), pin it by commit SHA in the consumer.

This keeps the Foundry’s iteration loop fast: change a Mold, re-cast, review the diff. Don’t bump versions, don’t manage compatibility tables, don’t write changelogs for every cast.

Reproducibility

Casting is deterministic end to end. Every cast records exactly what went into it (Mold hash, ref hashes, license lineage, artifact contracts). A reviewer can:

  • Check whether a cast is up-to-date (drift detection).
  • Reproduce deterministic cast outputs from the recorded Mold and refs.
  • Compare two casts’ provenance to explain content differences.

Assembly is byte-stable aside from timestamps, commit, and provenance history. There is no non-deterministic path left to carve out of that guarantee, which is why the drift gate can be a pass/fail check in CI rather than a diff a human reads.

What casting does not do

  • Does not write to the Foundry. Casting is read-only against content/molds/, content/patterns/, content/cli/, content/prompts/, content/examples/, and content/schemas/. All writes go to casts/.
  • Does not invoke gxwf or Planemo. Those are the generated skill’s responsibility at runtime, not casting time. (Validation tooling does invoke schemas, but that’s distinct.)
  • Does not update Molds. If casting reveals a generated skill is weak or wrong, migrate the needed instruction into the Mold body or referenced notes by hand, then re-cast.
  • Does not touch eval plans. eval.md is Foundry-only; never read by casting.

Minimum Exercise

To exercise the architecture without overbuilding:

  • One cast target: Claude. A second one starts by adding casts/<target>/_target.yml.
  • One casting model: pick one, pin in casts/claude/_target.yml.
  • Cast 3-4 Molds end-to-end: summarize-paper or interview-to-freeform-summary (exercises freeform Markdown handoff), implement-galaxy-tool-step (exercises pattern + example), advance-galaxy-draft-step (exercises orchestrator-shaped Mold with cli-command references and leaf sequencing), validate-galaxy-workflow (exercises terminal validation posture). Diversity exercises the per-kind dispatch, not just the prompt.
  • Manual foundry cast only.
  • Commit casts to the repo so we can review the actual outputs.

If those casts look reasonable and the provenance flow holds, scale to more Molds and more targets.