Document Generation
docs specs/docs/generation.kmd
Tipos de documento gerados por categoria de objeto (Stack, Area, Sector, Module, Flow, RFC), requisitos de capa, regras de identidade visual e templates CSS para PDFs. Consultado no início da Fase 3 do `/k-housekeep`.
When this spec applies
All triggers
- Gerar PDF, deep-dive ou documento por categoria (Stack/Area/Sector/Module/Flow/RFC)
- Atualizar capa, header ou identidade visual de docs gerados
- Iniciar Fase 3 do /k-housekeep
Specification body
Spec: Document Generation
Scope: Defines which document types are generated for each category of Koder Stack object (Stack, Area, Sector, Module, Flow, RFC), cover page requirements, and visual identity rules for generated PDFs.
Enforcement: /k-housekeep Phase 3 reads this spec and generates or updates the full PDF bundle accordingly.
1. Object categories
The Koder Stack has five object categories that drive documentation generation. Each category has a fixed set of document types (see §2).
| Category | Definition | Examples |
|---|---|---|
| Stack | The entire Koder Stack as a whole | — |
| Area | One of the 9 canonical Areas (docs/stack/areas.md) |
Foundation, Data Platform, Workspace … |
| Sector | A named grouping of related modules within an Area (second column in areas.md) |
Koder Linux, KDB, Edge/Jet, Intelligence … |
| Module | Any active module in the monorepo (see areas.md rows, third column) |
platform/id, infra/jet, apps/keys … |
| Flow | A named cross-cutting flow that spans two or more Areas (docs/stack/diagrams/flows/) |
auth flow, data-write flow, AI inference flow … |
2. Document types per category
2.1 Stack
| Document | Format | Source / Generator |
|---|---|---|
| Technical Reference | PDF (A4, Typst) | docs/stack/build/technical.typ → out/koder-stack-technical.pdf |
| Executive Slides | PDF (A4, Typst) | docs/stack/presentation/slides/main.typ → out/koder-stack-slides.pdf |
2.2 Area
One set of documents per Area (9 total). Output folder: <N>-<area-slug>/ in the bundle.
| Document | Format | Content |
|---|---|---|
| Area Slide Deck | PDF (A4 landscape, WeasyPrint) | Cover + module inventory (one card per module: icon, name, one-line description) + flows & integrations diagram + integration map (which modules call which) + sector breakdown |
| Area Deep-Dive | PDF (A4 portrait, WeasyPrint) | Cover + Area description + Sector table + per-module summary (3-5 lines each) + cross-module flow descriptions + diagrams (D2 rendered to PNG and embedded) |
| Area Diagrams | PDF (A4 landscape, WeasyPrint) | One page per diagram file under docs/stack/diagrams/areas/<area>.d2 (rendered via d2 --theme 0) |
2.3 Sector
One set of documents per Sector row in areas.md. Output folder: <N>-<area-slug>/sectors/<sector-slug>/.
| Document | Format | Content |
|---|---|---|
| Sector Slide Deck | PDF (A4 landscape, WeasyPrint) | Cover + module list (icon, name, one-line description for each module in the sector) + integration diagram within the sector + relationships to other sectors |
| Sector Overview | PDF (A4 portrait, WeasyPrint) | Cover + what the sector does + why it's grouped + module summaries + typical data flows within the sector |
2.4 Module
One set per active module. Output folder: <N>-<area-slug>/<module-name>/.
| Document | Format | Content |
|---|---|---|
| Deep-Dive | PDF (A4, WeasyPrint) | docs/stack/modules/<module>.md — role, couplings, interfaces, status |
| RFC(s) | PDF (A4, WeasyPrint) | Each .md / .kmd under <module>/docs/rfcs/ |
| Manual(s) | PDF (A4, WeasyPrint) | Each .md under <module>/docs/technical/, <module>/docs/user/, <module>/docs/operator/ |
| Slide Deck | PDF (A4 landscape, WeasyPrint) | Cover + what it does + architecture overview + key interfaces + status + roadmap (sourced from README + deep-dive) |
| README | PDF (A4, WeasyPrint) | <module>/README.md or <module>/README.kmd |
| CHANGELOG | PDF (A4, WeasyPrint) | <module>/CHANGELOG.md if it exists |
RFCs and Manuals may not exist for every module — skip silently if source files are absent.
2.5 Flow
One document per flow diagram file under docs/stack/diagrams/flows/.
| Document | Format | Content |
|---|---|---|
| Flow Diagram | PDF (A4 landscape, WeasyPrint) | Cover + rendered D2 diagram + written description of the flow (from companion .md if present, else auto-generated from diagram node labels) |
3. Cover page specification
Every generated PDF must start with a cover page. No exceptions.
3.1 Cover page layout (portrait documents)
┌─────────────────────────────────────────────┐
│ │
│ [icon 96×96 px, centered] ← Module only │
│ │
│ ──────────────────────────────────── │
│ KODER STACK │ ← brand line, 10pt, #94a3b8
│ <Area / Sector / Module / Flow name> │ ← category label, 10pt, #64748b
│ │
│ <Document Title> │ ← 28pt bold, #0f172a
│ │
│ <subtitle / tagline — one line> │ ← 14pt, #475569
│ │
│ ──────────────────────────────────── │
│ │
│ <Status badge if applicable> │ ← e.g. "Pre-Alpha", "Draft"
│ <Date> · Koder │ ← 9pt, #94a3b8
│ │
└─────────────────────────────────────────────┘
3.2 Cover page layout (landscape documents — slide decks, diagrams)
Same structure as portrait but centred horizontally on an A4 landscape page. Icon is 128×128px.
3.3 Icon placement rules
- Module documents: the module's
icon.svg(rasterised to 96px for portrait, 128px for landscape) appears centred above the title on the cover page. Area-first products (RFC-001) may keep the canonicalicon.svgat the product root (<area>/<product>/icon.svg) or at a distribution root (<area>/<product>/platform/icon.svg,<area>/<product>/app/icon.svg,<area>/<product>/app/<surface>/icon.svg). The generator resolves deepest-first for files inside a sub-product, falling back to the product root — it must never substitute the Koder brand mark when a module-localicon.svgexists anywhere in the product tree. - Area documents: use the area's representative icon if one exists under
docs/stack/presentation/assets/icons/<area-slug>.svg; otherwise use the Koder brand mark (meta/brand/koder-papelaria/koder-marca.svgscaled to 96px). - Sector documents: use the first module icon of the sector (alphabetical by module path) as representative icon.
- Stack documents: use the Koder brand mark.
- Flow documents: use the Koder brand mark.
Brand-fallback policy. The Koder brand mark may only be used as a cover icon for Stack, Area, and Flow documents. For any module document, if no module icon.svg can be located, the generator must render the cover page without any icon rather than substitute the Koder mark. Logging a warning is mandatory; silent substitution hides missing-icon bugs in the catalogue.
3.4 Icon in document body (first content page)
For module documents only: on the first content page (immediately after the cover), place the module icon inline at the left of the document title heading (<h1>). Implemented in the HTML template as:
<h1 class="doc-title">
<img src="{icon_path}" class="title-icon" alt="">
{document_title}
</h1>
.doc-title { display: flex; align-items: center; gap: 14px; }
.title-icon { width: 48px; height: 48px; flex-shrink: 0; }
This applies to: Deep-Dive, RFC, Manual, README, CHANGELOG, and Slide Deck (first slide title).
4. Content requirements per document type
4.1 Area Slide Deck — required slides
- Cover (§3)
- "What is <Area>?" — 3-5 sentences, area rule-of-thumb
- Sector map — one row per Sector: sector name + modules in it (pill list)
- Module cards — one slide per module: icon (64px) + name + one-line description + status badge
- Integration map — which modules depend on which (generated from deep-dive coupling tables)
- Key flows — one slide per flow that is internal to this Area
- Connections to other Areas — list of cross-area dependencies
4.2 Module Slide Deck — required slides
- Cover (§3, with module icon 128px centred)
- "What is <Module>?" — role, one-paragraph description
- Architecture overview — diagram (embed
docs/stack/diagrams/modules/<module>.d2if present, else text-based) - Primary couplings — table: dependency | purpose | protocol
- Interfaces — APIs, CLI commands, config keys (from deep-dive Interfaces section)
- Status & roadmap — status badge + 3-5 bullet points from backlog/STATUS
4.3 RFC — required sections
RFCs are author-written; the generator does not synthesise content. The generator only:
- Adds the cover page (§3)
- Adds the module icon to the first
<h1>(§3.4) - Reformats for A4 margins and page numbering
If an RFC source file already has a cover section (frontmatter with title:, status:, date:), extract those values for the cover page instead of inferring.
4.4 Manual — required sections
Same as RFC rule: generator adds cover + icon + layout, does not synthesise content.
5. Source → output mapping
The generator traverses these source locations in priority order for each module:
<module>/icon.svg → cover icon, h1 icon
<module>/README.md → README.pdf
<module>/README.kmd → README.pdf (prefer over .md if both exist)
<module>/CHANGELOG.md → CHANGELOG.pdf
<module>/STATUS.md → included in Slide Deck slide 6
<module>/docs/rfcs/*.md → RFC-*.pdf (one per file)
<module>/docs/rfcs/*.kmd → RFC-*.pdf
<module>/docs/technical/*.md → Manual-*.pdf
<module>/docs/user/*.md → Manual-*.pdf
<module>/docs/operator/*.md → Manual-*.pdf
docs/stack/modules/<module>.md → Deep-Dive.pdf
For Areas and Sectors, the generator synthesises the slide decks and overviews from:
docs/stack/areas.md(sector/module lists)docs/stack/modules/<module>.md(summaries per module)docs/stack/diagrams/areas/<area>.d2(integration diagrams)docs/stack/diagrams/flows/<flow>.d2(flow diagrams)
6. Naming conventions for output files
| Object | File name pattern |
|---|---|
| Area Slide Deck | <N>-<area-slug>/slides-<area-slug>.pdf |
| Area Deep-Dive | <N>-<area-slug>/overview-<area-slug>.pdf |
| Area Diagrams | <N>-<area-slug>/diagrams-<area-slug>.pdf |
| Sector Slide Deck | <N>-<area-slug>/sectors/<sector-slug>/slides-<sector-slug>.pdf |
| Sector Overview | <N>-<area-slug>/sectors/<sector-slug>/overview-<sector-slug>.pdf |
| Module Deep-Dive | <N>-<area-slug>/<module>/deep-dive.pdf |
| Module Slide Deck | <N>-<area-slug>/<module>/slides.pdf |
| Module RFC | <N>-<area-slug>/<module>/rfcs/RFC-NNN-<slug>.pdf |
| Module Manual | <N>-<area-slug>/<module>/docs/<filename>.pdf |
| Module README | <N>-<area-slug>/<module>/README.pdf |
| Module CHANGELOG | <N>-<area-slug>/<module>/CHANGELOG.pdf |
| Flow | flows/<flow-slug>.pdf |
| Stack Technical Reference | koder-stack-technical.pdf (root) |
| Stack Executive Slides | koder-stack-slides.pdf (root) |
7. What the generator must NOT do
- Invent content: if source data is absent (no RFC file, no deep-dive, no D2 diagram), skip the document and log a warning. Do not fabricate text.
- Override cover icons: if a module's
icon.svgdoes not conform to the icon spec (meta/docs/stack/specs/icons/products.kmd), use it anyway and log a warning — do not substitute a generic icon silently. - Translate: all generated text (labels, auto-generated descriptions, slide titles) must be in en-US (
meta/docs/stack/policies/language.kmd).
8. Slide deck CSS template (landscape, WeasyPrint)
@page {
size: A4 landscape;
margin: 1.5cm 2cm;
}
body { font-family: -apple-system, 'Segoe UI', 'DejaVu Sans', sans-serif;
font-size: 11pt; color: #1e293b; line-height: 1.5; }
.slide { page-break-after: always; min-height: 18cm; display: flex;
flex-direction: column; justify-content: flex-start; }
.slide-cover { justify-content: center; align-items: center; text-align: center; }
.slide-title { font-size: 22pt; font-weight: 700; color: #0f172a; margin-bottom: 8px; }
.slide-sub { font-size: 13pt; color: #475569; }
.slide-h2 { font-size: 15pt; font-weight: 600; color: #1e3a8a; margin-bottom: 12px; }
.card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.card { border: 1px solid #e2e8f0; border-radius: 8px; padding: 12px;
background: #f8fafc; }
.card-icon { width: 48px; height: 48px; }
.card-name { font-size: 11pt; font-weight: 700; color: #0f172a; margin: 6px 0 2px; }
.card-desc { font-size: 9pt; color: #64748b; }
.status { display: inline-block; padding: 2px 8px; border-radius: 12px;
font-size: 8.5pt; font-weight: 600; background: #fef3c7; color: #92400e; }
.status.prod { background: #dcfce7; color: #14532d; }
table { border-collapse: collapse; width: 100%; font-size: 9.5pt; margin: 12px 0; }
th, td { border: 1px solid #e2e8f0; padding: 7px 11px; text-align: left; }
th { background: #f1f5f9; font-weight: 600; color: #0f172a; }
10. Document type taxonomy
10.1 Classification criteria
Every source file in the monorepo that is eligible for PDF generation is classified into exactly one Document Type based on its path pattern and filename. The classification is used to route files into the correct individual PDFs (§2) and the correct consolidated PDFs (§11).
Exclusions — never included in any documentation bundle:
context/— internal configuration and rules**/src/**/*.kmd— source-embedded documentation (not standalone docs)**/.koder-rules/**— internal dev process rules**/.changeset/**— release automation metadata**/backlog/**— internal planning tickets (handled separately bykoder-stack-backlog.pdf, see §11)**/node_modules/**,**/vendor/**,**/target/**— generated artefacts
Top-level module filter: For READMEs and CHANGELOGs, only include files at depth <area>/<module>/README.{md,kmd} and <area>/<module>/CHANGELOG.md (i.e., module root level). Sub-package READMEs (e.g. platform/kdb/next/README.md) are excluded unless the sub-package is itself listed as a distinct module in areas.md.
10.2 Document type table
| Code | Type | Source pattern(s) | Quantity (surveyed) |
|---|---|---|---|
| OVW | Overview / Deep-Dive | docs/stack/modules/*.md · <module>/README.{md,kmd} (root only) |
~50 deep-dives + ~90 module READMEs |
| RFC | Design Proposal | **/docs/rfcs/*.{md,kmd} · docs/stack/rfcs/**/*.{md,kmd} |
~46 |
| ARC | Architecture | **/docs/technical/architecture*.md · **/docs/technical/flows*.md · docs/stack/diagrams/**/*.d2 |
~25 |
| REF | Reference | **/docs/technical/api-reference*.md · **/docs/technical/*-api.md · **/docs/technical/protocols*.md · **/docs/technical/configuration*.md |
~30 |
| OPS | Operations | **/docs/technical/infrastructure*.md · **/docs/technical/dependencies*.md · **/docs/technical/security*.md · **/docs/operator/*.md |
~25 |
| USR | User Guide | **/docs/user/*.md · **/docs/technical/user-*.md |
~10 |
| REL | Release / Changelog | <module>/CHANGELOG.md (root only) · <module>/STATUS.md |
~50 |
| SLD | Slides / Presentation | docs/stack/presentation/slides/main.typ · synthesised per-area, per-module slide decks |
1 Typst + N synthesised |
| GOV | Governance | <module>/CONTRIBUTING.{md,kmd} · <module>/CODE_OF_CONDUCT.{md,kmd} · <module>/SECURITY.{md,kmd} |
~24 |
| BKL | Backlog | **/backlog/{pending,in-progress,done}/*.md |
~2920 (internal only) |
10.3 Technical sub-classification rules
When a file matches multiple types (e.g. architecture.md could be ARC or OPS), apply in priority order:
- If filename contains
architectureorflows→ ARC - If filename contains
api,reference,protocol,record-api,configuration→ REF - If filename contains
infrastructure,dependencies,security,deployment,operator→ OPS - If filename contains
user-guide,tutorial,getting-started, or lives indocs/user/→ USR - If none of the above and lives in
docs/technical/→ classify as REF (conservative default)
11. Consolidated PDFs
At the end of Phase 3, after all individual module PDFs are generated, produce one consolidated PDF per document type that aggregates documents from every module into a single bookmarked file. These are the primary deliverables for external sharing, demos, and reference.
11.1 Consolidated PDF catalogue
| File name (root of bundle) | Types included | Description |
|---|---|---|
koder-stack-overview.pdf |
OVW | Stack reference + area overviews + all module deep-dives, ordered by Area |
koder-stack-rfcs.pdf |
RFC | All design proposals from all modules, ordered by Area then module |
koder-stack-architecture.pdf |
ARC | All architecture docs + embedded D2 diagrams, ordered by Area |
koder-stack-reference.pdf |
REF | All API, CLI, protocol and config references, ordered by Area |
koder-stack-operations.pdf |
OPS | All operations, infrastructure and security guides, ordered by Area |
koder-stack-user-guides.pdf |
USR | All end-user documentation, ordered by Area |
koder-stack-changelogs.pdf |
REL | All module changelogs + STATUS files, ordered by Area |
koder-stack-slides.pdf |
SLD | Executive slides — Typst compiled (already generated in Phase 1) |
koder-stack-technical.pdf |
OVW+ARC+REF+OPS | Full technical reference — Typst compiled (already generated in Phase 1) |
koder-stack-governance.pdf |
GOV | Contributing guides, code of conduct, security policies |
koder-stack-backlog.pdf |
BKL | All backlog tickets across all modules — internal only |
Omit a consolidated PDF if it would contain zero documents (e.g. if no USR files exist, skip koder-stack-user-guides.pdf and log a warning).
11.2 Cover page of consolidated PDFs
Each consolidated PDF has its own cover page following §3 with these specifics:
- Icon: Koder brand mark (
meta/brand/koder-papelaria/koder-marca.svgscaled to 96px) — never a module icon - Brand line:
KODER STACK - Category label:
Consolidated Reference - Title: the human-readable name (e.g.
RFCs & Design Proposals) - Subtitle:
All modules · <N> documents · <date>
11.3 Table of contents
Immediately after the cover, insert a ToC page listing every section (module or document) in the consolidated PDF, with page numbers. Format:
Area 1 — Foundation
platform/id Koder ID ............................. 3
apps/keys Koder Keys .......................... 12
platform/kompass Koder Kompass ....................... 19
Area 2 — Data Platform
platform/kdb KDB ................................. 27
...
11.4 Section dividers between modules
Between each module's documents, insert a section divider page:
┌─────────────────────────────────────────────┐
│ [Area colour band — left 8px] │
│ │
│ [module icon 64×64] │
│ <Module name> │ ← 18pt bold
│ <Area> › <Sector> │ ← 10pt, muted
│ <Module one-liner from deep-dive> │ ← 12pt
│ │
└─────────────────────────────────────────────┘
Area colour bands:
| Area | Colour |
|---|---|
| Foundation | #6366f1 (indigo) |
| Data Platform | #0891b2 (cyan) |
| Cloud Infrastructure | #0f172a (slate) |
| Observability | #16a34a (green) |
| Intelligence | #7c3aed (violet) |
| Developer Platform | #ea580c (orange) |
| Workspace | #2563eb (blue) |
| Industry Solutions | #b45309 (amber) |
11.5 Ordering within consolidated PDFs
- Documents ordered by Area (1 → 8)
- Within each Area, ordered by Sector (as listed in
areas.md) - Within each Sector, alphabetically by module path
- Within each module, by document priority: deep-dive / README first, then by filename alphabetically
11.6 Handling the backlog consolidated PDF
koder-stack-backlog.pdf is internal and treated differently:
- Include all
pending/,in-progress/, anddone/tickets per module - Section dividers show module name + ticket count per status
- No section divider page with icon — just a bold heading
- Format ticket entries as:
NNN — <title>(one line each) + full content below - Mark the PDF cover page as "INTERNAL — NOT FOR DISTRIBUTION" in red
11.7 Incremental update rule
A consolidated PDF is regenerated when any of its source documents changed since the last housekeep. Individual source PDFs that did not change are re-used from the previous run (their pages are extracted and re-embedded, not re-rendered).
9. Portrait document CSS template (WeasyPrint)
See meta/context/commands/k-housekeep.md §3.2 for the canonical CSS template (A4, 2cm margins, landscape fallback for wide tables).
The following additions apply to all generated module documents:
/* Cover page */
.cover { page-break-after: always; display: flex; flex-direction: column;
align-items: center; justify-content: center; min-height: 25cm;
text-align: center; }
.cover-brand { font-size: 10pt; color: #94a3b8; letter-spacing: .1em;
text-transform: uppercase; margin-bottom: 4px; }
.cover-cat { font-size: 10pt; color: #64748b; margin-bottom: 24px; }
.cover-icon { width: 96px; height: 96px; margin-bottom: 24px; }
.cover-title { font-size: 28pt; font-weight: 700; color: #0f172a;
line-height: 1.15; margin-bottom: 12px; }
.cover-sub { font-size: 14pt; color: #475569; margin-bottom: 32px; }
.cover-line { width: 60%; border-top: 1px solid #e2e8f0; margin: 0 auto 20px; }
.cover-meta { font-size: 9pt; color: #94a3b8; }
/* Title icon (first content page h1) */
h1.doc-title { display: flex; align-items: center; gap: 14px;
font-size: 21pt; color: #0f172a; }
h1.doc-title .title-icon { width: 48px; height: 48px; flex-shrink: 0; }
12. Screenshot capture for UI modules
Screenshots of module UIs are embedded in Manuals (USR and REF documents) and in Module Slide Decks. This section defines how they are captured, stored, named, and embedded.
12.1 Scope — which modules get screenshots
Screenshots apply only to modules that have a user-facing UI. The generator auto-detects by checking:
| Signal | Inferred platform |
|---|---|
<module>/pubspec.yaml exists |
Flutter app (desktop + mobile + optionally web) |
<module>/site/ exists with a running URL |
Web app |
| Both | Flutter app with web companion |
| Neither | No UI — skip screenshot capture entirely |
Modules that never get screenshots: SDKs (sdk/), CLIs, infra (infra/), data engines (data/), pure backend services with no web UI.
12.2 Storage location
All screenshots live at:
<module>/docs/assets/screenshots/
├── web-desktop/ ← Playwright, 1440×900
│ ├── 01-home.png
│ ├── 02-login.png
│ └── …
├── web-tablet/ ← Playwright, 768×1024
│ └── …
├── web-mobile/ ← Playwright, 390×844 (iPhone 14 viewport)
│ └── …
├── desktop-linux/ ← Xvfb + flutter run -d linux
│ └── …
├── mobile-android/ ← AVD + flutter run / adb screencap
│ └── …
└── screenshots.yaml ← optional: captions + navigation steps
Screenshots are committed to the repo — they are source assets, not build artefacts. The capture pipeline regenerates them on demand (not on every housekeep — see §12.6).
12.3 Naming convention
Files are named NN-<screen-slug>.png where NN is a two-digit sequence number that controls display order in the document:
01-home.png
02-login.png
03-dashboard.png
04-settings.png
Caption is derived from the filename: 02-login.png → "Login", 03-user-dashboard.png → "User dashboard". Override via screenshots.yaml (see §12.5).
12.4 Automated capture pipeline — per platform
12.4.1 Web (Playwright)
Requirements: playwright Python package, Chromium browser installed.
for each viewport in [desktop(1440,900), tablet(768,1024), mobile(390,844)]:
folder = web-desktop | web-tablet | web-mobile
1. Launch Playwright Chromium (headless)
2. Navigate to module URL (from koder.toml → url, or inferred from site/ hostname)
3. Wait for networkidle
4. Capture full-page screenshot → 01-home.png
5. If screenshots.yaml has navigation steps, execute each step and capture
6. Save to <module>/docs/assets/screenshots/<folder>/
Mobile viewport uses device_scale_factor=2 (retina). If a step requires login, use the test account from meta/context/credentials/ (never hardcode in spec).
12.4.2 Desktop — Flutter Linux (Xvfb)
Requirements: Xvfb, scrot, flutter SDK, module must compile for Linux.
1. Start Xvfb on display :99 (1280×800×24)
2. Run: DISPLAY=:99 flutter run -d linux --release 2>/dev/null &
3. Wait 8 seconds for app to reach idle state
4. Capture: DISPLAY=:99 scrot -u <module>/docs/assets/screenshots/desktop-linux/01-home.png
5. If screenshots.yaml has steps, simulate keypresses/clicks via xdotool
6. Kill flutter process, stop Xvfb
Limitation: only captures the initial screen unless screenshots.yaml defines navigation steps using xdotool commands.
12.4.3 Mobile — Android (AVD + ADB)
Requirements: Android SDK, an AVD named koder-pixel7 (Pixel 7, API 34), flutter SDK.
1. Check if AVD is already running: adb devices
2. If not: emulator -avd koder-pixel7 -no-window -no-audio &
3. Wait for boot: adb wait-for-device && adb shell getprop sys.boot_completed == "1"
4. Run: flutter run -d emulator-XXXX --release &
5. Wait 10 seconds for app idle
6. Capture: adb exec-out screencap -p > 01-home.png
7. Crop to device frame (strip status bar if solid colour top 72px)
8. Save to <module>/docs/assets/screenshots/mobile-android/
9. Kill flutter process (emulator stays running for reuse across modules)
12.4.4 Mobile — iOS (Simulator)
Requirements: macOS host with Xcode, an iOS simulator named iPhone 15. Only runs on macOS — skip silently on Linux.
xcrun simctl boot "iPhone 15"
flutter run -d "iPhone 15" --release &
sleep 10
xcrun simctl io booted screenshot <dest>/01-home.png
12.5 screenshots.yaml — navigation steps and captions (optional)
If the file <module>/docs/assets/screenshots/screenshots.yaml exists, the capture pipeline reads it for navigation instructions and caption overrides. Format:
# screenshots.yaml
module: platform/id
url: https://id.koder.dev # override auto-detected URL
auth: # use credential key from meta/context/credentials/
key: koder-id-test-user
screens:
- id: home
caption: "Home — sign-in options"
steps: [] # just load the URL
- id: login
caption: "Email and password login"
steps:
- click: "[data-testid=email-login]"
- wait: networkidle
- id: dashboard
caption: "User dashboard after authentication"
steps:
- fill: "[name=email]"
value: "{{auth.email}}"
- fill: "[name=password]"
value: "{{auth.password}}"
- click: "[type=submit]"
- wait: networkidle
desktop_steps: # xdotool commands for Linux desktop
- xdotool key Tab # move focus
- sleep 0.5
- xdotool key Return # activate
mobile_steps: [] # ADB/simctl input events (future)
If screenshots.yaml is absent, the pipeline captures only the initial landing screen (one screenshot per platform).
12.6 When to regenerate screenshots
Screenshots are not regenerated on every housekeep — they are expensive (require running apps, emulators). The generator regenerates a platform's screenshots for a module only when:
--screenshotsflag is passed explicitly to the generation script- The module's
screenshots.yamlchanged since the last capture - The
<platform>/subfolder is empty or missing - The module's major version changed (detected from
koder.tomlorpubspec.yaml)
Otherwise, existing PNGs are reused as-is.
12.7 Embedding screenshots in documents
When generating a Manual or Slide Deck PDF for a module that has screenshots, the generator:
- Discovers all PNGs in
<module>/docs/assets/screenshots/recursively, sorted by subfolder then filename - For Manuals (USR/REF): inserts a "Screenshots" section after the main content with one subsection per platform (Web · Desktop · Mobile). Each screenshot is full-width with a caption below.
- For Slide Decks: inserts a "UI Walkthrough" slide group — one slide per screenshot, with the caption as the slide title and the image filling 80% of the slide area.
- For Consolidated PDFs: screenshots are embedded in the per-module section just like in Manuals.
CSS for screenshot embedding in portrait documents:
.screenshot-section h3 { font-size: 11pt; color: #64748b; margin: 24px 0 8px;
text-transform: uppercase; letter-spacing: .06em; }
.screenshot-wrap { margin: 12px 0 20px; }
.screenshot-img { max-width: 100%; border: 1px solid #e2e8f0;
border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,.08); }
.screenshot-caption { font-size: 9pt; color: #94a3b8; margin-top: 6px;
text-align: center; font-style: italic; }
12.8 Image size limits
| Platform | Max width | Max file size |
|---|---|---|
| web-desktop | 1440px | 600 KB |
| web-tablet | 768px | 300 KB |
| web-mobile | 390px (2× retina → 780px) | 300 KB |
| desktop-linux | 1280px | 500 KB |
| mobile-android | 1080px (native) | 400 KB |
| mobile-ios | 1179px (iPhone 15 native) | 400 KB |
If a captured PNG exceeds the limit, compress with pngquant --quality=65-85 before saving.
12.9 What the generator must NOT do
- Invent screenshots: if capture fails for any reason, log a warning and skip — do not embed a placeholder image.
- Capture production credentials: navigation steps that require login must use test accounts from
meta/context/credentials/. Never embed real user data in screenshots. - Capture external services: only capture UIs served by the module itself (local dev server or the module's own production URL). Do not screenshot third-party pages.
- Block the housekeep on capture failure: screenshot capture failure is a warning, not an error — the rest of Phase 3 continues normally.
13. Diagram visual standard (D2)
All D2 diagrams under docs/stack/diagrams/ (aerial + per-area + flows + per-module) follow the same visual language so they feel like one family of illustrations when embedded in PDFs and slide decks. This section is the source of truth — docs/stack/build/build.sh and every .d2 file must conform.
13.1 Build command
Render every .d2 file with:
d2 --theme=0 --layout=elk --pad 100 <file>.d2 <file>.svg
rsvg-convert -w 3000 <file>.svg -o <file>.png
--theme=0(Neutral Default, light) — fundo branco; containers e nós trazem a cor viastyle.fillexplícito. Não usar o theme 200 dark antigo.--layout=elk(Eclipse Layout Kernel) — muito menos cruzamentos de arestas quedagre; arestas ortogonais e hierarquia mais limpa.--pad 100— respiração lateral generosa; evita que sombras sejam cortadas.- Rasterização em 3000px — nitidez em páginas A4 landscape de slide decks e no PDF técnico.
13.2 Shared classes (obrigatórias)
Todo .d2 com Áreas ou containers coloridos deve declarar o bloco classes abaixo no topo do arquivo, antes de qualquer nó. Isso é DRY: muda num lugar, aplica em todo canto.
classes: {
area: {
style: {
border-radius: 20
shadow: true
stroke-width: 0
font-size: 20
bold: true
font-color: "#ffffff"
}
}
node: {
style: {
border-radius: 12
stroke-width: 0
font-size: 15
font-color: "#0f172a"
fill: "#ffffff"
shadow: true
}
}
}
Containers de Área aplicam class: area; módulos/nós dentro deles aplicam class: node. Nunca repetir style.fill, style.font-color, border-radius inline em cada nó — use as classes.
13.3 Gradient fill por Área
Cada Área tem um par de cores (escuro → claro) que formam o fundo via linear-gradient. Isso dá profundidade e coesão — cores chapadas são proibidas para containers de Área.
| Área | Gradient fill |
|---|---|
| Foundation | linear-gradient(#1e3a8a, #3b82f6) |
| Data Platform | linear-gradient(#0f766e, #14b8a6) |
| Cloud Infrastructure | linear-gradient(#0369a1, #0ea5e9) |
| Observability | linear-gradient(#6d28d9, #a855f7) |
| Intelligence | linear-gradient(#9f1239, #f43f5e) |
| Developer Platform | linear-gradient(#a16207, #eab308) |
| Workspace | linear-gradient(#166534, #22c55e) |
| Industry Solutions | linear-gradient(#9a3412, #f97316) |
| Brand & Presence | linear-gradient(#334155, #64748b) |
Aplicar no container de Área:
foundation: Foundation {
class: area
icon: /home/koder/dev/koder/sites/foundation/icon.svg
style.fill: "linear-gradient(#1e3a8a, #3b82f6)"
linux: Koder Linux {class: node; icon: /home/koder/dev/koder/linux/distro/icon.svg}
...
}
13.4 Ícones embutidos nos nós
Cada container de Área recebe o ícone de sites/<area>/icon.svg (9 áreas têm todos). Cada nó de módulo recebe seu próprio icon.svg se existir; sem ícone, cai em pílula só-texto — não inventar placeholder. O /k-housekeep §1.6 já reporta módulos sem icon.svg como ⚠️.
- Usar caminho absoluto (
/home/koder/dev/koder/...) — D2 v0.7 não aceita paths relativos paraicon:. - O ícone aparece no canto do container/nó (top-left) automaticamente.
13.5 Estilo das arestas
Default para todas as arestas:
style: {stroke: "#94a3b8"; stroke-width: 2}
Arestas com label ("depends on", "authenticates", etc.) recebem estilo reforçado:
style: {stroke: "#475569"; stroke-width: 3; font-size: 14; font-color: "#334155"; bold: true}
13.6 Título do diagrama
Toda .d2 começa com um título markdown no topo. Para aerial e áreas:
title: |md
# Koder Stack
## Aerial view — 9 areas · 50+ modules
| {near: top-center; shape: text; style.font-size: 36; style.bold: true; style.font-color: "#0f172a"}
Fontes menores (26/22pt) para flows individuais. Cor sempre #0f172a (slate-900) para contraste em fundo branco.
13.7 Categorias de diagrama
| Categoria | Path | Estrutura | Classes usadas |
|---|---|---|---|
| Aerial | diagrams/aerial.d2 |
9 containers de Área, um por cor; módulos como pílulas; arestas inter-Área | area + node |
| Area | diagrams/areas/<area>.d2 |
1 container da Área com todos os módulos; arestas internas | area + node |
| Flow | diagrams/flows/<flow>.d2 |
Actors + etapas numeradas; sem containers de Área | só node (cor neutra ou cor da Área do actor) |
| Module | diagrams/modules/<module>.d2 |
Coupling deep-dive; nós = dependências externas | só node |
Para flows, actors de Áreas diferentes recebem style.fill individual com a cor sólida base da sua Área (não gradient — actors são pontos, não blocos). Exemplo: ator foundation/id → style.fill: "#1e3a8a"; style.font-color: white.
13.8 Proibições
- ❌ Tema dark (
--theme=200,--theme=201) — todos os diagramas são light. Inversão automática para dark mode dos PDFs fica para iteração futura. - ❌ Layout
dagre— sempreelk. - ❌
style.fillchapado em containers de Área — semprelinear-gradient. - ❌ Repetir estilo inline — sempre via
class. - ❌
icon.svgde placeholder ou genérico — só ícone real do módulo ou ausente. - ❌
stroke-width> 15 (limite do D2) ou < 1. - ❌ Fontes externas via
--font-regularenquanto não houver Inter/JetBrains instalados no host de build — ficar no Source Sans Pro default.
13.9 Regeneração
docs/stack/build/build.sh re-renderiza todos os .d2 para .svg + .png a cada execução do /k-housekeep §1.10. Os arquivos .svg e .png sob diagrams/ são build artefacts gitignored (docs/stack/.gitignore) — só o .d2 fonte entra no git. Após clone, rodar ./build/build.sh gera os assets localmente.
13.10 Pilot de referência
O diagrama canônico do estilo é docs/stack/diagrams/aerial.d2. Ao criar ou refatorar outro .d2, abrir o aerial como template e espelhar:
- Bloco
classesno topo - Título markdown com font-size 36/26/22
- Containers com
class: area+icon:+style.fill: "linear-gradient(...)" - Nós com
class: node+icon:quando existir - Arestas com estilo neutro padrão (§13.5)
References
commands/k-housekeep.mdspecs/icons/products.kmd