Architecture πŸ—οΈ

Stackwright is a typed DSL that compiles YAML into production-ready Next.js applications.

Visual rendering + constrained grammar + AI iteration = non-technical people building enterprise apps that are safe by construction.

The Big Picture

Stackwright transforms your intent into a working app through a predictable pipeline:

text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         STACKWRIGHT PIPELINE                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  YOUR    β”‚      β”‚PREBUILD  β”‚      β”‚  JSON    β”‚      β”‚ NEXT.js  β”‚
β”‚  YAMl    β”‚ ───▢ β”‚          β”‚ ───▢ β”‚  DATA    β”‚ ───▢ β”‚          β”‚
β”‚  FILES   β”‚      β”‚ compiles β”‚      β”‚  (static)β”‚      β”‚  SSG     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                                                              β”‚
                                                              β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚                        OUTPUT                           β”‚
                    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
                    β”‚  β”‚  Static  β”‚   β”‚ Theme    β”‚   β”‚ Typed    β”‚             β”‚
                    β”‚  β”‚  HTML    β”‚ + β”‚ CSS      β”‚ + β”‚ React    β”‚ = πŸš€ Fast   β”‚
                    β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   Web Apps   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Flow

Here's what happens when you build a Stackwright site:

text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          REQUEST FLOW                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Browser Request
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Next.js       β”‚
β”‚   getStaticPropsβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  JSON Loader    β”‚
β”‚ (no fs needed!) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Zod Schema    β”‚
β”‚   Validation    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚  Valid? ──▢ Yes ──▢ Continue
         β”‚             β”‚
         β”‚             No ──▢ Build Error (caught early!)
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ContentRenderer β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ThemeProvider  β”‚
β”‚  (CSS Variables)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Component      β”‚
β”‚  Registry       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
      HTML πŸŽ‰

YAML β†’ JSON Transformation

The prebuild step compiles your YAML into static JSON. Here's what that looks like:

YAML β†’ JSON

yaml
1content:
2  content_items:
3    - type: main
4      label: hero
5      heading:
6        text: "Hello, World!"
7      textBlocks:
8        - text: "Welcome to my site."
9          textSize: body1
10      buttons:
11        - text: "Get Started"
12          href: /getting-started
13          variant: contained
No Runtime Filesystem
The JSON is pre-generated at build time. Next.js serves static files β€” no fs.readFile at runtime. This makes Stackwright apps compatible with edge functions, CDN hosting, and serverless environments.

Package Architecture

Stackwright is a pnpm monorepo with 10 packages. Here's how they relate:

text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        PACKAGE DEPENDENCIES                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚@stackwright/types│◀── Base: Zod schemas, TypeScript types
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
           β”‚                 β”‚                 β”‚                 β”‚
           β–Ό                 β–Ό                 β–Ό                 β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  @stackwrightβ”‚  β”‚  @stackwrightβ”‚  β”‚  @stackwrightβ”‚  β”‚  @stackwrightβ”‚
    β”‚  -core       β”‚  β”‚  -nextjs    β”‚  β”‚  -cli       β”‚  β”‚  -mcp       β”‚
    β”‚             β”‚  β”‚             β”‚  β”‚             β”‚  β”‚             β”‚
    β”‚ Components  β”‚  β”‚ Next.js     β”‚  β”‚ CLI tools   β”‚  β”‚ MCP server  β”‚
    β”‚ Registry    β”‚  β”‚ Adapter     β”‚  β”‚ Validation  β”‚  β”‚ AI tools    β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚                 β”‚                 β”‚
           β”‚                 β”‚                 β”‚
           β–Ό                 β–Ό                 β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  @stackwrightβ”‚  β”‚  @stackwrightβ”‚  β”‚  @stackwrightβ”‚
    β”‚  -themes    β”‚  β”‚  -build-    β”‚  β”‚  -icons     β”‚
    β”‚             β”‚  β”‚  -scripts   β”‚  β”‚             β”‚
    β”‚ Theme systemβ”‚  β”‚ Prebuild    β”‚  β”‚ Lucide icon β”‚
    β”‚ CSS vars    β”‚  β”‚ pipeline    β”‚  β”‚ registry    β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
           β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  @stackwrightβ”‚
    β”‚  -ui-shadcn  β”‚
    β”‚             β”‚
    β”‚ Radix + Tailβ”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

File Structure

Where everything lives in the monorepo:

