How this repo works
Three things live in this repository, each with a different audience. Knowing which one you’re touching tells you where to work and what breaks if you get it wrong.
The three zones
harness-walle/
├── walle/ ← THE PRODUCT — everything shipped to consumers (except website's src/@walle/),
│ grouped by module — each answers "what does module X ship" on its own
│ ├── walle.yml the config: declares every managed/seed/inject path per module
│ ├── website/ MANAGED source (website/src/@walle/, website/schemas/) AND the
│ │ write-once seed for a fresh consumer (the whole site, minus the
│ │ excludes in walle.yml's website-seed-exclude)
│ ├── ci/ managed/ (composite actions), seed/ (starter workflows)
│ ├── ai/ managed/skills/ (managed Claude Code skills)
│ ├── backend/ seed/ (starter API routes, middleware)
│ ├── harness-coding/ inject/ (setup-devcontainer.project.block.sh, docker-compose.project.block.yml),
│ │ seed/ (.husky/, justfile.project) — no managed/: nothing vendored
│ │ from harness-coding itself, see below
│ └── cli/ cli.sh, validate-configs.mjs — cross-module engine
├── walle/website/ ← DEV TOOLING'S FIRST CONSUMER — the demo/showcase Astro site
│ ├── src/@walle/ the design system source (also shipped; stays outside `walle/` — see below)
│ ├── schemas/ JSON Schemas for consumer configs + manifest — cross-module
│ └── astrobook/, tests/ component stories + unit/playwright specs (dogfoods the product)
├── tests/e2e/ ← DEV TOOLING — never shipped, only used to build/verify walle itself
├── wiki/, CONTRIBUTING.md ← repo docs (this file, module/CLI/versioning references)
└── justfile*, .github/ ← repo meta (CI, dev commands)
Placement rule inside walle/: if a file is re-synced on every walle update → <module>/managed/.
If it’s written once and then belongs to the consumer → <module>/seed/. If it’s a block injected
into a file walle doesn’t own outright (a file that harness-coding or the consumer’s own
justfile.project created) → <module>/inject/. Whichever it is, add the src→dest mapping to
walle.yml — the CLI reads only the config, so no code change is needed. cli/ and the website/
seed are cross-cutting — shared engine/starter, not tied to one module.
Why harness-coding has no managed//seed/: walle doesn’t vendor any BASE devcontainer file
(Dockerfile, docker-compose.yml, the setup script — all harness-coding’s own). It only
injects its own extensions (corepack+yarn install, build-arg overrides) as [walle:START]/[walle:END]
marker blocks into setup-devcontainer.project.sh and docker-compose.project.yml — files
harness-coding already seeds write-once. If those files don’t exist yet, the injection creates
them containing just the walle block (reduced form) and warns to run harness-coding first.
If you’re changing what consumers receive — a component, a schema, a CLI behavior, a seed
file, a CI composite action — you’re working in walle/ or walle/website/src/@walle/. Test with
just e2e (simulates a real consumer via --source) before anything else.
If you’re changing the demo site — the pages under walle/website/src/pages/,
walle/website/src/configs/, content — you’re customizing walle’s own dogfood consumer, same as
any real consumer would. It doesn’t ship anywhere except this repo’s own gh-pages deploy.
If you’re changing tooling — a story in astrobook/, a Playwright spec in tests/, an e2e
scenario — nothing here reaches a consumer. It exists to build confidence in the product.
Why src/@walle/ sits outside walle/
The design-system source imports the consumer’s own configs by relative path
(src/@walle/config.ts does import configs from "../configs"), and that resolution happens
during Astro’s config-loading phase, before any path alias is available. Every consumer —
including this repo’s own demo site — has src/@walle/ sitting next to src/configs/. Moving
the core into walle/ would break that contract for everyone. It’s still part of the product;
it just can’t live inside the product root.
What ships, and how
cli.sh’s module_managed_map() and module_seed_paths() are the source of truth for what
gets copied where — see managed-vs-seed.md for the model and
modules.md for the per-module breakdown. The short version: MANAGED paths
(walle/cli → consumer scripts/@walle/, walle/schemas → consumer schemas/, etc.) are
re-synced on every walle update; SEED paths are written once and then belong to the consumer.
Modules are all optional except website. A consumer can run walle with nothing but the
website module — no CI starter, no AI harness, no devcontainer. Concretely: a consumer does
not need harness-coding (the
devcontainer module is opt-out, not a hard dependency — --no-harness-coding at init) and does
not need harness-ai or Claude Code (the
ai module is opt-in). Don’t design a module contract that assumes either is present.
How to release
Full policy and the maintainer checklist live in versioning.md.
In short: update CHANGELOG.md, confirm just e2e and yarn test are green, then
just release vX.Y.Z — it bumps package.json, commits, tags, and pushes; release.yml
publishes the GitHub release from the changelog entry.
Verifying a change before it ships
just e2e— the real integration test: scaffolds consumers from your working tree via--sourceand exercises init/update/add/check across every module, including a static+SSR build and a live server check.just validate-configs/yarn lint/yarn test— this repo’s own demo site is consumer #1; keep it green the same way any consumer would.just astrobook/just astrobook-test— visual catalog and regression suite for anything insrc/@walle/components.