Skip to content

Repository files navigation

Colophon

A colophon is the note at the back of a book naming its typefaces, materials, and makers. This is that — for your app's UI.

image image

Colophon gives AI coding agents a shared, living design system for every repo — seed it, edit it in a live canvas, prototype flows, and turn approved designs into production code.

Colophon ships two halves in one plugin:

  • a skill (skills/colophon/) that tells Copilot to treat .agents/design/ as the design source and build UI from its defined tokens, components, and principles; and
  • a canvas extension (extensions/colophon/) with two canvases:
    • Colophon canvas: that renders and edits the defined design system live, and
    • Prototype canvas: that renders device-framed, click-through mockups, including colophon/prototype tools and hooks so the agent has an initialized design system in context.

Quick start

Github Copilot App

In a repository you want to design or prototype:

  1. Install the plugin:
copilot plugin install karkarl/colophon
  1. Reload or restart Copilot so it discovers the plugin.
  2. Open the Colophon canvas. If the repository has no design system yet, choose Start fresh, Import tokens, or Scan codebase.
  3. Save the proposal to create .agents/design/. From then on, Colophon supplies that shared design context when you ask Copilot to build or change UI.

Open the Prototype canvas when you are ready to create or preview a click-through flow. Commit .agents/design/ so the rest of the team works from the same system.

Slash commands

Command What it does
/colophon Opens the Colophon design-system canvas.
/prototype Opens the Prototype canvas for the repository's click-through flow.
/design-validate Validates the design system and reports every error and warning without modifying files.
/design-scan Scans existing UI sources and reports an unsaved design-system proposal with its evidence.
/prototype-validate Validates prototype parsing, navigation, component, and design-token references without modifying files.
/prototype-export Validates and writes a standalone interactive prototype export, or reports why export was blocked.

The five workflow commands are declarative plugin commands in commands/, so hosts can discover them consistently. /colophon is supplied by the Colophon canvas.

How it works

1. The design system lives in the repo: .agents/design/

File What it is
design.json Tokens: authority, brand, colors, typography, spacing, radii, shadows, principles
components.jsonc A structured element-tree with token-bound Auto Layout — the component patterns your team has agreed on
principles.md Prose voice / information hierarchy / do & don't

These are plain files. Commit them, review them in PRs, edit them by hand or in the canvas.

design.json: the design contract and agent hand-off

design.json is the durable contract between people, the canvas, and agents: it names the visual system and tells an agent how that system becomes production UI.

The core design fields—brand, colors, typography, spacing, radii,shadows, and principles—are framework-agnostic design intent. Agents use their names and usage guidance rather than inventing ad-hoc values. components.jsoncdescribes reusable patterns for canvas preview and implementation guidance; it is not automatically shipping code.

The authority block is the production hand-off. It removes the ambiguity that normally exists when a design-system preview and the app's implementation use different technologies:

Field What it tells people and agents
authority.designSource Who owns the design. "self" (the default) means .agents/design/ is the design source of truth.
authority.port The app-wide default production target. Leave it null when no separate implementation needs a port from the design contract.
authority.port.authoritySource What the UI actually ships as, such as Native WinUI 3 / C# or SwiftUI. That implementation wins when it differs from the canvas preview.
authority.port.syncSource The skill, repository, or reference an agent must use to port the design into the production target—for example, microsoft/win-dev-skills.
authority.port.helperAgent An optional specialist agent or skill that performs the port.
authority.owner / authority.port.owner The team or person responsible for keeping the canonical implementation aligned with the design.
authority.syncProcess How the preview examples and production implementation stay in sync, such as a documented XAML-to-design update process.
authority.portOverrides[] Exceptions for a particular area or \components[]\\. An override uses the same port fields, so a chat surface can ship with Reactor while the rest of an app ships natively.

For example, a native app can keep Colophon as its shared design source while explicitly directing agents to the implementation that ships:

{
  "authority": {
    "designSource": "self",
    "owner": "@contoso/design-systems",
    "syncProcess": "Review preview and WinUI changes together in every UI PR.",
    "port": {
      "authoritySource": "Native WinUI 3 / C#",
      "syncSource": "microsoft/win-dev-skills",
      "helperAgent": "win-dev-skills",
      "owner": "@contoso/windows-ui"
    },
    "portOverrides": []
  }
}

