npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@galaxy-foundry/cast

v0.12.2

Published

The deterministic half of casting for Foundry-pattern instances — bundle placement, drift reconciliation, and the provenance record. The kinds, slug map and renderers stay per-instance.

Downloads

1,976

Readme

@galaxy-foundry/cast

Casting — turning a Mold into a frozen, target-specific skill artifact that can be re-derived byte-for-byte and checked for drift.

A cast is only worth anything if it can be reproduced. This package holds the whole of that: resolving each declared reference, placing its bytes, applying the redistribution policy, rendering the skill document, sweeping what stopped being a reference, and writing the provenance record. None of it varies by domain.

What is not here is everything that names a Foundry's own world — its kinds, its slug map, its validators, its renderers. Kind layouts and addresses arrive as explicit request inputs; rendering and instance checks arrive through CastHooks, so a Foundry adds its knowledge without forking the assembly.

cast is an early extraction rather than an admitted shared-substrate package. Its first consumer's committed bundles provide a byte-identity oracle; adoption by a second independent Foundry is what tests whether this boundary is genuinely reusable. See Deterministic casting architecture for the ownership map and the full flow.

import { castMold, castsTargetDir, loadTargetConfig } from '@galaxy-foundry/cast';

const targetDir = castsTargetDir(repoRoot, 'claude');

const outcome = await castMold({
  repoRoot,
  bundleRoot: bundleDir(targetDir, mold.name),
  targetName: 'claude',
  target: loadTargetConfig(targetDir),
  mold, // read off disk by you
  castContract, // the `cast:` half of your reference contract
  refKinds,
  slugMap,
  metaByPath,
  kindLayouts: DEFINITIONS,
  hooks: MY_HOOKS,
  check: args.check,
  note: null,
});

for (const error of outcome.errors) console.error(error);
process.exitCode = outcome.errors.length ? 1 : 0;

kindLayouts is the instance's Kind table, keyed by note type. Casting reads only its layout projection: shape, companions, and additionalCompanions. A companion with disposition bundled travels automatically; foundry-only and cast-input do not. Fixed membership is never repeated in note frontmatter or in the reference contract. A Kind with additionalCompanions: 'allow' may still let an individual note name its open-ended companion set.

Errors and drift come back as values and nothing is printed, because a cast that found four unresolved refs has produced a result rather than suffered a failure — and how that is rendered is the caller's decision. The one thing castMold decides is whether to publish, since that is a question about the staged bundle rather than about presentation.

Hooks are how a Foundry attaches, and they refuse rather than default

renderers supplies a function per non-verbatim mode; skillLede and skillSections say what the cast document contains; bundleFiles contributes files beyond the document and _provenance.json; bundleChecks runs an instance's own checks over the finished bundle.

One is optional, and that is the test of the boundary: a Foundry whose corpus is research notes has no artifacts, no tools and no commands, and should still cast. packageLoader answers the package-export strategy, and a contract that declares it while registering nothing gets an error naming the reference that asked rather than a fallback.

payload-companion needs no hook. Which file a note ships in its own place is the note's Kind saying disposition: bundled on exactly one companion — the same layout that expands companions for every other kind. An instance answering separately would be answering from that declaration anyway, with the freedom to disagree with it.

packageLoader exists because a bare import(spec) resolves relative to the file running it. Written inside this package, it would look for your dependencies beside its own installed copy. (spec) => import(spec), written anywhere in your tree, is the whole implementation.

Drift is a value, never an exit

reconcile reports what it found and, unless this is a --check run, brings the file into line. It does not decide what stale means. A caster reconciles many artifacts in one run and has to report them together, and it fails for reasons that are not file comparisons at all — an unresolved reference, a licence that forbids the mode it was asked for. Those verdicts have to combine, which they cannot do if one of them has already called process.exit.

The --check path is deliberately inert on disk. It writes nothing, and reconcileText creates the parent directory only on the write path — a check that created the bundle directory would make the next check pass for the wrong reason.

A drifted entry keeps the hash that was actually on disk, via recordedHash. The record reports what the check found, not what it wanted to find.

Placement belongs to the target

Where bundles sit is a property of the target, declared once in its _target.yml:

bundle_path: 'skills/{mold}'

That one declaration is why the Claude target's directory doubles as a Claude Code plugin root. A target that declares nothing gets one directory per bundle, named for it.

So does the vocabulary

What the document is called, and what a cast of a Mold is called, are the target's too:

document:
  path: SKILL.md
  noun: skill

SKILL.md is what one agent harness looks for; skill is what that harness calls what it finds. Both are required, with no default — a default would be the same assumption spelled as a fallback, and no longer visible in any target file. _provenance.json is not here: the record is the caster's own account of what it did, and everything that reads a bundle without knowing which target made it finds the record by that name.

required_outputs defaults to those two, so a target that requires exactly what casting writes says nothing. Declare it only to require something else.

Still hardcoded, and named here rather than generalised on one example: the document's name:/description: frontmatter. The target already declares that pair in skill_constraints.frontmatter_required, but closing the gap needs a rule for which value fills a declared key — which needs a second target to design against.

Quote it. bundle_path: {mold} is not the string it looks like — unquoted braces are YAML flow-mapping syntax, so it loads as { mold: null }, and bundlePathOf says so by name rather than letting a string operation fail three frames away.

Every function here takes the target directory, not a repo root and a target name. Where a Foundry keeps its targets is that Foundry's layout; castsTargetDir offers casts/<target>/ as the convention the first casting instance settled on, and nothing above it depends on that choice.

The provenance record

PROVENANCE_SCHEMA_VERSION is bumped when the record shape narrows. Adding an optional field leaves older records valid and needs no bump. Removing a field, or removing a value from an enum, makes a document that was valid yesterday invalid today — and one version number naming two incompatible contracts is worse than no version at all.

readProvenanceCarryOver preserves the hand-recorded half of an existing record: who cast it, when, under what note, what was left open. None of it is derivable from the sources, so a caster that rebuilt the record from scratch would drop it silently — and a drift gate cannot catch that, because the gate compares against exactly what the caster would write.

Licences are checked against what the cast did

applyLicensePolicy runs the shared redistribution-policy table over the assembled refs, keyed off each ref's recorded derived posture. A Foundry-authored own-words summary is outside the source licence's redistribution policy; a ref that preserves upstream expression remains governed by it. The cast mode is deliberately irrelevant: copying or rendering cannot change whose expression the note contains. The helper also stamps the content hash of any declared licence file, so the record says which licence text was in force.

It returns one message per violation rather than throwing. A cast reports all its problems together, and a licence failure has to combine with the unresolved refs and drifted artifacts found in the same run.

Which notes must declare a license_file at all stays with your validator: only an instance can tell a Foundry-authored licence annotation from genuine third-party redistribution.

Install

npm install @galaxy-foundry/cast

License

MIT