Code Architecture
This record answers what implementation exists today, what each part owns, and which direction its dependencies flow. Note semantics belong to content-model, physical placement to repository-layout, and what runs to build-and-validation.
Current stack
Dependencies run one way. Shared packages take explicit inputs; they never discover this repository’s paths, vocabulary, or acceptance rules. The instance never reimplements a mechanism a package owns.
There is one application, site/, and no local package workspace or standalone build CLI. The
casting commands also live under site/ because they consume the same TypeScript kinds and content
binding; their generated artifacts live at the repository root under casts/.
Kind definitions
site/src/types/ owns the
note kinds. Each kind is a directory holding three files: schema.ts (the strict Zod contract,
shape, and companion declarations), kind.md (why each required field is required), and
example.md (a minimal note parsed against its own schema by the tests, so the documentation stays
executable).
types/context.ts builds the KindContext a kind receives: the base envelope, the license-id
primitive, the typed-reference entry, and — for the kinds that need to interrogate rather than
merely validate — the tag registry and license policy themselves. Method and Application notes
have to ask which facet declared a proposed anchor; a Paper note has to ask what a license row
permits. types/index.ts is the single enumeration of concrete kinds, exported both as a keyed
DEFINITIONS map and an ordered KINDS array.
@galaxy-foundry/kind-schema
supplies the definition, assembly, and companion mechanics. It ships no domain kinds. The
directory-per-kind layout is a cross-instance contract implemented independently in all three
Foundries, not a local preference. The library’s
package-boundary rationale
explains why the reusable mechanism stops short of owning those kinds.
The Paper kind is the one exception to a kind being wholly local, and it is a deliberate one. Its
source-facing frontmatter — bibliographic identity, license posture, and read coverage — is the
shared contract from
@galaxy-foundry/source-note,
spread into the kind and refined by that package’s coherence rules. Describing someone else’s work
is the same problem in every Foundry; what stays local is which kinds are source notes, and
everything that describes the note rather than its source.
Contract composition
site/src/lib/frontmatter-schema.ts
is the composition point. It assembles each kind against the live registries, exposes them as
NOTE_KINDS, states the content root once as CONTENT_DIR with a contentPath helper, and declares
COLLECTIONS — the one mapping from content location to kind, glob, and schema.
COLLECTIONS is also the route table and the wiki-link precedence order, and both facts are
content decisions rather than formatting ones; content-model owns why the rows sit in the order
they do. No page, test, or resolver may carry a second collection list.
site/src/content.config.ts is a thin Astro adapter over that table. Its collections are spelled
out one at a time rather than mapped, because a .map collapses every row to the widest common
type and Astro stops discriminating the frontmatter shapes.
Registries and shared substrate
site/src/lib/registries.ts
joins the instance-owned halves of the shared contracts into the one object every kind context is
built from:
meta-tags.tsloadsmeta_tags.ymlthrough@galaxy-foundry/tag-registry;reference-contract.tsloads both the reference vocabulary and its cast declarations through@galaxy-foundry/cast, which composes the shared@galaxy-foundry/reference-contractterms and narrows cast modes to this instance’s supported set;@galaxy-foundry/license-policysupplies the redistribution table as bundled data, with no local file to keep in step.
Both loaders resolve their file relative to the site working directory and cache it. The adapters supply paths and concrete vocabularies; they do not re-export or reimplement a package API.
Content and link access
site/src/lib/content-reader.ts
binds
@galaxy-foundry/content-reader
to the collection table, a route mapping, and this corpus’s alias rule. Its exported factory accepts
a content-path resolver: Astro supplies its content-relative frame, while casting supplies a
repository-root frame. Both therefore get filesystem enumeration, note ids, frontmatter, aliases,
and link targets from the same reader rather than maintaining parallel corpus walks. Its
boundary design
shows why Astro types stay on the application side of that seam.
remark-wiki-links.ts adapts that resolver with
@galaxy-foundry/wiki-links
for astro.config.mjs. This is the one module reachable from the Astro config, and the constraint
it carries is easy to trip: config loads outside Astro’s module graph, so nothing reachable from it
may import astro:content. Here the content reader is filesystem-based and imports no Astro
runtime, which is what keeps the constraint satisfied without a second module split.
remark-citation-links.ts is the second module the config reaches, and carries the same
constraint plus one of its own. It links a note’s numbered citation markers — [3], [1, 2],
[7–9] — to the entries of that note’s own bibliography, giving each entry an id and each written
number a link, and failing the build when a marker names an entry the list does not hold. Which
heading opens a bibliography is not its decision: it reads referenceHeadingTerms from
audit-citations.config.json as raw JSON, because the package that owns that vocabulary is a
development dependency the site build may not import. The config is found by walking up from the
working directory, since a module-relative import.meta.url is a /@fs/… URL under Vite rather
than a path on disk.
render-vault-doc.ts is the corresponding path for a loose document — currently only the glossary.
It resolves links through the same reader, renders with marked, and adds the bold-term anchors the
glossary’s own page links into.
companions.ts measures a directory-shaped note’s siblings against its kind’s declarations rather
than trusting frontmatter, which is why environment has no locked field.
Presentation registries
tags.ts, design-records.ts, and detail-routes.ts are presentation registries over already
validated content: they decide which notes appear on a surface and what to label them. tags.ts
also projects an optional facet_tag into the guide that leads a tag page; the page takes its guide
label from the declaring kind, so Method and Application anchors share one mechanism. They do not
define note membership, and each is held to the collection table by a test — DETAIL_ROUTES in
both directions, the tag surface by the registry-drift check.
motifs.ts is domain furniture with no content dependency at all: a stable hash from a note’s
metadata to repeatable point-cloud and barcode geometry, so a note’s marginalia is derived rather
than authored and never changes between builds.
Reading application
site/src/pages/ owns routes. Every collection detail page runs through one route,
[collection]/[...slug].astro, with collection-specific metadata in explicit branches; the common
frame, breadcrumb, and tag links live once. Per-collection index pages, the glossary, the tag
surface, the design index, and the home page are the remaining routes.
The reading shell — document skeleton, header, navigation, theme toggle, search, footer — is not
here. It comes from
@galaxy-foundry/site-kit,
and site/src/layouts/Base.astro is only the composition point: it hands the package a
SiteIdentity and the base URL and receives the markup. The
site-kit runtime note
documents the server-rendered shell and its small progressive-enhancement boundary.
What stays local is that identity, the palette and type system in src/styles/global.css (custom
properties the kit names but does not ship), and the domain components in src/components/. That
stylesheet also has to point Tailwind at the package, because source detection does not look inside
node_modules, and the built-output test is what checks it did.
Shipping no stylesheet has two further consequences, and both fail without an error. Element
defaults here belong in @layer base, because unlayered CSS outranks every layer whatever its
specificity: a bare a { color } outside one repaints the header and footer the kit colours with
utilities, and the style-contract check still passes, since the utility is emitted and merely
outranked. The shell’s behaviour at narrow widths is local for the same reason — navVisible is one
number measured against a wide bar, and no count fits a phone, so the wrapping rule is this
stylesheet’s to write. Built-output tests hold both.
site/src/pages/gallery/ is the visual acceptance surface for that boundary. It imports every case
from @galaxy-foundry/site-kit/specimens and renders the shared components through this instance’s
theme; package-declared isolated and document surfaces receive generated standalone routes.
Local specimen groups place the filtration hero, persistence divider, point-cloud fingerprint,
topology breadcrumb, and every declared reference kind beside the shared cases without moving
their domain vocabulary into the package. Built-output tests require complete shared and local
coverage, every standalone route, the gallery’s design-index link, and the intended search policy.
src/pages/usage/ is the publication surface for committed casts. lib/casts.ts discovers targets
from their _target.yml declarations, resolves bundle placement through @galaxy-foundry/cast,
and exposes the same inventory to the usage index, per-skill static routes, and the source Mold’s
cast panel. lib/repo-root.ts anchors that filesystem read on Astro’s configured project root, so
prerender bundling cannot silently turn a populated cast tree into an empty page.
The Astro application is a pure reader. It validates and renders source but does not mutate notes or cast artifacts. The only client-side code is progressive enhancement — the homepage filtration control — and there is no UI framework. Mutation is confined to explicit build-time commands.
Generation, citation audit, and casting
site/scripts/generate-kind-manifest.ts derives src/types/kinds.generated.json from the live kind
definitions, their kind.md and example.md, and the collection table, through
@galaxy-foundry/kind-manifest.
It imports the same contracts validation does rather than building a parallel model, and it has a
--check mode. build-and-validation owns when it runs; the library’s
manifest-provenance note
describes the trust boundary.
The citation audit is a second build-time path, not part of the reader stack above.
@galaxy-foundry/audit-citations
owns extraction, provider normalization, comparison, adjudication, and report rendering.
audit-citations.config.json supplies this instance’s corpus and provider policy;
site/src/lib/citation-audit.ts binds the package to committed evidence and exposes the offline
replay used by site/tests/citation-audit.test.ts. Live provider access stays in the scheduled
workflow. repository-layout owns the committed files and build-and-validation the commands
and gates. See the shared
citation-audit architecture
for the separation between evidence acquisition, replay, and adjudication.
The tool-alignment audit is a second checker on that same path, and it is local. Its evidence is
already in the repository — each fixture’s prose is checked against the pixi.toml and pixi.lock
committed beside it — so there is no provider layer, no refresh, and nothing to acquire.
site/src/lib/audit/tool-alignment/ holds the parts that know about pixi: manifest and lock
parsing, the claim grammar, comparison, and report rendering. The parts that know about neither pixi
nor citations are no longer here at all — they are @galaxy-foundry/audit-base, which
audit-citations also consumes.
Two artifacts feed that grammar: the Environment note, and the manifest’s own header comment. They
differ only in how a file becomes prose, so extract.ts exposes an entry point per artifact over
one shared scan rather than a grammar per file — two grammars would drift apart exactly as the two
files do. The artifact a claim came from travels with it in span.artifactKind, which is also the
first exercise that field has had: a discriminator with one value is a field nothing has tested.
The local half is tool-alignment/lifecycle.ts, and what it holds is exactly what the package
refuses to own. The verdicts and the evidence states, because the two checkers share one value of
each and a common union would be a lowest common denominator or an untagged mixture. The claim id,
because a citation candidate has no kind and a claim does, so one sentence can produce a channel
claim and a version claim over one span. The corpus digest, because this one hashes ordered ids and
the citation one hashes full records, which answer different questions about what counts as the same
corpus. Each is a divergence that was found rather than assumed.
That boundary was laid out to make the extraction question answerable rather than to presume the
answer, and the answer came out cleanly: the shapes are one contract with the vocabulary taken out.
The two byte-identical files moved unchanged, the re-typed shapes moved as parameterized schemas,
and the local file is what is left. audit/tool-alignment-README.md keeps the comparison and the
remaining known limits.
Casting is the other build-time path. cast-corpus.ts projects the shared content index into the
two maps the cast engine consumes. cast-spec.ts composes that corpus with the Kind definitions,
reference contract, target-independent hooks, and supported modes. The local scripts are thin
terminal adapters over @galaxy-foundry/cast: one casts a named Mold, and one checks or rewrites
the committed set. The target file under casts/claude/ owns bundle placement and runtime-path
constraints; the Environment Kind owns which companions are bundled. TDA code contributes the
domain prose around those shared mechanics, not a second caster.
Publication adds no second cast. The claude target is a portable Agent Skills tree, with one thin
plugin manifest for Claude Code and one for Codex inside the target directory, plus each runtime’s
repository marketplace manifest at the repository root. Both runtime adapters point at
casts/claude/skills/; tests/cast-publishing.test.ts checks their identity, placement, and
portable name/description frontmatter.
Deliberate absences
- No package workspace. One application, so contracts live beside it. Extracting them becomes worthwhile when a second consumer needs them without depending on the Astro project.
- No server or database. The output is a static site with a static search index.
A record must not describe machinery as running before it runs. A reader who finds a present-tense sentence about a command and then cannot find the command has no way to tell whether the record is aspirational or the checkout is broken.
Code orientation
| Concern | Primary location |
|---|---|
| note kinds, context, enumeration | site/src/types/ |
| schema and collection composition | site/src/lib/frontmatter-schema.ts |
| Astro collection wiring | site/src/content.config.ts |
| instance registries | site/src/lib/registries.ts and its loaders |
| file discovery, ids, link map | site/src/lib/content-reader.ts |
| Markdown link adapters | site/src/lib/remark-wiki-links.ts, render-vault-doc.ts |
| companion measurement | site/src/lib/companions.ts |
| presentation registries | site/src/lib/tags.ts, design-records.ts, detail-routes.ts |
| shell composition and identity | site/src/layouts/Base.astro, site/src/lib/site-identity.ts |
| shared and local visual acceptance | site/src/pages/gallery/, site/src/lib/gallery.ts |
| domain furniture | site/src/components/, site/src/lib/motifs.ts |
| routes | site/src/pages/ |
| committed-cast discovery and usage UI | site/src/lib/casts.ts, site/src/pages/usage/, site/src/components/CastArtifacts.astro |
| corpus and contract tests | site/tests/ |
| kind-manifest generator | site/scripts/ |
| cast composition and commands | site/src/lib/cast-*.ts, site/scripts/cast.ts, site/scripts/check-casts.ts |
| cast target and committed bundles | casts/ |
| runtime plugin and marketplace adapters | casts/claude/.{claude,codex}-plugin/, .claude-plugin/, .agents/plugins/ |
| citation-audit binding and test | site/src/lib/citation-audit.ts, site/tests/citation-audit.test.ts |
| citation policy and committed evidence | audit-citations.config.json, audit/ |
| audit lifecycle shared by both | @galaxy-foundry/audit-base |
| verdicts, evidence states, claim ids | site/src/lib/audit/tool-alignment/lifecycle.ts |
| pixi claim grammar and comparison | site/src/lib/audit/tool-alignment/ |
| tool-alignment binding and test | site/src/lib/tool-alignment-audit.ts, site/tests/tool-alignment.test.ts |
Update this record when a component, dependency seam, entry point, or deliberate absence changes.