With no port or overrides, design.json and components.jsonc remain the framework-agnostic design contract and an agent implements that contract in the repository's chosen production technology. With a port target, the skill, injected context, and managed AGENTS.md pointer tell agents what is canonical, what reference to use, and what not to copy verbatim. This keeps the canvas useful without turning components.jsonc into a competing source of production code.

2. The canvas renders + edits it

Open the Design System canvas to see the system rendered live:

  • Design system - Brand board, color palette, type scale, spacing/radii/shadows, principles.
  • Live component previewscomponents.jsonc is rendered by a small pure JSON→DOM interpreter (no framework runtime, works offline) using the system's own tokens, so you see real UI, not just code. Format v3 keeps every object layer relational with a stable id, supports semantic Auto Layout, and adds explicit parent-relative freeform positioning.
  • Inline editing — change a color/font/brand text and Save to repo writesdesign.json back. File edits stream back into the canvas via SSE.
  • Exact inspection — toggle Inspect to select brand, color, typography, spacing, radius, shadow, principle, component, or individual rendered component layer by its exact JSON Pointer path. Edit the object inline, save it to design.json / components.jsonc, or attach it to chat.
  • Visual component editing — Inspect opens a synchronized three-pane workspace: component layers on the left, the live canvas in the center, and Properties / JSON on the right. Select layers from the tree or rendered preview, then edit direction, gap, padding, margin, alignment, justification, wrapping, growth, grid columns, and fill/hug sizing through token-backed controls. Spacing combo boxes step through the design-system scale by default; Snapped switches them to free pixel values when a composition needs an intentional exception. Typography pickers preview each design-system text style and family in its own typeface. Color pickers expose the full token palette, an explicit None / transparent choice, and a native spectrum control for a custom override. Appearance controls inherit from the parent/class by default and write sparse overrides for typography, colors, radius, shadow, and text alignment. Drag layers before, after, or inside another element; duplicate/delete layers; and undo/redo before saving. In Inspect mode, drag an absolutely positioned child directly on a freeform preview to update its parent-relative X/Y coordinates live; one undo step is recorded when it is dropped.

components.jsonc v3 uses stable IDs and token names for semantic layout, with fixed pixel dimensions reserved for intentional freeform composition:

{
  "id": "card-root",
  "el": "article",
  "class": "ds-card",
  "layout": {
    "mode": "vertical",
    "gap": "2",
    "padding": "5",
    "align": "stretch",
    "width": "fill"
  },
  "margin": { "top": "2" },
  "appearance": {
    "textStyle": "heading",
    "color": "ink",
    "background": "surface",
    "radius": "lg"
  },
  "children": []
}

layout.mode accepts vertical, horizontal, grid, freeform, or none. Layout also supports gap, padding, align, justify, wrap, grow, columns, width, and height; margin lives on the node. Width and height accept fill, hug, or non-negative pixel numbers in v3. Spacing values reference keys in design.json (plus 0 and auto) by default. Unsnapped non-negative numbers are explicit pixel values. Format v1 remains readable, while v2 and later require unique stable IDs within each component so canvas selections and future layer moves remain durable.

A freeform parent establishes a local coordinate system without flattening the relational tree. Direct children opt into arbitrary placement with finite pixel coordinates:

{
  "id": "board",
  "el": "section",
  "layout": { "mode": "freeform", "width": 640, "height": 400 },
  "children": [
    {
      "id": "card",
      "component": "Card",
      "position": { "mode": "absolute", "x": 120, "y": 48 },
      "layout": { "width": 240, "height": 160 }
    }
  ]
}

Omitting position keeps a child in normal flow. Auto Layout drag operations still reorder or reparent children; freeform movement updates only the child node's parent-relative x and y.

