<!-- contamination-scan: skip
     This guide deliberately shows literal `docs/design-system/INDEX.md`,
     `src/components/ui/`, "Neo-Brutalism", etc. as examples of what
     `baldart configure` autodetects and what consumers replace with config
     keys. Autofixing them would destroy the guide's pedagogical value. -->
# BALDART Project Configuration

This guide explains the v3.x configuration system that lets you reuse the same BALDART skills across projects with different file layouts, design philosophies, technology stacks, and audience segments — without forking the framework.

If you are migrating an existing v2.x install, jump to **§ 9 Migration Cheat Sheet**.

## What changed in v3.1.0

v3.0.0 introduced the configuration system (`baldart.config.yml`, overlays, `${paths.X}` indirection). v3.1.0 added on top:

- **Centralized versioning** via `.baldart/state.json` — `baldart version` now reports installed version + install date + drift from remote + last-push info.
- **Automated contribution flow** — `baldart push` now auto-bumps `VERSION`, writes the CHANGELOG entry, creates the annotated tag, and runs a contamination scan with autofix (no more "next steps required" manual workflow).
- **`/baldart-push` skill** for conversational guidance through the contribution flow.

There are no config-schema changes between v3.0 and v3.1; existing `baldart.config.yml` files keep working. `state.json` is auto-seeded on the first `add` / `update` / `push` after upgrading.

## 1. Why this exists

Before v3.0.0, BALDART skills hard-coded the paths and opinions of a single reference project (a multi-merchant fidelity / loyalty platform). Examples that used to live inside `ui-design/SKILL.md`:

- `docs/design-system/INDEX.md` as a BLOCKING read
- `src/components/ui/` as the primitives root
- "Neo-Brutalism" as the design philosophy
- "Recharts v3 + `@nivo/heatmap` only" as the charting stack
- `merchant` and `customer` as the audience segments

Drop the same framework into a SaaS admin tool with no design system, a TypeScript backend with no UI, or a marketing site with shadcn defaults — and the skills broke or produced wrong output.

v3.0.0 solves this with **three layers**:

1. `baldart.config.yml` — structural facts (paths, identity, stack, feature flags).
2. Skills reference `${paths.X}` etc. instead of hard-coded paths.
3. `.baldart/overlays/<skill>.md` — project-specific opinions that extend or override base skill rules.

The protocol is documented in [`framework/agents/project-context.md`](../agents/project-context.md). This document is the practical user-facing guide.

## 2. The three layers at a glance

```
your-repo/
├── baldart.config.yml          ← Layer 1: structural facts (committed, customizable)
├── .baldart/
│   └── overlays/                ← Layer 3: project-specific opinions (committed)
│       ├── ui-design.md
│       ├── copywriting.md
│       └── ...
└── .framework/                  ← Layer 2: framework payload (do not edit)
    └── .claude/skills/<name>/
        └── SKILL.md             ← Generic, references layer 1 keys
```

| Layer | File | Updated by `baldart update`? | Authored by |
|---|---|---|---|
| 1 — Variables | `baldart.config.yml` | Never | You (via `baldart configure`) |
| 2 — Skills (generic) | `.framework/.../SKILL.md` | Yes (symlinked) | Framework |
| 3 — Overlays | `.baldart/overlays/*.md` | Never | You |

## 3. First-run workflow

```bash
# 1. Install the framework
npx baldart add

# 2. Generate the config (interactive — autodetects ~80% of values)
#    Already invoked at the end of `add` unless you skipped it.
npx baldart configure

# 3. (Optional) Author overlays for the skills that have project-specific opinions
cp .framework/templates/overlays/ui-design.fidelity-example.md \
   .baldart/overlays/ui-design.md
$EDITOR .baldart/overlays/ui-design.md

# 4. Commit everything
git add baldart.config.yml .baldart/overlays/
git commit -m "chore: BALDART v3 project configuration"
```

## 4. `baldart.config.yml` schema

Source of truth: [`framework/templates/baldart.config.template.yml`](../templates/baldart.config.template.yml). The four top-level sections:

### 4.1 `version`

Schema version (integer). Bumped only when `paths.*` / `features.*` keys change in a backwards-incompatible way. `baldart update` warns if the framework expects a higher version than your config declares.

