baldart 4.78.2 → 4.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,48 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.80.0] - 2026-06-29
9
+
10
+ **Codex-native subagents — the 32 BALDART agents are now installed for Codex, not just Claude.** A portability bug surfaced in the field: a skill running on Codex delegated to `codebase-architect` (*"invoke the codebase-architect agent"*), but the agent did not exist in the Codex tree and there was no obvious mechanism to spawn it, so the model **improvised** a generic explorer sub-agent. Root cause (confirmed against the OpenAI Codex docs, June 2026): the framework treated subagents as Claude-only — the Codex tool adapter declared `supportsSubagents() === false` / `agentsDir() === null`, so the agent definitions under `framework/.claude/agents/` were **never installed into a Codex tree**. But **Codex now has custom agents** (subagents) — they were simply in a different shape than Claude's, and BALDART had not yet mapped them. This release closes that gap.
11
+
12
+ Because a Codex custom agent is a **different on-disk artifact** than a Claude subagent — a TOML file at `.codex/agents/<name>.toml` with `name` / `description` / `developer_instructions` (+ optional `model_reasoning_effort`), spawned **by name** — the skill-style "one source, two symlinks" model does not apply. Instead the same `framework/.claude/agents/<name>.md` stays the **single SSOT** and BALDART **transpiles** it to `.toml` on install/update (new `src/utils/codex-agent-transpiler.js`): frontmatter `name`/`description` → same, body → `developer_instructions`, `effort` (low|medium|high|xhigh|max) → `model_reasoning_effort` (xhigh/max clamp to high), `model` **omitted on purpose** (opus/sonnet/haiku have no 1:1 Codex model → inherit the parent session). The generated `.toml` is a real file (you cannot symlink `.md` → `.toml`) carrying a `# baldart-generated:` marker, so an `update` regenerates it idempotently and a user fork (no marker) is never clobbered. Overlays apply **first** (the markdown `## [OVERRIDE]/[APPEND]/[PREPEND]` overlay is merged, then transpiled) — Codex agents honour `.baldart/overlays/agents/<name>.md` exactly like Claude. The transpile rides on the **existing** `MERGE_KINDS` machinery via one new adapter hook, `transpilerFor(kind)` (`codex` returns a transpiler for `agent`; `claude` returns null), so nothing else in the merge path changed and Claude is byte-for-byte unaffected. Existing Codex consumers pick it up on the next `npx baldart update`. AGENTS.md's "MUST invoke codebase-architect" + no-silent-fallback rules are now tool-aware (the agent exists on both tools; spawn by name on Codex). Verified end-to-end: all 32 real agents transpile to valid TOML (parsed with `@iarna/toml`), idempotency / source-change-regen / user-fork-protection / overlay-aware-transpile all pass.
13
+
14
+ **Standing convention** (the user's explicit ask: *every agent from now on is natively Codex-compatible*): any new agent is auto-portable — drop a `.md` under `framework/.claude/agents/`, keep `name`+`description` frontmatter, put behaviour in the body (→ `developer_instructions`), and don't rely on an agent spawning a further agent (Codex `agents.max_depth: 1`, consistent with BALDART's `## Role boundary`). Skills were already Codex-native (identical format). Authoritative design: [`framework/docs/CODEX-AGENTS.md`](framework/docs/CODEX-AGENTS.md).
15
+
16
+ **MINOR** — additive capability (Codex consumers gain 32 agents; existing Claude installs unchanged). **No new `baldart.config.yml` key** — rides on `tools.enabled` containing `codex`, so the schema-change propagation rule does NOT apply. Slash commands / dynamic workflows / output styles stay Claude-only (`commandsDir`/`workflowsDir`/`outputStylesDir` remain null for Codex — no Codex equivalent).
17
+
18
+ ### Added
19
+
20
+ - **`src/utils/codex-agent-transpiler.js`** — pure `.md` → `.toml` transpiler (`mdAgentToToml`, `isGeneratedToml`, `mapEffort`). Emits `developer_instructions` as a TOML multi-line **literal** (`'''…'''`) so arbitrary markdown survives byte-for-byte, with an escaped `"""…"""` fallback only when the body itself contains `'''`.
21
+ - **`framework/docs/CODEX-AGENTS.md`** — design + field-mapping table + the per-agent authoring contract.
22
+
23
+ ### Changed
24
+
25
+ - **`src/utils/tool-adapters/codex.js`** — `agentsDir()` → `.codex/agents` (was null), `supportsSubagents()` → true (was false), new `transpilerFor(kind)` hook returning the TOML transpiler for `agent`. Header comment corrected (Codex DOES have custom agents now).
26
+ - **`src/utils/tool-adapters/claude.js`** — added `transpilerFor()` → null (explicit no-op: Claude consumes every payload in its native format).
27
+ - **`src/utils/symlinks.js`** — `_mergeBulkDir` routes a kind through the new `_installTranspiledFile` (generate tool-native file, overlay-merged first when present) when the adapter declares a transpiler; `verifySymlinks` recognises transpiled `.toml` (via `isGeneratedToml`) as framework-managed alongside symlinks and overlay-generated `.md`.
28
+ - **`framework/AGENTS.md`** — the "MUST invoke `codebase-architect`" and no-silent-substitution rules are now tool-aware: the agent exists on both tools (Claude → Task/`subagent_type`; Codex → spawn by name at `.codex/agents/codebase-architect.toml`); the #56869 specifics stay Claude-scoped, the principle stays universal.
29
+ - **`framework/.claude/agents/REGISTRY.md`** + **`CLAUDE.md`** — document the Codex-native subagent convention + the authoring contract.
30
+
31
+ ## [4.79.0] - 2026-06-29
32
+
33
+ **New skill `/ds-handoff` — the field-level, 1:1 Claude Design handoff brief.** When `/prd` reached the "hand off to Claude Design" branch, the prompt it produced described each screen only coarsely — *purpose / states / actions / data shown* — and never the exact fields. With no field-level contract, Claude Design **imagines** control types, required-ness, validation, defaults and enum values to cover the gap, so the result is never 1:1. The root cause: BALDART had **no mandatory phase** that enumerated a screen's real fields, and **no coverage gate** verifying them before the prompt was emitted (field discovery was manual discovery-questions). `/ds-handoff` fixes this end-to-end: it (1) identifies each screen's backing data entities, (2) **grounds the field inventory in the project's real schemas** (Zod / TS types / form schemas) by composing existing retrieval (code-graph → LSP → `codebase-architect` → Grep — **no new AST/Zod parser**, an over-scoped fragility the design refused), (3) reconciles fields↔screens (which fields show / are editable / group into which card), (4) runs a **coverage gate** that **BLOCKS** emission in interactive mode when a backed screen's `{control, required}` are unverified — degrading gracefully to user-confirmation when no formal schema exists (portable / Codex), (5) renders the **mandatory field-level template** (a 9-column field-inventory table per screen + actions / states / responsive). It becomes the **single SSOT** for the Claude Design prompt: `/prd` Step 3.0 Branch B now **delegates** to it (graceful inline-coarse fallback when the skill is unavailable), and the old inline `/prd` template is **retired**. Usable standalone via `/ds-handoff <screens-or-feature>` (e.g. an ad-hoc orchestrator + `ui-expert` run). A THIN orchestrator — it **cites** `design-system-protocol.md` (Functional Traceability Gate `backed/decorative/orphan` vocabulary + Reference Tables numbers) and **reads** `discovery-phase.md`'s `mockup_analysis` as input, never duplicating their rules (no dual-SSOT).
34
+
35
+ **MINOR** — new skill (40 portable skills). **No new `baldart.config.yml` key** — rides on the already-present `features.has_design_system` (BLOCKING gate; REFUSE + suggest `/design-system-init` when `false`) + `features.has_prd_workflow` when delegated, so the schema-change propagation rule does NOT apply. Claude + Codex portable (the gate degrades, subagent steps fall back to Grep). No agent / template / routine outside the skill changed; `discovery-phase.md` (`mockup_analysis`) and `card-schema.md` (`component_bindings`) are deliberately **untouched** (the field layer is a skill-local artifact, not a card/state schema field).
36
+
37
+ ### Added
38
+
39
+ - **`/ds-handoff`** (`framework/.claude/skills/ds-handoff/`) — `SKILL.md` (thin 8-step orchestrator), `assets/claude-design-handoff-prompt.template.md` (the mandatory field-level template — replaces the retired `/prd` coarse template), `references/field-extraction.md` (retrieval order + control-type mapping table + readonly detection), `references/coverage-gate.md` (BLOCK-vs-degrade logic + the worked "Fornitori" example). Gated on `features.has_design_system`.
40
+
41
+ ### Changed
42
+
43
+ - **`/prd`** (`framework/.claude/skills/prd/references/ui-design-phase.md`) — Step 3.0 Branch B now **delegates** the Claude Design handoff prompt to `/ds-handoff` (passing the resolved context so it skips its own screen-resolution), presents what it returns, and persists `mockups.field_inventory_path`. Graceful **inline-coarse fallback** (stated explicitly) when `/ds-handoff` is unavailable.
44
+ - **`framework/agents/skills-mapping.md`** — expanded from a curated 11-skill subset to the **full 40-skill routing map** (Design System, Internationalization, Retrieval/Toolchain Bootstrap, Framework Maintenance categories added; per-entry `features.*` gating noted; decision tree + chains updated with the design-system + Claude-Design-handoff flows), so the routing doc the agent reads covers every shipped skill including `ds-handoff`.
45
+
46
+ ### Removed
47
+
48
+ - **`framework/.claude/skills/prd/assets/claude-design-handoff-prompt.template.md`** — the coarse `/prd` handoff template, superseded by the field-level template in `ds-handoff/assets/` (single SSOT; coarse content survives inline in the Branch B fallback).
49
+
8
50
  ## [4.78.2] - 2026-06-29
9
51
 
10
52
  **The "visual-verify every `ui-expert` intervention" hard rule was investigated and deliberately NOT built.** The ask sounded obvious — wire an invariant `UI_VISUAL_UNVERIFIED` forcing a visual check after every `ui-expert` implementation. Three adversarial reviewers (distinct lenses) refuted the diagnosis: (1) standalone skills already verify — `/ui-design` has its generator/evaluator Playwright loop, `/ds-new` + `/ds-edit` delegate to `ui-expert`'s own BLOCKING pre-work + `ds-gate` + the coherence report, `/ds-render` feeds `/e2e-review` Phase 4b; (2) the invariant would be redundant with the existing `DS_*` coherence codes + the `coverage-gap` finding, and would fire **constantly** on every Storybook-less project — the gate-with-no-exit structural false-positive the framework explicitly avoids — plus risk the assertion-fitting the verifier trio forbids; (3) the real driver the obvious diagnosis missed: **visual verification is deliberately deferred to where a ground-truth exists** (a composed route / a mockup) — an inert scaffolded primitive has nothing to be judged against, so verifying it *now* judges the void. The single useful residue (a deterministic `PostToolUse` hook would beat prose if one ever wanted to harden `/new`'s own prose-driven Phase 2.6) was logged, not built. So this release ships only the **zero-cost, non-regressive nudge**: a documentation pointer making explicit *where* route-level fidelity lives.
package/README.md CHANGED
@@ -212,14 +212,14 @@ Skills always-ask when required keys are missing — never silently default.
212
212
  never overwrites your file. Full guide:
213
213
  [`framework/docs/PROJECT-CONFIGURATION.md`](framework/docs/PROJECT-CONFIGURATION.md).
214
214
 
215
- ### Skills (37 portable skills)
215
+ ### Skills (40 portable skills)
216
216
 
217
217
  Skills live under `.claude/skills/` and are auto-discovered by Claude Code.
218
218
  Bundled skills:
219
219
 
220
220
  - **Workflow**: `new`, `new2` (v4.16.0 — EXPERIMENTAL workflow-hosted `/new`, Claude-only, for A/B testing context economy), `prd`, `prd-add`, `bug`, `simplify`, `worktree-manager`, `issue-review`, `context-primer`
221
221
  - **Code quality**: `skill-creator`, `find-skills`, `webapp-testing`, `playwright-skill`, `lsp-bootstrap` (v3.10.0), `graphify-bootstrap` (v4.21.0 — code knowledge graph), `graph-align` (v4.21.0 — doc↔graph alignment), `toolchain-bootstrap` (v4.41.0 — curated dev toolchain), `e2e-review` (v3.18.0)
222
- - **Design**: `frontend-design`, `ui-design`, `motion-design`, `gamification-design`, `design-system-init` (v3.11.0 — bulk registry bootstrap/upgrade), `ds-new` (v4.69.0 — single-element guided creation: one component or token, reuse-first → optional scaffold → document + register + govern + verify; the on-the-fly twin of `design-system-init`), `ds-edit` (v4.70.0 — deliberate edit of one existing element: resync / extend-variant / breaking / re-govern; regenerates the spec preserving agentic fields + prose, same canonical template)
222
+ - **Design**: `frontend-design`, `ui-design`, `motion-design`, `gamification-design`, `design-system-init` (v3.11.0 — bulk registry bootstrap/upgrade), `ds-new` (v4.69.0 — single-element guided creation: one component or token, reuse-first → optional scaffold → document + register + govern + verify; the on-the-fly twin of `design-system-init`), `ds-edit` (v4.70.0 — deliberate edit of one existing element: resync / extend-variant / breaking / re-govern; regenerates the spec preserving agentic fields + prose, same canonical template), `ds-render` (v4.76.0 — render primitives in isolation to PNG via Storybook+Playwright), `design-sync` (v4.76.0 — mirror the registry to its Claude Design satellite), `ds-handoff` (v4.79.0 — field-level 1:1 Claude Design handoff brief: grounds every screen's fields in the real data schemas + coverage-gates before emitting; the SSOT for the Claude Design prompt, delegated from `/prd`)
223
223
  - **Product**: `seo-audit`, `copywriting`, `api-design-principles`
224
224
  - **Knowledge**: `doc-writing-for-rag`, `capture` (LLM wiki overlay)
225
225
  - **Internationalization**: `i18n` (v4.52.0 — audit the context registry + context-aware translation into native locale files), `i18n-adopt` (v4.52.0 — one-shot migration that externalizes all hardcoded strings on an existing codebase); both gated on `features.has_i18n`
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.78.2
1
+ 4.80.0
@@ -2,7 +2,9 @@
2
2
 
3
3
  Quick-reference for all custom agents. Use this to route tasks to the right specialist.
4
4
 
5
- **Location**: `.claude/agents/<name>.md` | **Invoke via**: `Task` tool with `subagent_type="<name>"`
5
+ **Location**: `.claude/agents/<name>.md` | **Invoke via**: `Task` tool with `subagent_type="<name>"` (Claude) — or **by name** as a Codex custom agent (Codex)
6
+
7
+ > **Codex-native (since v4.80.0)**: every agent here is portable to Codex. The same `<name>.md` is **transpiled** to `.codex/agents/<name>.toml` on install/update (`name`/`description` → same, body → `developer_instructions`, `effort` → `model_reasoning_effort`, `model` omitted). Authoring stays single-source: drop a `.md`, it auto-installs for both tools. Keep `name`+`description` frontmatter, put behaviour in the body, and don't rely on an agent spawning a further agent (Codex `agents.max_depth: 1`). Design: [`framework/docs/CODEX-AGENTS.md`](../../docs/CODEX-AGENTS.md).
6
8
 
7
9
  > **Machine-readable source of truth (since v3.20.0)**: the filesystem directory `framework/.claude/agents/` is authoritative for the list of BALDART agents. The `agent-discovery-gate.js` PreToolUse hook, the `agent-discovery-info.sh` SessionStart hook, and `baldart doctor` enumerate the directory directly (every `<name>.md` except this file is an agent — no manifest JSON is shipped). Adding a new agent means dropping `<name>.md` here; no other touchpoint.
8
10
 
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: ds-handoff
3
+ effort: medium
4
+ description: >
5
+ Produce a FIELD-LEVEL, 1:1, interaction-complete handoff brief for Claude Design
6
+ — every screen's real fields (label, control type, required, validation, default,
7
+ enum source, helper text, editable-vs-readonly), grounded in the project's actual
8
+ data schemas (Zod / TS types / form schemas) via a coverage gate that BLOCKS prompt
9
+ emission when a backed screen's fields are unverified. The single SSOT for the
10
+ Claude Design handoff prompt: `/prd` Step 3.0 Branch B delegates here; usable
11
+ standalone via `/ds-handoff <screens-or-feature>`. A THIN orchestrator — cites
12
+ `design-system-protocol.md` (Functional Traceability Gate, Reference Tables) and
13
+ reads `mockup_analysis` as input, never duplicating their rules; reuses existing
14
+ retrieval (code-graph / LSP / codebase-architect / Grep) rather than shipping a
15
+ schema-extractor tool. Use when the user says /ds-handoff, "handoff a Claude
16
+ Design", "prompt per Claude Design", "brief field-level", "prepara il prompt
17
+ mockup". Gated on features.has_design_system.
18
+ ---
19
+
20
+ # DS Handoff — field-level Claude Design brief
21
+
22
+ The fix for the "the prompt describes structure but not the fields, so Claude
23
+ Design imagines" failure. A mockup prompt that lists screens only as
24
+ *purpose / states / actions / data shown* forces the design tool to invent control
25
+ types, required-ness, validation, defaults and enum values. This skill enumerates
26
+ every backing field **from the real code**, reconciles it per screen, **verifies
27
+ coverage before emitting**, and renders the mandatory field-level template.
28
+
29
+ It is a conductor: each step DELEGATES to an existing module and cross-pointers to
30
+ it. No cascade / schema / traceability rule is re-described here (re-describing it
31
+ is how it drifts from the SSOT).
32
+
33
+ ## Project Context
34
+
35
+ **Reads from `baldart.config.yml`:** `paths.design_system`,
36
+ `paths.components_primitives`, `paths.design_tokens`, `paths.ui_guidelines`,
37
+ `paths.prd_dir`, `stack.framework`, `stack.charting`, `stack.animation`,
38
+ `identity.*`, `features.has_design_system`, `features.has_lsp_layer`,
39
+ `features.has_code_graph`, `features.has_i18n`.
40
+
41
+ **Writes:** the rendered prompt → `${paths.prd_dir}/<slug>/handoff/claude-design-prompt.md`;
42
+ the optional field inventory → `${paths.prd_dir}/<slug>/mockups/field-inventory.md`.
43
+ Source-read-only otherwise (it never edits app code or the registry).
44
+
45
+ **Gated by features:** `features.has_design_system` (BLOCKING). When `false`,
46
+ REFUSE and recommend `/design-system-init` (§ 5 of the prompt + the per-region
47
+ component binding need a registry). When delegated from `/prd` it also rides on
48
+ `features.has_prd_workflow`. See `design-system-protocol.md` § Gating.
49
+
50
+ **Overlay:** loads `.baldart/overlays/ds-handoff.md` if present (brand voice,
51
+ mandated output format, project control conventions).
52
+
53
+ **On missing/empty keys:** ask the user; do not assume defaults. See
54
+ `framework/agents/project-context.md` § 3.
55
+
56
+ ## Effort
57
+
58
+ **Baseline:** `effort: medium` (frontmatter). **Inline override:** pass
59
+ `effort=<low|medium|high|xhigh|max>` anywhere in the invocation to scale reasoning
60
+ depth for this run — detect it once at kickoff and strip the token before consuming
61
+ user input. Level→behavior mapping, parsing contract, and precedence caveats:
62
+ `framework/agents/effort-protocol.md`.
63
+
64
+ ## Invocation
65
+
66
+ `/ds-handoff <screens-or-feature>` (standalone) · `/ds-handoff` (ask). When called
67
+ by `/prd` Step 3.0 Branch B, the caller passes the resolved context (state-file
68
+ path + feature title/objective/user_flow/personas/screens_in_scope/mockup_analysis
69
+ + brand + DS flag) — skip the standalone screen-resolution prompt (Step 1's ask).
70
+
71
+ ## Pre-flight
72
+
73
+ - **P0 — gate.** `features.has_design_system: false` → REFUSE + suggest
74
+ `/design-system-init`. (DELEGATE `design-system-protocol.md` § Gating.)
75
+ - **P1 — mode.** *Delegated* (a `/prd` state-file path was passed) vs *standalone*
76
+ (`/ds-handoff <args>`). The mode only changes where screens + top-level context
77
+ come from (Step 1); Steps 2–8 are identical.
78
+
79
+ ---
80
+
81
+ ## Workflow
82
+
83
+ Each step is a delegation. Read the cited SSOT; do not paraphrase it.
84
+
85
+ 1. **Resolve screens in scope.** *Delegated* → read `screens_in_scope[]` +
86
+ `mockup_analysis` from the `/prd` state file `## UI Design` (reuse the caller's
87
+ collection — do NOT re-derive). *Standalone* → derive screens from the arg;
88
+ on ambiguity, ONE `AskUserQuestion` listing route/page candidates from a
89
+ `codebase-architect` probe. Never proceed on silence.
90
+
91
+ 2. **Identify backing entities per screen.** Name the entity/entities each screen
92
+ reads or writes. A screen may legitimately have **zero** entities (pure
93
+ navigation / dashboard chrome) — that is valid and MUST NOT trip the gate
94
+ (Step 5).
95
+
96
+ 3. **Locate & extract the real field definitions.** DELEGATE — see
97
+ [references/field-extraction.md](references/field-extraction.md) for the
98
+ retrieval order (code-graph → LSP → `codebase-architect` → Grep, each with
99
+ silent fallback) and the control-type mapping table. Per field capture: label,
100
+ control, required, validation, default, enum/options source, helper,
101
+ editable-vs-readonly. The skill ships **no** AST/Zod parser — it composes
102
+ existing retrieval and applies the documented mapping; anything it cannot ground
103
+ becomes the literal `da definire`.
104
+
105
+ 4. **Reconcile fields ↔ screens.** Not every field appears on every screen. Per
106
+ screen decide the shown subset, editable vs readonly, and card grouping —
107
+ informed by `mockup_analysis.screens[].layout / component_props / states` when
108
+ present (read as input; owned by `discovery-phase.md`), user intent (standalone),
109
+ and the entity field set.
110
+
111
+ 5. **Coverage gate (BLOCK vs degrade).** DELEGATE —
112
+ [references/coverage-gate.md](references/coverage-gate.md). It reuses the
113
+ `backed / decorative / orphan` vocabulary from `design-system-protocol.md`
114
+ § Functional Traceability Gate (CITE, never redefine). Field coverage: every
115
+ screen with ≥1 backing entity must have each shown field present with non-`da
116
+ definire` `{control, required}`. **BLOCK (interactive):** STOP + ONE consolidated
117
+ `AskUserQuestion` over the unverified backed screens + unbacked-orphan fields.
118
+ **DEGRADE:** no formal schema / empty extraction / Codex → downgrade BLOCK to
119
+ user-confirmation (present best-effort, ask the user to fill `da definire`);
120
+ never hard-abort.
121
+
122
+ 6. **Fill the mandatory template.** Populate
123
+ [assets/claude-design-handoff-prompt.template.md](assets/claude-design-handoff-prompt.template.md)
124
+ with the reconciled per-screen specs + the top-level sections (brand / design
125
+ system / stack / cosa restituirmi). § 5's numeric constraints are the
126
+ `{{tokens.*}}` placeholders that **cite** `design-system-protocol.md` § Reference
127
+ Tables — copy values verbatim from the protocol, never invent numbers. Strip
128
+ empty conditionals.
129
+
130
+ 7. **Persist the inventory artifact.** Write
131
+ `${paths.prd_dir}/<slug>/mockups/field-inventory.md` (the reconciled inventory)
132
+ so it survives restarts and feeds re-entry (`/prd` Step 1.6 Mockup Intake) +
133
+ downstream `component_bindings` reconciliation. Standalone with no prd-dir
134
+ convention → present inline + offer to persist.
135
+
136
+ 8. **Emit the prompt.** Present the rendered template inside a fenced markdown
137
+ code-block, prefixed verbatim:
138
+
139
+ > Incolla il prompt qui sotto in Claude Design. Quando hai i mockup pronti,
140
+ > tornami con i **path locali** dei file (PNG, HTML, TSX, o link Figma) e
141
+ > riprendo da qui.
142
+
143
+ *Delegated* → return the rendered prompt + the `field-inventory.md` path to
144
+ `/prd`, which owns the state-file mutation (`mockups.handoff_prompt_path`,
145
+ `mockups.field_inventory_path`, `mockups.status: pending_external`). *Standalone*
146
+ → save under `${paths.prd_dir}/<slug>/handoff/` and report the paths.
147
+
148
+ ---
149
+
150
+ ## Inline fallbacks (portability + fail-safe)
151
+
152
+ - **No `Workflow` tool needed** — this skill is prose-orchestrated.
153
+ - **Codex (no subagents):** Step 3's `codebase-architect` degrades to inline Grep
154
+ (per `references/field-extraction.md`); the gate degrades BLOCK → user-confirmation
155
+ (Step 5). Runs end-to-end.
156
+ - **No LSP / no code-graph:** silent fallback down the retrieval order. Surface a
157
+ broken layer via `baldart doctor`, never abort here.
158
+ - **No formal schema in the stack:** the DEGRADE branch — best-effort inventory +
159
+ user confirmation of every `da definire`. Always-ask-never-assume
160
+ (`project-context.md` § 3).
161
+
162
+ ## /prd integration
163
+
164
+ `/prd` Step 3.0 Branch B (`prd/references/ui-design-phase.md`) OWNS the decision to
165
+ hand off to Claude Design; `/ds-handoff` OWNS the prompt. `/prd` invokes this skill
166
+ with the resolved context and presents what it returns. If the skill is unavailable
167
+ (Codex without it linked / an older install), `/prd` falls back to an inline
168
+ **coarse** brief and says so explicitly — the prose stays SSOT, delegate-or-else-inline
169
+ (the same opt-in contract as `/prd` → `/ds-new`).
170
+
171
+ ## See Also
172
+
173
+ - `framework/agents/design-system-protocol.md` — Functional Traceability Gate
174
+ (the `backed/decorative/orphan` vocabulary), Reference Tables (the § 5 numbers),
175
+ the registry cascade this skill's binding column relies on.
176
+ - `framework/.claude/skills/prd/references/discovery-phase.md` — the
177
+ `mockup_analysis` schema this skill reads as input (NEVER redefines).
178
+ - `framework/.claude/skills/prd/references/ui-design-phase.md` — the `/prd`
179
+ delegation site (Step 3.0 Branch B) + the re-entry that consumes the artifact.
180
+ - `framework/.claude/skills/ds-new/SKILL.md` / `ds-edit` — when the brief surfaces
181
+ a genuinely-new component, these create/edit it canonically.
182
+ - `framework/agents/code-search-protocol.md` — the code-graph/LSP/Grep retrieval
183
+ layer Step 3 composes.
@@ -0,0 +1,197 @@
1
+ # Claude Design Handoff Prompt — Field-Level Template
2
+
3
+ > The MANDATORY template for the Claude Design handoff prompt. Populated by the
4
+ > `ds-handoff` skill ([../SKILL.md](../SKILL.md)) — invoked standalone or
5
+ > delegated from `/prd` Step 3.0 Branch B. This is the **single SSOT** for the
6
+ > prompt shape; the old coarse `/prd` template is retired.
7
+ >
8
+ > All `{{placeholders}}` resolve from the `ds-handoff` field inventory (Steps 1–5),
9
+ > the PRD state file when delegated, `baldart.config.yml`, and optional overlays.
10
+ >
11
+ > Render rules:
12
+ > - Conditional sections (`{{#if …}} … {{/if}}`) are emitted only when true. Skip
13
+ > the whole section (heading included) when false.
14
+ > - Lists (`{{#each …}}`) render one row/bullet per item; emit "—" if empty.
15
+ > - The rendered output is presented inside a fenced markdown code-block so the
16
+ > user can copy-paste it verbatim into Claude Design.
17
+ > - **`da definire`** is a real, literal cell value — never a guess. It signals a
18
+ > fact the field-extraction step could not ground in code; Claude Design must
19
+ > ask, not invent (always-ask-never-assume).
20
+
21
+ ---
22
+
23
+ # Feature: {{feature_title}}
24
+
25
+ ## 1. Obiettivo
26
+
27
+ {{feature_objective_one_sentence}}
28
+
29
+ ## 2. User flow
30
+
31
+ {{user_flow_summary}}
32
+
33
+ {{#if primary_personas}}
34
+ **Personas target**:
35
+ {{#each primary_personas}}
36
+ - {{this.name}} — {{this.context}}
37
+ {{/each}}
38
+ {{/if}}
39
+
40
+ ## 3. Schermate in scope — specifica field-level
41
+
42
+ > **Questo è un contratto 1:1.** Ogni campo, controllo, validazione e opzione
43
+ > qui sotto è **estratto dallo schema dati reale** del progetto. NON inventare,
44
+ > aggiungere o rinominare campi; NON inventare tipi di controllo, validazioni,
45
+ > default o valori di enum. Una cella **`da definire`** = chiedimelo, non
46
+ > indovinarla. Un campo marcato **readonly** è di sola lettura: NON dargli un
47
+ > controllo editabile (input/select/toggle) — rendilo come testo statico.
48
+ >
49
+ > **Vincolo di tracciabilità funzionale.** Inserisci SOLO controlli e affordance
50
+ > (bottoni, icone-azione, voci di menu, tab, toggle) legati a una funzione
51
+ > elencata. Non aggiungere chrome interattivo "per completezza visiva": ogni
52
+ > affordance senza funzione diventa codice morto. Elementi puramente decorativi
53
+ > (icone di sezione, marchi) marcali esplicitamente **decorativi**.
54
+
55
+ {{#each screens_in_scope}}
56
+ ### {{this.name}}
57
+
58
+ **Identità** — Route: `{{this.route}}`{{#if this.slot_id}} · Artboard: `{{this.slot_id}}`{{/if}}{{#if this.screen_id}} · Screen id: {{this.screen_id}}{{/if}}
59
+ - **Scopo**: {{this.purpose}}
60
+ - **Entità backing**: {{this.backing_entities}} <!-- es. "Fornitore (supplierSchema)"; "—" se schermata di sola navigazione -->
61
+
62
+ **Layout (regioni & nesting)**:
63
+ {{#each this.regions}}
64
+ - `{{this.region}}` → **{{this.component}}**{{#if this.props}} ({{this.props}}){{/if}}{{#if this.contains}} → contiene: {{this.contains}}{{/if}}
65
+ {{/each}}
66
+
67
+ {{#if this.fields}}
68
+ **Field inventory** — ogni riga è un campo reale dello schema:
69
+
70
+ | Campo (label) | Controllo | Required | Validazione/Vincoli | Default | Opzioni / sorgente enum | Helper text | Mode | Card/gruppo |
71
+ |---|---|---|---|---|---|---|---|---|
72
+ {{#each this.fields}}
73
+ | {{this.label}} | {{this.control}} | {{this.required}} | {{this.validation}} | {{this.default}} | {{this.options}} | {{this.helper}} | {{this.mode}} | {{this.card}} |
74
+ {{/each}}
75
+ {{/if}}
76
+
77
+ {{#if this.cards}}
78
+ **Raggruppamento in card**:
79
+ {{#each this.cards}}
80
+ - **{{this.title}}**: {{this.fields}}
81
+ {{/each}}
82
+ {{/if}}
83
+
84
+ {{#if this.actions}}
85
+ **Azioni & interazioni**:
86
+
87
+ | Azione | Effetto | Destinazione | Abilitata quando | Traccia a |
88
+ |---|---|---|---|---|
89
+ {{#each this.actions}}
90
+ | {{this.action}} | {{this.effect}} | {{this.destination}} | {{this.enabled_when}} | {{this.traces_to}} |
91
+ {{/each}}
92
+ {{/if}}
93
+
94
+ {{#if this.states}}
95
+ **Stati → rappresentazione**:
96
+ {{#each this.states}}
97
+ - `{{this.state}}` → {{this.representation}}{{#if this.traces_to}} (traccia a {{this.traces_to}}){{/if}}
98
+ {{/each}}
99
+ {{/if}}
100
+
101
+ {{#if this.list_item}}
102
+ **Dato per-riga / per-card** (lista):
103
+ {{#each this.list_item.fields}}
104
+ - {{this.label}} — {{this.note}}
105
+ {{/each}}
106
+ - Azioni di riga: {{this.list_item.row_actions}}
107
+ - Empty / sort / paginazione: {{this.list_item.list_behavior}}
108
+ {{/if}}
109
+
110
+ {{#if this.responsive}}
111
+ **Responsive**:
112
+ {{#each this.responsive}}
113
+ - {{this}}
114
+ {{/each}}
115
+ {{/if}}
116
+
117
+ {{/each}}
118
+ > **Nota per l'export.** Dai al canvas di questa feature un titolo che contenga il
119
+ > nome feature («{{feature_title}}»), e numera gli artboard in modo coerente con
120
+ > gli ID schermata qui sopra (es. screen id 3.1 → artboard `s31`). Scaricherò il
121
+ > bundle completo del workspace per ritrovare esattamente le TUE schermate.
122
+
123
+ {{#if brand_voice}}
124
+ ## 4. Brand & voice
125
+
126
+ - **Tono**: {{brand_voice.tone}}
127
+ - **Personalità**: {{brand_voice.personality}}
128
+ - **Do**: {{brand_voice.do}}
129
+ - **Don't**: {{brand_voice.dont}}
130
+ {{#if brand_voice.references}}
131
+ - **Riferimenti visivi**: {{brand_voice.references}}
132
+ {{/if}}
133
+ {{/if}}
134
+
135
+ {{#if has_design_system}}
136
+ ## 5. Design system constraints
137
+
138
+ > Riusa SOLO i token e le primitive elencate. Se devi proporre qualcosa di nuovo,
139
+ > segnalalo esplicitamente nella consegna così posso aggiornare il registro.
140
+
141
+ ### Token chiave
142
+
143
+ ```
144
+ {{design_tokens_excerpt}}
145
+ ```
146
+
147
+ ### Primitive da riusare
148
+
149
+ {{#each registered_primitives}}
150
+ - **{{this.name}}** — {{this.purpose}} ({{this.path}})
151
+ {{/each}}
152
+
153
+ ### Vincoli numerici (da `design-system-protocol.md`)
154
+
155
+ - Type scale: {{tokens.type_scale}}
156
+ - Spacing scale: {{tokens.spacing_scale}}
157
+ - Radius: {{tokens.radius_scale}}
158
+ - Contrast minimo: {{tokens.contrast_target}} (WCAG AA + APCA Lc ≥ {{tokens.apca_target}})
159
+ - Motion durations: {{tokens.motion_durations}}
160
+ {{/if}}
161
+
162
+ ## 6. Stack target
163
+
164
+ - **Framework**: {{stack.framework}}
165
+ - **Output preferito**: {{output_format_preference}} <!-- "HTML/CSS standalone" | "React component (Tailwind)" | "Figma frame" -->
166
+ {{#if stack.charting}}
167
+ - **Charting library**: {{stack.charting}}
168
+ {{/if}}
169
+ {{#if stack.animation}}
170
+ - **Animation library**: {{stack.animation}}
171
+ {{/if}}
172
+
173
+ ## 7. Cosa restituirmi
174
+
175
+ Per ogni schermata elencata in § 3:
176
+
177
+ 1. **PNG export** ad alta risoluzione (≥ 2x) di OGNI stato richiesto (es. `dettaglio-fornitore__loading.png`, `dettaglio-fornitore__populated.png`).
178
+ 2. {{output_format_preference_block}} <!-- "Codice HTML/CSS in un file unico" | "Codice React (.tsx) con import Tailwind" | "Link Figma alla frame" -->
179
+ 3. **Mappa di tracciabilità campo→funzione** — per OGNI campo della field inventory,
180
+ conferma che sia presente e col controllo/mode indicati. Se un campo di § 3 manca
181
+ nel tuo design, **segnalalo, non ometterlo silenziosamente**. Per OGNI elemento
182
+ interattivo o iconografico, una riga `elemento → funzione che lo motiva`, oppure
183
+ marcalo **decorativo**. Qualunque elemento non tracciabile elencalo come
184
+ *orphan da decidere* — così scelgo se dargli funzione, renderlo decorativo o
185
+ rimuoverlo, invece di implementarlo a vuoto.
186
+ 4. **Note inline** su:
187
+ - Componenti nuovi (non nel registry sopra) introdotti e perché.
188
+ - Token deviation: qualunque colore/spacing/radius fuori dalla palette sopra, con motivazione.
189
+ - Decisioni di layout non ovvie (priority sort, hierarchy visiva, density).
190
+
191
+ Quando hai pronto, dimmi i **path locali** dei file (PNG/HTML/TSX) — li importerò
192
+ in questa sessione per analisi e validazione contro il design system.
193
+
194
+ ---
195
+
196
+ <!-- baldart-handoff: do-not-edit-manually -->
197
+ <!-- Generated from ds-handoff/assets/claude-design-handoff-prompt.template.md by the ds-handoff skill -->
@@ -0,0 +1,109 @@
1
+ # Coverage gate — verify the fields BEFORE emitting the prompt
2
+
3
+ `ds-handoff` Step 5. The gate that makes the brief 1:1: it refuses to emit a prompt
4
+ whose backed screens have unverified fields, so Claude Design never has to imagine.
5
+ It reuses the `backed / decorative / orphan` vocabulary from
6
+ `design-system-protocol.md` § Functional Traceability Gate — **CITE it, never
7
+ redefine it**. That gate governs *interactive/iconographic affordances*; this gate
8
+ applies the same discipline one level deeper, to **data fields**.
9
+
10
+ ## What is checked
11
+
12
+ ### Axis 1 — Field coverage (the BLOCK condition)
13
+
14
+ For every screen with **≥ 1 backing entity** (Step 2): each shown field in its
15
+ inventory must be present with, at minimum, a non-`da definire` **Controllo** and
16
+ **Required**. A backed screen whose inventory is empty, or whose shown fields carry
17
+ `da definire` in `{control, required}`, is **unverified** → a BLOCK condition.
18
+
19
+ Validation / default / helper / enum-source cells MAY remain `da definire` (they
20
+ degrade gracefully — Claude Design will ask), but `{control, required}` are the
21
+ floor: without them the design tool cannot even place the right widget.
22
+
23
+ ### Axis 2 — Field traceability (advisory + resolve)
24
+
25
+ Reuse the protocol's classification, applied to fields:
26
+
27
+ | Class | Definition | Outcome |
28
+ |---|---|---|
29
+ | **Backed** | Field exists in the entity schema AND is placed on a screen | OK — in the inventory |
30
+ | **Decorative** | Static display (a computed value shown read-only, a label) | `mode: readonly`, never blocks |
31
+ | **Orphan — unbacked** | A field in the inventory that traces to NO schema field | Resolve: "da definire o rimuovere" — escalate (see below) |
32
+ | **Orphan — unplaced** | A schema field placed on NO screen in scope | **Advisory** — surface "confermare se fuori scope"; NOT a BLOCK |
33
+
34
+ ## BLOCK vs DEGRADE
35
+
36
+ **BLOCK (interactive mode, a human is present):** STOP. Do not emit the prompt.
37
+ Surface — never silently — every unverified backed screen and every unbacked-orphan
38
+ field, then raise **ONE consolidated `AskUserQuestion`** (consistent with
39
+ always-ask-never-assume and "no silent deferral"). Offer per item: supply the
40
+ missing fact / mark the field decorative-readonly / drop it. Only after the user
41
+ resolves them do you proceed to Step 6.
42
+
43
+ **DEGRADE (graceful, never hard-abort):** downgrade BLOCK → user-confirmation when
44
+ - no formal schema exists in the stack (the entity is plain TS objects / untyped), OR
45
+ - field extraction returned empty across all retrieval tiers, OR
46
+ - running under Codex with no subagents / no-TTY.
47
+
48
+ In DEGRADE: present the best-effort inventory with its `da definire` cells visible,
49
+ and ask the user to fill or confirm them before emission. The prompt still ships —
50
+ with honest `da definire` cells the user has seen — rather than aborting the flow.
51
+
52
+ ## False-positive guards (do NOT block on these)
53
+
54
+ By construction the gate excludes:
55
+ - **Zero-entity screens** — pure navigation / dashboard chrome / marketing screens
56
+ have no backing entity and so no field-coverage obligation. Never block them.
57
+ - **Decorative regions** — labels, section icons, computed read-only displays.
58
+ - **Framework noise** — `.framework/`, `.baldart/`, telemetry/generated files are
59
+ never a backing schema.
60
+ - **Unplaced schema fields** — advisory only (a field legitimately out of this
61
+ feature's scope is not a defect).
62
+
63
+ The BLOCK condition is deliberately narrow: *a backed screen whose inventory is
64
+ empty or has unverified `{control, required}`*. Everything else informs, not blocks.
65
+
66
+ ## Worked example — "Fornitori" (suppliers)
67
+
68
+ Backing schema discovered in Step 3:
69
+
70
+ ```ts
71
+ const supplierSchema = z.object({
72
+ ragione_sociale: z.string().min(1).max(120),
73
+ partita_iva: z.string().regex(/^IT\d{11}$/),
74
+ email: z.string().email().optional(),
75
+ categoria: z.enum(["materie_prime", "servizi", "logistica"]),
76
+ pagamento_giorni: z.number().int().min(0).max(120).default(30),
77
+ attivo: z.boolean().default(true),
78
+ note: z.string().max(500).optional(),
79
+ created_at: z.date(), // server-set
80
+ });
81
+ ```
82
+
83
+ Reconciled inventory for **Dettaglio Fornitore** (`/fornitori/:id`, screen 3.2,
84
+ backing: `Fornitore (supplierSchema)`):
85
+
86
+ | Campo (label) | Controllo | Req | Validazione/Vincoli | Default | Opzioni / enum | Helper text | Mode | Card |
87
+ |---|---|---|---|---|---|---|---|---|
88
+ | Ragione sociale | text input | sì | 1–120 caratteri | — | — | da definire | editable | Anagrafica |
89
+ | Partita IVA | text input | sì | pattern `IT` + 11 cifre | — | — | "Formato: IT01234567890" (da confermare) | editable | Anagrafica |
90
+ | Email | email input | no | formato email | — | — | da definire | editable | Contatti |
91
+ | Categoria | select | sì | enum | — | materie_prime · servizi · logistica | da definire | editable | Anagrafica |
92
+ | Giorni pagamento | number input | sì | intero 0–120 | 30 | — | "Termini di pagamento" (da confermare) | editable | Condizioni |
93
+ | Attivo | toggle | no | boolean | true | — | da definire | editable | Stato |
94
+ | Note | textarea | no | max 500 caratteri | — | — | da definire | editable | Note |
95
+ | Creato il | testo statico | — | — | — | — | — | readonly | Metadati |
96
+
97
+ Actions:
98
+
99
+ | Azione | Effetto | Destinazione | Abilitata quando | Traccia a |
100
+ |---|---|---|---|---|
101
+ | Salva | PATCH /suppliers/:id | resta su dettaglio + toast | form valido & dirty | US-fornitori-edit |
102
+ | Annulla | scarta modifiche | torna a /fornitori | sempre | US-fornitori-edit |
103
+ | Elimina | DELETE /suppliers/:id | torna a /fornitori | fornitore non collegato a ordini | da definire (orphan?) |
104
+
105
+ Gate verdict on this screen: **PASS the BLOCK floor** — every shown field has a
106
+ grounded `{control, required}`. The `da definire` helper cells and the `Elimina`
107
+ enable-condition/traceability are surfaced (advisory) so the user can resolve them,
108
+ but they do not block emission. `created_at` is correctly `readonly` (testo statico,
109
+ no input) — the exact hallucination the gate prevents.