Visual values inherit through normal component classes and the element hierarchy. An omitted appearance key means inherit; selecting a different value in Properties writes only that token override. Supported overrides are fontFamily, textStyle, color, background, borderColor, borderWidth, radius, shadow, and textAlign. Color properties may also contain an explicit six-digit hex value. The reserved $none value produces transparent colors, a square radius, or no shadow without colliding with design-token names. Border thickness (px) in both component and prototype Properties writes appearance.borderWidth, a non-negative finite pixel number (fractions allowed). An explicit thickness draws a solid border using the selected border color, or the existing CSS color; 0 removes it. Clear the field to remove the width/style override and restore class or component styling. The same property is supported in component interaction states and standalone exports. The thickness field uses the same numberbox and increment/decrement buttons as Margin, but always edits pixels rather than snapping to spacing tokens. Arrow keys step by one pixel. Property dropdowns share a single down-chevron icon.

Interactive component previews

Element and component-reference nodes can optionally declare states and on:

{
  "id": "picker",
  "el": "button",
  "attrs": { "type": "button" },
  "appearance": { "background": "$none", "color": "ink" },
  "states": {
    "hover": { "background": "line" },
    "pressed": { "background": "paper" },
    "hoverPressed": { "background": "surface" },
    "disabled": { "color": "muted" }
  },
  "control": {
    "chrome": "none",
    "focus": { "kind": "outline", "color": "accent" }
  },
  "on": { "click": { "open": "PickerOptions" } },
  "children": ["Format"]
}

Each state is a sparse appearance override with the same validation, including existing six-digit hex and $none support. The precedence is base, hover, pressed, then hoverPressed when both apply. Disabled is exclusive (base plus disabled). Omitted properties restore their previous inline/class/inherited values. On a component reference, states merge by state and property over the component root; an explicit on replaces the root's action, and control merges by field. Existing definitions without these fields retain their styling. Interaction metadata (states, on, and control) is supported only outside SVG subtrees. Validation rejects it on SVG roots and descendants, including expanded component references. Put interactions on an HTML button wrapping an SVG icon.

Defining states.disabled does not disable a control. Use attrs.disabled: true for native controls or attrs["aria-disabled"]: "true". The gallery's State selector offers Live, Rest, Hover, Pressed, Hover + pressed, and Disabled for screenshots. It applies to state-bearing nodes in that preview only, never saves to JSON, and cannot re-enable an authored disabled control. Live follows primary pointer and button keyboard input. Inspect mode selects/edits layers instead of opening flyouts. Entering Inspect clears forced preview states and disables the State selector so temporary disabled previews do not block layer selection.

on.click.open is a literal, exact component name, not a node ID or interpolated prop. The target renders with its own defaults and design tokens in a non-clipping flyout. Only one flyout opens at a time; nested flyouts are not supported. Escape restores trigger focus; outside click and focus leaving dismiss without stealing focus. Native radio changes select and dismiss. Radio groups are isolated per component render. Selection is transient: reopening restores defaults and does not update the trigger's label. These interactions work in the gallery, Prototype canvas, and self-contained exports; they do not define production framework behavior.

