Modules

A walle consumer declares which modules it uses in .harness-walle/manifest.json (part of the .harness-walle/ metadata folder — see below). Each module has two file classes:

  • MANAGED — paths that walle re-syncs on every init/update/add. They live under @walle/ namespaces. Do not hand-edit them; changes are overwritten on the next update.
  • SEED — files written once at init/add if absent, and never touched again by update. They are yours to edit freely from the first write.

website is mandatory. All other modules are opt-in. See managed-vs-seed.md for a full explanation of the model.

.harness-walle/ metadata folder

Every consumer has a .harness-walle/ folder holding walle’s own metadata — not a module, always present:

Path What it is
.harness-walle/manifest.json The consumer manifest (schemaVersion, name, walleVersion, modules, etc.) — same schema previously at the root .walle.config.json
.harness-walle/config.yml Consumer-facing setup config (currently just docs: true/false). Created with defaults if absent, NEVER-TOUCH after — yours to edit freely
.harness-walle/lock Single line: the resolved source ref (a tag, or local when --source is used). Written on every init/update
.harness-walle/docs/ Curated copy of cli.md, modules.md, managed-vs-seed.md, versioning.md from the pinned release. Refreshed on every init/update unless .harness-walle/config.yml’s docs: false

A consumer on an older layout — a root .walle.config.json, or the earlier .walle/ folder — is migrated automatically on the next CLI command: the folder is renamed to .harness-walle/, a schemaVersion: 2 files map is reshaped to v3 (grouped by module), and the old file is removed. No manual action needed.


website (mandatory)

The core design system: layout, components, configs, CLI scripts, and schemas.

Activate: always active; cannot be omitted.

MANAGED paths:

Path What it contains
src/@walle/ Components, layouts, scripts, styles, utils, config
schemas/ JSON schemas for app.json, navbar.json, footer.json, theme.json, manifest
scripts/@walle/ cli.sh, validate-configs.mjs
justfile.project (marker block) [walle:START]/[walle:END] block: just targets dev, build, walle, walle-update, walle-check, validate-configs
.vscode/settings.json (marker block) // [walle:START]/// [walle:END] block: Prettier/ESLint/Astro/MDX editor settings
.vscode/extensions.json (marker block) // [walle:START]/// [walle:END] block: recommended extensions (Astro, MDX, Prettier, ESLint)

SEED paths:

Path Purpose
README.md Starter readme for the consumer project; edit freely
justfile.project Consumer’s own recipes live here alongside the injected walle block; created once, then yours (the walle block itself is re-synced by update — see above)
.husky/pre-commit, .husky/pre-push Git hooks (yarn lint, yarn format, yarn test:unit), matching this repo’s own hooks — written once at init, yours to customize freely after

.vscode/ marker blocks: injected via the same inject_marker_block() mechanism as AGENTS.md and justfile.project, using // (JSONC) comment markers instead of #/<!-- -->. A fresh init creates either file containing just the block if it doesn’t exist yet; an existing consumer file gets the block inserted (as JSON object members for settings.json, as array items under recommendations for extensions.json) and only that content is rewritten on update — everything else in the file is preserved. Anywhere cli.sh needs to parse these files programmatically, it strips // comment lines before JSON.parse.

How the marker block works: walle.justfile doesn’t exist — its recipes are injected directly into the consumer’s own justfile.project between [walle:START]/[walle:END] markers, the same non-destructive mechanism used for AGENTS.md. If justfile.project doesn’t exist yet, it’s created with just the block; if it exists without markers, the block is appended; content outside the markers is never touched. A consumer still on the old walle.justfile + import layout is migrated automatically on the next update (old file removed, import line removed, block injected in its place).


ci

CI/CD starter: GitHub Actions workflows wired to walle’s reusable composite actions.

Activate:

cli.sh add ci
# or at init: cli.sh init -n <name> -m website,ci

MANAGED paths:

Path What it contains
.github/workflows/actions/@walle/ Reusable composite actions (build, test) — updated with each walle release

SEED paths (created once, consumer-owned):

Path Purpose
.github/workflows/test.yml Test workflow; calls the managed website-tests composite action
.github/workflows/deploy.yml Deploy workflow; wire your deploy steps here

Edit test.yml and deploy.yml freely — they’re yours. The managed composite actions under actions/@walle/ receive improvements on each walle update without touching your workflows.