### 4.2 `paths` — where the project's canonical docs and source roots live

Empty string `""` means the concept doesn't exist in your project. Skills gated by the matching `features.*` flag will skip the related BLOCKING read when both the path is empty and the feature is `false`.

| Key | Typical value | Used by |
|---|---|---|
| `design_system` | `docs/design-system` | ui-design, frontend-design, prd, bug, kie-ai, simplify, playwright-skill, webapp-testing, gamification-design |
| `ui_guidelines` | `docs/references/ui-guidelines.md` | ui-design, frontend-design, copywriting, gamification-design |
| `api_index` | `docs/references/api/index.md` | doc-writing-for-rag |
| `api_schemas` | `docs/references/api/schemas.md` | doc-writing-for-rag |
| `api_errors` | `docs/references/errors.md` | doc-writing-for-rag |
| `components_primitives` | `src/components/ui` | ui-design, simplify |
| `components_root` | `src/components` | ui-design, simplify |
| `global_styles` | `src/app/globals.css` | ui-design |
| `backlog_dir` | `backlog` | new, prd, context-primer |
| `adrs_dir` | `docs/decisions` | prd, prd-add |
| `prd_dir` | `docs/prd` | prd, prd-add, ui-design |
| `docs_dir` | `docs` | code-reviewer, senior-researcher, worktree-manager (rg-search fallback root) |
| `references_dir` | `docs/references` | new, prd, context-primer, doc-writing-for-rag, simplify |
| `wiki_dir` | `docs/wiki` | capture, context-primer |
| `e2e_tests_dir` | `tests/e2e` | playwright-skill, e2e-review (v3.18.0) |

### 4.2.1 `e2e_review` — tuning for the BLOCKING end-to-end review gate (v3.18.0+)

Only consulted when `features.has_e2e_review: true`. The block governs how the `/e2e-review` skill (auto-invoked by `/new` Phase 2.6 on UI cards) decides what blocks, how aggressively it retries, and what counts as an acceptable user override.

```yaml
e2e_review:
  fidelity_tolerance: strict       # strict | balanced | lenient
  max_self_heal_iterations: 2
  pixel_diff_threshold: 0.02
  require_override_reason: true
```

| Key | Type | Default | Effect |
|---|---|---|---|
| `fidelity_tolerance` | enum (`strict`/`balanced`/`lenient`) | `strict` | `strict` blocks on Critical + Major + Minor findings (Minor with `confidence: low` auto-demote to advisory to absorb font-rendering / anti-aliasing variance); `balanced` blocks on Critical + Major, Minor advisory; `lenient` blocks on Critical only. |
| `max_self_heal_iterations` | int | `2` | After gating findings, the orchestrator re-spawns `coder` with the findings as fix instructions and re-runs functional + visual phases. Matches the existing `/new` Phase 2.5 retry policy. After exhaustion, the override path engages. |
| `pixel_diff_threshold` | float `0.0`–`1.0` | `0.02` | When the implementation screenshot vs mockup pixel-diff is below this fraction, the orchestrator skips the Vision call for that route and treats it as a pass. Primary latency / cost saver — most routes pass pixel-diff cleanly. Set higher to skip Vision more aggressively; set to `0.0` to always invoke Vision. |
| `require_override_reason` | bool | `true` | When self-heal exhausts iterations and the user chooses to override the gate, a written reason is mandatory. The reason is recorded both in the batch tracker's `## Issues & Flags` (as `[E2E-OVERRIDE] <reason>`) and in `.baldart/e2e-review/<CARD-ID>/report.json`. Set `false` to allow silent override (not recommended). |

### 4.3 `identity` — brand and audience facts

| Key | Type | Notes |
|---|---|---|
| `brand_name` | string | Public product name |
| `design_philosophy` | string | Free-form, one line. Examples: `"Neo-Brutalism"`, `"Glassmorphism"`, `"Minimalist"`, `"Material 3"`, `""` (no opinion). Drives aesthetic decisions in `ui-design`, `frontend-design`, `kie-ai`, `motion-design`. |
| `language` | BCP-47 tag | `"en"`, `"it"`, etc. Drives copy register in `copywriting`, error-message language in `ui-design`. |
| `audience_segments` | array of strings | Domain split, e.g. `["merchant","customer"]` or `["b2b","b2c"]`. Empty `[]` = no segmentation. Drives prompts in `copywriting`, evaluation in `ui-design`. |

