diff --git a/docs/design/visualize-repo-map.md b/docs/design/visualize-repo-map.md new file mode 100644 index 0000000..a314f04 --- /dev/null +++ b/docs/design/visualize-repo-map.md @@ -0,0 +1,315 @@ +# Visualize: Repo Map + +**Status:** draft +**Owner:** ai-devkit maintainers +**Last updated:** 2026-08-18 +**Scope:** Feature-level. Deepens `docs/design/visualize.md` for one material +type: a map of a repository's own architecture, traced from its real code. +Resolves several Open Points that the parent doc left unresolved. + +The parent doc specifies a Source Resolver, Form Selector, Renderer pipeline +over three source kinds: a doc path, a tracker query, an inline description. +This document adds a fourth source kind, the repository's own code, and +specifies the contract that makes the pipeline's promises enforceable rather +than aspirational. + +## Mission + +Produce a map of a codebase that a person and an agent can reason against +together, where every building and every connection carries the file that +proves it. The map exists to be discussed, not admired. A confident diagram +that quietly invents a relationship is worse than no diagram, because every +later conversation inherits the false premise. + +## Principles + +1. **Cited or absent.** A node or an edge without a `file:line` gathered in + this run does not appear. This is enforced by schema validation, not by + asking the model nicely. +2. **The model emits data, never pixels.** The analysis pass produces one + validated JSON document. Renderers are fixed code. Nothing about how the + map looks is decided per invocation by a language model. +3. **Legibility caps the map, not compute.** An isometric grid stops being + readable near twenty buildings. Altitude is chosen to land inside that + budget on any repo size. +4. **Say what was hidden.** Folding and unresolved relationships are first + class fields in the document and are rendered in the explainer panel. + Silent truncation is the failure this design most wants to prevent. +5. **Style is an axis, not the output.** Isometric 2.5D is one of several + renderings of one dataset. A process flow forced into 3D buildings is + worse than a clean flat diagram. + +## Architecture + +``` + ┌─── the contract ───┐ + │ │ + ┌───────────────┐ ┌───────────┐ │ ┌──────────────┐ │ ┌────────────┐ + │Source Resolver│──▶│Form │──┼─▶│ Scene Graph │──┼─▶│ Renderers │ + └───────────────┘ │Selector │ │ │ (validated) │ │ └────────────┘ + doc path └───────────┘ │ └──────────────┘ │ iso 2.5D + tracker query type │ nodes+citations │ flat 2D + inline text style │ edges+paths │ full 3D + ▸ repo code ◂ altitude │ payload samples │ static SVG + (new) form │ folded[] gaps[] │ + └────────────────────┘ +``` + +The Scene Graph is the waist of the design. Every capability agreed for this +feature is a consequence of it: three visual styles are three consumers of one +dataset; the static SVG is a fourth consumer rather than a second pipeline; +drill down is a nested document rather than a new mechanism; and the website +playground's assets are reproducible because they are renderer output, not +screenshots. + +## Components + +### Repo Analyzer + +**Location:** `skills/visualize/references/analysis.md` +**Owns:** what is true about this repository. +**Does not own:** layout, grouping aesthetics, style. + +Reads `docs/ai/` when present, purely as a routing hint for where to look. +Otherwise enumerates entrypoints, manifests, and configuration itself. Either +path converges on the same next step: trace imports and call sites, recording a +`file:line` for every node and every edge discovered in this run. A stale +`docs/ai/` costs speed, never truth, because no citation is ever inherited from +it. + +### Scene Graph schema + +**Location:** `skills/visualize/references/scene-graph.md` and +`skills/visualize/assets/scene-graph.schema.json` +**Owns:** what a valid map is. +**Depends on:** nothing. + +A machine checkable JSON Schema, not prose, so that validation is a gate rather +than a convention. Required structure: + +1. `nodes[]`, each with an id, a label, a kind, and a non empty `citations[]` + of `file:line` entries. +2. `edges[]`, each with a source, a target, a path kind of `control` or `data`, + a non empty `citations[]`, and zero or more `samples[]`. +3. `samples[]`, each a real snippet with its own citation. These are what the + moving dots carry and what a reader inspects on click. +4. `folded[]`, every group the altitude budget collapsed, each naming the files + behind it. +5. `gaps[]`, every relationship the analyzer suspected but could not cite. +6. `children`, an optional nested scene graph per node, for drill down. + +Schema validation rejects a document where any node or edge has an empty +`citations[]`. That single rule is what converts principle 1 from an intention +into a mechanism. + +### Renderer bundle + +**Location:** `skills/visualize/assets/renderer/` +**Owns:** how a map looks. +**Depends on:** the schema only. + +Four consumers of one input: isometric 2.5D, flat 2D, full 3D, and static SVG. + +Deterministic: the same scene graph must produce byte identical output. No +timestamps, no random seeds, no unordered iteration over maps or sets. Golden +tests and the reproducibility of the playground's twelve assets both rest on +this, so it is a renderer requirement rather than a nicety. Animation is driven +from values in the document, not from generation time entropy. + +Vanilla and self contained: no CDN, no build step, and no dependency on the +website's `three` or `@react-three/fiber`. This is required, not preferred. +`cmk:agent-vendors` specifies a cross package path rule in +`references/vendored-layout.md`: no file inside a skill package may reference +anything outside it by relative traversal, because vendored packages travel +independently into consuming repos under `.agents/skills/cmk-visualize/`. A +renderer that reached for the website's dependencies would work here and dangle +everywhere else. + +### Skill surface + +**Location:** `skills/visualize/SKILL.md`, `TESTS.md`, `eval.json` + +Trigger phrases, the Form Selector's four axes, the per invocation durable +versus ephemeral decision, and the rule that an invalid scene graph blocks +rendering outright. + +### Playground surface + +**Location:** `app/visualize/page.tsx`, `components/marketing/visualize/`, +`public/visualize/` + +Not part of the vendored skill. Depends on the skill only through generated +output, never through imports. Specified in its own section below. + +## Mechanisms + +### Form selection + +Four independent axes, resolved from explicit user language, falling back to +defaults: + +1. **Diagram type.** System Architecture only in v1. Process Flow and + AI / Data Flow are designed for and deferred. +2. **Visual style.** Isometric 2.5D by default, flat 2D, or full 3D. +3. **Altitude.** Budgeted by default, or a named subsystem. +4. **Output form.** Interactive artifact by default, or static SVG. + +Independence is the point. Adding a diagram type later must not touch style, +altitude, or form. + +### Altitude + +Default is a node budget of twelve to twenty buildings. The analyzer picks the +grouping level that lands inside it: per file on a small repo, per package or +per service on a monorepo. Every collapse is recorded in `folded[]` with the +files behind it, so folding summarizes without destroying evidence. + +A named subsystem is an explicit override for when the caller already knows +which slice they want, and traces that slice without folding. + +### Drill down + +Sub maps are generated eagerly, in the same pass, to a fixed depth cap. An +artifact that needs a second invocation to open a building is not self +contained. The depth cap is what keeps eager generation bounded on a large +repository. + +### One invocation, end to end + +1. Form Selector resolves the four axes. +2. Analyzer routes on the presence of `docs/ai/`. +3. Analyzer traces imports and call sites, collecting citations. +4. Altitude fold applies, recording `folded[]`. +5. Payload sampling attaches real snippets to edges. +6. Scene graph is validated. Invalid means no render and a report naming the + offending element. +7. Style and form select one renderer. +8. Interactive output publishes as an artifact; static SVG writes into the repo + when the invocation warrants durability. + +## Failure paths + +1. **Invalid scene graph.** Render blocked, offending node or edge named. Never + a partial picture. +2. **Uncitable relationship.** Not drawn. Recorded in `gaps[]` and printed in + the explainer panel. +3. **Budget exhausted.** Fold harder and record it. Never truncate silently. +4. **Host has no artifact capability.** The static SVG path still works, since + it needs no runtime. Consistent with the parent doc's failure path. +5. **Stale `docs/ai/`.** Degrades speed, not correctness. +6. **Dynamic dispatch or an unparseable language.** Recorded in `gaps[]`, never + guessed. +7. **Secret captured in a payload sample.** Redact by pattern at sample time, + and never sample from files matching the repository's ignore and secret + patterns. + +## Cross-cutting concerns + +### Security + +Payload sampling reads real snippets out of real files, which is a new exposure +this feature introduces and the parent doc does not cover. Two rules bound it: +files matching ignore and secret patterns are never sampled, and sampled text is +redacted by pattern before it enters the scene graph. The scene graph is the +publishable artifact, so redaction happens before the document exists, not +before it renders. + +An artifact publish is typically link shareable. A repo map exposes internal +structure and code snippets, so the skill confirms before publishing a map of a +private repository rather than treating render intent as share intent. + +## Website playground + +A dedicated surface for `cmk:visualize`, replacing the plainer showcase the +parent doc implies. + +**Prompt composer.** Three knobs, with the prompt text updating live and changed +lines highlighted, so the effect of a choice is visible as a diff. A copy button +is the primary action. + +**Knobs in v1.** Diagram type cannot be a knob while only one type exists, so +v1 exposes style times altitude times output form, three by two by two. Diagram +type becomes a fourth knob when the catalog grows, and the composer is built so +adding a knob does not mean rebuilding it. + +**Preview matrix.** Twelve pre-rendered assets, one per knob combination, so +flipping a knob swaps to the real corresponding output rather than an +illustration. The assets are produced by running the real renderer over the +`ai-devkit` scene graph, which means they cannot drift from what the skill +emits, and regenerating them is a dogfooding pass rather than a maintenance +chore. + +## Testing + +1. **Schema gate tests.** Fixture scene graphs, valid and invalid, asserting + that invalid documents block rendering rather than warn. +2. **Renderer golden tests.** Identical scene graph in, byte identical output, + which is what makes the twelve playground assets reviewable as diffs. +3. **Analyzer honesty test.** Run against a fixture repository with a known + structure and assert that every emitted citation resolves to a real + `file:line` and that the claimed relationship is actually present there. + This is the test that catches invention and is the most important one here. +4. **Kit conventions.** `TESTS.md` and `eval.json`, following + `skills/interpret/`. +5. **Dogfood.** Run against `ai-devkit` itself. That run produces the + playground's twelve assets, so the demo and the test fixture are the same + artifact. + +## Delivery sequence + +This design covers two deliverables that want separate implementation plans, +because the second consumes the first's output: + +1. **The skill.** Schema first, then analyzer, then renderers, then the skill + surface. The schema is built first because every other piece is defined + against it, and getting it wrong invalidates work downstream. +2. **The playground.** Cannot start until the skill can emit a real scene graph + for `ai-devkit`, since its twelve assets are renderer output. Attempting it + earlier would mean mocking the very thing the page exists to demonstrate. + +## Constraints + +1. First code carrying skill in this kit. Every existing skill is markdown only: + `SKILL.md`, `eval.json`, `references/`, with one `agents/` directory. Shipping + `assets/` is a new convention, accepted deliberately. It is compatible with + `cmk:sync`, whose `content_hash` covers a package's files in sorted path + order, so no change to sync is required. +2. The renderer must run with no network and no build step, per the cross + package path rule above. +3. Interactive output depends on the host exposing an artifact style publish + capability. Behavior without one is specified in Failure paths. + +## Later checklist + +Recorded so the ambition is not lost, and explicitly not designed here: + +1. **Process Flow** and **AI / Data Flow** diagram types, which reuse the same + analysis pass and slot in as diagram type values. +2. **The broader diagram generator surface**: Smart Factory and IoT scene + diagrams, teaching and course content diagrams, 3D product structure + diagrams, planning and travel route maps. These cannot reuse the repo + analysis pass, since there is no codebase behind a travel route, and the + citation invariant does not apply to them. Adopting them would make this two + skills wearing one name, so any future move here should start by asking + whether it is a separate skill. +3. **Diagram type as a fourth playground knob**, once more than one type exists. + +## Open Points + +1. **Trigger phrases.** Still inherited from the parent doc's Open Points and + still unresolved. Needs a pass against this repo's frontmatter convention. +2. **Depth cap for eager drill down.** The mechanism is decided, the specific + cap is not, and it should be set from a real monorepo measurement rather + than guessed. +3. **Node budget boundaries.** Twelve to twenty is an eyeball figure. Worth one + calibration pass against three real repositories of different sizes. +4. **Requirements doc.** Still none, so `cmk:design`'s upstream conflict check + is still skipped, exactly as the parent doc records. + +## Links + +1. **Parent design:** `docs/design/visualize.md` +2. **Vendoring rules:** `cmk:agent-vendors`, `references/vendored-layout.md` +3. **Sync and hashing:** `cmk:sync`, `references/skills-lock.md` +4. **Related skills:** `cmk:codebase-docs` (routing hint source), + `cmk:design` (parent doc owner), `cmk:glossary` (term promotion) diff --git a/docs/design/visualize.md b/docs/design/visualize.md new file mode 100644 index 0000000..dfecf3f --- /dev/null +++ b/docs/design/visualize.md @@ -0,0 +1,220 @@ +# Visualize + +**Status:** draft +**Owner:** ai-devkit maintainers +**Last updated:** 2026-08-13 +**Scope:** Feature-level — a new `cmk:visualize` skill that renders existing +content (a doc, a tracker query, a description) into a reviewable visual; +it does not design systems or write specs — that is `cmk:design`'s job. + +This document specifies `cmk:visualize`: a skill that turns content someone +already has — an architecture doc, a protocol flow, a week's resolved +tickets, a raw description given in the prompt — into a rendered visual +someone can actually look at, instead of a wall of markdown or a +general-purpose video tool. It does not invent content; it renders what +exists or what the user just described. + +## Mission + +Give every material type a reviewable rendered form, without forcing a +single output shape onto content that doesn't fit it. A rendered +architecture diagram, an animated protocol-flow teaser, and a slide deck +summarizing a week's shipped tickets are three different rendering +problems sharing one skill because they share the same three-stage shape +(resolve source → pick form → render), not because they share an output +format. + +Serves anyone who already has content and wants it *seen*, not anyone who +needs help deciding what to build — that request routes to `cmk:design`, +`cmk:requirements`, or `cmk:adr` instead. + +## Principles + +- **Render, never invent.** The skill draws from a real source — an + existing doc, a live tracker query, or content the user just described in + the prompt. It never fabricates architecture, protocol steps, or progress + that isn't in the source. If the source is thin, the render is thin; the + skill does not pad it. +- **Durable vs. ephemeral is a per-invocation decision, not a + per-material-type rule.** An architecture diagram usually belongs beside + its spec in `docs/design/`; a marketing teaser for a protocol flow + usually does not belong in the docs tree at all. The skill decides case + by case (see Mechanisms § Render), not by a fixed table mapping "type A + always writes a file." +- **Compose, don't duplicate.** Tracker access, doc reading, and content + synthesis are already other skills' jobs (`cmk:delivery-workflow` for + tracker state, `cmk:design`/`cmk:requirements`/`cmk:adr` for the docs + themselves). This skill's own logic is limited to source resolution, + form selection, and rendering — it calls into existing mechanisms for + everything upstream of that rather than re-implementing tracker queries + or doc parsing. +- **One skill, three stages — not four skills, one per material type.** + Architecture, protocol, progress-report, and slide/demo output all pass + through the same Source → Form → Render pipeline. Splitting by material + type was considered and rejected (see Open Points) because the two + motivating examples — a tracker-sourced slide and an animated marketing + teaser — both cross whatever boundary a type-based split would draw. + +## Architecture + +``` + ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ + input ─▶ Source Resolver ─▶ Form Selector ─▶ Renderer ─▶ reviewable output + └───────────────────┘ └───────────────────┘ └───────────────────┘ + doc | tracker query static | animated Artifact publish + | inline description diagram | slide deck (+ durable doc + | dashboard write, if warranted) +``` + +- **Source Resolver** — identifies what's being visualized and fetches it. + Three source kinds: an existing doc path (`docs/design/*.md`, + `docs/decisions/*.md`, `docs/reports/*.md`), a live tracker query (delegated + to `cmk:delivery-workflow`'s tracker access — this skill does not talk to + the tracker directly), or content given inline in the prompt with no + backing doc. Owns: resolving "what does the user mean by *this*" to + concrete content. Does not own: writing or editing the source content — + read-only with respect to docs and tracker state. +- **Form Selector** — maps the request's intent to an output shape: static + diagram, animated diagram, slide deck, or dashboard-style summary. Reads + intent from explicit user language ("beautiful slide," "animation," + "teaser") over material type — a protocol flow can render as a static + diagram *or* an animated teaser depending on what was asked. Owns: + picking the shape and the durable-vs-ephemeral call. Does not own: + the actual rendering. +- **Renderer** — produces the reviewable output. Publishes via the host + agent's Artifact-equivalent capability (see Constraints) for the + reviewable link; conditionally also writes a durable version into the + docs tree per the Form Selector's call. Owns: visual quality and + house style. Does not own: content accuracy — that's inherited from + whatever the Source Resolver handed it. + +## Mechanisms + +### Source resolution + +- **Doc source**: user names or implies an existing file. Resolver reads it + in full; if the path doesn't exist, the skill says so and asks rather + than guessing a path or inventing content to fill the gap. +- **Tracker source**: user describes a query in tracker terms ("tickets + resolved this week"). Resolver delegates the actual query to + `cmk:delivery-workflow`'s tracker access rather than re-implementing + tracker API calls; this skill only shapes the *rendering* of whatever + that returns. +- **Inline source**: user describes the content directly in the prompt + (e.g., dictates a protocol flow with no backing doc). Resolver treats the + prompt text itself as the source of truth for this render — it does not + retroactively require a doc to exist first. +- **Ambiguous source**: if more than one of the above plausibly applies (a + doc *and* a live tracker both seem relevant), the skill asks rather than + picking one silently. + +### Form selection + +- Explicit output-shape language in the request ("slide," "animation," + "teaser," "diagram") wins over any default tied to material type. +- Absent explicit language, default by source kind: a design/decision doc + defaults to a static diagram (cheapest, matches the doc's own + implementation-agnostic register); a tracker query defaults to a + dashboard/slide-style summary; an inline description defaults to + whatever shape best fits what was described, decided at render time. +- The durable-vs-ephemeral call: a render is written into `docs/` only when + it visualizes content that already lives there (i.e., it's a companion + render of an existing design/decision/report doc) *and* the user hasn't + signaled a one-off/marketing intent ("teaser," "for my product"). A + tracker-sourced slide or an explicitly-marketing render is Artifact-only + by default — nothing is committed unless the user asks for it to be. + +### Render + +- The reviewable output is always published through the host agent's + Artifact-equivalent capability (this environment's `Artifact` tool is the + reference implementation) — a rendered, link-shareable page, not a + markdown dump back into chat. +- Visual quality follows whatever design-quality-bar mechanism the host + environment provides for that capability (this environment's + `artifact-design` skill is the reference) rather than the skill hand-rolling + its own style rules. +- When the Form Selector calls for a durable copy, the skill writes it to + the doc-appropriate location using **Mermaid embedded in the markdown**, + not a bespoke component — this keeps the durable artifact dependency-free + and natively viewable on GitHub without relying on the rendering + capability that produced the reviewable version still existing later. + The Artifact render and the durable Mermaid version are allowed to differ + in polish; they are not required to be pixel-identical. + +### Failure paths + +- Source doesn't resolve (bad path, empty tracker result, prompt too thin + to render anything meaningful) → the skill says so and asks for more, + rather than rendering a placeholder. +- Host environment has no Artifact-equivalent capability available → the + skill degrades to describing the intended visual in text and, if a + durable Mermaid version is warranted, still writes that (Mermaid needs no + special rendering capability) — it does not silently fail or fall back to + producing a video. + +## Cross-cutting concerns + +### Security + +- Artifact-equivalent publishing typically produces a link-shareable page. + A render sourced from a live tracker query (e.g., "this week's resolved + tickets") may surface information the team didn't intend to make + shareable — the skill confirms before publishing anything tracker-sourced + if the tracker content looks like it could include sensitive fields + (assignee PII beyond names, customer identifiers, anything the tracker + itself marks confidential), rather than assuming render intent implies + share intent. +- The skill never reads credentials, tokens, or MCP configuration to + satisfy a visualization request — if a tracker or doc source requires + access the current session doesn't already have, it says so rather than + attempting to escalate its own access. + +## Constraints + +- Depends on the host agent exposing an Artifact-equivalent + publish-and-share capability; behavior without one is specified in + Mechanisms § Failure paths, not left undefined. +- Tracker access is entirely inherited from `cmk:delivery-workflow` — this + skill has no tracker-specific code of its own and breaks cleanly (asks, + doesn't guess) if that skill or its tracker connection is unavailable. +- Trigger phrasing follows this repo's existing convention (natural-language + quoted phrases in the skill's own frontmatter description, callable via + `/cmk:visualize` too) — exact phrase set is an Open Point, not decided + here. + +## Open Points + +- **Exact trigger phrases** — draft candidates from this conversation: + `"visualize this"`, `"make me a slide/diagram of..."`, `"animate this + flow"`, `"summarize this as a slide"` — needs a real pass against this + repo's phrase-writing convention (see other `SKILL.md` frontmatter) before + it ships. +- **Splitting demo/slides/presentation out later** — rejected for v1 (see + Principles), but if slide-deck rendering ends up needing meaningfully + different tooling (e.g. reveal.js/Marp) than diagram rendering, revisit + whether Renderer needs two real backends behind one Form Selector rather + than one. +- **Glossary terms** — this doc coins "Source Resolver," "Form Selector," + and "Renderer" inline because this repo has no `docs/requirements/glossary.md` + yet (per `cmk:glossary`'s own convention). Once one exists, promote these + terms there rather than leaving them defined only in this doc. +- **No requirements doc exists for this feature.** This design doc has + nothing in `docs/requirements/` to link yet — normally `cmk:design` checks + upstream requirements for conflicts; that check is skipped here because + there's nothing to check against. Worth a `cmk:requirements` pass before + this moves past `draft`. +- **Confirmation UX for the tracker-security check** — "confirms before + publishing" (Cross-cutting § Security) isn't specified as an exact + prompt/flow yet. + +## Links + +- **Deeper design:** `docs/design/visualize-repo-map.md` specifies the repo-map + material type in detail, adds the repository's own code as a fourth source + kind, and pins the scene-graph contract the pipeline renders from. +- **Requirements:** none yet — see Open Points. +- **Decisions:** none yet. +- **Related skills:** `cmk:design` (spec source for architecture/decision + renders), `cmk:delivery-workflow` (tracker source), `cmk:glossary` (term + promotion, once established).