backend

Astro API routes for server-side logic. Requires SSR — enable it in src/configs/app.json before or after adding the module.

Activate:

cli.sh add backend

Then enable SSR in src/configs/app.json:

{
  "astro": {
    "ssr": { "enabled": true, "adapter": "node" }
  }
}

MANAGED paths: none. The module seeds a starter route; the rest is consumer-owned.

SEED paths:

Path Purpose
src/pages/api/health.ts Example health-check API route (GET /api/health)
src/pages/api/echo.ts Example POST echo endpoint (POST /api/echo) — returns the request body
src/middleware.ts Request-ID middleware stub — attaches X-Request-Id to every response

Seed files have export const prerender = false so they remain server-rendered even in hybrid output. Add your own routes under src/pages/api/ following the same pattern. Edit src/middleware.ts freely — walle update never touches it.

Check warning: cli.sh check warns if backend is active but astro.ssr.enabled is not true.


ai

AI harness: syncs an AGENTS.md marker block and managed Claude Code skills into the consumer.

Activate:

cli.sh add ai
# or at init: cli.sh init -n <name> -m website,ai

MANAGED paths:

Path What it contains
.claude/skills/@walle/ Managed walle skills (walle-update, walle-customize)
AGENTS.md (marker block) [walle:START]/[walle:END] block: CLI guide, active-modules map with MANAGED/SEED boundaries, just commands

SEED paths: none.

How the marker block works: on every update, the CLI rewrites only the content between the [walle:START] and [walle:END] markers in AGENTS.md. Content outside the markers (including other tools’ blocks) is never touched. If the markers are absent, the CLI appends the full block at the end of the file. Consumer-owned skills outside .claude/skills/@walle/ are left intact.

The marker block is generated from the manifest modules — it lists only the modules the consumer has declared, with their correct MANAGED/SEED paths.


devcontainer

Injects walle’s own extensions into harness-coding’s devcontainer scaffold. Unlike the other modules, it is not tracked in the manifest modules array — it is a standalone flag (devcontainer.enabled) because it is opt-out at init (seeded by default) rather than opt-in.

Walle vendors no devcontainer BASE file — Dockerfile, docker-compose.yml, the setup script, justfile, and harness-coding’s own CLI stay exclusively harness-coding’s to own and update. Instead, init runs harness-coding’s CLI first (update --force) to establish that base, then injects walle’s own small extensions into the files harness-coding just created. So a single init yields a complete, current base — no separate harness-coding step. The base is fetched from harness-coding main over the network; override the source with the WALLE_HARNESS_CODING_CLI env var (path to a local cli.sh) for offline or e2e runs.

Activate:

cli.sh init -n <name>                       # runs harness-coding + injects, by default
cli.sh init -n <name> --no-harness-coding   # skip it (stub justfile fallback, no base)
cli.sh add devcontainer                     # re-inject later on a consumer that skipped it

MANAGED paths (marker blocks, injected — not whole files):

Path What the injected block contains
.devcontainer/scripts/setup-devcontainer.project.sh corepack enable + yarn install
.devcontainer/docker-compose.project.yml Walle’s build-arg overrides (e.g. CLAUDE_CLI_ENABLE=false)

Both are injected via the same [walle:START]/[walle:END] marker contract used for AGENTS.md and the website module’s justfile.project block: if the target file doesn’t exist yet (consumer never ran harness-coding), it’s created containing just the walle block — reduced functionality (no full devcontainer boot), with an explicit warning naming the exact harness-coding bootstrap command to run. If the file exists, the block is appended (no markers yet) or rewritten in place (markers present); the rest of the file is never touched.

SEED paths:

Path Purpose
.devcontainer/devcontainer.json Consumer-owned devcontainer entrypoint

docker-compose.project.yml and setup-devcontainer.project.sh are not SEED paths of this module — they’re harness-coding’s own SEED files; walle only injects into them (see above). Local-only overrides (docker-compose.local.yml, setup-devcontainer.local.sh, justfile.local, .harness-coding/lock) are gitignored — never committed, freely customizable per developer.

Check coverage: cli.sh check reports the SEED path’s presence when devcontainer.enabled is true, and warns (not just informs, unlike other modules’ seeds) if it’s missing — it’s expected to exist from init, so absence usually means something was deleted.

Your cart

Your cart is empty.