### 4.4 `stack` — technology choices skills must respect

```yaml
stack:
  charting:
    canonical: ["recharts", "@nivo/heatmap"]
    forbidden: ["chart.js", "echarts", "victory"]
    wrappers_root: "src/components/charts"   # optional project wrappers
  animation:
    canonical: ["framer-motion"]
    forbidden: []
  testing:
    e2e: "playwright"                         # or "cypress", or ""

  # Stack-cardinal scalars (since v3.15.0). Used by /prd, coder,
  # api-perf-cost-auditor, /new, code-reviewer, security-reviewer to branch
  # vocabulary, gate sections, anti-pattern checklists, deploy commands.
  database: "firestore"        # firestore|supabase|postgres|mysql|mongodb|dynamodb|sqlite|none|""
  auth_provider: "firebase-auth" # firebase-auth|supabase-auth|clerk|auth0|cognito|nextauth|lucia|custom|none|""
  framework: "nextjs"          # nextjs|remix|sveltekit|astro|nuxt|rails|django|fastapi|express|none|""
  deployment: "vercel"         # vercel|firebase|aws|gcp|cloudflare|render|fly|self-hosted|none|""

  # Schema-deploy safety invariant (since v4.33.0). Default false (no-op).
  schema_deploy_from_trunk_only: false   # true → /new + new2 auto-deploy schema only from git.trunk_branch
```

Skills propose only `canonical` libraries and refuse `forbidden` ones. Empty
`canonical` = ask the user before proposing a library.

**Stack-cardinal scalars (v3.15.0+).** The four scalar keys (`database`,
`auth_provider`, `framework`, `deployment`) drive stack-aware branching across
the skill/agent set:

- `/prd` Schema Verification Gate picks the registry path matching
  `stack.database` (Firestore field-registry, Prisma schema, SQL migrations,
  Mongo validator).
- `/prd` Section 5 of the PRD template renders the index variant matching
  `stack.database` (Firestore composite, SQL B-tree, Mongo compound,
  DynamoDB GSI/LSI).
- `api-perf-gate` keyword scan adds DB-specific anti-patterns only when the
  matching `stack.database` is set; universal patterns always run.
- `coder.md` Database Index Invariant ships the right migration kind for
  the resolved `stack.database`.
- `api-perf-cost-auditor` reads the four scalars at session start and cites
  them in every audit header, so the user knows which variant applied.
- `/new` Production Readiness Checklist picks deploy commands matching
  `stack.deployment` + `stack.database` (firebase deploy, vercel deploy,
  supabase db push, CDK/Terraform apply).
