diff --git a/.claude/agents/codemod-runner.md b/.claude/agents/codemod-runner.md new file mode 100644 index 0000000000..66fa7c4be0 --- /dev/null +++ b/.claude/agents/codemod-runner.md @@ -0,0 +1,17 @@ +--- +name: codemod-runner +description: Writes and runs codemod scripts that replace hardcoded visual values with token references in ui/src/index.css. Use for Phase 2 of the design simplification run — mechanical refactors only. +tools: Read, Write, Edit, Bash, Glob, Grep +model: sonnet +--- + +You perform mechanical refactors via scripts, never hand-edits. Follow DESIGN.md at the repo root. + +Rules: + +- The token destination is ui/src/index.css (Tailwind v4), optionally a tokens.css imported by it. NEVER create a parallel token source. Tokens that must be runtime-tunable go in a NON-inline block — `@theme inline` bakes literals at build time. +- Where a hardcoded value EXACTLY matches an existing token, replace it with that token reference. Otherwise extract the value into a new token VERBATIM — no normalizing, rounding, or inventing a scale. Ugly values stay ugly. +- Every rewrite happens through a codemod script committed to scripts/ before it is run. Scripts must be idempotent and reviewable. +- Third-party style overrides that cannot use tokens go on a documented allowlist in the token source, each with an inline comment saying why. +- Verify after every script run: rg gates (zero hardcoded hex, zero arbitrary px/bracket values in ui/src/components/** and ui/src/pages/** outside the allowlist), pnpm typecheck, and the Storybook snapshot suite. Snapshots must match the Phase 0 baseline exactly. +- If a replacement cannot be made without visual change, skip it and record it in TOKEN-AUDIT.md under "Needs human decision". diff --git a/.claude/agents/token-auditor.md b/.claude/agents/token-auditor.md new file mode 100644 index 0000000000..e2c0922aaa --- /dev/null +++ b/.claude/agents/token-auditor.md @@ -0,0 +1,16 @@ +--- +name: token-auditor +description: Scans ui/src/ for hardcoded visual values, duplicate components, and shadcn replacement candidates; produces TOKEN-AUDIT.md and COMPONENT-INVENTORY.md. Read-only on source — never modifies component files. Use for Phase 1 of the design simplification run. +tools: Read, Grep, Glob, Bash +model: sonnet +--- + +You inventory design-system debt in this repository. Follow DESIGN.md at the repo root; read PRIOR-ART.md first — a previous audit found only 6 of ~220 drift sites were exact-value-mappable to existing tokens, so expect most hardcoded values to need new verbatim tokens. + +Your outputs (written to the repo root): + +1. TOKEN-AUDIT.md — every hardcoded color/spacing/radius/type/shadow value in ui/src/, with frequency, file locations, and near-duplicate clusters (e.g. 13/14/15px used interchangeably). For each value, note whether it EXACTLY matches one of the ~80 existing tokens in ui/src/index.css (semantic / brand / domain tiers — see DESIGN.md). Flag clusters for human review; never merge or normalize them. Include a "Needs human decision" section. + +2. COMPONENT-INVENTORY.md — all components under ui/src/components/ (24 primitives in ui/, ~277 feature components), their variants, and suspected duplicates with evidence (similar props, similar rendered output, copy-pasted origins). Include a "shadcn candidates" section: (a) custom components duplicating an available shadcn primitive, (b) installed shadcn components that drifted from the registry (npx shadcn@latest diff where available), (c) raw Radix/plain elements where an installed shadcn wrapper exists. For each, state the recommended replacement and expected visual impact. Recommendations only — merges and swaps happen in later human-approved runs, never this one. + +Never modify source files. Bash access is for read-only commands (rg, find, npx shadcn diff) and writing the two report files only. diff --git a/AGENTS.md b/AGENTS.md index ddefe527d6..de96a4170e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -220,3 +220,7 @@ PR #2218 (`feat/external-adapter-phase1`) adds external adapter support. See roo - `createServerAdapter()` must include ALL optional fields (especially `detectModel`) - Built-in UI adapters can shadow external plugin parsers; external override pause/resume should restore the built-in parser. - Reference external adapters: Droid (npm); Hermes can also be tested as an override package. + +## Design system + +`DESIGN.md` at the repo root is the source of truth for UI design decisions. The token-only rule applies to all `ui/` changes: every color, spacing, radius, type, shadow, and motion value comes from the token layer in `ui/src/index.css` — no hex, raw px, or arbitrary Tailwind bracket values in components. diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000000..e8cdffee9b --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,56 @@ +# Paperclip Design Principles + +**Status:** v0.3 — anchor document for design-language simplification. Governs structure, not brand. Brand values (color, type, iconography) are intentionally unspecified: they are being redesigned and will land as token values only. Nothing in `ui/` may hardcode them. Spacing/radius scales are likewise TBD pending the token audit (see Principle 3). + +Changes from v0.2: token layer location corrected to the repo's real source (`ui/src/index.css`); existing token tiers inventoried; snapshot-coverage scope bounded for Run 1; the issue→task copy rename moved out of the zero-visual-change run. + +## What this document is for + +Agents and humans modifying `ui/` treat this file as the source of truth for design decisions. Storybook is the verification surface — it documents the system; it does not define it. If a change conflicts with this document, change this document first (with review) or change the code. + +## Product stance + +Paperclip is an operational control plane: org charts, tasks, heartbeat runs, budgets, approvals, audit logs. The user is an operator scanning state and making decisions. Every screen should answer, in order: *what is happening, does it need me, what do I do about it.* Density in service of scanning beats whitespace in service of aesthetics — but density comes from information, never from chrome. + +## The token layer (where visual values live) + +The single token source is **`ui/src/index.css`** (Tailwind v4; there is no tailwind config file — tokens are CSS custom properties consumed via `@theme`). Do NOT create a parallel token source such as `ui/src/tokens/` — that would produce two sources of truth. If index.css grows unwieldy, extracted values may live in a `tokens.css` **imported by index.css** so the pipeline still has one root. + +Tailwind v4 gotcha: `@theme inline` bakes literal values at build time. Any token that must be runtime-tunable (theme editor, dark mode overrides) must be defined in a NON-inline block. + +Existing tiers already in index.css (~80+ tokens) — extraction maps to these on **exact value match** before minting anything new: + +1. **Semantic tier** — shadcn core set: `--background`, `--foreground`, `--card`, `--primary`, `--secondary`, `--muted`, `--accent`, `--destructive`, `--border`, `--input`, `--ring`, `--sidebar-*`, `--chart-1..5` (OKLCH, light/dark overrides). +2. **Brand tier** — agent gradients `--agent-1a/1b..10a/10b` (fixed hex) and status hues `--status-task-*` / `--status-agent-*` (WCAG-tuned; see inline comments). +3. **Domain tier** — match-chip tokens `--chip-match-*`, annotation highlights `--paperclip-doc-annotation-highlight-*`, plus motion/typography tokens. + +## Principles + +1. **One way to say each thing.** One component per job. One Button, one Card, one Badge, one Table, one EmptyState. Variants are props, not new components. Before creating a component, prove no existing one covers the job. +2. **Tokens are the only source of visual values.** All color, spacing, radius, type size/weight, shadow, and motion values come from the token layer. No hex, no raw px, no ad-hoc Tailwind arbitrary values (`p-[13px]`) in components. If a needed value doesn't exist, add a token — don't inline it. +3. **Spacing routes through tokens; the scale comes later.** During simplification, extract every spacing and radius value verbatim into tokens — do not normalize, round, or invent a scale. The final scale is a design decision made by a human after reviewing the token audit. Structural rules apply now: vertical rhythm within a container uses one gap value, not per-element margins, and siblings never carry both margin and gap. +4. **Hierarchy through structure, not decoration.** Prefer position, size, and weight over borders, backgrounds, and dividers. Every border, divider, and background fill must justify itself; when in doubt, remove it. A screen should survive the removal of one visual layer. +5. **Status is systematic.** States like running / paused / blocked / awaiting-approval / over-budget map to a single semantic status token set used identically everywhere (badge, row, chart, log). An operator learns the vocabulary once. +6. **Machine values look machine-made.** IDs, costs, token counts, timestamps, and log output use the monospace token and consistent formatting helpers. Never format these ad hoc per screen. +7. **Words are part of the system.** One name per concept across the entire UI — the canonical term is *task* (never *issue* or *ticket* in copy, labels, or empty states). Buttons name the action ("Approve hire," not "Submit"). Errors say what happened and what to do. Empty states say what to do first. **Note:** enforcing the task rename is a visible change and is explicitly OUT of the zero-visual-change extraction run; it happens in its own follow-up run. +8. **Agent-modifiable by design.** The system must be changeable via instructions: single token source, lint rules that enforce it, and this document kept current. A correct change should be expressible as "edit tokens + run checks," not "visit 40 files." + +## Enforcement (what "compliant" means for the extraction run) + +- **Zero visual change is proven, not promised:** Storybook visual snapshots are baselined before any refactor, and all snapshots match baseline after it. A change that alters rendered output must be intentional and human-approved. +- **Baseline scope for Run 1:** the shared primitives in `ui/src/components/ui/` (each gets a story if missing — there are only ~24) plus the ~46 existing stories under `ui/storybook/stories/`. Do NOT attempt a story for every feature component (~277) in this run; full coverage is a later effort. +- Mechanical rewrites (value extraction, renames) are done via committed codemod scripts in `scripts/`, not hand-edits — reviewable once, repeatable forever. +- Token layer is the single source (`ui/src/index.css`, per above) consumed via CSS variables / Tailwind theme — never values copied into components. +- Lint/grep gates pass: zero hardcoded hex values, zero arbitrary spacing values, zero raw font-size declarations in `ui/src/components/**` and `ui/src/pages/**` outside the token layer and a documented allowlist (third-party overrides, intentional opt-outs commented inline). +- `pnpm build`, `pnpm typecheck`, and `pnpm build-storybook` pass. +- AGENTS.md links here and states the token-only rule. + +Aspirational (NOT gating this run): no duplicate components; every component has exactly one story covering its variants; all UI copy says "task". + +## Out of scope (do not do during simplification) + +No visual redesign, no new colors or typefaces, no layout restructuring, no new dependencies beyond snapshot tooling, no component consolidation/merges (audit + recommend only), no copy renames, no changes to server code or app logic. Simplification means fewer parts, same product. + +## Prior art (read before auditing) + +See `PRIOR-ART.md` — a previous audit pass (PAP-280/283/284, on the `PAP-282-playground` branch, NOT on master) found that of ~220 hardcoded drift sites, only 6 were exact-value-mappable to existing tokens; expect the verbatim extraction to mint many new tokens that the human scale-collapse step later merges. It also drafted usage rules (radius tiers, CTA tiers, named type styles) that are good candidates for the post-audit scale decision. diff --git a/GOAL-PROMPT.md b/GOAL-PROMPT.md new file mode 100644 index 0000000000..8c17fb90f8 --- /dev/null +++ b/GOAL-PROMPT.md @@ -0,0 +1,103 @@ +# /goal Prompt — Design Language Simplification, Run 1 (v2) + +Paste everything inside the code block below into Claude Code after typing `/goal`, from inside this worktree. Prerequisites already satisfied on this branch: DESIGN.md, PRIOR-ART.md, KNOWN-DUPLICATES.md at repo root; token-auditor + codemod-runner in `.claude/agents/`. + +v2 changes vs v1: token destination corrected to `ui/src/index.css`; Phase 0 snapshot scope bounded; component consolidation (old Phase 3) and the issue→task rename REMOVED from this run (they become their own human-gated follow-up runs); DONE-WHEN expressed as runnable commands. + +``` +Refactor Paperclip's UI so every visual value flows through the single +existing token layer, with provably zero visual change, working in this +isolated git worktree. DESIGN.md at the repo root is the source of truth +for all design decisions; follow it exactly. Read PRIOR-ART.md before +auditing. + +SETUP +You are already inside a dedicated git worktree on branch +design/token-extraction. All work happens here. Never touch master, +switch branches, create new worktrees, or modify other working trees. +Commit after each phase and in small, reviewable steps within phases, +with descriptive messages. + +WORK IN PHASES, IN ORDER +Delegate Phase 1 to the token-auditor subagent and Phase 2 to the +codemod-runner subagent (defined in .claude/agents/). Handle Phase 0 +yourself. Hand context between phases through the committed report +files, not conversation memory. + +Phase 0 — Baseline (before changing ANY component): +- Set up Storybook visual snapshot testing (Storybook test-runner with + image snapshots, or equivalent already-compatible tooling; Storybook + lives at ui/storybook/, launched via `pnpm storybook`). +- Coverage scope: the shared primitives in ui/src/components/ui/ (add a + minimal story for any of the ~24 that lack one) plus all existing + stories under ui/storybook/stories/. Do NOT write stories for the + ~277 feature components in this run. +- Commit passing baseline snapshots. Every later phase must keep + snapshots matching this baseline. + +Phase 1 — Audit (no code changes): +- Produce TOKEN-AUDIT.md at the repo root: every hardcoded + color/spacing/radius/type/shadow value in ui/src/, its frequency, + file locations, and near-duplicate clusters (e.g. 13/14/15px used + interchangeably). Flag clusters for human review — do NOT merge them. + Cross-reference the existing ~80 tokens in ui/src/index.css: for each + hardcoded value, note whether it exactly matches an existing token. +- Produce COMPONENT-INVENTORY.md: all components, their variants, and + suspected duplicates with evidence (similar props, similar rendered + output, copy-pasted origins). Include a "shadcn candidates" section: + (a) custom components duplicating an available shadcn primitive, + (b) installed shadcn components drifted from the registry + (npx shadcn@latest diff where available), (c) raw Radix/plain + elements where an installed shadcn wrapper exists. For each, state + the recommended replacement and expected visual impact. + ALL consolidation and swap items are RECOMMENDATIONS ONLY — no + merges, no swaps, no deletions in this run. + +Phase 2 — Extraction (mechanical, via codemod): +- Token destination is ui/src/index.css (Tailwind v4; optionally a + tokens.css imported by index.css). Do NOT create a parallel token + source. Tokens that must be runtime-tunable go in a NON-inline + @theme/:root block (inline @theme bakes literals). +- Where a hardcoded value EXACTLY matches an existing token, replace it + with that token. Otherwise add a new token containing the audited + value VERBATIM — no normalizing, rounding, or inventing a scale. + Ugly values stay ugly; they are the audit. +- Write codemod scripts, committed to scripts/, that perform the + replacements. Run them. Do not hand-edit values file-by-file. +- Third-party style overrides that cannot use tokens go on a documented + allowlist in the token source, each with an inline comment saying why. + +DONE WHEN (all verified in this worktree) +1. The snapshot suite passes against the Phase 0 baseline — zero + visual change. +2. ui/src/index.css (plus any imported tokens.css) is the only token + source; components consume values only through it. +3. rg gates pass: zero hex color literals, zero arbitrary + px/bracket-value Tailwind classes, zero raw font-size declarations + in ui/src/components/** and ui/src/pages/** outside the documented + allowlist. +4. TOKEN-AUDIT.md and COMPONENT-INVENTORY.md exist, are current, and + each has a "Needs human decision" section (even if empty). +5. pnpm build, pnpm typecheck, and pnpm build-storybook all exit 0. + +GUARDRAILS +- Preserve rendered output exactly. If a replacement cannot be made + without visual change, skip it and record it in TOKEN-AUDIT.md under + "Needs human decision", and move on. +- No redesign, no layout changes, no new colors/typefaces, no component + merges or deletions, no copy renames (including issue→task — that is + a separate later run), no new dependencies beyond snapshot tooling, + no server/app-logic changes. +- If reality conflicts with DESIGN.md, note the conflict in + TOKEN-AUDIT.md instead of guessing. +- If a phase cannot be completed, stop and report rather than partially + applying it. +``` + +## After the run (human steps) + +1. Eyeball pass: `pnpm storybook` here and in the master tree (`-p 6007`), flip between tabs. +2. Read TOKEN-AUDIT.md; choose the real spacing/radius scale (PRIOR-ART.md has drafted rules to start from). +3. Tune tokens; snapshots now fail intentionally — the diff folders are your design-review contact sheet. This is also where the ui.shadcn.com/create preset lands, as token-value edits. +4. Review COMPONENT-INVENTORY.md; approve a merge list and shadcn-swap list → those become Run 2 and Run 3, each its own /goal. +5. Merge to master when satisfied (rebase first if master moved). Scrap path: `git worktree remove ../paperclip-design-simplify --force`. diff --git a/KNOWN-DUPLICATES.md b/KNOWN-DUPLICATES.md new file mode 100644 index 0000000000..82b08cc8c3 --- /dev/null +++ b/KNOWN-DUPLICATES.md @@ -0,0 +1,14 @@ +# Known duplicates & off-limits areas (human-maintained) + +Seed list for the audit. Add components you already believe are redundant, and any screens the run must not touch. The auditor treats entries here as leads to verify, not verdicts. + +## Suspected duplicates / overlap (leads) + +- Chat composers: the shared `ChatComposer` vs `MarkdownEditor`-based task composer — deliberately NOT unified in a prior pass (PAP-101); audit the overlap but flag as "Needs human decision". +- Agent bubble action rows: `AgentBubbleActionRow.tsx` had two parallel implementations created by concurrent work at one point — verify only one remains. +- Status glyphs/chips: `StatusIcon` vs inline-mention chips vs task chips — intentionally separate systems per prior work; document, don't merge. + +## Off-limits in this run + +- `ui/src/components/theme-editor/` and anything under experimental theme/playground paths, if present on this branch. +- Server code, adapters, CLI — everything outside `ui/`. diff --git a/PRIOR-ART.md b/PRIOR-ART.md new file mode 100644 index 0000000000..695f805e46 --- /dev/null +++ b/PRIOR-ART.md @@ -0,0 +1,21 @@ +# Prior art: PAP-280 design-token audit (branch `PAP-282-playground`, not on master) + +A previous audit/relink pass ran against this codebase in mid-2026. Its code never merged to master, but its findings are directly reusable by the token audit. Read this before Phase 1. + +## Key findings to inherit + +- **Drift is mostly NOT same-value-mappable.** The relink pass (commit `032d6c8db` on the branch) attempted to swap hardcoded values for existing semantic tokens *without visual change* and found only **6 exact-value swaps** possible (`text-muted-fg`, `rounded-md`) out of ~220 audited drift sites (~193 color / 23 radius / 7 type). Implication for Phase 2: expect to mint many new verbatim tokens; do not force-fit near-misses onto existing tokens — that changes pixels. +- **Token gap clusters identified** (commit `96689351d`): recurring un-tokenized needs were a code-surface background, an accent blue, and a muted feed text color — these became `--surface-code`, `--accent-blue`-style gap tokens on the branch. Audit should check whether the same clusters still dominate. +- **Tailwind v4 tunability gotcha** (learned the hard way): `@theme inline` bakes literals at build time; tunable tokens must live in a non-inline block. + +## Drafted usage rules (branch commit `6ba86cd4f` — candidates for the human scale decision, NOT current master state) + +- **Radius:** one monotonic scale `sm 6 / md 8 / lg 10 / xl 14 / 2xl 16 / full`. Assignments: sm=chips/badges/pills; md=buttons/inputs/menu items (default); lg=cards/popovers/panels; xl=dialogs/sheets/overlays; 2xl=hero/onboarding only; full=avatars/dots/capsules. Nested elements step down one tier from their container. (Master's current values differ — verify in the audit.) +- **CTA tiers:** three-tier button prominence — Primary (`default`/`destructive`): the single commit action per view; Secondary (`secondary`/`outline`): supporting actions; Tertiary (`ghost`/`link`): row actions, cancels, toolbar icons. +- **Type styles:** nine named intent styles (backed by `--text-*` tokens incl. `micro` 11px / `nano` 10px) instead of re-deriving `text-lg font-semibold` per call site. Color is a separate axis. +- **Drift-prevention contract:** no raw hex for chrome — use `background / card / muted / accent / border / muted-foreground`; when a needed value has no token, add a semantic token; intentional opt-outs (code/terminal blocks) carry a comment saying why, so a future re-link pass leaves them alone. + +## Reusable machinery on the branch + +- A theme playground / theme editor with portable `*.theme.json` export-import (whole-app live retheme, A/B compare). Useful later for the human scale-collapse and brand/preset tune steps — not needed for the extraction run. +- `.claude/skills/design-guide/` skill + `ui/src/pages/DesignGuide.tsx` showcase page (branch versions are richer than master's).