Skip to content

Improve the Colophon canvas plugin: authority model, theming, sticky chrome, floating validation, collapsible setup - #3

Merged
karkarl merged 9 commits into
mainfrom
karkarl-improve-colophon-canvas-plugin
Jul 20, 2026
Merged

Improve the Colophon canvas plugin: authority model, theming, sticky chrome, floating validation, collapsible setup#3
karkarl merged 9 commits into
mainfrom
karkarl-improve-colophon-canvas-plugin

Conversation

@karkarl

@karkarl karkarl commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

This PR reworks the Colophon canvas plugin (extensions/colophon/) to address the design-authority and drift concerns Scott raised in his review of the OpenClaw seed PR, and layers on a round of canvas UX refinements so the inspector feels like part of the app it documents.

Two themes run through the work:

  1. Make the design/code authority relationship explicit so the design files can stay the source of truth for design while a framework-native port (WinUI 3 / C#) stays canonical for what ships — without the two silently drifting apart.
  2. Make the canvas itself calmer and more usable — theme-aware background, sticky chrome, a floating validation bar that explains itself, and a collapsible one-time setup section.

Addresses Scott's review on openclaw/openclaw-windows-node#962 and the follow-up #962 (comment).

Note: this PR only touches the Colophon plugin in this repo. The OpenClaw seed (.agents/design/ in #962) is updated separately.

Addressing Scott's review

Scott's core objection was that a design system pinning raw hex values fights the real app, which sources its colors from framework-native resources — so the design files and the shipping app would drift, and it was unclear which one wins. The response is an explicit, configurable authority model rather than an implicit one:

  • Design stays the source of truth for design intent, but each area can declare a port to a framework-native target. When a port is declared, the native resource is canonical for the shipped value and the design-file hex becomes a labeled preview, not a competing truth.
  • Authority and sync source are configurable per area. The native UI (WinUI 3 / C#) ports via microsoft/win-dev-skills; the chat surface (a React-style framework) can point its sync source at microsoft/microsoft-ui-reactor. Reactor has no helper agent yet — that's a known WIP and the config allows for it.
  • Tokens carry the binding breadcrumbsresource, owner, syncProcess — so agents bind the real native resource instead of hardcoding preview hex (which is exactly how drift starts).
  • A validate smoke-check enforces the contract: if a token declares a port, it must also carry the resource / owner / syncProcess breadcrumbs that keep the design copy tied to the native copy. It stays quiet when there's no port (nothing to drift).

What's in this PR

Authority & sync model

  • Reworked authority into design-as-source-of-truth + configurable per-area port targets (canonical vs. derived), replacing the earlier implicit model.
  • Tokens gained resource binding plus owner and syncProcess metadata.
  • Added validate.mjs — a drift smoke-check with a /api/validate endpoint and a canvas validate action. Enforces the port → resource/owner/syncProcess contract; exits non-zero on errors for CI use.

Cross-repo isolation (bug fix)

  • Fixed a leak where sessions in other worktrees were picking up this repo's design system. The working directory is now anchored to the session, not process.cwd(), so each repo's seeded design stays in that repo only.

Canvas UX refinements

  • Theme-aware background — the inspector background (and neutral chrome tokens) now follow the selected Light / Dark / High-contrast theme instead of a fixed light shell, by routing the chrome's neutral tokens through the design system's own --color-* vars.
  • Sticky topbar fix — the top bar now stays pinned while scrolling. Root cause was body { height: 100% } capping the body box to one viewport and breaking position: sticky past the first screen; changed to min-height: 100vh.
  • Floating validation bar — validation results now surface in a fixed infobar just below the sticky topbar (aria-live="polite"), with context-aware copy that describes exactly what is checked and adapts to whether a port is declared.
  • Collapsible setup section — the "Set up a design system" block is now a <details> disclosure with a clickable summary and rotating chevron. It only appears pre-setup and is rarely needed once seeded, so it can be tucked away; open/closed is remembered best-effort and defaults to open for first-run guidance.

Docs

  • Updated README.md and skills/colophon/SKILL.md to describe the authority model, port targets, and the validate workflow.

Commits

  • 26f9263 Add canonical vs derived authority model to design systems
  • 16df81b Rework authority into design-SoT + configurable per-area port targets
  • 7725657 Fix cross-repo design-system leak: anchor workdir to session, not process.cwd()
  • 79ae758 Add theme variants, resource binding, and validation to Colophon
  • a234cb6 Theme the inspector background and fix sticky topbar
  • 9ba0c61 Float the validation result and describe what it checks
  • d4d7e35 Make the setup section collapsible

Testing

  • node --check on all edited JS; node validate.mjs passes clean on the bundled sample (no port) and produces exactly the expected warnings on a ported seed.
  • Canvas reopened after each change; served HTML/CSS/JS verified to contain the intended markup; read / validate / theme-switch actions confirmed working across Light / Dark / HC.

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

karkarl and others added 7 commits July 16, 2026 10:57
Colophon hard-coded one authority model: .agents/design/ is *the source of
truth* and Copilot generates UI from it. That's right for web/JSX-first repos
(tokens compile to CSS vars) but wrong for native apps (WinUI 3 / XAML), where
native XAML/C# + observed behavior are canonical and the JSON/JSX are derived,
non-shipping mirrors. Raised by Scott on openclaw-windows-node#962.

Introduce an explicit authority.model on design.json (canonical | derived;
absent/unknown => canonical, preserving current behavior) plus canonicalSource,
maintainer, and syncNote. Thread it through every agent-facing surface:

- readAuthority() helper in designio.mjs
- buildSummary / sessionStartContext / promptContext flip framing when derived
- SKILL.md documents both modes; softens unconditional 'source of truth'
- AGENTS.md pointer block emits the 'derived / native wins / maintainer' caveat
  (ensureAgentsPointer reads authority from design.json)
- colophon tool header no longer says 'follow it exactly' for derived systems
- plugin.json / marketplace.json / README qualify 'source of truth'
- canvas Brand board gains an editable Authority control; scan of a repo with no
  web styling (the XAML case) proposes a derived system automatically
- fix latent evidence.fileCount (was undefined; scan returned scannedFiles)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Design files stay the source of truth for design (framework-agnostic).
Replace the canonical/derived toggle with per-surface port targets: an
authoritySource (what the surface ships as, e.g. native WinUI 3/C#) and a
syncSource (the reference/skill to port design into it, e.g. win-dev-skills),
plus an optional helperAgent. App-wide default (authority.port) with per-area
overrides (authority.portOverrides), e.g. a React-style chat surface -> Reactor.
No port target => files are also the implementation SoT (web/JSX, unchanged).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…cess.cwd()

The extension resolved .agents/design/ against a module-global currentWorkdir seeded from process.cwd(). In the app, a forked extension's process.cwd() is the Copilot home dir (not the repo) and sessionRef.workspacePath is the CLI session-state dir - so any tool/canvas invocation without an explicit workingDirectory loaded the wrong repo's design system, leaking one repo's styles into another session.

Resolve the workspace strictly from authoritative per-invocation signals: hook input.workingDirectory (required by BaseHookInput) and canvas ctx.session.workingDirectory. The anchor (sessionWorkdir) starts null and is never seeded from process.cwd(); when unknown, loadDesign(null) falls back to the bundled sample - never another repo. Canvas actions now also consult ctx.session.workingDirectory.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Addresses review feedback on the design-system authority model:

- Colors are preview-only when a port target ships (native impl is
  canonical); agents bind each color's `resource` key (e.g. WinUI
  ThemeResource) instead of the preview hex.
- Colors carry Light/Dark/High-contrast preview values; canvas gains a
  theme switch and theme-aware CSS vars / swatches.
- Authority gains `owner` (who owns the canonical implementation) and
  `syncProcess` (how previews stay aligned), plus per-port `owner`.
- New validate.mjs smoke-check (schema/parse on design.json + structural
  check on components.jsx) surfaces drift: a port set without resource
  mappings, missing owner, or missing syncProcess. Wired to /api/validate,
  a canvas `validate` action, and a CLI runner (exits non-zero on error).
- Agent-facing context reframes design files as design SoT with the
  shipping implementation canonical when a port exists.
- Sample seeds Light/Dark/High-contrast so the toggle/validator are
  demonstrable out of the box.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- The canvas page background now follows the selected preview theme's
  app/page background (paper) with matching ink text, and the chrome's
  neutral tokens (surface/line/ink/muted) are routed through the design
  system's --color-* vars so the whole inspector — not just the live
  previews — reflects Light / Dark / High-contrast.
- Fix the sticky topbar: body used height:100%, which capped the body box
  at one viewport so the header unstuck after the first screen of scroll.
  Switch to min-height:100vh, and drop the stale -24px side margins left
  over from when the topbar lived inside .wrap.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- The validation result now renders in a fixed infobar pinned just below
  the sticky topbar (top offset derived from the topbar height, repositioned
  on resize) instead of inline in the document flow, so it stays visible
  while scrolling and no longer pushes content down. Opaque background,
  elevation shadow, and a short slide-in.
- The infobar now explains what validate actually checks: design.json
  parsing + core token groups and components.jsx structure, and — when a
  native port is declared — the resource/owner/syncProcess breadcrumbs that
  keep the design files and the shipping app from drifting apart. The copy
  adapts to whether a port is declared (no port -> drift checks don't apply).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The "Set up a design system" block only appears before setup and is rarely
needed once seeded, so make it a collapsible <details> disclosure with a
clickable summary header and a rotating chevron. The open/closed choice is
remembered best-effort in localStorage and defaults to open so first-run
stays guided. Native marker is hidden; keyboard focus ring added.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@karkarl
karkarl marked this pull request as ready for review July 20, 2026 16:44
@karkarl
karkarl requested a review from Copilot July 20, 2026 16:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reworks the Colophon canvas plugin to make the design-vs-shipping authority model explicit (including optional per-surface “port targets”), and improves the canvas UX with theme-aware chrome, sticky header behavior, a floating validation panel, and a collapsible setup section.

Changes:

  • Introduces an explicit authority/port model (authority, port targets/overrides, resource bindings) and threads it through summaries + AGENTS.md pointer framing.
  • Adds a validation workflow (CLI + /api/validate + canvas action/UI) to smoke-check .agents/design/ for schema/syntax and drift signals.
  • Improves canvas usability: Light/Dark/High-contrast previews, themed chrome tokens, sticky top bar fix, floating validation banner, and collapsible onboarding.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
skills/colophon/SKILL.md Updates skill guidance to reflect “design leads, implementation ships” and the new authority/port workflow.
README.md Documents authority/port targets and clarifies design intent vs shipped implementation.
plugin.json Updates plugin description to include port targets and the design-vs-implementation model.
extensions/colophon/validate.mjs Adds CLI/API validation for design.json + components.jsx (schema/syntax + drift-related checks).
extensions/colophon/styles.css Makes chrome theme-aware, fixes sticky behavior, adds theme switch + floating validation + collapsible onboarding styles.
extensions/colophon/sources.mjs Seeds authority in scratch tokens; scanner pre-fills port target for “looks native” repos and extends evidence.
extensions/colophon/sample/design.json Adds authority and per-theme color variants to the bundled sample.
extensions/colophon/renderer.mjs Adds theme switch UI and a validation slot near the top bar.
extensions/colophon/extension.mjs Anchors workdir to session signals, adds validate action + /api/validate, and enriches tool messaging for ported repos.
extensions/colophon/designio.mjs Implements authority parsing/normalization + port target rendering, preview-only color behavior, and themed CSS-var emission.
extensions/colophon/context.mjs Injects authority/port target guidance into summaries and hook-provided context.
extensions/colophon/client.js Adds theme switching, authority editor UI, per-theme color editing/preview, floating validation UI, and collapsible onboarding behavior.
.github/plugin/marketplace.json Updates marketplace description to match the new authority/port model.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread extensions/colophon/client.js
Comment thread extensions/colophon/renderer.mjs Outdated
Comment thread extensions/colophon/client.js
Comment thread extensions/colophon/validate.mjs
karkarl and others added 2 commits July 20, 2026 10:08
…me toggle

Resolves the actionable Copilot/dual-model review findings on #3:

- validate.mjs: the port drift contract (resource mapping on every color,
  authority.owner, authority.syncProcess) is now an ERROR when a port target
  is set, not a warning. Previously the CLI exited 0 even with the contract
  unfulfilled, so CI could not gate drift despite the docs claiming it did.
  Systems with no port target are unaffected (checks stay dormant).

- client.js setColorValueForTheme: editing the Light preview on a color that
  already carries a themes map now also updates the canonical `value`, so
  readers that prefer `value` (baseColorValue, summaries, validation) can no
  longer report a stale hex that disagrees with the light preview.

- renderer.mjs / client.js setTheme: theme toggle buttons now carry
  type="button" and aria-pressed, and setTheme keeps aria-pressed in sync so
  the selected theme is announced to assistive tech. type="button" added to
  the other topbar buttons too to avoid any default-submit behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Follow-up to the dual-model review on #3, fixing the two remaining findings:

- hasPort() now counts a port target only once it names a source/owner (and
  overrides only once they name an area/component/source), mirroring the
  server-side normalization in designio.normPortTarget/readAuthority. Before,
  toggling a port on and leaving every field blank flipped the canvas into
  preview-only mode even though the empty port was dropped on save — so what
  you saw before saving disagreed with what persisted. The local checkbox
  still keys off object presence (renamed hasDefaultPort) so the fields still
  appear the instant you toggle it on.

- render() now carries a generation counter and discards its post-await
  component append if a newer render started meanwhile. renderComponents()
  awaits a CDN fetch on first load, so a theme switch during that window could
  previously append a duplicate component section.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@karkarl
karkarl merged commit b2fb4f6 into main Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants