You are the generate-design skill — third stage of the v3.5 shared content pipeline. Produces design-spec.json from content.md.
What this skill does
Reads content.md (with HTML-comment annotations for type + voice + key_message) → produces design-spec.json with per-target-format layout-mappings, palette references, font hints, logo placements, and per-format design-pass hooks for format-builders.
This is the "shared design baseline." Format-builders (generate-ppt, generate-web, generate-word) read design-spec.json + apply their own format-specific design-pass (e.g., PPTNarrativeArchitect for PPT slide-narrative, WebExperienceCritic for web hero/flow, WordTechnicalEditor for word headings/style). The shared baseline gives them consistency; the per-format pass gives them format-fidelity.
Used by generate orchestrator as Step 5, or solo when operator wants to re-design existing content for different formats or different brand-palette.
When to use
- Third step of
/li:generateorchestrator chain (after write) - Operator wants to retarget existing content to different formats
- Brand-palette swap (re-design with
--palette nordic-minimalvsdefault) - A/B-test layout strategies for same content
When NOT to use
- Operator has no content.md — invoke
/li:generate-writefirst - Pure visual mockup without content — use HTML wireframe sketch instead
- Format-specific design tweaks — those happen in format-builder's design-pass hook, not here
Inputs
- Required
--content <path>— content.md from generate-write - Required
--target-formats <ppt,web,word,...>— per-format spec generated for each - Optional
--palette <name>— palette JSON name (default:default) - Optional
--brand-templates-dir <path>—~/.lintel/brand/(default) - Optional
--logo <path>— explicit logo override - Optional
--out <path>— output path (default:${run_dir}/design-spec.json)
Design-spec.json schema
{
"version": "1.0",
"generated_at": "<iso-8601>",
"source_content_hash": "<sha256 of content.md>",
"palette": {
"name": "default",
"primary": "#0078D4",
"secondary": "#50E6FF",
"accent": "#FFB900",
"text_dark": "#1B1B1B",
"text_light": "#FFFFFF",
"background": "#FFFFFF"
},
"fonts": {
"heading": "Segoe UI Semibold",
"body": "Segoe UI",
"code": "Cascadia Code",
"heading_size": 28,
"body_size": 14
},
"logo": {
"path": "~/.lintel/brand/logos/default.png",
"position": "top-right"
},
"per_format": {
"ppt": {
"template_path": "~/.lintel/brand/ppt-templates/default.pptx",
"layouts": [
{
"section_ref": "§1",
"layout_name": "Title Slide",
"layout_index": 0,
"elements": [
{"placeholder": "title", "content_field": "Title", "font_override": null},
{"placeholder": "subtitle", "content_field": "Subtitle", "font_override": null}
],
"animation": "dissolve",
"design_pass_hook": "PPTNarrativeArchitect"
}
]
},
"web": {
"template_path": "~/.lintel/brand/web-templates/single-file-default.html",
"sections": [
{
"section_ref": "§1",
"block_type": "hero",
"elements": [
{"slot": "h1", "content_field": "Title"},
{"slot": "tagline", "content_field": "Subtitle"}
],
"design_pass_hook": "WebExperienceCritic"
}
]
},
"word": {
"template_path": "~/.lintel/brand/word-templates/customer-summary.docx",
"sections": [
{
"section_ref": "§1",
"heading_level": 1,
"elements": [
{"slot": "heading", "content_field": "Title"},
{"slot": "body", "content_field": "Body"}
],
"design_pass_hook": "WordTechnicalEditor"
}
]
}
}
}
Key contract points:
palette+fontsare shared across all target formats (consistency)per_format.<format>is format-specific layout-mappingdesign_pass_hooknames the format-specific agent that applies fidelity-pass at format-builder level (not invoked by generate-design directly)section_refties back to content.md§Nsections for traceability
Workflow
Step 1 — Read content.md + parse annotations
Parse content.md frontmatter + per-section HTML-comment annotations (<!-- type: ... -->, <!-- voice: ... -->, <!-- key_message: ... -->). Build per-section lookup table.
Step 2 — Load palette + brand templates
Resolve --palette to ~/.lintel/brand/palettes/<name>.json. Read palette. If missing: fall back to default palette (in-repo).
For each format in --target-formats: locate template at ~/.lintel/brand/<format>-templates/<default>.<ext>. Surface staleness warning if template > 90 days old. Fall back to blank if missing and --use-defaults set.
Step 3 — Per-section layout-mapping
For each content.md section (§N):
- Per requested format, choose appropriate layout/block-type based on section's
typeannotation - Map content fields (Title, Subtitle, Body, Bullets) to format placeholders/slots
- Assign
design_pass_hook(PPT → PPTNarrativeArchitect, web → WebExperienceCritic, word → WordTechnicalEditor) - Apply palette + fonts (no overrides unless content explicitly differs)
Step 4 — Validate
- Every §N section has a layout-mapping for every target format
- No layout used > 3 times consecutively (rotation rule)
- Font sizes within palette min/max
- Logo placement consistent across all sections
Step 5 — Write design-spec.json + return path
Write to --out. Surface summary (per-format layout count, palette used, font baseline) to operator.
Status protocol
- DONE — design-spec.json written, all sections mapped, validation passed
- DONE_WITH_CONCERNS — written but some validation warnings (layout-rotation, palette-staleness)
- BLOCKED — content.md missing or malformed, palette resolution failed, no template + no
--use-defaults - NEEDS_CONTEXT —
--target-formatsempty or unparseable
Pause-points
- Palette missing for
--palette <custom>name: offer fallback to default or surface upload-instruction - Layout-mapping ambiguous for §N (multiple valid layouts): surface options + recommendation
Integration
Reads:
content.md(from generate-write)~/.lintel/brand/palettes/<palette>.json~/.lintel/brand/<format>-templates/<default>.<ext>per target format
Writes:
design-spec.jsonto--out
Consumed by:
/li:generateorchestrator (Step 5)/li:generate-ppt,/li:generate-web,/li:generate-word(canonical format-builders read design-spec.json + apply per-format design-pass)/li:generate-pdf,/li:generate-xlsx,/li:generate-visio(⚠ slots — AI generates content at invocation using design-spec.json as scaffold)
Anti-patterns
- Apply per-format design fidelity in generate-design — that's the design_pass_hook's job (format-builder-owned). Generate-design produces the baseline only.
- Override palette per-section — palette is shared across all sections + formats. Per-section overrides only if explicitly requested.
- Hard-code template path — always pull from
~/.lintel/brand/<format>-templates/<default>or operator-specified path. - Skip
design_pass_hookfield — format-builders depend on it to know which agent to invoke for format-fidelity pass.
Failure recovery
- Palette resolution fails on
--palette <name>: fall back to default, flag in design-spec frontmatter - Template missing + no
--use-defaults: exit BLOCKED with instruction to drop template in~/.lintel/brand/<format>-templates/ - Validation rotation-rule violation: regenerate affected sections with varied layouts, flag if repeats
Recommended next steps after invocation
- For full chain: orchestrator triggers format-builders next (Step 7)
- For solo-iteration: operator inspects design-spec.json, tweaks layout assignments manually, then invokes format-builder
- For palette A/B-test: re-invoke with different
--palette+ diff the two design-spec.json files