Contact Us

File Ownership Model

DOC-00006 reference implementor, developer

File Ownership Model

Every file in the project belongs to exactly one owner: CORE (the shared theme framework) or SITE (the per-client customization layer). Ownership defines where new work should live, which files site teams may customize directly, and which paths npm run sync:core is allowed to update.

Who this is for

  • Implementors adding new components or utilities to the core theme
  • Developers customizing a site instance
  • AI agents deciding where to place new files or which files are safe to edit

Root Ownership Zones

The charter defines a three-zone model at the src/ root:

  • Shared purpose-based rootssrc/components/, src/lib/, and src/pages/
  • Core split-concern rootsrc/core/
  • Site split-concern rootsrc/site/

That high-level model is implemented with a few explicit exceptions and adjunct paths:

ZoneOwnershipPurpose
src/components/SITE-OWNEDSite-specific components (not shadow overrides)
src/core/CORE-OWNEDCore side of split concerns plus core-only supporting code. Current subtrees include components/, config/, content/, lib/, pages/, styles/, and assets/.
src/site/SITE-OWNEDSite side of split concerns: config/, styles/, assets/, and component shadow overrides.
src/lib/CORE-OWNEDShared utilities, integrations, contracts, and helpers used across routes and components.
src/pages/MixedMixed by implementation. Files marked // CORE-OWNED are part of the sync surface; unmarked files or // SITE-OWNED files are site-controlled. Current CORE-OWNED examples include API routes, OG generation, sitemap/robots/RSS routes, and the home-page stub. Theme-docs routes live under src/core/pages/theme-docs/.
src/content/SITE-OWNEDSite-authored content collections such as pages, articles, and page fragments.

When a concern has both core and site aspects, it is split under src/core/ and src/site/. Site-specific components that do not shadow core components live in src/components/. Theme documentation content is a deliberate CORE-OWNED exception inside src/core/content/theme-docs/ so documentation updates propagate through core sync.

Path Ownership Summary

CORE-OWNED — src/core/ (core side of split concerns):

  • src/core/components/ — UI components (includes docs/ for shared Docs Kit components like DocsSidebarNav)
  • src/core/config/ — schemas, requirements, Docs Kit factory (docs-collection-factory.ts, docs.schema.ts), theme-docs collection and defaults
  • src/core/content/ — CORE-OWNED theme documentation content
  • src/core/lib/ — core-only content and remark utilities
  • src/core/pages/ — CORE-OWNED injected routes, currently theme-docs/*
  • src/core/styles/ — token definitions, base CSS
  • src/core/assets/ — icons, vendor files

CORE-OWNED — other src/ root:

  • src/lib/ — shared utilities, integrations, contracts
  • src/scripts/ — source-adjacent helper scripts used by the app build/runtime

SITE-OWNED — src/components/ (site-specific components):

  • src/components/ — site-specific components that are not shadow overrides. Imported via @/components/. Does not enter the core override chain.

SITE-OWNED — src/site/ (site side of split concerns):

  • src/site/config/ — site identity, platform settings (platform.config.ts), menus, font configuration (fonts.config.ts), site-docs collection configuration (site-docs.ts)
  • src/site/styles/ — token overrides
  • src/site/assets/ — site images, fonts (for local provider alternative)
  • src/site/components/ — component overrides

SITE-OWNED — other:

  • src/content/ — content collections
  • src/content.config.ts — site collection registry; imports CORE-OWNED theme-docs schema from src/core/config/ and SITE-OWNED site-docs schema from src/site/config/
  • public/ — static assets
  • astro.config.mjs
  • .env

CORE-OWNED — outside src/:

  • scripts/ — build, validation, sync, and release scripts

Ownership Markers

Source files use a first-line comment to declare their owner:

// CORE-OWNED
// SITE-OWNED

Marker requirements depend on the file’s location:

  • Core-owned paths (src/core/, src/lib/, src/scripts/, scripts/): markers are required. The // CORE-OWNED marker must be present.
  • Site-owned directory paths (src/site/, src/components/, src/content/): the directory determines ownership. Markers are recommended for clarity but not required. The linter does not flag missing markers in these paths. If a marker is present, it must be // SITE-OWNED — a // CORE-OWNED marker in a site-owned directory is an error.
  • src/pages/: the // CORE-OWNED marker is the sync allowlist. Files without that marker are treated as SITE-OWNED. This fail-safe direction protects downstream routes from accidental overwrite. (D-D4-02)
  • Markdown content: directory ownership applies. Markdown and MDX entries in src/content/ do not need markers. Theme-docs markdown under src/core/content/theme-docs/ is CORE-OWNED by path.

The “recommended but not required” rule for site-owned directories reflects the reality that production sites are built by both humans and AI agents — not all implementers will follow the convention of adding markers to every file, and the directory boundary already provides the necessary ownership signal.

Sync Behavior

npm run sync:core updates the downstream site’s CORE-OWNED surface from the upstream core ref. The implementation is path-allowlisted and deterministic; it does not infer ownership from git history or local edits.

Directory-based sync — these paths sync as complete CORE-OWNED trees:

  • src/core/
  • src/lib/
  • src/scripts/
  • scripts/

Marker-based syncsrc/pages/ is synced file-by-file. Only files with a // CORE-OWNED marker in the upstream source are eligible for update. Unmarked files and // SITE-OWNED files are left alone. In the current implementation this covers infrastructure and framework routes such as:

  • src/pages/api/*
  • src/pages/og/*
  • src/pages/robots.txt.ts
  • src/pages/rss.xml.ts
  • src/pages/sitemap.astro
  • src/pages/sitemap.xml.ts
  • src/pages/index.astro

Theme-docs routes are not part of the mixed src/pages/ area anymore. They live in src/core/pages/theme-docs/ and enter the site via the theme-docs integration, so they follow the directory-based CORE sync path instead.

Site stub seeding — after core-owned files sync, the script seeds required site-owned support files when they are missing, such as src/site/config/platform.config.ts and required src/site/styles/* stubs. Existing downstream files are never overwritten; seeding only prevents synced core imports from breaking older sites that do not have a newly introduced site-owned support file yet.

Exclusion filter — after directory-based and marker-based sync complete, the script reads .downstream-exclude from the upstream core ref (via git show, never from the local disk copy) and filters the sync output. Files matching exclude patterns are restored to their pre-sync state (if they existed) or removed (if new from upstream). This prevents development artifacts (.docs/, AGENTS.md, CLAUDE.md, etc.) from appearing in the downstream working tree even though they live inside synced directories. The exclusion filter only acts on files the sync staged — it never touches existing site files outside the sync surface, even if they match an exclude pattern.

Core docs copy — after the exclusion filter, the sync script copies AGENTS.md, ARCHITECTURE.md, CLAUDE.md, and .docs/standards/GIT.md from the core git ref into a .core/ directory at the child site root. These files are core-owned and overwritten on every sync:core run. Site-owned root-level AGENTS.md, CLAUDE.md, and ARCHITECTURE.md provide site-specific guidance and reference .core/ for platform conventions — they are seeded at bootstrap by create-site.mjs and never overwritten by sync.

Not synced:

  • src/components/ (SITE-OWNED)
  • src/site/ (SITE-OWNED)
  • src/content/ (SITE-OWNED)
  • src/content.config.ts (SITE-OWNED — imports CORE-OWNED collection helpers but remains site-controlled)
  • public/ (SITE-OWNED)
  • astro.config.mjs (SITE-OWNED)
  • Files matching .downstream-exclude patterns (development artifacts — excluded from sync output)

After sync: sites must run npm run validate before committing the update.

Site Customization Layers

Sites customize through a layered hierarchy, from least to most invasive:

  1. Design tokens — Override visual properties in src/site/styles/ (colors, spacing, typography)
  2. Configuration — Override identity and behavior in src/site/config/ (site name, menus, analytics)
  3. Content — Add and edit site pages and articles in src/content/. Theme documentation is CORE-OWNED in src/core/content/theme-docs/ and syncs automatically.
  4. Static assets — Replace favicons, fonts, and images in public/
  5. Component shadow/overlay — Replace a core component entirely in src/site/components/

Most sites only need layers 1–4. Layer 5 is the escape hatch for structural component changes that tokens and props cannot address.

Component Shadow/Overlay

Components use a three-tier resolution model:

  • src/site/components/ — shadow overrides (SITE-OWNED, checked first)
  • src/core/components/ — core components (CORE-OWNED, fallback)
  • src/components/ — site-specific components (SITE-OWNED, independent, not in the override chain)

To override a core component, create a file at the same relative path under src/site/components/:

  • Core: src/core/components/primitives/Button.astro
  • Site override: src/site/components/primitives/Button.astro

The component override plugin substitutes file contents at load time. Any import that resolves to a file under src/core/components/ is compiled with the matching file from src/site/components/ when that override exists. The module id remains the core path, which keeps Astro scoped-style ids aligned between the substituted template and styles. The override must implement the same prop interface as the component it replaces. Shadow overrides are logged at build/dev startup.

Because the core module id is preserved, relative imports inside an override resolve from the matching src/core/components/ directory. Use aliases such as @site/... or @/components/... for site-only helper components or utilities.

Site-specific components in src/components/ are imported via @/components/ and bypass the override chain entirely.

Overrides are opt-in and granular — sites only shadow the specific components they need to change.

public/ Directory

The public/ directory is fully SITE-OWNED. Core provides sensible defaults at project initialization time; sync:core never touches it.

Sites replace favicons, social images, and the web manifest as part of setup. Font customization is handled via src/site/config/fonts.config.ts, which imports core defaults from src/core/config/fonts.config.ts and can replace them with a custom font set.

Breaking Changes

A change is breaking (requires major version bump) when it:

CategoryBreakingNon-breaking
Config contractsRemove/rename field; change typeAdd optional field with default
Content schemasRemove/rename frontmatter field; change typeAdd optional field with default
Token contractsRemove/rename semantic token; change layerAdd new token; change primitive value
Validation gatesRemove gate step; tighten thresholdAdd gate step; relax threshold
Ownership boundariesMove path from src/site/ to coreMove path from core to site
Component APIsRemove/rename prop; change required/optionalAdd optional prop with default

Breaking changes require a BREAKING CHANGE: footer in the commit and migration guidance in the changelog.

REQ-00106 normative The theme shall function as a Parent Theme equivalent.
REQ-00108 normative Theme overrides shall survive upgrades and updates shall flow downstream without breaking customizations; upgrade compatibility is a mutual contract between upstream and downstream.
REQ-00109 normative Themes shall be distributable across repositories.
REQ-00127 normative Overrides shall not break token completeness, accessibility invariants, or routing/metadata invariants.
REQ-00195 normative The theme shall follow Semantic Versioning (SemVer). Minor versions shall be backwards-compatible. Major versions may contain breaking changes, which shall be documented with migration notes.
REQ-00196 normative Significant architectural, technology, and process decisions shall be documented as Architecture Decision Records (ADRs) and tracked in the project decisions log.

Search

Search across pages and articles. Use arrow keys to navigate results.

Search across pages and articles.

Loading search...

Search is unavailable. Please try again later.

    No results for ""

    Try different keywords or fewer words.