- `stack.schema_deploy_from_trunk_only` (boolean, v4.33.0+, default `false`) is a
  **stack-agnostic safety invariant**: when `true`, `/new` and `new2` auto-execute a
  remote schema/RLS/index/migration deploy **only** when the current branch ==
  `git.trunk_branch`. From any non-trunk branch / git worktree the deploy is never
  auto-run — the migration stays committed and the remote deploy is deferred ("happens
  from trunk after merge") and tracked as a `db-migration-deploy` residual. This prevents
  migration-history desync / "code-ahead-of-schema" outages on projects that build
  multiple cards in parallel worktrees against one shared remote datastore. The actual
  command + env loader stay in the project overlay — core only enforces the branch gate.
  `baldart configure` defaults it to `true` when it detects parallel worktree usage.
- `security-reviewer` evaluates access rules per `stack.database`
  (Firestore rules, Supabase RLS, Mongo validators, DynamoDB IAM,
  Postgres RLS+GRANT).
- `bug/logging-patterns.md` picks the framework-native debug switches
  matching `stack.framework`.

**Always-ask contract on empty.** When a scalar is `""` and a skill needs it,
the skill asks the user once and suggests running `npx baldart configure` to
persist the answer. Skills NEVER assume a default — empty means "ask".
`baldart update` flags newly-introduced scalar keys via the schema-drift
detector and auto-offers `baldart configure`.

### 4.5 `features` — explicit booleans gating BLOCKING reads

Every flag MUST be present as `true` or `false` once `baldart configure` has run. **Never default to `false` from absence** — that breaks the always-ask contract. Skills prompt and persist if a flag is missing.

| Flag | Meaning |
|---|---|
| `has_design_system` | The project has docs rooted at `paths.design_system`. When `true`, `ui-design`, `bug`, `frontend-design`, `simplify`, `playwright-skill` etc. treat the INDEX as BLOCKING. |
| `multi_tenant_theming` | The project supports per-tenant theme overrides. Activates themed-surface text/bg pairing rules in `ui-design`, `playwright-skill`, `webapp-testing`. |
| `has_api_docs` | Canonical API docs at `paths.api_index`. Gates `doc-writing-for-rag` schemas/errors workflow. |
| `has_backlog` | Card-driven workflow (`paths.backlog_dir` + AGENTS.md card protocol). `new` skill refuses to run without it. |
| `has_adrs` | ADR workflow. Architectural decisions get logged in `paths.adrs_dir`. |
| `has_prd_workflow` | PRD workflow (`paths.prd_dir`). `/prd` and `/prd-add` skills refuse to run without it. |
| `has_wiki_overlay` | LLM-wiki overlay (`paths.wiki_dir`). `/capture` skill refuses to run without it. |
| `has_lsp_layer` | LSP symbol-search layer (since v3.10.0). When `true`, `codebase-architect`, `context-primer`, `bug`, `prd`, `new`, and `simplify` prefer LSP `find-references` / `go-to-definition` over Grep for identifier queries. Wired by `framework/agents/code-search-protocol.md`. The flag also triggers `baldart configure` (and the `/lsp-bootstrap` skill) to install the matching language servers. |
| `has_code_graph` | Code knowledge graph layer (Graphify, since v4.21.0). When `true`, agents prefer the graph for **structural/relational** queries (`graphify query`/`path`/`affected`) via `framework/agents/code-graph-protocol.md`, and the LLM-wiki overlay is fed by Graphify's native `GRAPH_REPORT.md`. Triggers `baldart configure` / `/graphify-bootstrap` to install Graphify (`pipx install graphifyy`). Install is never silent in CI — `baldart doctor` backfills. Falls back silently to LSP→Grep→Git. |

### 4.6 `lsp` — installed language servers (since v3.10.0)

Populated by `baldart configure` and the `/lsp-bootstrap` skill when `features.has_lsp_layer: true`. Leave empty otherwise.

| Key | Meaning |
|---|---|
| `lsp.installed_servers` | List of language IDs (`typescript`, `python`, `go`, `rust`, `ruby`, …) whose server BALDART has recorded for this project. Identifiers map 1:1 to adapter files under `src/utils/lsp-adapters/`. |
| `lsp.auto_verify` | When `true` (default), `baldart doctor` re-verifies the binaries are reachable **on `$PATH`** (via `command -v`, mirroring how the Claude Code LSP tool spawns them) on every run. Disable on CI if the verify step is too noisy. |

### 4.7 `graph` — code knowledge graph state (since v4.21.0)

Populated by `baldart configure` / the `/graphify-bootstrap` skill when `features.has_code_graph: true`. Scalars only (no arrays) by design. See `framework/docs/CODE-GRAPH-LAYER.md`.

| Key | Meaning |
|---|---|
| `graph.output_dir` | Directory Graphify writes the graph + report to (relative to the graphed root). Graphify's native default is `graphify-out`. Add it to `.gitignore` — generated artifact, never versioned. |
| `graph.auto_rebuild_hook` | When `true` (default), `configure` / `/graphify-bootstrap` run Graphify's native `graphify hook install` (post-commit hook that rebuilds the graph, no API cost). `baldart doctor` restores it if missing. |
| `graph.register_mcp` | When `true`, register Graphify's MCP server (`graphify-mcp`) with the AI tool (best-effort `claude mcp add`). Opt-in: the CLI path (`graphify query`) works without it. |

**Install modes per adapter:**

- `typescript`, `python` — installed globally via npm (`npm install -g typescript-language-server typescript` / `pyright`). Global on purpose: the consumer spawns the server by name from `$PATH`, so a project-local devDep under `node_modules/.bin/` would never be reachable. A binary present only in `node_modules` is reported `installed-but-unreachable`, not `verified`.
- `go`, `rust`, `ruby` — installed via system tools (`go install …`, `rustup component add …`, `gem install …`). BALDART prints the command; the user runs it.

**Fallback contract.** When the LSP layer is enabled but a server is missing or broken, agents silently fall back to Grep — code search never fails because of LSP issues. `baldart doctor` surfaces the mismatch and offers reinstall.

## 5. The overlay system

Overlays let you keep project-specific opinions out of `baldart.config.yml` (which is for structural facts only). They live in `.baldart/overlays/<skill-name>.md`, one file per skill that needs project-specific extension.

### 5.1 Frontmatter

```yaml
---
base_skill: ui-design          # MUST match the skill directory name
base_skill_version: 3.0.0      # framework version this overlay was authored against
mode: extend                   # extend (default) | override
---
```

- `mode: extend` (default) — overlay rules are **added** to the base skill.
- `mode: override` — sections in the overlay **replace** conflicting sections in the base.
- Inside any overlay, a section marked `## [OVERRIDE] <topic>` replaces the same `<topic>` from the base skill regardless of mode.

### 5.2 Precedence

When base skill, config, and overlay all have something to say:

1. **Config wins on facts** (paths, feature flags, identity).
2. **Overlay wins on opinions** (stricter thresholds, mandated styles, forbidden vocabulary). If overlay overrides a config value, the skill emits a one-line notice in its output.
3. **Base skill provides the default** when neither config nor overlay applies.

### 5.3 Version drift

`baldart status` and `baldart update` check `base_skill_version` against the installed framework version. When the framework advances past an overlay's version:

- The skill loads the overlay normally.
- It emits a single-line WARNING at the start of its output: `overlay <name> targets v<X>, installed v<Y> — review for drift`.
- `baldart status` lists drifted overlays.

Non-blocking by design. Silent overrides are worse than noisy ones.

### 5.4 Recommended skills to author overlays for

These skills had heavy hard-coding before v3.0.0; if your project has opinions in any of these areas, an overlay is the place for them:

| Skill | Common overlay content |
|---|---|
| `ui-design` | Design philosophy mandates, theming pairing rules, charting wrappers, browser open command, evaluation thresholds |
| `copywriting` | Brand voice pillars, audience register matrix, forbidden vocabulary, language-only rules |
| `frontend-design` | Aesthetic mandates, illustration-motion contract |
| `prd` / `prd-add` | Project terminology, mandatory review gates, design-system reads for UI PRDs |
| `kie-ai` | Illustration character library, video-prompt motion vocabulary, forbidden aesthetics |
| `bug` | Project debug entry points (env summary helper, cache debug switch, error-code module) |
| `playwright-skill` / `webapp-testing` | Test URLs, auth helpers, theming token-pair assertions |
| `capture` | Wiki-log helper import path, domain vocabulary |
| `gamification-design` | Reward economy facts, customer surface motion vocabulary |

The framework ships starter examples for the heaviest ones in `framework/templates/overlays/`:

- `ui-design.fidelity-example.md`
- `copywriting.fidelity-example.md`

## 6. Skill behaviour when config is missing or empty

**Always-ask, never-assume**. Configured in v3.0.0 per option A.

If a skill encounters:

- A `paths.X` key that is `""` and is required for the current task → ask the user.
- A `features.Y` flag that is **absent from the YAML** (not just `false`) → ask the user, persist the answer.
- A `stack.Z.canonical` array that is empty and is required → ask the user.

The skill suggests running `npx baldart configure` so the answer is durable. If the user declines, the skill proceeds with the provided value, marking it as ASSUMED in its output.

Never:

- Default to `false` from absence.
- Invent a path.
- Silently skip a BLOCKING read.

## 7. Example: ground-up config for a fresh React SaaS

```yaml
version: 1
paths:
  design_system: ""                           # no formal DS yet
  ui_guidelines: docs/style-guide.md
  api_index: ""
  api_schemas: ""
  api_errors: ""
  components_primitives: src/components/ui
  components_root: src/components
  global_styles: src/index.css
  backlog_dir: ""                             # using Linear, not local backlog
  adrs_dir: docs/decisions
  prd_dir: ""
  references_dir: docs
  wiki_dir: ""
  e2e_tests_dir: tests/e2e
identity:
  brand_name: "Acme SaaS"
  design_philosophy: "Minimalist"
  language: en
  audience_segments: ["admin", "end-user"]
stack:
  charting:
    canonical: ["recharts"]
    forbidden: []
    wrappers_root: ""
  animation:
    canonical: ["framer-motion"]
    forbidden: []
  testing:
    e2e: "playwright"
features:
  has_design_system: false
  multi_tenant_theming: false
  has_api_docs: false
  has_backlog: false                          # disables /new
  has_adrs: true
  has_prd_workflow: false                     # disables /prd
  has_wiki_overlay: false                     # disables /capture
```

In this project, `/new`, `/prd`, `/prd-add`, `/capture` refuse to run (they require their workflow). `ui-design` operates with `paths.ui_guidelines` only as its BLOCKING read, and applies a Minimalist aesthetic with English copy targeting admin or end-user.

## 8. Example: porting the legacy fidelity-app

The pre-v3.0.0 BALDART skills assumed this project. To reproduce that behavior exactly:

```bash
npx baldart configure
```

Autodetection should populate most values. Then drop in the example overlays:

```bash
cp .framework/templates/overlays/ui-design.fidelity-example.md \
   .baldart/overlays/ui-design.md
cp .framework/templates/overlays/copywriting.fidelity-example.md \
   .baldart/overlays/copywriting.md
```

Open both and edit. They contain the Neo-Brutalism + Recharts + merchant-theming + 4-pillar-brand-voice content that used to live in the skills. Adapt freely — these are starting points.

## 9. Migration cheat sheet (v2.x → v3.x)

If your project was using BALDART v2.x:

1. `npx baldart update` — pulls v3.0.0, runs configure-check.
2. `npx baldart configure` — interactive prompts, autodetection. Confirm each detected path/flag.
3. For each opinionated skill you actually used (ui-design, copywriting, bug, etc.):
   - If you relied on the pre-v3 hard-coded opinions (Neo-Brutalism, merchant/customer, Recharts-only): copy the matching `*.fidelity-example.md` from `.framework/templates/overlays/` into `.baldart/overlays/` and adapt.
   - If you want the generic behavior: do nothing, skip the overlay.
4. `npx baldart status` — verify config, overlays, and any version-drift warnings.
5. Commit `baldart.config.yml` and `.baldart/overlays/`.

The skills will fail loudly (asking the user) if anything required is missing — there is no silent degradation.

### v3.0 → v3.1 upgrade

No config changes needed. After `npx baldart update`:

- `.baldart/state.json` is seeded automatically on the next CLI invocation (`add` / `update` / `push`).
- `npx baldart version` will show enriched output (install date, remote drift, last-push info).
- `npx baldart push` now auto-bumps `VERSION` and writes the CHANGELOG entry instead of leaving them as manual steps.
- `/baldart-push` is the new slash skill that walks you through the contribution flow.

## 10. FAQ

**Q. Can I edit `baldart.config.yml` directly?**
Yes. It's a regular YAML file. `baldart configure` re-runs interactively and preserves your edits.

**Q. Can I author overlays without ever running `baldart configure`?**
You'd need to hand-write `baldart.config.yml`. Use the template at `framework/templates/baldart.config.template.yml` as a starting point.

**Q. How do skills know which overlay to load?**
Convention: `.baldart/overlays/<skill-name>.md`, where `<skill-name>` matches the skill directory name (e.g. `ui-design`, not `UI Design`).

**Q. Can one overlay reference another?**
No cross-overlay references. Each overlay extends only its own base skill. If two skills share opinions (e.g. design philosophy), put the opinion in `baldart.config.yml` (`identity.design_philosophy`) — that's exactly what the config is for.

**Q. What if the framework removes a config key in a future version?**
That's a MAJOR version bump (`baldart push` will prompt for the classification). The CHANGELOG documents the removed key and a migration step. Your old config is preserved on disk; the new framework version simply ignores the unknown key.

**Q. Where does `baldart update` log changes to my config?**
It never modifies `baldart.config.yml`. It only warns when the framework's template gained new keys not yet in your config — you decide if and when to re-run `configure`.

**Q. The autodetection got something wrong. How do I correct it?**
Re-run `npx baldart configure`. Each prompt shows the autodetected default; type a different value to override.