Run node --test extensions/colophon/*.test.mjs for regression coverage. The browser tests use installed Chrome/Edge without an npm dependency; set COLOPHON_BROWSER to a Chromium executable on other hosts (otherwise those tests report a skip).

control is an opt-in browser chrome reset/focus treatment for native buttons, textual inputs, textareas, and contenteditable elements. chrome: "none" removes the browser bevel/border and textarea resize handle, and requires a visible focus replacement. Focus kind is outline or underline; color must name a design color token (not a literal color or $none). Text entry uses focus; buttons use keyboard focus visibility. Forced-colors mode retains a visible focus cue. Control eligibility is checked after resolving component defaults and authored reference props, including interpolated input types and contenteditable values. Overrides that resolve to unsupported controls are rejected. No global Windows styling or raw-CSS escape hatch is introduced; ordinary Field and Button patterns are unchanged. Edit these optional fields in the JSON inspector.

If a repo has no .agents/design/ yet, the canvas shows a bundled starter system plus a 3-way onboarding panel (below).

2b. Seeding a repo — three ways

When there's no .agents/design/, choose how to start; refine everything in the canvas after.

Mode What it does
Start fresh Bundled starter (the "Northlight" system) or a blank skeleton (grayscale + one accent, system fonts). Writes immediately.
Import tokens Point at a repo-relative .json path or paste token JSON. Adapts our schema, flat {name:hex}, nested Tailwind / Style-Dictionary (colors/fontFamily/spacing/borderRadius), and W3C {$value} tokens. Loads as a proposal to refine, then Save.
Scan codebase Walks the repo's CSS/JSX/styles and extracts colors (prefers named CSS vars), fonts, spacing, radii, shadows — classifying unnamed colors into ink/paper/accent. Loads as a proposal to refine, then Save.

Starter/scratch write straight to .agents/design/; import/scan load an unsaved proposal with a review bar (Save to repo / Discard). Any first save also scaffolds components.jsonc + principles.md, and drops an idempotent AGENTS.md pointer at the repo root (see below).

2c. Seeding also writes an AGENTS.md pointer

When it seeds a repository, Colophon idempotently adds a managed AGENTS.md block—creating the file if needed—so agents load .agents/design/ before UI work.

3. Copilot references it automatically (the skill + tool + hooks)

  • colophon skill — instructs the agent, on any UI work, to read .agents/design/and generate UI from its tokens, components, and principles (not ad-hoc styles).
  • colophon tool — the agent calls it to get the system as text before UI work.init=true scaffolds .agents/design/ from the starter; scan=true proposes one from the repo's existing UI when none exists yet.
  • Hooks — when a repository contains .agents/design/design.json, onSessionStartannounces the system exists and onUserPromptSubmitted detects UI-related prompts ("build a settings page", "fix the button styling") to inject it. Repositories without an initialized design system receive no Colophon prompt context; use the canvas orcolophon tool explicitly to seed one.

4. Prototype canvas: click-through mockups from the design system

A second canvas turns the design system into click-through prototypes — so a team can shape a flow by talking to Copilot instead of redlining in Figma, review it visually, then convert a screen to code.

The Screens menu on the left lists screens in document order and highlights the current screen. Choose a screen to navigate, or use Back to return; the menu also follows click-through navigation. It uses the toolbar's neutral styling, independent of the prototype's design tokens and preview theme. Standalone exports use the same menu.

Use the + beside Screens to name a new screen. With no sections, the Sections subtitle is hidden and the section dropdown offers Ungrouped and Add section. Choose Add section to create a group and assign the selected screen to it. The new-screen dialog offers the same option with a section-name field, creating the screen and group together. Once a section exists, the Sections subtitle and its + appear. Use Selected screen's section to move a screen into an existing group or back to Ungrouped. Delete screen asks for confirmation and removes links to that screen and flows that start there. Changes remain drafts until Save in the sidebar or inspector; save errors leave the draft intact. You can delete the last screen and start again. Exports preserve the groups but omit authoring controls.

Groups are stored in prototypes.jsonc as optional sections: [{ "id": "onboarding", "name": "Onboarding" }]; each grouped screen has a sectionId. Section order follows the array, with ungrouped screens first and document order preserved within each group. Existing files without sections keep their flat list. Agent patches can use upsertSection with a section object, then upsertScreen with screen.sectionId.

  • Format — prototypes live at .agents/design/prototypes.jsonc: a framework-agnostic scene graph (layout primitives + references to your components.jsonc by name + navigation as data), never shipping code. It's pure data, so it renders safely and Copilot can patch a single node by id without rewriting the file. Every save re-emits a stable, key-ordered file plus a Markdown flow outline for painless PR review.
  • Device frames — preview each screen in web breakpoints, desktop-app windows (Windows/WinUI, macOS), mobile (iPhone/Android), and tablet — selectable, rotatable, with custom sizes and a zoom-to-fit — like Chrome DevTools' device toolbar, but including native app chrome.
  • Interactions (v1) — navigate between screens, simple state (toggles, tabs), open/close modals, and visibility bound to state. Click through it live in the canvas, rendered with your real tokens + components in Light/Dark/High-contrast.
  • Structured properties — toggle Inspect to select a layer in the preview or Layers tree. Layers and its history/actions occupy the left sidebar, before Screens; Properties / JSON stay on the right of the preview. Properties is the default tab: edit its stable ID, text, image, component-instance content, layout, dimensions, padding, margin, and sparse appearance overrides. Typography previews, palette swatches, explicit None, custom colors, and snapped/free spacing reuse Colophon's token-backed controls. Instance content changes never modify a component definition. JSON remains available for exact edits, including navigation and complex props. Editor buttons and selection/focus highlights use neutral chrome; preview components and palette swatches retain the design system's own colors.
  • Live local draft — typing previews valid changes immediately. Finishing an input commits one local edit; Escape cancels its preview. Invalid values show an error instead of entering the saved document. Changes stay local until Save writes prototypes.jsonc; save failures preserve the draft.
  • History and movement — undo/redo applies to property edits, JSON edits, and layer operations. Duplicate creates fresh IDs; delete removes the selected layer. Drop before/after a tree row to reorder, or inside a layout to reparent. In a freeform layout, drag a directly positioned child in the preview: its parent-relative pixel coordinates change without flattening the tree. Each completed drag is one undoable edit, and Escape cancels an active drag.
  • Send to chat — selected elements can be sent to Copilot as context for the next request, including the source, screen, exact JSON Pointer path, draft state, and element payload.
  • Convert to code — a first-pass codegen action turns the JSONC scene graph and component intent into code for the configured production target. The current web target emits React/JSX using ds-* conventions; a native port target emits a hand-off scaffold and porting notes for WinUI/SwiftUI through the same authority mechanism.
  • prototype tool — Copilot authors and reads prototypes from conversation: action of read (flow outline), validate (dangling navigation / unknown components or tokens), patch (surgical scene-graph ops), codegen (convert a screen), export(standalone browser artifact), or publish (explicit GitHub Pages deployment).

Sharing a design system or prototype

Audience Share this What they need
Designers and developers Commit .agents/design/ and open a pull request Repository access; they can open the Colophon and Prototype canvases in Copilot.
Someone continuing the agent work Share the Copilot agent session from the repository's Agents view Repository access. A session is useful for context and hand-off, not as a public presentation.
Stakeholders and reviewers Use Export in the Prototype canvas The generated .agents/design/prototype-export/index.html is a self-contained, interactive file that opens in any modern browser.
A broad browser audience Use Publish in the Prototype canvas GitHub authentication with repository admin access. Colophon writes only its generated file to gh-pages and opens the resulting GitHub Pages URL.
A team adopting the canvas extension Share the extension as a private GitHub gist The recipient can install the gist through Copilot, then open it in their own workspace.

Export is the safe default: it preserves screens, device frames, themes, click-through interactions, and component rendering without a Copilot session, a loopback server, or an internet connection. Publish is intentionally separate and asks for confirmation. It uses the authenticated GitHub CLI/API, never stages or commits the active working tree, and refuses to overwrite a GitHub Pages configuration that is not already based on gh-pages.

Agent/host-facing actions

Colophon canvas:

  • inspect_selection — return the exact selected design.json or components.jsonc object and its JSON Pointer path.
  • attach_selection — send that object to chat as context for the user's next request.
  • read — return the current system as a text summary.
  • init — scaffold .agents/design/ (non-destructive); mode: "starter" | "scratch".
  • scan — scan existing UI and return a proposed system (text + evidence); writes nothing.
  • validate — schema/parse + component checks; writes nothing.
  • refresh — tell the open canvas to reload from disk.

Prototype canvas:

  • read / outline — return the Markdown flow outline (screens, nodes, navigation).
  • inspect_selection — return the exact selected JSON element and its JSON Pointer path.
  • attach_selection — send that selection to chat as context for the user's next request.
  • patch — apply surgical scene-graph ops (upsertScreen, setNode, patchNode, setNav, …) and save.
  • validate — dangling navigation targets, unknown component/token references.
  • codegen — convert a screen to code for the configured port target.
  • export — write a self-contained interactive prototype-export/index.html below .agents/design/.
  • publish — explicitly export and publish to the repository's gh-pages branch via the authenticated GitHub CLI/API, without touching the active working tree.
  • refresh — tell the open canvas to reload from disk.

Repo layout

plugin.json                       plugin manifest (skills + extensions)
.github/plugin/marketplace.json   makes this repo its own plugin marketplace
skills/colophon/SKILL.md          the "build UI from .agents/design/" skill
extensions/colophon/              the canvas extension:
  extension.mjs   wiring: canvases + tools + hooks + loopback server + file IO
  designio.mjs    locate / load / scaffold / save .agents/design/ ; AGENTS.md pointer ; token  CSS vars
  context.mjs     UI-intent detection + the summary/context text Copilot receives
  sources.mjs     seed generators: scratch skeleton, token importer, codebase scanner
  renderer.mjs    tiny iframe shell (design canvas)
  client.js       the in-canvas inspector app (onboarding, render, edit, live previews)
  property-controls.js / property-controls.css  shared token-backed inspector controls
  styles.css      canvas chrome + the ds-* component runtime (from tokens)
  prototypeio.mjs  load / save / surgically patch / validate prototypes.jsonc (scene graph)
  proto-render.js  in-canvas JSON→DOM interpreter + interaction/state runtime
  components-runtime.js  browser-only component runtime used by standalone exports
  proto-client.js  the Prototype canvas app (device frames, inspect/edit/layers, click-through)
  proto-properties.js  structured properties with caller-owned preview/commit transactions
  proto-layout.js  shared flat layout, appearance validation, and styling
  proto-renderer.mjs / proto.css   prototype iframe shell + device-frame styles
  proto-outline.mjs                Markdown flow-outline generator
  protocodegen.mjs                 convert a screen to code for the port target
  prototypeexport.mjs              standalone HTML export writer
  pagespublish.mjs                 explicit GitHub Pages publisher
  sample/         bundled starter design system + sample prototypes.jsonc
```

## Notes & limitations (experimental)
- Component and prototype previews render with a pure in-canvas JSON→DOM interpreter, so
  they work fully offline — no CDN, no React/Babel.
- Design-system inspection supports token editing plus visual Auto Layout controls,
  drag/reparent, duplicate/delete, undo/redo, and exact JSON fallback for
  `components.jsonc` layers. Fixed/min/max dimensions, absolute positioning,
  responsive variants, and multi-selection are not yet part of the component schema.
- Prototype layers support structured properties and JSON editing, local live
  drafts, undo/redo, duplicate/delete, tree reordering/reparenting, and direct
  freeform movement. The model stays flat: `layout` is a discriminator such as
  `"stack"`, `"row"`, `"grid"`, `"scroll"`, `"freeform"`, or `"none"`; dimensions,
  spacing, margin, and `position` live on the node, not a nested layout object.
  Standalone exports include rendering and navigation, not authoring controls.
  Native `codegen` remains a best-effort hand-off scaffold; the web/React target is deterministic.
- Canvas APIs are an experimental SDK surface and may change.

## Installation and team setup

Colophon is a Copilot plugin **and** its own marketplace, so there are a few ways in.

**Install it as a plugin (recommended — includes the skill and both canvases):**
```bash
copilot plugin install karkarl/colophon
```

**Or register Colophon's marketplace, then install by name:**
```bash
copilot plugin marketplace add karkarl/colophon
copilot plugin install colophon@colophon
```

Restart or reload Copilot after installation, then open the **Colophon** or
**Prototype** canvas in the workspace.

**Configure it for a team:** declare the plugin in the repository's
`.github/copilot/settings.json` through the `enabledPlugins` field and commit that
file. Each teammate also needs repository access and a Copilot environment that
supports plugins. Use `~/.copilot/settings.json` instead to enable it across all of
your own repositories.

**Install only the canvas extension (no skill):** the extension lives in
`extensions/colophon/`. Install that subdirectory into
`~/.copilot/extensions/colophon/`, or point the `install_extension` tool at
`https://github.com/karkarl/colophon/tree/main/extensions/colophon`.

The standalone extension is useful for canvas-only evaluation. Prefer the plugin for
normal use because it also provides the UI-design skill and automatic design-system
context.

## License

MIT  see [LICENSE](./LICENSE).

About

Live, editable design systems in your repo — a Copilot CLI canvas extension that designers and developers refine together, and the agent references automatically.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages