23 KiB
Session log
This file tracks work completed across Claude Code sessions. Every agent MUST read this file before starting work and update it after completing work.
Format
Each entry follows this structure:
### Session [date] — [brief description]
**Agent(s):** [which agents were active]
**Work completed:**
- [bullet points of what was done]
**Decisions made:**
- [any design/architecture decisions with brief rationale]
**Open questions:**
- [anything unresolved that needs human input]
**Next steps:**
- [what should happen next]
Sessions
Session 2026-03-24 — Project scaffold setup and hygiene
Agent(s): Manual (no agents invoked — setup phase)
Work completed:
- Fixed missing
.storybook/directory (main.ts + preview.tsx with MUI ThemeProvider) - Created
.gitignore(was missing entirely) - Created
.mcp.jsonwith Figma remote MCP config - Removed malformed
{.claude/agents,.claude/...}directory tree (bash brace expansion bug) - Created 3 agent definitions: token-architect, component-builder, story-writer
- Created 8 slash commands: create-tokens, build-atom, build-molecule, build-organism, write-stories, sync-tokens, status, review-component
- Migrated commands from
.claude/commands/to.claude/skills/<name>/SKILL.mdformat with YAML frontmatter - Fixed critical Style Dictionary v4 config: converted from CommonJS to ESM (
StyleDictionaryclass API) - Changed
build:tokensscript fromstyle-dictionary build --config ...tonode style-dictionary/config.js - Added
"type": "module"to package.json for ESM support - Changed SD output from
tokens.tstotokens.js(Style Dictionary v4 generates JS, not TS) - Registered
@storybook/addon-designsin.storybook/main.ts(was installed but not configured) - Added CSS token import to
.storybook/preview.tsx - Added Card and Link to CLAUDE.md atom list (were missing)
- Fixed broken Penpot/Storybook MCP references in
docs/reference/mcp-setup.md - Improved agent instructions with pre-flight dependency checks, story checklist enforcement, token validation steps, and MUI theme mapping guide
- Created
src/components/{atoms,molecules,organisms}/directories - Fixed
bootstrap.shto check for.storybook/dir instead ofnode_modules/@storybook - Verified
npm run build:tokensruns successfully (empty output expected — no tokens yet) - Verified Storybook runs at http://localhost:6006
Decisions made:
- Skills use
.claude/skills/<name>/SKILL.mdformat (not.claude/commands/) - Style Dictionary v4 config is a standalone ESM script run via
node, not CLI - British spelling for filenames (
colours.json), standardcolornamespace for token paths
Open questions:
- Slash commands
/create-tokensetc. showing "Unknown skill" — may need Claude Code restart to discover newly created skills. User should test after restarting.
Next steps:
Verify slash commands work after Claude Code restart✓ Skills workingBegin Step 1:✓ Done/create-tokenswith brand colours, fonts, and reference material
Session 2025-03-25 — Token creation (Step 1)
Agent(s): token-architect (via /create-tokens skill)
Work completed:
- Extracted brand colours from user-provided swatch image (12 colours across 3 palettes)
- Reviewed 5 Parsons FA 1.0 Figma screens for colour application context
- Reviewed 2 FA 2.0 Design System Template screens (buttons + inputs)
- Created complete primitive tokens:
- Colour scales (50-950): brand (warm gold), sage (cool grey-green), neutral, red, amber, green, blue + white/black
- Typography: 3 font families (Montserrat, Noto Serif SC, JetBrains Mono), font size scale (xs-4xl + mobile), weights, line heights, letter spacing
- Spacing: 4px-based scale (2px-80px), border radius scale
- Effects: 4 shadow levels, 3 opacity values
- Created complete semantic tokens:
- Colour mappings: text (9 variants), surface (6), border (6), interactive (7), feedback (8)
- Typography roles: display, h1-h4, bodyLarge, body, bodySmall, caption, label, overline — each with font family, size, weight, line height, letter spacing + mobile size overrides
- Spacing: component (xs-lg), layout (gutter, section, page, padding) with mobile/desktop variants
- Fixed Style Dictionary v4.4.0 CSS output: added
usesDtcg: trueflag (required for DTCG format CSS generation) - Generated outputs:
- CSS: 245 custom properties in
src/theme/generated/tokens.csswithvar()references for semantic tokens - JS: 258 named exports in
src/theme/generated/tokens.js - JSON: flat export in
tokens/export/tokens-flat.json
- CSS: 245 custom properties in
- Updated MUI theme (
src/theme/index.ts):- All palette colours mapped from token imports
- All typography variants mapped (h1-h6, body1, body2, subtitle1/2, caption, overline, button)
- 3 custom typography variants added: display, bodyLarge, label (with TS module declarations)
- Responsive font sizes via @media queries for display, h1, h2, h3
- Component overrides for Button and Card border radius
- Updated docs/design-system.md with actual brand colours, palettes, and font stacks
- Updated docs/memory/decisions-log.md with 8 design decisions (D001-D008)
- Updated docs/memory/token-registry.md with complete token reference
Decisions made:
- D001: Primary brand colour is #BA834E (warm gold from swatch)
- D002: Primary text colour is #2C2E35 (charcoal, not pure black)
- D003: Brand link colour uses #B0610F (copper, meets WCAG AA)
- D004: Sage palette as secondary (calming contrast to warm primary)
- D005: Noto Serif SC for display/H1-H2, Montserrat for H3+ and body
- D006: Warning text uses amber.700 for AA compliance
- D007: Style Dictionary requires usesDtcg: true for CSS output
- D008: Responsive typography via explicit @media queries in MUI theme
Open questions:
- Font name confirmation: user wrote "Not Serif SC" — interpreted as "Noto Serif SC" (Google Font). Needs confirmation.
- brand.500 (#BA834E) has 3.7:1 contrast on white — AA for large text only. Primary buttons use white text on this background, which works for button-sized text. Should we darken the primary CTA colour for better accessibility, or is the current value acceptable?
- Token collision warning: benign collision on
$type: "color"set in both primitives and semantic colour files. Doesn't affect output.
Next steps:
Confirm display font name (Noto Serif SC vs something else)Begin Step 2: Build first atom component (Button recommended as it exercises the most tokens)✓ Done- Consider adding Google Fonts import for Montserrat and Noto Serif SC to index.html or Storybook preview
Session 2026-03-25 — Button atom (Step 2)
Agent(s): Claude Opus (via conversation)
Work completed:
- Reviewed 3 Figma component sets: Icons (29:54), Button (28:50), Text Button (32:1361)
- Created button component tokens (
tokens/component/button.json): height, paddingX, paddingY, fontSize, iconSize, iconGap, borderRadius for xs/sm/md/lg sizes - Rebuilt token pipeline — 25 new button tokens generated across CSS/JS/JSON outputs
- Updated MUI theme (
src/theme/index.ts) with comprehensive MuiButton overrides:- 4 sizes: xs (28px), small (32px), medium (40px), large (48px)
- Contained, outlined, text variants for primary and secondary colours
- Hover backgrounds using brand.100 and sage.100 for outlined/text variants
- Focus-visible outline (2px solid interactive.focus, 2px offset)
- Disabled elevation via
disableElevation: truedefault prop - Custom
xssize via MUI variant system + module augmentation
- Created Button component (
src/components/atoms/Button/Button.tsx):- Wraps MUI Button with React.forwardRef
- Custom props:
loading(spinner + disabled),underline(text-decoration for text variant) - Accepts all MUI ButtonProps (variant, color, size, startIcon, endIcon, fullWidth, etc.)
- Created barrel export (
src/components/atoms/Button/index.ts) - Created comprehensive Storybook stories (
Button.stories.tsx): 16 stories covering Default, Variants (primary/secondary), AllSizes, Icons, Disabled, Loading, TextWithUnderline, FullWidth, LongContent, CompleteMatrix - Storybook builds successfully with Button stories
Decisions made:
- D009: Merge Text Button into Button atom — text buttons are
variant="text"with optionalunderlineprop, not a separate component - D010: Button sizes adjusted for touch targets — xs: 28px, sm: 32px, md: 40px, lg: 48px (lg meets 44px minimum)
- D011: Use
@mui/icons-materialover Font Awesome — native MUI integration, no adapter needed, tree-shakeable - D012: Responsive sizing is a composition concern — Button size is an explicit prop, not responsive by default. Layouts choose the right size per breakpoint.
Open questions:
- primary.main maps to brand.600 (copper #B0610F) for AA compliance, but Figma designs show brand.500 (warm gold #BA834E) as primary button fill. Should we adjust? Current mapping prioritises accessibility.
- Google Fonts import still needed for Montserrat and Noto Serif SC in Storybook
- Icon approach confirmed as @mui/icons-material — should we create any custom SvgIcon components for FA-specific icons?
Next steps:
User to review Button in Storybook and provide feedback on colours/sizing✓ Feedback received- Build Typography atom
- Add Google Fonts to Storybook preview
Log D009-D012 in decisions-log.md✓ Done
Session 2026-03-25b — Button refinements from user review
Agent(s): Claude Opus (via conversation)
Work completed:
- Fetched Figma Secondary/Brand and Secondary/Grey button details — discovered they are soft-filled (tonal) buttons, not outlined
- Added custom
variant="soft"to MUI Button — tonal/muted fill treatment- Primary soft: brand.200 bg (#EBDAC8), brand.700 text (#8B4E0D), brand.300 hover
- Secondary soft: neutral.200 bg (#E8E8E8), neutral.700 text (#404040), neutral.300 hover
- Changed MUI secondary palette from sage to neutral grey (neutral.600 main, neutral.700 dark, neutral.300 light)
- Updated all secondary button overrides (outlined, text) from sage to neutral
- Moved loading spinner from left to right side of button text
- Updated stories: added FigmaMapping story, soft variant stories, LoadingToSuccess pattern story
- Logged D013-D015 in decisions log
Decisions made:
- D013: Added
softvariant for tonal buttons — maps to Figma Secondary/Brand and Secondary/Grey - D014: Secondary palette changed from sage to neutral grey
- D015: Loading spinner positioned on right
Open questions:
- primary.main maps to brand.600 (copper #B0610F) for AA compliance, but Figma designs show brand.500 (warm gold #BA834E) as primary button fill. Should we adjust?
- Google Fonts import still needed for Montserrat and Noto Serif SC in Storybook
- Icon approach confirmed as @mui/icons-material — should we create any custom SvgIcon components for FA-specific icons?
- Sage palette no longer used for buttons — consider if it should be re-introduced as a custom colour later
Next steps:
User to re-review Button in Storybook✓ Approved as good baselineBuild Typography atom✓ DoneAdd Google Fonts to Storybook preview✓ Done
Session 2026-03-25c — Typography atom + housekeeping
Agent(s): Claude Opus (via conversation)
Work completed:
- Added Google Fonts loading: Montserrat (400/500/600/700) + Noto Serif SC (600/700) in
.storybook/preview-head.htmlandindex.html - Created Typography component (
src/components/atoms/Typography/Typography.tsx):- Thin wrapper around MUI Typography with React.forwardRef
- Custom prop:
maxLinesfor CSS line-clamp truncation - All MUI Typography props passed through (variant, color, align, component, gutterBottom, etc.)
- Created barrel export (
src/components/atoms/Typography/index.ts) - Created comprehensive Storybook stories (9 stories): Default, HeadingHierarchy, BodyVariants, UIText, Colours, SemanticHTML, MaxLines, RealisticContent, FontFamilies
- Added "Future enhancements" tracking table to component-registry.md — deferred items (IconButton, destructive colours, link-as-button) tracked with triggers for when to address them
- Logged D016 (primary colour confirmed as copper brand.600) in decisions-log.md
- Storybook builds successfully
Decisions made:
- D016: Primary button colour confirmed as copper (brand.600) — user approved
- Typography atom is a thin wrapper + maxLines — no over-engineering
Open questions:
- Icon approach confirmed as @mui/icons-material — should we create any custom SvgIcon components for FA-specific icons?
- Sage palette no longer used for buttons — consider if it should be re-introduced as a custom colour later
Next steps:
- User to review Typography in Storybook
- Build next atom (Input or Card recommended — Input for forms, Card for service listings)
- Consider building FormField molecule next if Input is done (label + input + helper text)
Session 2026-03-25d — Typography expansion (21 variants)
Agent(s): Claude Opus (via conversation)
Work completed:
- Reviewed user's FA 2.0 Figma type scale (node 23:30) — 21 variants across 6 categories, 3 responsive breakpoints
- Expanded primitive typography tokens: added fontSize.2xs (11px), fontSize.display.* sub-group (hero 80px through sm 32px), mobile overrides for all display and heading sizes
- Rewrote semantic typography tokens: 21 variants with specific line-heights and letter-spacing per variant
- Rewrote MUI theme typography section: refactored to wildcard import (
import * as t), added all 21 variants with module augmentations, responsive scaling via @media queries - Updated Google Fonts: added Noto Serif SC weight 400 (Regular) for display text
- Updated Typography component JSDoc with full variant guide
- Rewrote Typography stories: 10 stories including CompleteScale (all 21 variants matching Figma layout)
- Key font changes: headings now Montserrat Bold (not serif), display now Regular 400 (not Bold), body now Medium 500 (not Regular)
Decisions made:
- D017: Headings use Montserrat Bold, not Noto Serif SC (supersedes D005)
- D018: Display weight is Regular 400, not Bold
- D019: Body weight is Medium 500 (user preference, 450 not available)
- D020: 21 typography variants across 6 categories
Next steps:
User to review expanded type scale in Storybook✓- Fine-tune heading sizes if they don't match Figma exactly (h2-h6 were estimated)
Build next atom (Input or Card)✓ Input done
Session 2026-03-25e — Input atom
Agent(s): Claude Opus (via conversation)
Work completed:
- Reviewed FA 2.0 Figma Input Field design (node 39:713) — 9 states × 4 toggle properties = ~90 variants
- Analysed Figma design and provided feedback: identified 7 improvements (leading icons, size variation, required indicator, select vs input naming, multiline, character count, error icon treatment)
- Created Input component tokens (
tokens/component/input.json): height (sm/md), paddingX, paddingY (sm/md), fontSize, borderRadius, gap, iconSize — 9 tokens total - Rebuilt token pipeline — 9 new input tokens generated across CSS/JS/JSON outputs
- Updated MUI theme (
src/theme/index.ts) with comprehensive MuiOutlinedInput overrides:- Border colours per state: neutral.300 default, neutral.400 hover, brand.500 focus, error/success for validation
- Focus ring: double box-shadow (2px white gap + 4px brand.500) matching Figma's elevation-special/focus-ring effect
- Error + focus ring: error-coloured ring
- Disabled background: neutral.100
- Two sizes via minHeight: medium (48px), small (40px)
- Icon sizing: 20px via InputAdornment
- Notch legend hidden for external label pattern
- Multiline padding normalisation
- Created Input component (
src/components/atoms/Input/Input.tsx):- Composes FormControl + InputLabel + OutlinedInput + FormHelperText
- External label pattern (InputLabel with position:static, no floating)
- Custom props:
label,helperText,success,startIcon,endIcon,fullWidth - Label stays neutral on error/focus/success (per Figma design)
- Required asterisk on label (via MUI InputLabel)
- Success state: green border + green helper text (not a native MUI state)
- Error helper text has
role="alert"for screen readers aria-describedbyconnection between input and helper text- Supports multiline via
multiline+rows/minRows/maxRows
- Created barrel export (
src/components/atoms/Input/index.ts) - Created comprehensive Storybook stories (11 stories): Default, FigmaMapping, AllStates, Required, Sizes, SizeAlignment, WithIcons, PasswordToggle, Multiline, ValidationFlow, ArrangementForm, CompleteMatrix
- Logged D021-D025 in decisions log
- Updated component registry (Input → review)
- Storybook builds successfully
Decisions made:
- D021: External label pattern, not MUI floating label
- D022: Two sizes — medium 48px (matches Button large), small 40px (matches Button medium)
- D023: Focus ring uses brand.500 warm gold (Figma spec), not brand.600
- D024: Label stays neutral on error/success (calmer for FA audience)
- D025: Added startIcon/endIcon convenience props and success validation state
Open questions:
- Should error+focus ring be error-coloured or brand-coloured? Currently error-coloured (reinforces the validation state during keyboard navigation)
- FormField molecule may now be unnecessary — Input already includes label + helper text. Consider repurposing FormField as a layout/validation wrapper instead.
- Should we add a character count feature? (Useful for textarea fields like special instructions)
Next steps:
User to review Input in Storybook✓Build next atom (Card, Badge, or Chip recommended)✓ Card done- Consider whether FormField molecule is still needed given Input's built-in label/helperText
Session 2026-03-25f — Card atom
Agent(s): Claude Opus (via conversation)
Work completed:
- Created card component tokens (
tokens/component/card.json): borderRadius, padding (default 24px / compact 16px), shadow (default md / hover lg), border, background — 7 tokens total - Rebuilt token pipeline — 7 new card tokens generated across CSS/JS/JSON outputs
- Updated MUI theme (
src/theme/index.ts) with MuiCard overrides:- Root: card token border radius, background, resting shadow (shadow.md), smooth transition
- Outlined variant: no shadow, card border colour
- Created Card component (
src/components/atoms/Card/Card.tsx):- Two visual variants: elevated (shadow, default) and outlined (border)
interactiveprop: hover shadow lift (shadow.lg), pointer cursor, focus-visible outlinepaddingprop: "default" (24px), "compact" (16px), "none" (raw children for full-bleed)- Uses CardContent internally for padded variants; raw children when none
- Thin wrapper pattern consistent with Button and Typography
- Created barrel export (
src/components/atoms/Card/index.ts) - Created 8 Storybook stories: Default, Variants, Interactive, PaddingPresets, PriceCardPreview, ServiceOptionPreview, WithImage, RichContent
- Preflight passed all 5 checks
- Committed and pushed to Gitea
Decisions made:
- Card uses MUI spacing units (p: 4/6) for padding presets rather than CSS variables — consistent with MUI-first approach
- Elevation set to 0 on MuiCard; box-shadow applied directly from card tokens for precise control
- Interactive hover uses CSS variable (
var(--fa-card-shadow-hover)) for shadow.lg - No new design decisions needed — Card follows existing token/design conventions from design-system.md
Open questions:
- Should interactive cards have a subtle border-colour change on hover in addition to shadow lift?
- Should we add a "selected" state for ServiceOption-style cards (e.g., brand border + brand.50 background)?
Next steps:
User to review Card in Storybook✓ Feedback received — add selected + hover bg
Session 2026-03-25g — Card selected state + hover background
Agent(s): Claude Opus (via conversation)
Work completed:
- Reviewed FA 1.0 Figma designs for card usage patterns:
- ListItemPurchaseOption (2349:39505): selectable cards with 4 states × 2 viewports
- ListItemAddItem (2350:40658): toggle/switch pattern — deferred to future Toggle component
- Added
selectedprop: brand border (2px, warm gold #BA834E) + warm background (brand.50 #FEF9F5) - Added hover background fill: interactive cards now fill with neutral.50 on hover (matching Figma's inactive→hover pattern)
- Hover on selected cards preserves warm background instead of switching to neutral
- Elevated interactive cards still get shadow lift on hover; outlined ones only get bg fill
- Added 3 new card tokens: border.selected, background.hover, background.selected
- Added 4 new stories: Selected, OptionSelect (single-select with radio semantics), MultiSelect (checkbox toggle), OnDifferentBackgrounds (white vs grey surface)
- Replaced ServiceOptionPreview story with the more complete OptionSelect and MultiSelect patterns
- Preflight passed all 5 checks
- Committed and pushed to Gitea
Decisions made:
- Selected state uses 2px brand border (not 1.5px from Figma 1.0) — 2px aligns with our focus ring width and sits on the 2px sub-grid
- Selected background uses brand.50 (warm tint) not neutral.50 (grey) — warm tint reinforces the brand connection and distinguishes selected from hovered
- Hover bg fill uses neutral.50 (not brand.50) for unselected cards — keeps hover subtle and neutral
- Toggle/switch pattern from Figma (ListItemAddItem) is a separate component concern, not Card
Next steps:
User to review Card selected/hover states in Storybook✓ ApprovedBuild Badge or Chip atom next✓ Badge done
Session 2026-03-25h — Badge atom
Agent(s): Claude Opus (via conversation)
Work completed:
- Searched FA 2.0 and Parsons 1.0 Figma files for badge/chip/tag components — none found, designed from conventions
- Created badge component tokens (
tokens/component/badge.json): height, paddingX, fontSize, iconSize, iconGap, borderRadius for sm/md — 10 tokens total - Built Badge component (
src/components/atoms/Badge/Badge.tsx):- Pill-shaped, display-only status indicator (not interactive)
- 6 colour intents: default, brand, success, warning, error, info
- 2 variants: soft (tonal bg + coloured text, default) and filled (solid bg + white text)
- 2 sizes: small (22px) and medium (26px)
- Optional leading
iconprop for contextual icons - All soft colours use CSS variables from token system — no hardcoded hex
- Warning text uses amber.700 for WCAG AA compliance
- Created 10 Storybook stories including realistic compositions (InPriceCard, ServiceStatus)
- Preflight passed all 5 checks
- Committed and pushed to Gitea
Decisions made:
- Badge defaults to soft variant — calmer, more appropriate for FA's sensitive context. Filled variant for high-priority emphasis only.
- Badge uses Box (span) not MUI Chip — keeps it simple, display-only, no interactive baggage
- Pill shape (borderRadius.full) distinguishes badges from rectangular UI elements
- Brand soft colours match Button soft (brand.200 bg, brand.700 text) for visual consistency
Next steps:
- User to review Badge in Storybook
- Build Chip atom next (interactive variant of badge — clickable, deletable)
- Begin PriceCard molecule once Badge and Card are both approved