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
<rect width="1040" height="700" rx="28" class="architecture-canvas" />
<rect width="1040" height="700" rx="28" fill="url(#architecture-grid)" />
<text x="60" y="38" class="architecture-tier-label">CONSUMERS</text>
<a
href="https://github.com/jmchilton/bio-topo-foundry/tree/main/site/src"
aria-label="Browse the Astro reader source on GitHub"
>
<g class="architecture-card architecture-card-reader">
<rect x="60" y="58" width="430" height="126" rx="18" class="architecture-node" />
<circle cx="92" cy="90" r="8" class="architecture-status-dot" />
<text x="112" y="96" class="architecture-node-label">RUNTIME READER</text>
<text x="88" y="132" class="architecture-node-title">Astro application</text>
<text x="88" y="158" class="architecture-node-detail">pages · layouts · domain components</text>
<text x="456" y="151" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
<a
href="https://github.com/jmchilton/bio-topo-foundry/tree/main/site/tests"
aria-label="Browse the build-time verification source on GitHub"
>
<g class="architecture-card architecture-card-audit">
<rect x="550" y="58" width="430" height="126" rx="18" class="architecture-node" />
<circle cx="582" cy="90" r="8" class="architecture-status-dot" />
<text x="602" y="96" class="architecture-node-label">BUILD-TIME PRODUCTION + VERIFICATION</text>
<text x="578" y="132" class="architecture-node-title">Artifacts and checks</text>
<text x="578" y="158" class="architecture-node-detail">casts · tests · manifests · citation audit</text>
<text x="946" y="151" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
<path
d="M 275 184 V 236 H 520 V 272"
class="architecture-connector"
marker-end="url(#architecture-arrow)"
/>
<path
d="M 765 184 V 236 H 520 V 272"
class="architecture-connector architecture-connector-audit"
marker-end="url(#architecture-arrow-audit)"
/>
<g class="architecture-composition">
<rect x="60" y="272" width="920" height="204" rx="24" class="architecture-composition-shell" />
<text x="88" y="307" class="architecture-tier-label">INSTANCE COMPOSITION</text>
<text x="950" y="307" text-anchor="end" class="architecture-owner-label">owned here</text>
<a
href="https://github.com/jmchilton/bio-topo-foundry/blob/main/site/src/lib/frontmatter-schema.ts"
aria-label="Open the frontmatter schema composition source on GitHub"
>
<g class="architecture-card">
<rect x="88" y="330" width="270" height="116" rx="16" class="architecture-node" />
<text x="112" y="362" class="architecture-node-label">01 · CONTRACTS</text>
<text x="112" y="396" class="architecture-node-title architecture-node-title-small">Schema + collections</text>
<text x="112" y="423" class="architecture-node-detail">frontmatter-schema.ts</text>
<text x="328" y="421" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
<a
href="https://github.com/jmchilton/bio-topo-foundry/blob/main/site/src/lib/registries.ts"
aria-label="Open the instance registry source on GitHub"
>
<g class="architecture-card">
<rect x="385" y="330" width="270" height="116" rx="16" class="architecture-node" />
<text x="409" y="362" class="architecture-node-label">02 · INSTANCE DATA</text>
<text x="409" y="396" class="architecture-node-title architecture-node-title-small">Registries</text>
<text x="409" y="423" class="architecture-node-detail">vocabulary + policy adapters</text>
<text x="625" y="421" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
<a
href="https://github.com/jmchilton/bio-topo-foundry/blob/main/site/src/lib/content-reader.ts"
aria-label="Open the content-reader adapter source on GitHub"
>
<g class="architecture-card">
<rect x="682" y="330" width="270" height="116" rx="16" class="architecture-node" />
<text x="706" y="362" class="architecture-node-label">03 · ADAPTERS</text>
<text x="706" y="396" class="architecture-node-title architecture-node-title-small">Reader + caster</text>
<text x="706" y="423" class="architecture-node-detail">links · routes · cast binding</text>
<text x="922" y="421" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
</g>
<path d="M 520 476 V 512 H 207 V 550" class="architecture-connector" marker-end="url(#architecture-arrow)" />
<path d="M 520 476 V 550" class="architecture-connector" marker-end="url(#architecture-arrow)" />
<path d="M 520 512 H 833 V 550" class="architecture-connector" marker-end="url(#architecture-arrow)" />
<text x="60" y="536" class="architecture-tier-label">DEPENDENCIES</text>
<a
href="https://github.com/jmchilton/bio-topo-foundry/tree/main/site/src/types"
aria-label="Browse the local kind definitions on GitHub"
>
<g class="architecture-card architecture-card-dependency">
<rect x="60" y="550" width="294" height="112" rx="18" class="architecture-node" />
<text x="86" y="583" class="architecture-node-label">LOCAL CONTRACTS</text>
<text x="86" y="618" class="architecture-node-title architecture-node-title-small">Kind definitions</text>
<text x="86" y="644" class="architecture-node-detail">site/src/types/</text>
<text x="324" y="639" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
<a
href="https://github.com/jmchilton/bio-topo-foundry/tree/main"
aria-label="Browse the local Foundry vocabularies on GitHub"
>
<g class="architecture-card architecture-card-dependency">
<rect x="373" y="550" width="294" height="112" rx="18" class="architecture-node" />
<text x="399" y="583" class="architecture-node-label">LOCAL VOCABULARIES</text>
<text x="399" y="618" class="architecture-node-title architecture-node-title-small">Instance policy</text>
<text x="399" y="644" class="architecture-node-detail">tags · references</text>
<text x="637" y="639" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
<a
href="https://github.com/jmchilton/foundry-lib/blob/main/docs/concepts/shared-substrate.md"
aria-label="Read the foundry-lib shared substrate documentation on GitHub"
>
<g class="architecture-card architecture-card-substrate">
<rect x="686" y="550" width="294" height="112" rx="18" class="architecture-node" />
<text x="712" y="583" class="architecture-node-label">SHARED SUBSTRATE</text>
<text x="712" y="618" class="architecture-node-title architecture-node-title-small">@galaxy-foundry/*</text>
<text x="712" y="644" class="architecture-node-detail">explicit inputs · no path discovery</text>
<text x="950" y="639" class="architecture-link-glyph" aria-hidden="true">↗</text>
</g>
</a>
</svg>
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 two kinds that need to interrogate rather than
merely validate — the tag registry and license policy themselves. A Method note has to ask which
facet declared a tag; 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.
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.
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. 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.
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.
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.
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.
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/ |
| 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/ |
| 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/ |
Update this record when a component, dependency seam, entry point, or deliberate absence changes.