[AI] Add impeccable design skill and project design context (#8653)

* [AI] Add impeccable design skill wiring and project design context

Commit only the shareable parts of the impeccable frontend-design skill
setup: defensive hook wiring (.codex, .cursor, .github hooks that no-op
when the skill is not installed locally) and the generated design
context files (PRODUCT.md, DESIGN.md, DESIGN.json) derived from the
existing component-library tokens and themes. The skill payload itself
is gitignored; developers install it locally.

Co-Authored-By: Claude Fable 5 <[email protected]>

* [AI] Recommend installing the impeccable skill to agents at boot

AGENTS.md documents the install step, a Claude Code SessionStart hook
surfaces it when the skill is missing from the checkout, and the Codex
and Copilot hook wiring echoes the same hint instead of silently
no-oping.

Co-Authored-By: Claude Fable 5 <[email protected]>

* [AI] Mention DESIGN.json among committed design context files

Co-Authored-By: Claude Fable 5 <[email protected]>

* [AI] Keep DESIGN.json out of the repo as a generated artifact

It is a regenerable sidecar of DESIGN.md consumed only by the locally
installed impeccable live panel, so gitignore it like the skill payload.

Co-Authored-By: Claude Fable 5 <[email protected]>

* [AI] Clarify that DESIGN.md hex values are the light-theme mapping

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
This commit is contained in:
Matiss Janis Aboltins
2026-08-14 17:16:55 +00:00
committed by GitHub
co-authored by Claude Fable 5
parent 93909fc805
commit 56800dc813
11 changed files with 345 additions and 5 deletions
+10
View File
@@ -1,5 +1,15 @@
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "[ -d \"$CLAUDE_PROJECT_DIR/.claude/skills/impeccable\" ] || echo 'The impeccable design skill is recommended for UI work in this repo but is not installed in this checkout. Before doing design/UI work, offer to install it with: npx impeccable install (then use /impeccable). See the UI Design section in AGENTS.md.'"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit|NotebookEdit",
+29
View File
@@ -0,0 +1,29 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|apply_patch",
"hooks": [
{
"type": "command",
"command": "[ ! -f \".agents/skills/impeccable/scripts/hook.mjs\" ] || node \".agents/skills/impeccable/scripts/hook.mjs\"",
"timeout": 5,
"statusMessage": "Checking UI changes"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "if [ -f \".agents/skills/impeccable/scripts/hook.mjs\" ]; then node \".agents/skills/impeccable/scripts/hook.mjs\"; else echo \"The impeccable design skill is recommended for UI work in this repo but is not installed in this checkout. Install it with: npx impeccable install\"; fi",
"timeout": 30,
"statusMessage": "Design deep pass"
}
]
}
]
}
}
+20 -4
View File
@@ -1,10 +1,26 @@
{
"version": 1,
"hooks": {
"beforeShellExecution": [{ "command": "./.cursor/hooks/guard-shell.sh" }],
"beforeMCPExecution": [
{ "command": "./.cursor/hooks/before-mcp-github.sh" }
"beforeShellExecution": [
{
"command": "./.cursor/hooks/guard-shell.sh"
}
],
"afterFileEdit": [{ "command": "./.cursor/hooks/after-file-edit.sh" }]
"beforeMCPExecution": [
{
"command": "./.cursor/hooks/before-mcp-github.sh"
}
],
"afterFileEdit": [
{
"command": "./.cursor/hooks/after-file-edit.sh"
}
],
"preToolUse": [
{
"command": "[ ! -f \".cursor/skills/impeccable/scripts/hook-before-edit.mjs\" ] || node \".cursor/skills/impeccable/scripts/hook-before-edit.mjs\"",
"timeout": 5
}
]
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"version": 1,
"hooks": {
"postToolUse": [
{
"type": "command",
"matcher": "edit|create|apply_patch",
"bash": "if [ ! -f \"$(git rev-parse --show-toplevel)/.github/skills/impeccable/scripts/hook.mjs\" ]; then echo \"The impeccable design skill is recommended for UI work in this repo but is not installed in this checkout. Install it with: npx impeccable install\"; else ! node -e \"process.exit(Math.min(parseInt(process.versions.node,10),22)===22?0:1)\" 2>/dev/null || node \"$(git rev-parse --show-toplevel)/.github/skills/impeccable/scripts/hook.mjs\"; fi",
"timeoutSec": 5
}
]
}
}
+8
View File
@@ -69,6 +69,14 @@ bundle.mobile.js.map
.claude/worktrees/*
.claude/settings.local.json
# Impeccable skill: payload is installed locally per developer, only the
# defensive hook wiring and design context files are committed
.impeccable/config.local.json
DESIGN.json
**/skills/impeccable/
.cursor/agents/impeccable-*.md
.github/agents/impeccable-*.agent.md
# Misc
.#*
+1 -1
View File
@@ -4,5 +4,5 @@
"yarn sync:tsconfig-references"
],
"**/*.{js,mjs,jsx,ts,tsx,md,json,yml,yaml}": "oxfmt --no-error-on-unmatched-pattern",
"**/*.{js,mjs,jsx,ts,tsx}": "oxlint --fix --type-aware --quiet"
"**/*.{js,mjs,jsx,ts,tsx}": "oxlint --fix --type-aware --quiet --no-error-on-unmatched-pattern"
}
+2
View File
@@ -1,6 +1,8 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "import", "jsx-a11y"],
// Vendored third-party agent skill scripts; not maintained in this repo
"ignorePatterns": ["**/skills/impeccable/**"],
"jsPlugins": [
"./packages/eslint-plugin-actual/lib/index.js",
"eslint-plugin-typescript-paths",
+10
View File
@@ -263,6 +263,16 @@ Regenerate i18n files with `yarn generate:i18n`.
Wrap standalone financial numbers with `FinancialText` (or `styles.tnum` where
wrapping isn't possible).
### 6. UI Design (impeccable skill)
This repo uses the [impeccable](https://www.npmjs.com/package/impeccable)
design skill for designing, restyling, or reviewing UI. The skill payload is
not committed — only its hook wiring and the project design context
(`PRODUCT.md`, `DESIGN.md`) are. `DESIGN.json` is a generated sidecar of
`DESIGN.md`; regenerate it locally with `$impeccable document` when needed. If your harness's `skills/impeccable/`
directory (e.g. `.claude/skills/impeccable/`) is missing, install it with
`npx impeccable install`, then invoke `/impeccable` for design tasks.
## Code Style & Conventions
### TypeScript Guidelines
+212
View File
@@ -0,0 +1,212 @@
---
name: Actual Budget
description: Local-first personal finance, built around envelope budgeting
# All color values are the light-theme palette mapping; dark and midnight
# remap the same semantic roles via `theme.*` tokens (see The Semantic Token Rule).
colors:
actual-purple: '#8719e0'
actual-purple-hover: '#a368fc'
navy-ink: '#102a43'
navy-slate: '#627d98'
navy-mist: '#e8ecf0'
navy-frost: '#f7fafc'
page-text: '#272630'
surface-white: '#ffffff'
positive-green: '#147d64'
negative-red: '#e12d39'
link-blue: '#1980d4'
warning-gold: '#b88115'
typography:
display:
fontFamily: 'Inter Variable, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif'
fontSize: '30px'
fontWeight: 600
headline:
fontFamily: 'Inter Variable, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif'
fontSize: '20px'
fontWeight: 700
letterSpacing: '0.5px'
title:
fontFamily: 'Inter Variable, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif'
fontSize: '15px'
fontWeight: 500
body:
fontFamily: 'Inter Variable, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif'
fontSize: '16px'
fontWeight: 400
fontFeature: 'tnum, ss01, ss04'
label:
fontFamily: 'Inter Variable, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif'
fontSize: '13px'
fontWeight: 400
rounded:
sm: '4px'
md: '6px'
spacing:
xs: '5px'
sm: '10px'
md: '16px'
lg: '20px'
components:
button-primary:
backgroundColor: '{colors.actual-purple}'
textColor: '{colors.surface-white}'
rounded: '{rounded.sm}'
padding: '5px 10px'
button-primary-hover:
backgroundColor: '{colors.actual-purple-hover}'
textColor: '{colors.surface-white}'
button-normal:
backgroundColor: '{colors.surface-white}'
textColor: '{colors.navy-ink}'
rounded: '{rounded.sm}'
padding: '5px 10px'
input:
backgroundColor: '{colors.surface-white}'
textColor: '{colors.page-text}'
rounded: '{rounded.sm}'
padding: '5px'
---
# Design System: Actual Budget
## 1. Overview
**Creative North Star: "The Home Office"**
Actual feels like a tidy personal desk: familiar, unpretentious, everything within reach. It is a tool people open weekly for years to reconcile accounts and move envelope money around, so the interface optimizes for routine, not first impressions. Density is moderate-to-high (this is a table-driven app), feedback is instant, and decoration is close to zero. The financial numbers are the interface; everything else exists to keep them legible and trustworthy.
The system explicitly rejects fintech-startup gloss (gradient heroes, glassmorphism, crypto-dashboard neon) and corporate banking UI (navy-and-gold enterprise-portal density). It is calm, trustworthy, and practical, and it must render identically well in three themes: light, dark, and midnight.
**Key Characteristics:**
- Table-first layouts with tabular numerals everywhere money appears
- One accent (Actual Purple) used sparingly for primary actions and selection
- Semantic color tokens only; components never hardcode hex values
- Utilitarian, compact components built for daily repetition
- Flat-first surfaces; shadows reserved for transient overlays
## 2. Colors
A calm navy-neutral base with one confident purple accent and strict semantic roles for money.
All hex values in this file (frontmatter included) are the light-theme palette mapping. The dark and midnight themes remap the same semantic roles to different palette values, so never use these hexes directly in components — route every color through the `theme.*` semantic tokens (see The Semantic Token Rule below).
### Primary
- **Actual Purple** (#8719e0): The single brand accent. Primary buttons, selected rows and borders, active navigation, mobile header. Hover lightens to **Lifted Purple** (#a368fc).
### Neutral
- **Navy Ink** (#102a43): Sidebar background, darkest text. The app's anchor dark.
- **Page Ink** (#272630): Default body text on light surfaces.
- **Navy Slate** (#627d98): Secondary and subdued text, table headers.
- **Navy Mist** (#e8ecf0): Page background, table borders, dividers.
- **Navy Frost** (#f7fafc): Hover rows, raised header rows.
- **Surface White** (#ffffff): Tables, cards, menus, modals.
### Tertiary (semantic money and status colors)
- **Positive Green** (#147d64): Positive amounts and funded budgets.
- **Negative Red** (#e12d39): Negative amounts, overspending, failures.
- **Link Blue** (#1980d4): Links and informational highlights.
- **Warning Gold** (#b88115): Underfunded templates, pending states.
### Named Rules
**The Semantic Token Rule.** Components never use raw palette values or hex codes. Every color goes through the `theme.*` semantic layer (`--color-*` custom properties) so all three themes (light, dark, midnight) stay correct. A hardcoded hex in a component is a bug.
**The One Accent Rule.** Actual Purple appears on well under 10% of any screen: primary action, current selection, active nav. It never decorates.
**The Never-Color-Alone Rule.** Positive/negative money state is conveyed by sign and context as well as color; green/red are reinforcement, never the only signal.
## 3. Typography
**Body Font:** Inter Variable (with system-ui fallback stack)
**Label/Mono behavior:** Same family; financial figures switch on tabular OpenType features
**Character:** One workhorse sans at compact sizes. No display serif, no font pairing games: hierarchy comes from weight and size, and the typographic star is the number column.
### Hierarchy
- **Display** (600, 30px): Page-level headings and large balances. Rare.
- **Headline** (700, 20px, 0.5px letter-spacing): Section titles.
- **Title** (500, 15px): Emphasized in-table and card text.
- **Body** (400, 16px): Default text.
- **Label** (400, 13px): Table meta, menus, dense secondary text; 12px and 10px steps exist for the tightest spots.
### Named Rules
**The Tabular Number Rule.** Every standalone financial figure renders with `font-feature-settings: "tnum", "ss01", "ss04"` (via `FinancialText` or `styles.tnum`) so digits align in columns and disambiguate. A proportional-figure money column is a bug.
## 4. Elevation
Flat-first with ambient shadows. Structure comes from 1px borders (Navy Mist) and background shifts (White on Mist, Frost on hover), not depth. Shadows exist only to lift **transient** surfaces above the page: menus, tooltips, popovers, modals. Persistent surfaces like tables and cards sit flat or carry the faint card shadow at most.
### Shadow Vocabulary
- **Card** (`box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)`): Resting cards and small raised widgets.
- **Ambient** (`box-shadow: 0 2px 4px 0 rgba(0,0,0,0.1)`): Focused inputs, subtle lift.
- **Large** (`box-shadow: 0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)`): Tooltips, popovers, floating panels.
### Named Rules
**The Transient-Only Rule.** If a surface stays on screen, it gets a border. If it appears on interaction and disappears, it may cast a shadow.
## 5. Components
Utilitarian and quick: compact paddings, instant state feedback, built for daily repetition. All values below are the light theme; every color routes through the semantic token layer.
### Buttons
- **Shape:** Gently rounded (4px radius), compact padding (5px 10px)
- **Primary:** Actual Purple background, white text; hover lifts to Lifted Purple with a soft shadow transition (`box-shadow .25s`)
- **Normal:** White background, Navy Ink text, 1px navy border
- **Bare:** Transparent, 5px padding; background tint on hover/press. The workhorse for in-table actions
### Inputs / Fields
- **Style:** White background, 1px border, 4px radius, 5px padding
- **Focus:** Border switches to the selected accent; big inputs drop the border and take the ambient shadow instead
- **Big variant:** 10px padding for mobile and prominent forms (40px minimum touch height on mobile)
### Cards / Containers
- **Corner Style:** 6px radius on table containers (top corners), 4px elsewhere
- **Background:** Surface White on Navy Mist page background
- **Shadow Strategy:** Card shadow at most; structure via 1px Navy Mist border
- **Internal Padding:** 16-20px
### Navigation
- **Sidebar:** Navy Ink background, light navy text; hover darkens the row, selection marked with a purple accent and purple text. Status states (pending/positive/failed) tint the item background gold/green/red
- **Mobile:** Purple header, white nav bar, purple selected item
### Pills / Chips
- **Style:** Editor pills: tinted background, 4px radius, 3px 5px padding. Used for rule conditions and inline tokens
### Signature Component: The Money Table
The core surface of the app. White rows on 1px Navy Mist borders, Frost hover, purple-bordered selection, sticky header with Slate 13px text, amounts right-aligned in tabular figures colored by the semantic money tokens. Alternate-row striping is theme-controlled, never hardcoded.
## 6. Do's and Don'ts
### Do:
- **Do** route every color through `theme.*` semantic tokens so light, dark, and midnight themes all work. Test all three.
- **Do** wrap standalone financial numbers in `FinancialText` or apply `styles.tnum`.
- **Do** keep components compact and quick: 4px radii, 5-10px paddings, instant hover/press states.
- **Do** reuse the existing component library (`@actual-app/components`) before writing new UI.
- **Do** keep Actual Purple scarce: primary action and selection only.
- **Do** respect the breakpoints: 512px (small), 730px (medium), 1100px (wide); mobile touch targets are at least 40px tall.
### Don't:
- **Don't** use fintech-startup gloss: gradient heroes, glassmorphism, neon accents, crypto-dashboard styling (PRODUCT.md anti-reference).
- **Don't** use corporate banking UI patterns: navy-and-gold, enterprise-portal density, legalese energy (PRODUCT.md anti-reference).
- **Don't** hardcode hex values or raw `--palette-*` colors in components; the semantic layer is the only entry point.
- **Don't** rely on color alone for positive/negative amounts.
- **Don't** put shadows on persistent surfaces; shadows are for transient overlays only.
- **Don't** use `border-left`/`border-right` thicker than 1px as a colored accent stripe.
- **Don't** animate layout properties; transitions are for color, opacity, and shadow (like the button's `box-shadow .25s`).
+34
View File
@@ -0,0 +1,34 @@
# Product
## Register
product
## Users
People managing their own household finances: privacy-minded budgeters, self-hosters, and families who want full control of their money data. They use Actual regularly (often daily or weekly check-ins) on desktop and mobile, mid-workflow: reconciling accounts, categorizing transactions, adjusting envelope budgets, reviewing reports. Many migrated from other budgeting apps and value that Actual is local-first, free, and open-source.
## Product Purpose
Actual Budget is a local-first personal finance tool built around envelope budgeting. It exists so people can track and plan their money without handing data to a third party — everything runs on their own device or server, with optional sync. Success looks like users trusting the numbers, completing routine money tasks quickly, and sticking with their budget over months and years.
## Brand Personality
Calm, trustworthy, practical. The interface should feel like a dependable tool that stays out of the way: quiet confidence, no flash, no urgency theatrics. Money is stressful enough — the UI's job is to make it feel manageable and under control.
## Anti-references
- Fintech-startup gloss: gradient heroes, glassmorphism, crypto-dashboard neon.
- Corporate banking UI: navy-and-gold, enterprise-portal density, legalese energy.
## Design Principles
- **The numbers are the interface.** Financial figures are the primary content; typography, alignment, and tabular numerals serve legibility of amounts above all decoration.
- **Trust through restraint.** No visual tricks that could make users doubt what they're seeing. Boring and correct beats clever.
- **Fast routine, gentle depth.** Everyday tasks (categorize, reconcile, budget) must be frictionless; power features reveal themselves progressively without cluttering the default view.
- **Local-first honesty.** The UI reflects the product's values: no dark patterns, no upsells, no attention-grabbing — the user owns the tool, not the other way around.
- **Consistent across surfaces.** Desktop, web, and mobile share one design language via the shared component library; new work reuses existing components and theme tokens.
## Accessibility & Inclusion
Target WCAG 2.1 AA: sufficient contrast in all themes (light, dark, midnight), full keyboard navigation, respect for reduced-motion preferences, and color-blind-safe use of color (never color alone to convey positive/negative amounts).
@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [MatissJanis]
---
Add design context files (PRODUCT.md and DESIGN.md) and hook wiring for the impeccable AI design skill