text
stackwright/
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ core/                    # YAMLβ†’React engine
β”‚   β”‚   └── src/
β”‚   β”‚       β”œβ”€β”€ components/      # React components
β”‚   β”‚       β”‚   β”œβ”€β”€ base/        # Content types
β”‚   β”‚       β”‚   β”œβ”€β”€ structural/  # Layout (PageLayout, NavSidebar)
β”‚   β”‚       β”‚   β”œβ”€β”€ narrative/   # Carousel, Timeline
β”‚   β”‚       β”‚   └── content/     # Map, etc.
β”‚   β”‚       β”œβ”€β”€ config/         # Default config
β”‚   β”‚       └── utils/          # Registries, renderers
β”‚   β”‚
β”‚   β”œβ”€β”€ types/                  # Zod schemas, TypeScript types
β”‚   β”‚   └── src/
β”‚   β”‚       β”œβ”€β”€ types/          # Content schemas
β”‚   β”‚       └── schemas/         # JSON schemas
β”‚   β”‚
β”‚   β”œβ”€β”€ nextjs/                 # Next.js adapter
β”‚   β”‚   └── src/components/     # NextImage, NextLink, etc.
β”‚   β”‚
β”‚   β”œβ”€β”€ themes/                 # Theme system
β”‚   β”‚   └── src/ThemesProvider.tsx
β”‚   β”‚
β”‚   β”œβ”€β”€ build-scripts/          # Prebuild pipeline
β”‚   β”‚   └── src/
β”‚   β”‚       β”œβ”€β”€ prebuild.ts     # Main entry
β”‚   β”‚       └── ...             # Transformers
β”‚   β”‚
β”‚   β”œβ”€β”€ cli/                    # Developer CLI
β”‚   β”‚   └── src/commands/       # init, validate, etc.
β”‚   β”‚
β”‚   β”œβ”€β”€ mcp/                    # MCP server
β”‚   β”‚   └── src/tools/           # AI authoring tools
β”‚   β”‚
β”‚   β”œβ”€β”€ icons/                  # Icon registry
β”‚   β”‚   └── src/registry.ts
β”‚   β”‚
β”‚   └── ui-shadcn/              # Radix + Tailwind
β”‚       └── src/components/
β”‚
└── examples/
    └── stackwright-docs/        # This documentation site
        β”œβ”€β”€ pages/              # YAML page files
        β”‚   β”œβ”€β”€ index/
        β”‚   β”œβ”€β”€ getting-started/
        β”‚   β”œβ”€β”€ content-types/
        β”‚   └── ...
        β”œβ”€β”€ stackwright.yml     # Theme config
        └── public/
            └── images/         # Co-located images

Package Details

Here's what each package does:

@stackwright/core

**The engine.** YAML→React compilation, component registry, content rendering, hooks, utilities. Exports: `renderContent()`, `stackwrightRegistry`, `registerComponent()`.

@stackwright/types

**The grammar.** Zod schemas for all content types, TypeScript types, JSON schemas for IDE support. The source of truth for what's valid YAML.

@stackwright/nextjs

**The adapter.** Next.js-specific components: `StackwrightImage`, `StackwrightLink`, `createStackwrightNextConfig()`. Handles App Router and Pages Router.

@stackwright/themes

**The skin.** CSS custom properties theming, `ThemeProvider`, `ColorModeScript` for dark mode. Your stackwright.yml colors become CSS variables.

@stackwright/build-scripts

**The compiler.** Prebuild pipeline: YAML→JSON compilation, image copying, search index generation. Runs before `next build` via predev/prebuild hooks.

@stackwright/cli

**The CLI.** `npx launch-stackwright`, `stackwright validate`, `stackwright preview`. Developer interface for scaffolding and testing.

@stackwright/mcp

**The AI bridge.** MCP server exposing content authoring tools, visual rendering preview, git workflow to AI agents. Enables the Otter Raft.

@stackwright/icons

**The icons.** Lucide icon registry. `registerDefaultIcons()` makes all Lucide icons available by name in YAML. Add custom icons the same way.

@stackwright/ui-shadcn

**The components.** Radix UI primitives styled with Tailwind CSS: Accordion, Tabs, Dialog, etc. More flexible than core components for complex UI.

Component Registry

The component registry maps YAML `type` values to React components:

typescript
1// How it works internally:
2 
3// 1. Components register themselves
4export const componentRegistry = {
5  'main': MainContentGrid,
6  'text_block': TextBlockGrid,
7  'carousel': Carousel,
8  'video': Media,
9  'map': Map,
10  // ... 15 more
11};
12 
13// 2. ContentRenderer looks up the type
14function renderContentItem(contentItem) {
15  const Component = componentRegistry[contentItem.type];
16  return <Component {...contentItem} />;
17}
18 
19// 3. You can add custom components
20registerComponent('my-custom-type', MyCustomComponent);
21 
22// 4. YAML maps to component
23// - type: main          β†’ MainContentGrid
24// - type: video         β†’ Media
25// - type: my-custom     β†’ MyCustomComponent (custom!)
Custom Components
Add your own content types with `registerComponent()`. The schema validation and theme system work automatically. The Otter Raft uses this to generate validated YAML.

Safe by Construction

Stackwright's constrained grammar creates a fundamentally different security posture:

Bounded Expressiveness

The Zod schema defines exactly what behaviors are possible. No escape hatch to arbitrary code execution. You audit the framework once β€” every app is safe.

Build-Time Validation

Every content change is validated against the schema before it reaches the browser. Bad YAML fails the build, not the user.

Auditable Surface Area

Security review reduces to reviewing the component library β€” a fixed, bounded codebase. Not thousands of YAML files.

Safe AI Generation

When an AI agent generates YAML, it literally cannot express unsafe behavior. The schema is the security policy.

Common Extension Points

Stackwright apps are standard Next.js apps. Extend freely:

Custom Components

Add React components anywhere in the page:

```tsx

// pages/index.tsx

<PageLayout {...props}>

<MyCustomWidget />

</PageLayout>

Custom Content Types

Register new YAML types:

```tsx

registerComponent(

'my-type',

MyComponent

);

Custom Providers

Add React context providers:

```tsx

<MyProvider>

<PageLayout {...props} />

</MyProvider>

Custom Prebuild

Extend the prebuild pipeline:

```ts

// stackwright.yml

prebuild:

hooks:

afterCompile: myTransform

See Also

Now that you understand how it works, start building: