Agent Collaboration Guide
🤖 AI Agents: This is your single source of truth. Read this file before you touch anything.
Every other doc in the repo (.github/copilot-instructions.md,ATLAS.md,README.md) defers to this file.
If anything contradicts what’s written here, this file wins.
Welcome back. This file is your map to the entire Utopie monorepo.
🗂️ What Is This Repository?
This is the Utopie monorepo — the creative studio behind every project. It contains two things:
- The Standard Framework (
packages/) — A modular Astro framework (@stnd/*) providing classical typography, a module system, and edge-first infrastructure. - Applications (
apps/) — Websites and tools built on Standard.
Projects & Domains
| Project | Location | Domain(s) |
|---|---|---|
| Standard Framework | packages/ |
— (npm: @stnd/*) |
| Standard Framework Landing | apps/stnd.build/ |
stnd.build |
| Standard Garden | apps/stnd.gd/ |
standard.garden, stnd.gd |
| L’art d’enseigner | apps/ade/ |
lartdenseigner.com |
| Obsidian Folio | apps/obsidian/ |
— |
| Desktop App | apps/desktop/ |
— |
| macOS App | apps/macos/ |
— |
The Story
Standard started as a CSS framework built on classical theory — golden ratio, Swiss grid, baseline rhythm. Then Astro came along and offered a way to package not just design but also server-side logic, JavaScript, and components into one integration. So Standard became @stnd/core.
Standard Garden is a utility — Pastebin for prose. Paste text, get a beautiful URL in 10 seconds. No account needed. It runs “standard” — meaning the framework renders content with almost no CSS overrides.
L’art d’enseigner is a teaching enterprise website built by Francis and his wife (an orthopédagogue in Québec) to help parents with homeschooling. It shares the Standard Framework but has its own domain models, its own content, its own world.
Both apps prove the same thesis: Standard provides the foundation, the app provides the soul.
Utopie (utopie.studio) is the creative studio umbrella — the monorepo that houses the framework and every project built on it.
📜 RULES
👑 THE GOLDEN RULE OF NAMING
We follow the “Universal vs. Unique” naming philosophy:
- Unique Concept? Give it a Proper Name. If a package creates a new experience or unique product category (e.g.,
module,garden), give it a poetic, branded name. - Technical Utility? Use Industry Standards. If a package performs a standard technical function, use the universal industry name (e.g.,
@stnd/stylesinstead ofdesign,@stnd/uiinstead ofcompo). This makes the DX invisible and predictable.
These are non-negotiable. Every commit must honor them.
- No backward compatibility. No shims. No legacy aliases. If code is old, it’s gone. We are pre-release — backward compat is futile and creates spaghetti.
- DRY code. Before writing any method or helper, check if one already exists. If you must create one, put it in the proper file — not inline.
- Use Astro native features as much as possible.
.astrofiles contain no logic. Only model instance usage and template rendering. Server-side logic lives in model classes and helper files.- Module architecture follows vertical slice. Each module (feature unit) is self-contained in its own folder under
modules/. The@modulesimport alias is auto-registered by@stnd/core— always use@modules/for cross-module imports, never relative paths that climb out of a module. - The
src/folder is minimal. Only Astro-mandated files (content.config.ts,env.d.ts) and dev artifacts (tests, scripts, migrations). ALL application code — routes, layouts, components, middleware, models, styles — lives inmodules/. - Files marked with
// @agents lock truecannot be modified without explicit user permission. - If you detect anything violating these rules, add it to your task list. Clean architecture is what keeps this project alive.
- Always test with
pnpm buildin the relevant app after making changes. - Document Fatal Errors. Every fatal error or major configuration issue must have a dedicated documentation page in
apps/stnd.build. The error message in the log must include a link to this specific page (e.g.,https://stnd.build/actions-not-found) explaining the “What”, “Why”, and “How” of the problem.
🛠️ System Tooling & Environment (Golden Setup)
Ce fichier documente les outils et la configuration système optimisés pour les agents IA sur cette machine. L’agent doit prioriser l’utilisation de ces outils pour une performance et une fiabilité maximales.
🚀 Runtimes & Core Tools (Homebrew)
Les exécutables suivants sont verrouillés sur les versions Homebrew (configurés via alias dans config.fish) :
- Node.js :
v25.6.1(Commandes :node,npm,npx) - Package Manager :
pnpmv10.28.1(Chemin forcé :/opt/homebrew/bin/pnpm) - Python :
v3.14.2(Commandes :pythonetpython3pointent vers Homebrew)
📝 Editors & Note Taking
- Editeur principal : Zed. L’agent doit savoir que c’est l’environnement privilégié.
szed: Fonction Fish pour éditer des fichiers système avec les droitssudovia Zed (szed /etc/hosts).obsidian: Commande personnalisée pour manipuler et ajouter des notes dans le “Digital Garden”. Indispensable pour la gestion de la connaissance.
🎨 Visual Aliases & Navigation
Le shell fish est configuré avec les alias suivants pour une meilleure visibilité :
ll:eza -l —icons —git -a(Liste détaillée avec icônes et état Git)ls:eza —icons(Liste simple avec icônes)lt:eza —tree —level=2(Vue en arborescence)cat:bat(Lecture avec coloration syntaxique)z/zi:zoxide(Saut intelligent entre les répertoires)p: Alias pourpnpmy:yazi(Explorateur de fichiers terminal ultra-rapide)
🔍 Modern CLI Utilities (Preferred)
Utiliser ces outils au lieu de leurs équivalents POSIX classiques :
Exploration & Recherche
fd: Recherche de fichiers (remplacefind).rg(ripgrep) : Recherche de contenu (beaucoup plus rapide quegrep).fzf: Fuzzy finder pour les sélections interactives.yazi: Gestionnaire de fichiers terminal moderne.
Git & Développement
lazygit: Interface TUI pour Git (à privilégier pour les commits complexes et le debug d’historique).gh: GitHub CLI pour gérer les PR, issues et dépôts.shellcheck: Analyseur statique pour garantir la qualité des scripts shell.tldr: Aide simplifiée pour les commandes (plus rapide queman).
Monitoring & Réseau
jq: Manipulation et formatage de fichiers JSON.httpie(http) : Client HTTP moderne et coloré (remplacecurlpour les tests API).btm(bottom) : Monitoring système (CPU, RAM, Processus).
🛠️ Autres outils disponibles (Brew)
- Images/Vidéo :
ffmpeg,imagemagick,libheif. - Extraction de texte :
tesseract(OCR). - Développement :
rustup(Rust),cmake,platformio,cocoapods. - Sécurité :
1password-cli.
🏗️ Architecture
The Three Layers
┌─────────────────────────────────────────────────────┐
│ APPS (apps/) │
│ Standard Garden, L'art d'enseigner, Obsidian, etc. │
│ Each app: astro.config + modules/ + minimal src/ │
├─────────────────────────────────────────────────────┤
│ STANDARD FRAMEWORK (packages/) │
│ @stnd/core orchestrates everything │
│ @stnd/core provides module engine + StandardRoot │
│ @stnd/modules provides built-in modules (catalog) │
│ @stnd/styles provides the CSS framework │
│ + press, client, launcher, compo, layout, etc. │
├─────────────────────────────────────────────────────┤
│ INFRASTRUCTURE │
│ Cloudflare (Pages, D1, R2, KV, Vectorize, Workers) │
│ Astro (SSR, View Transitions, Content Collections) │
│ Svelte 5 (Runes mode for interactive islands) │
└─────────────────────────────────────────────────────┘
Package Map (packages/)
SHARED Layer (pure utilities — imports nothing)
| Package | What it does |
|---|---|
@stnd/utils |
Pure functions: slugify, deepMerge, formatDate, excerptWords, validateEmail, etc. |
@stnd/log |
Scoped structured logging (server + client) |
@stnd/styles |
CSS framework: golden ratio, Swiss grid, OKLCH color system, typographic scale |
@stnd/fonts |
Self-hosted typeface modules (Inter, Kalice, IBM Plex Mono, etc.) |
@stnd/themes |
Temperaments: humanist, technical, editorial, academic, gallery, international |
CORE Layer (infrastructure — imports SHARED only)
| Package | What it does |
|---|---|
@stnd/server |
StandardRoot, StandardModel, auth (JWT/sessions), CORS, errors, i18n |
@stnd/core |
THE ORCHESTRATOR — bootstraps modules, Vite aliases, virtual modules, middleware |
@stnd/modules |
Built-in modules (toast, confetti, lab, launcher, styles, etc.) |
FEATURE Layer (capabilities — imports CORE + SHARED, never each other)
| Package | What it does |
|---|---|
@stnd/press |
Markdown → HTML, typography transforms, document conversion (DOCX/PDF) |
@stnd/client |
Browser utilities: keyboard, gestures, clipboard, stores, e-ink detection |
@stnd/launcher |
Universal command palette engine (Svelte 5) |
@stnd/ui |
Shared Astro/Svelte components (Logo, Menu, Toast, Dropdown, etc.) |
@stnd/layout |
Base layouts: Base.astro, Meta.astro, Encrypted.astro |
@stnd/cloudflare |
Cloudflare integration (image optimization, deployment) |
@stnd/ai |
AI integration (OpenRouter) |
@stnd/lab |
Dev tool: live CSS token inspector |
Import Hierarchy (Strict — violate this and we will find you)
SHARED → imports nothing
CORE → imports SHARED only
FEATURE → imports CORE + SHARED
NEVER imports other FEATURE packages
🌿 How Apps Work
Both stnd.gd and ade follow the same pattern:
File Structure
apps/my-app/
├── astro.config.mjs # Imports @stnd/core with module config
├── wrangler.toml # Cloudflare bindings (D1, R2, KV, etc.)
├── modules/ # ALL application code lives here (@modules/ alias)
│ ├── root/ # 🦴 The Root — foundation module (the binding)
│ │ ├── index.module.js # Root manifest (middleware, actions, aliases)
│ │ ├── models/ # Domain models (Root, Visitor, Author, Note, Garden)
│ │ │ ├── Root.ts # Request context — extends StandardRoot
│ │ │ ├── middleware.ts # Asset skip + Root initialization (order: -100)
│ │ │ ├── actions.ts # Astro server actions
│ │ │ └── … # Visitor, Author, Note, Garden, etc.
│ │ ├── layouts/ # App layouts (Base, Forest views, Header, Footer)
│ │ ├── components/ # App-wide components (Logo, etc.)
│ │ └── client/ # Client-side boot and URL utilities
│ ├── feature-a/ # Feature module (vertical slice)
│ ├── feature-b/ # Another feature module
│ └── launcher/ # Launcher module (command palette)
├── src/ # MINIMAL — only Astro-mandated files
│ ├── content.config.ts # Content collections (required by Astro)
│ ├── env.d.ts # TypeScript declarations (required by Astro)
│ └── [tests, scripts, migrations — dev artifacts only]
├── content/ # Static content files (markdown, MDX)
└── public/ # Static assets (images, fonts, favicon)
The Root Module: Every app has one foundation module (typically
root/). It contains the domain models, core layouts, and client boot — the binding that holds every other module together. Feature modules import from the root; the root never imports from features. This is enforced bydependency-cruiser.
The Module Manifest
// modules/my-feature/index.module.js — every module has one
export default {
id: “my-feature”,
name: “My Feature”,
description: “What this module does”,
// Routes (Astro pages)
routes: [
{ path: “/feature”, entrypoint: “./routes/index.astro” },
{ path: “/feature/[slug]”, entrypoint: “./routes/[slug].astro” },
],
// Middleware (order < 0 = runs first, 0+ = runs after)
middleware: [
{ entrypoint: “./middleware.ts”, order: -100 },
],
// Styles
styles: [“./styles/feature.scss”],
// Actions (Astro server actions)
actions: “./actions.ts”,
// Vite aliases
aliases: { “@my-feature”: “.” },
// Dependencies (other modules this one needs)
dependencies: [“root”],
};
The Litmus Test
“If I delete this module folder, does the site crash?”
- YES → It belongs in the root module. Be careful.
- NO → It’s a feature module. It should be removable without breaking anything else.
Import Rules Within modules/
root/ → imports @stnd/* packages only (never feature modules)
feature-a/ → imports root/ and @stnd/* packages
feature-b/ → imports root/ and @stnd/* packages
feature-a/ ✗ → NEVER imports feature-b/ (no cross-module imports)
All cross-module imports use the @modules/ alias:
import { Note } from ‘@modules/root/models/Note’;
import Author from ‘@modules/root/models/Author’;
import Base from ‘@modules/root/layouts/Base.astro’;
import { getCurrentSlug } from ‘@modules/root/client/urls’;
⚙️ The Request Lifecycle
HTTP Request hits Cloudflare Edge
│
├─ Module middleware runs (ordered by priority)
│ ├─ Asset skip (static files bypass Root — performance)
│ └─ Root.enter(context)
│ ├─ Resolves env (cloudflare:workers or runtime fallback)
│ ├─ Extracts DB, Bucket, KV bindings
│ ├─ Hydrates Visitor/User from JWT session cookie
│ ├─ Resolves Garden context (commons vs personal)
│ └─ Attaches to context.locals.root
│
├─ Astro page / API endpoint renders
│ └─ Accesses context.locals.root for everything
│
└─ Response returned
StandardRoot → App Root
Each app extends StandardRoot from @stnd/server:
// StandardRoot (packages/server) provides: env, db, kv, url, ctx, waitUntil()
// App Root adds: domain-specific models and services
class Root extends StandardRoot {
declare public visitor: Visitor; // App-specific user model
public garden!: Garden; // App-specific domain context
static async enter(context: APIContext): Promise<Root> {
const root = await super.enter(context) as Root;
// Guard: fail loud if bindings are missing
if (!root.env || !root.db) {
throw new Error(“Runtime environment not available”);
}
// Wire app-specific services
root.bucket = root.env.GARDEN_BUCKET;
root.visitor = await Visitor.fromUrl(root, context);
root.garden = await Garden.resolve(root);
return root;
}
}
StandardModel (Caching)
// Any domain model can extend StandardModel for automatic KV caching
class Note extends StandardModel<NoteData, Root> {
static async load(root: Root, slug: string) {
return this.withCache(root, `note:${slug}`, async () => {
return await root.db.prepare(“SELECT * FROM notes WHERE slug = ?“)
.bind(slug).first();
}, 300); // 5 min TTL
}
}
📂 Standard Garden (apps/stnd.gd/) — Detail
What It Is
Pastebin for prose. The fastest way from thought to beautiful URL.
- Anonymous users paste text → get a
/a/nano_idURL (expires in 7 days) - Free accounts → 10 permanent notes at
/@username/slug - Paid accounts ($4/month) → unlimited notes, private notes, custom domain
Domain Models (@folio/base/models/)
| Model | Purpose |
|---|---|
Root |
Request context — extends StandardRoot, owns Visitor + Garden |
Visitor |
The person making the request (authenticated or anonymous) |
Garden |
Content space — commons (standard.garden) or personal (subdomain/custom domain) |
Author |
The owner of content — identity, settings, custom CSS, custom domain |
Note |
A piece of content — extends StandardModel for caching |
ThemeResolver |
Resolves which Temperament to apply based on frontmatter + author defaults |
Mycelium |
Discovery network — backlinks, semantic search, related notes |
Key Folios
| Folio | What it does |
|---|---|
base 🦴 |
Foundation — domain models (Root, Visitor, Author, Note, Garden), layouts (Base, Forest, Header, Footer), client boot, stones (shared UI). Middleware at order -100. |
pages |
Static pages and dynamic note rendering |
api |
REST API endpoints |
writer |
Note editor (CodeMirror-based) |
launcher |
Command palette actions and views |
design |
Garden-specific CSS overrides |
graft |
Obsidian module sync / import |
cdn |
Image and asset delivery |
upload-system |
File upload handling |
user-feed |
RSS and feed generation |
press-math/mermaid/p5 |
Content extension folios |
Middleware Flow
The base registers middleware at order -100 (runs first):
- Asset check — Static files (.css, .js, .png, etc.) skip Root initialization
- Root.enter() — Creates the full request context (env → db → Visitor → Garden)
- Attach —
context.locals.rootavailable to all downstream code - Fail loud — If Root fails, returns 503 immediately
📂 L’art d’enseigner (apps/ade/) — Detail
What It Is
A website for Francis and his wife’s homeschooling enterprise. Orthopédagogie + parent empowerment.
Domain Models (@folio/base/models/)
| Model | Purpose |
|---|---|
Root |
Request context (env, db, user) — does NOT extend StandardRoot yet (migration planned) |
User |
Authenticated user with access_rights for formations, magic link auth |
Key Folios
| Folio | What it does |
|---|---|
base 🦴 |
Foundation — Middleware, Root, User, layouts (Header/Footer/Base), components (Card, CTA), styles, home route |
chronique |
Blog-style articles |
services |
Service pages |
formation |
E-learning courses (early stage) |
langagier |
Language-specific formation |
faqs |
FAQ sections |
testimonials |
Client testimonials |
stripe |
Payment integration |
launcher |
Command palette |
video_player |
Video player component |
ambiant |
Ambient/mood features |
Auth Flow
ADE uses magic links (email-based):
- User enters email → OTP code + magic link sent via Resend
- Magic link → one-click login (JWT session cookie)
- OTP code → manual entry fallback
- Session stored in
ade_sessioncookie (30-day expiry) User.fromRequest()resolves user from session on every request
🎨 Design Philosophy
The Three Pillars
- Respect for the Author — Professional typography applied automatically. Swiss Grid. Golden Ratio. Your mom’s recipe looks like a cookbook.
- Respect for the User — Don’t waste their time. Speed is respect. 10 seconds from thought to URL.
- Respect for the World — Efficient code on the edge is ecological stewardship. 10,000 users for <$200/month.
The Vocabulary
We use physical metaphors, not abstract programmer terms:
| Programmer Term | Standard Term | Why |
|---|---|---|
| Background color | Paper (—color-background) |
The surface where thoughts rest |
| Text color | Ink (—color-foreground) |
The permanent mark of content |
| Accent color | Signal (—color-accent) |
Where attention flows |
| Border | Rule (—color-border) |
Structural division |
| Theme | Temperament | The DNA of content |
/temp/ URLs |
/a/ |
Annual / Anonymous / Aisle |
| User profile | /@username |
Identity first |
The Six Temperaments
- International — Swiss minimalism (Helvetica/Inter)
- Technical — Graph paper, monospace, safety orange (IBM Plex Mono)
- Humanist — Warm serifs, cream paper (Garamond/Jenson)
- Editorial — Newspaper authority, drop caps (Source Serif)
- Academic — Scholarly, sidenotes, journal-style
- Gallery — Invisible UI, museum-style
Users don’t choose themes. We apply the right typography automatically. They can override via frontmatter (theme: technical), but the default is always beautiful.
OKLCH Color System
One seed color generates the entire harmonious palette:
—color-accent: #d65d0e; /* User picks Safety Orange */
/* We extract the DNA and rotate hues */
—pigment-red: oklch(var(—safe-l) var(—safe-c) 25);
—pigment-yellow: oklch(var(—safe-l) var(—safe-c) 85);
—pigment-green: oklch(var(—safe-l) var(—safe-c) 145);
—pigment-blue: oklch(var(—safe-l) var(—safe-c) 240);
—pigment-purple: oklch(var(—safe-l) var(—safe-c) 300);
Pastel stays pastel. Neon stays neon. Military stays military.
🔧 Common Patterns
API Response Format
// Success
{ success: true, data: {…}, message: “Optional” }
// Error
{ success: false, error: “User-friendly message”, details: “Technical details” }
Database Queries (Always Prepared)
const note = await db
.prepare(“SELECT * FROM notes WHERE slug = ? AND owner_id = ?”)
.bind(slug, userId)
.first();
Logging
import Log from “@stnd/log”;
const log = Log({ scope: “FeatureName” });
log.info(“Operation started”, { userId, noteId });
log.warn(“Something unexpected”, { context });
log.error(“Failed to process”, { error, stack: error.stack });
Error Handling in API Endpoints
import { withErrorHandling, Errors } from “@stnd/server/errors”;
export const POST = withErrorHandling(async ({ request, locals }) => {
const root = locals.root;
if (!root.visitor || root.visitor.raw.isAnonymous) {
throw Errors.authRequired();
}
// … your logic
return new Response(JSON.stringify({ success: true, data }));
});
Auth Utilities
import { signJWT, verifyJWT, getSession, createSession } from “@stnd/server/auth”;
const token = await signJWT({ id: user.id, email: user.email }, secret);
const session = await getSession(request, secret, “my-session”);
Svelte 5 (Runes Only)
<script>
let count = $state(0);
let doubled = $derived(count * 2);
$effect(() => {
console.log(`Count is now ${count}`);
});
</script>
No old Svelte ¾ patterns. No $: reactive statements. Runes only.
🛠️ Development
Key Commands
# Standard Garden
cd apps/stnd.gd
pnpm dev # Dev server on port 8089
pnpm build # Production build
pnpm db:reset:local # Reset local D1 database
# L'art d'enseigner
cd apps/ade
pnpm dev # Dev server on port 8083
pnpm build # Production build
# Run tests (stnd.gd)
cd apps/stnd.gd
pnpm test:unit # Vitest
pnpm test:e2e # Playwright
Environment Variables
Each app has its own .env:
JWT_SECRET=dev-secret-key-change-me PUBLIC_API_URL=/api
# Cloudflare bindings are auto-configured by Wrangler
Wrangler Bindings
Access via locals.runtime.env or import(“cloudflare:workers”):
const db = env.DB; // D1 database
const bucket = env.GARDEN_BUCKET; // R2 storage
const kv = env.GARDEN_KV; // KV store
const ai = env.AI; // Cloudflare AI
const vectorize = env.VECTORIZE; // Vectorize index
📝 Documentation Habits
Comment the “Why”, Not the “What”
// ❌ Bad
// Set the user ID
userId = 123;
// ✅ Good
// Anonymous notes expire after 7 days to encourage account creation
// while keeping storage costs sustainable (~$200/month for 10K users)
if (!user) {
expiresAt = Date.now() + 7 * 24 * 60 * 60 * 1000;
}
Use “We”, Not “I”
This is collaborative. “We implemented…” not “I implemented…”
Commit Messages (Conventional)
feat: add drag-and-drop image upload
fix: resolve auth token expiration bug
refactor: move middleware from src/ to folio system
docs: update AGENTS.md with current architecture
🧭 Decision Framework
When facing a choice, ask:
- Does it add friction? → Reject it
- Does it waste time? → Reject it
- Does it waste resources? → Reject it
- Is it a tool or a trap? → Tools let users leave. Traps keep them.
- Does it belong in the framework or the app? → If two apps need it, it’s framework. If one app needs it, it’s a folio.
When in doubt, choose simplicity. A well-made tool doesn’t need to justify itself.
🔗 Essential Files
Utopie Monorepo Root
AGENTS.md— You are here. The single source of truth for AI agents.ATLAS.md— The poetic framework (how the system feels)README.md— Public-facing project overviewpackages/README.md— Full Standard Framework documentation.dependency-cruiser.cjs— Enforces module boundary rulespnpm-workspace.yaml— Workspace configuration
Standard Garden (apps/stnd.gd/)
astro.config.mjs— Framework + module configurationwrangler.toml— Cloudflare bindings (D1, R2, Vectorize)modules/root/index.module.js— Root manifest (the foundation)modules/root/models/Root.ts— The domain root (extends StandardRoot)modules/root/models/Visitor.ts— User/session modelmodules/root/models/middleware.ts— Request lifecycle (asset skip + Root init)modules/root/models/Note.ts— Content model (extends StandardModel)modules/root/models/Garden.ts— Content space (commons vs personal)modules/root/models/Author.ts— Content owner (identity, settings, custom CSS)modules/root/layouts/Base.astro— Root HTML layoutmodules/root/client/boot.js— Client-side initialization
L’art d’enseigner (apps/ade/)
astro.config.js— Framework + module configurationwrangler.toml— Cloudflare bindings (D1, KV)modules/root/index.module.js— Root manifest (the foundation)modules/root/models/Root.ts— Domain root (does NOT extend StandardRoot yet)modules/root/models/User.ts— User model (magic link auth)modules/root/middleware.ts— Request lifecycle
Standard Framework (packages/)
packages/core/standard.js— The orchestrator integrationpackages/server/src/StandardRoot.ts— Base request context classpackages/server/src/StandardModel.ts— Abstract model with KV cachingpackages/server/src/auth.ts— JWT + session managementpackages/server/src/errors.ts— Error handling frameworkpackages/core/src/loader.js— Module discovery and loadingpackages/core/src/virtual.js— Virtual module generatorspackages/styles/— CSS framework source
🧭 Quick Reference: Where Things Live (Cheat Sheet)
Want to… → Look in…
──────────────────────────────────────────────────────────────
Change how a request is bootstrapped → modules/root/models/Root.ts
Change auth / session logic → modules/root/models/Visitor.ts
Add a new domain model → modules/root/models/
Change the base HTML layout → modules/root/layouts/Base.astro
Add a new page route → modules/<feature>/routes/
Add a launcher command → modules/launcher/actions/
Add a writer toolbar extension → modules/writer-toolbar/
Change CSS framework tokens → packages/styles/
Change markdown rendering → packages/press/
Change how modules are discovered → packages/core/src/loader.js
Change Vite aliases / virtual mods → packages/core/standard.js
Run boundary checks → npx depcruise —config ../../.dependency-cruiser.cjs modules/
Last Updated: 2025-02-08
Maintained With: Care, craft, and a healthy respect for typography
“A well-made tool doesn’t apologize for its purpose. It simply serves it with quiet dignity.”