Skip to content
Merged
2 changes: 1 addition & 1 deletion .github/plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"plugins": [
{
"name": "colophon",
"description": "Keeps a repo's design system in .agents/design/ as the source of truth, renders/edits it in a Copilot canvas, and makes Copilot generate UI from its tokens, components, and principles.",
"description": "Keeps a repo's design system in .agents/design/ as a shared, versioned design source, renders/edits it in a Copilot canvas, and makes Copilot generate UI from its tokens, components, and principles — the source of truth for design, with configurable per-area port targets that say what each surface ships as (React web, native WinUI/XAML, SwiftUI) and which reference/skill ports the design into it.",
"version": "0.1.0",
"source": "."
}
Expand Down
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ automatically.

Colophon ships two halves in one plugin:
- a **skill** (`skills/colophon/`) that tells Copilot to treat `.agents/design/` as
the source of truth and build UI from its tokens, components, and principles; and
the design source and build UI from its tokens, components, and principles; and
- a **canvas extension** (`extensions/colophon/`) that renders and edits the system
live, and exposes a `colophon` tool + hooks so the agent always has it in context.

Expand All @@ -22,12 +22,32 @@ Colophon ships two halves in one plugin:
### 1. The design system lives in the repo: `.agents/design/`
| File | What it is |
| --- | --- |
| `design.json` | Tokens: brand, colors, typography, spacing, radii, shadows, principles |
| `design.json` | Tokens: authority, brand, colors, typography, spacing, radii, shadows, principles |
| `components.jsx` | "Pseudocode React" — 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 vs. port — the design leads, the implementation ships

The design files are always the **source of truth for design** — tokens, component
intent, and principles — and are framework-agnostic. `components.jsx` is design
intent for the canvas preview, **not** shipping code. What varies is how a design
becomes shipping code, which `design.json` records in an `authority` block:

| Field | Meaning |
| --- | --- |
| `authority.designSource` | Who owns the *design* (default `"self"` = these files). |
| `authority.port` | App-wide default **port target**: `authoritySource` (what the UI ships as — e.g. `Native WinUI 3 / C#`, `SwiftUI`), `syncSource` (the reference/skill to port design → that implementation — e.g. `microsoft/win-dev-skills`), and optional `helperAgent`. |
| `authority.portOverrides[]` | Per-area / per-component overrides — e.g. a React-style **chat** surface targeting [Reactor](https://github.com/microsoft/microsoft-ui-reactor). Each has `area`, `components[]`, and the same three port fields. |

No `port`/overrides ⇒ the files are both the design **and** the implementation
source of truth (web/JSX repos) — Colophon's original behavior, unchanged. Scanning
a repo with no web styling (a native/XAML app) pre-fills a port target for you to
complete. The skill, the injected context, and the `AGENTS.md` pointer all reflect
these port targets, so agents know what each surface ships as and which skill to
port the design with — they never ship `components.jsx` verbatim.

### 2. The canvas renders + edits it
Open the **Design System** canvas to see the system rendered live:
- Brand board, color palette, type scale, spacing/radii/shadows, principles.
Expand Down
280 changes: 265 additions & 15 deletions extensions/colophon/client.js

Large diffs are not rendered by default.

41 changes: 35 additions & 6 deletions extensions/colophon/context.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// sessionStartContext -> one-time announcement the design system exists
// promptContext() -> per-turn nudge to consult it before writing UI

import { colorList, DESIGN_SUBPATH } from "./designio.mjs";
import { colorList, readAuthority, portLines, DESIGN_SUBPATH } from "./designio.mjs";

const UI_TERMS = [
"ui", "ux", "page", "screen", "view", "component", "layout", "design",
Expand Down Expand Up @@ -59,6 +59,17 @@ export function buildSummary(design) {
? `Source: proposed from imported tokens — not saved yet. Review in the Design System canvas, then save to ${DESIGN_SUBPATH}/.`
: `Source: bundled starter (no ${DESIGN_SUBPATH}/ in this repo yet — call the "init" action to seed it)`;
lines.push(sourceLine);

const authority = readAuthority(t);
if (authority.hasPort) {
lines.push(
"Authority: these files are the source of truth for DESIGN (tokens, component intent, principles) " +
"and are framework-agnostic — components.jsx is design intent for preview, not shipping code. The " +
"shipping implementation below is canonical; treat token values and components.jsx as derived examples. " +
"To ship, port the design into this app's implementation via the port target(s) below:"
);
for (const l of portLines(authority, { bullet: " - " })) lines.push(l);
}
lines.push("");

if (brand.voice) lines.push(`Voice: ${brand.voice}`);
Expand All @@ -67,8 +78,14 @@ export function buildSummary(design) {
lines.push("");

if (colors.length) {
lines.push("Colors:");
for (const c of colors) lines.push(` - ${c.name}: ${c.value}${c.usage ? ` — ${c.usage}` : ""}`);
const previewOnly = authority.hasPort;
lines.push(previewOnly
? "Colors (PREVIEW-ONLY hex — bind the mapped `resource` in code, never the raw value, so light/dark/high-contrast stay correct):"
: "Colors:");
for (const c of colors) {
const res = c.resource ? ` → resource ${c.resource}` : "";
lines.push(` - ${c.name}: ${c.value}${res}${c.usage ? ` — ${c.usage}` : ""}`);
}
lines.push("");
}

Expand Down Expand Up @@ -105,7 +122,16 @@ export function buildSummary(design) {

export function sessionStartContext(design) {
const brand = design.tokens?.brand || {};
const authority = readAuthority(design.tokens);
if (design.source === "repo") {
if (authority.hasPort) {
const targets = portLines(authority, { bullet: "" }).join("; ");
return [
`This repository has a design system at ${DESIGN_SUBPATH}/ (brand: ${brand.name || "unnamed"}). These files are the source of truth for DESIGN and are framework-agnostic — components.jsx is design intent for preview, not shipping code, and the color hex values are preview-only swatches.`,
`Before creating or changing any UI, read ${DESIGN_SUBPATH}/design.json, components.jsx, and principles.md and follow their tokens and patterns. The shipping implementation is canonical: to ship, port the design using the port target(s): ${targets}. Bind each color's mapped resource key rather than hard-coding the preview hex.`,
`You can open the "Colophon" canvas to view/edit it (with Light/Dark/High-contrast preview), or call the colophon tool for a text summary.`,
].join(" ");
}
return [
`This repository has a design system at ${DESIGN_SUBPATH}/ (brand: ${brand.name || "unnamed"}).`,
`Before creating or changing any UI, read ${DESIGN_SUBPATH}/design.json, components.jsx, and principles.md and follow them — reuse the defined color/type/spacing tokens and component patterns instead of inventing new ones.`,
Expand All @@ -117,9 +143,12 @@ export function sessionStartContext(design) {

export function promptContext(design) {
const brand = design.tokens?.brand || {};
const head = design.source === "repo"
? `The user's request looks UI-related and this repo has a design system (${brand.name || "unnamed"}) at ${DESIGN_SUBPATH}/.`
: `The user's request looks UI-related. There's no ${DESIGN_SUBPATH}/ in this repo yet, but a starter design system is available.`;
const authority = readAuthority(design.tokens);
const head = design.source !== "repo"
? `The user's request looks UI-related. There's no ${DESIGN_SUBPATH}/ in this repo yet, but a starter design system is available.`
: authority.hasPort
? `The user's request looks UI-related and this repo has a design system (${brand.name || "unnamed"}) at ${DESIGN_SUBPATH}/ — the source of truth for design (framework-agnostic). Follow its tokens/patterns, then port the design into this app's canonical implementation via the configured port target(s); the color hex is preview-only, so bind each color's mapped resource key instead.`
: `The user's request looks UI-related and this repo has a design system (${brand.name || "unnamed"}) at ${DESIGN_SUBPATH}/.`;
return [
head,
"Consult it before writing UI: use the colophon tool (or read the files) and honor its color, typography, spacing, radius tokens, component patterns, principles, and anti-references.",
Expand Down
Loading