Claude Free Design Contract
Updated: 2026-07-23
This project separates backend/function work from the design surface.
Claude Design's delivered surface is the visual UI source of truth. Functional state transitions and production behavior remain governed by the props/controller/domain contracts. Codex must not force Claude's surface into the removed vanilla DOM structure or any previous CSS system.
The current frontend source of truth is src/react/.
Codex owns:
- auth/session mechanics
- data routing and service actions
- app state needed to persist and hydrate Claude's UI
- runtime interaction semantics and production wiring
- controlled inputs, search/filter/IME behavior, canonical IDs, and navigation
- workout session, exercise, set hierarchy
- Supabase read/write
- recovery, PR, guild calculations
- event commands and render data
- backend/service functions needed by Claude's app
- functional integration and regression tests, including narrowly scoped bindings inside
src/react/ui/**
Claude owns:
- visual flow and screen choreography
- layout
- visual hierarchy
- spacing
- typography
- component shape
- mobile and desktop composition
- CSS class names
- DOM nesting
- responsive behavior
- design-surface framework choice. If Claude ships a React prototype, the current app surface should be React.
R&R: Visual Design vs. Functional Integration
The boundary is based on responsibility, not only on the directory containing the code. src/react/ui/** is the design surface, but production behavior inside that surface still belongs to Codex.
| Concern | Claude Design | Codex |
|---|---|---|
| Screen surface | Layout, markup composition, CSS, typography, spacing, responsive structure, animation | Preserve the approved surface while integrating it |
| Visual states | Design how loading, pending, empty, error, selected, and disabled states look | Define when those states occur and drive them from app/controller state |
| Inputs and search | Design the control, results list, focus treatment, and visual feedback | Own controlled values, IME, debounce, normalization, matching, canonical IDs, and result data |
| Actions and navigation | Design where controls appear and how interaction is visually communicated | Bind callbacks, route transitions, back behavior, concurrency, failure, retry, and optimistic updates |
| Data and domain rules | Render the supplied contract, including fixture examples | Own auth, RPC, persistence, hydration, merging, validation, calculations, and account isolation |
| Tests | Check visual states, responsive behavior, overflow, and that controls emit the documented intents | Check semantic outcomes, integration, persistence, race conditions, and regressions |
Codex may make narrowly scoped functional-integration changes inside src/react/ui/** when production wiring cannot be completed outside it. This includes accepting an agreed prop, binding an existing control to a callback, forwarding composition/keyboard events, removing duplicated business logic, and adding a semantic marker, accessibility attribute, or type needed by the contract. Codex must not use that exception to redesign layout, styling, typography, spacing, visual hierarchy, or component composition.
Claude may change any visual implementation while preserving the agreed props/callbacks or semantic markers. Claude does not need to implement the real controller, service, storage, or domain algorithm for the design to be complete.
Preview boundary
Claude's preview is a visual and interaction-contract harness, not a second app runtime. It may use fixtures, local display state, and mock callbacks to show all approved visual states and demonstrate that a control emits the expected intent.
Since 2026-08-19, fixtures and previews exist only in Claude Design's local environment — they are not part of this repository or of any delivery. The transfer channel for behavior is the props contract alone (docs/process/design-codex-transfer-contract.md).
- Preview-only fixtures and adapters stay in Claude Design's local environment and are never part of this repository or the production app.
- A mock may record
onSearchInput("바벨로우"); it must not become the production search implementation. - Preview or screen code must not reproduce search matching, canonicalization, catalog merging, persistence, authentication, RPC behavior, or domain calculations.
- A successful preview means the surface renders and emits the contract. Codex still owns end-to-end production integration and semantic tests.
This lets Claude test every visual state without forcing Claude to simulate every production function. If a preview needs realistic results, Codex supplies fixture outputs or a mock controller contract instead of duplicating the real algorithm in the screen.
Viewport width
The mobile surface is fluid from 360px to 600px — that is its normal state, not an edge case. The 390×844 preview frame is the reference width, not an upper bound: the phone tier has no column cap (iPhone 16/17 Plus·Pro Max render at 440px) and wide touch screens (fold, iPad, landscape) render a 600px column. Fixed-pixel widths on components are allowed only as max-width; a delivery that breaks at 360, 440, or 600 is a contract violation and is audited at intake. Tiers and verification viewports: docs/platform/viewport-tiers.md.
Core Rule
Claude may replace the app surface from the ground up.
When Claude ships a complete design prototype or React surface, that artifact wins over previous app HTML, CSS, and visual-flow assumptions. Preview mocks do not supersede production functional contracts. Codex adds data, auth, persistence, calculations, and event wiring without redesigning the interface.
The semantic data-lg-* contract is useful when Codex needs DOM-level wiring. It must not be used to constrain Claude's layout, visual structure, or chosen component model.
Current app HTML, current app CSS, screenshots, and previous prototypes are not design constraints. They may be used by Codex to locate existing behavior during integration, but Claude should not treat them as a required layout, component hierarchy, spacing system, or visual direction.
Any HTML snippet in this document is a marker inventory only. It shows which semantic attributes exist; it does not require the shown tag name, DOM nesting, order, wrapper count, spacing, or visual grouping.
Supported Attributes
data-lg-hook: one unique functional elementdata-lg-list: repeated functional elementsdata-lg-action: user command triggerdata-lg-field: user input fielddata-lg-slot: dynamic render targetdata-lg-view: view or screen rootdata-lg-panel: dashboard/mobile panel controlled by the page registrydata-lg-value: current semantic value for a tag-independent field componentdata-lg-state: functional state tokens such asactive,selected,completed,locked,resume,empty, oreditingdata-lg-status: domain status values such ascompleted,missed, orplanneddata-lg-option-value: value for a custom option inside a field component
The app looks for data-lg-* only.
Functional state is never expressed through CSS classes. Claude may rename, remove, or replace presentation classes freely. If a redesigned element needs a state for behavior or styling, keep the semantic data-lg-state or data-lg-status attribute and style that attribute.
Generated cards and templates follow the same rule. Codex renderers may fill cloned card internals, but they target only data-lg-slot and data-lg-action inside the clone. Claude may change tags, nesting, and class names inside templates as long as these semantic internal slots/actions remain.
Choice fields are tag-independent. Claude may use a native <select>, hidden input, button group, segmented control, or custom picker. The app reads and writes the semantic field value through data-lg-field plus data-lg-value; custom options should carry data-lg-option-value.
Marker-only example:
<input data-lg-field="workout.set.reps" type="number" />
<input data-lg-field="workout.set.load" type="number" />
<div data-lg-hook="conditionButtons" data-lg-field="workout.session.condition" data-lg-value="보통">
<button type="button" data-lg-option-value="좋음">좋음</button>
<button type="button" data-lg-option-value="보통">보통</button>
</div>
<button data-lg-action="workout.picker.select">
Select
</button>
<div data-lg-hook="draftList"></div>
<template>
<article>
<span data-lg-slot="workout.set.entryLabel"></span>
</article>
</template>Claude Can Change Freely
- Replace
index.htmllayout structure. - Replace the design surface framework or component structure.
- Rename or remove CSS classes.
- Use any presentation class names and DOM structure.
- Split mobile and desktop into totally different DOM shapes.
- Move buttons and slots anywhere in the view.
- Change all visual wrappers, cards, panels, grids, and navigation layout.
- Change tag types for fields and controls.
- Add, remove, or reorder presentation-only wrappers.
- Create a fresh CSS structure for a screen without preserving previous layout CSS.
Claude Must Preserve
- The user-approved functional intent:
- login/profile gate
- dashboard pages
- workout start
- plan check
- workout record
- exercise picker
- exercise finish note
- session finish
- The session hierarchy:
- day
- sessions
- exercises
- sets
- A clear functional boundary for Codex to connect auth, Supabase, and calculations.
data-lg-*markers only when the chosen design surface uses DOM-level semantic wiring.- Equivalent React props/callbacks or service boundaries when the chosen design surface is React.
React Props Contracts
Screen-level React props contracts live under docs/contracts/.
Current frozen pilot:
docs/contracts/session-screen-props.mddocs/contracts/workout-screen-props.md
When a screen has a frozen props contract, Claude may redesign the screen freely inside that interface. Codex wires containers, service calls, persistence, and any minimal component-level event binding needed by that interface.
Measured PR presentation invariants
The PR surface receives exact measured NRM state for repetition targets 1 through 20. These values have a stricter meaning than estimated strength:
- A missing exact NRM is shown as missing (
-or an equivalent empty state). It must not be derived from another repetition target with inverse Epley or any other formula. - e1RM is a separate, explicitly labelled estimate. It never fills the measured 1RM hero, measured NRM cells, strength-grade input, PR delta, or PR count.
current1RMIsBaseline: truemeans the user supplied a historical 1RM without a known date. Show it as an undated baseline; do not display signup time, source-row creation time, or today's date as its achievement date.current1RMSourceKindand eventsourceKinddistinguishsession_setfromhistorical_1rm. An event delta exists only for a strict measured transition.- Historical 1RM input must expose an optional achievement date plus an explicit unknown-date choice. A known date is sent as
achievedOn; unknown is sent asnulland must never be replaced with signup time, creation time, or today. repMaxesis keyed by the exact performed repetition count. A100 kg x 10set may populate only 10RM, never 1RM, 3RM, 5RM, or 8RM.
These are functional data invariants, not layout constraints.
Mobile PR exercise search handoff
Target the mobile 주요 종목 리스트 관리 and 1RM 직접 입력 surfaces in src/react/ui/mobile/screens/PrTools.tsx. Preserve the approved visual composition; this handoff changes only the search behavior and its props boundary.
Codex supplies one controller-owned search prop:
type MobilePrExerciseSearch = {
input: string;
query: string;
items: PrExerciseSearchItem[];
results: PrExerciseSearchItem[];
hasQuery: boolean;
isPending: boolean;
onInput(value: string, isComposing?: boolean): void;
onCompositionStart(): void;
onCompositionEnd(value: string): void;
onCommit(value?: string): void;
onClear(): void;
};Codex connects that prop to the existing visual surface without recreating search logic or changing the approved composition. Claude Design preserves the input, result-list, pending, empty, clear, close, and selection surfaces and the agreed props/markers:
- The input is controlled by
search.input. onChangecallssearch.onInput(value, nativeEvent.isComposing).- Composition start/end call the matching controller callbacks. Enter calls
search.onCommit(value)only when the native event is not composing. - An empty query renders
search.items; a committed query renderssearch.results. Whilesearch.isPending, keep the previous committed results instead of flashing a false empty state. - Closing the sheet or choosing an exercise calls
search.onClear()before closing. Selection still routes through the existingonOpenExercise(id). - The list must remain live while the versioned catalog hydrates. Do not copy or snapshot
itemswhen the sheet opens; the same query must be reevaluated when catalog items arrive. - Keep the existing
pr.favEdit.search,pr.manual.search,prFavAddInput, andprManualAddInputmarkers.
Search normalization, token matching, canonical-ID deduplication, and Korean IME debounce live only in exerciseSearch.ts and searchController.ts. UI code must not add its own includes, toLowerCase, whitespace replacement, alias merge, catalog merge, or canonical-ID conversion. Codex must feed the controller the full active catalog so aliases, equipment, body part, and exercises without records remain searchable; DB or RPC changes are not required.
Required behavior:
바벨로우and바벨 로우return the same canonicalbarbell-rowitem.Barbell Row, reversed English tokens, and catalog aliases resolve to that same single item.- An in-progress Korean composition never commits a stale intermediate query.
- Clear, close, selection, tab exit, and account change cannot resurrect a pending query.
- A query entered before catalog hydration updates automatically when the catalog arrives and must not be finalized as “no results” prematurely.
- Exercises without PR records remain searchable and open their empty detail.
These are functional search invariants, not layout or styling instructions.
High-Change Workout Hooks
These are the hooks most likely to be used in new designs:
The snippets below are not layout prescriptions. Claude may place these markers on different tags, move them anywhere in the flow, wrap them differently, or split mobile/desktop markup completely.
<section data-lg-hook="workoutView" data-lg-view="workout.flow"></section>
<section data-lg-hook="sessionStartStep" data-lg-view="workout.start"></section>
<section data-lg-hook="sessionRecordStep" data-lg-view="workout.record"></section>
<section data-lg-hook="sessionFinishStep" data-lg-view="workout.finish"></section>
<input data-lg-field="workout.session.date" />
<input data-lg-field="workout.session.startTime" />
<div data-lg-hook="conditionButtons" data-lg-field="workout.session.condition" data-lg-value="보통">
<button type="button" data-lg-option-value="좋음"></button>
<button type="button" data-lg-option-value="보통"></button>
</div>
<textarea data-lg-field="workout.session.preNote"></textarea>
<button data-lg-action="workout.usePlan"></button>
<button data-lg-action="workout.skipPlan"></button>
<button data-lg-action="workout.finishStep"></button>
<button data-lg-action="workout.finish.home"></button>
<button data-lg-hook="addExerciseButton" data-lg-action="workout.exercise.add"></button>
<div data-lg-hook="exerciseTabs" data-lg-slot="workout.exercise.tabs"></div>
<div data-lg-hook="draftList" data-lg-slot="workout.draft.list"></div>
<div data-lg-slot="workout.set.entryLabel"></div>
<input data-lg-field="workout.set.load" />
<input data-lg-field="workout.set.reps" />
<button data-lg-action="workout.exercise.finish"></button>
<section data-lg-hook="exercisePickerView" data-lg-view="workout.picker"></section>
<input data-lg-field="workout.picker.search" />
<div data-lg-hook="exerciseSearchResults"></div>
<button data-lg-action="workout.picker.select"></button>
<button data-lg-action="workout.picker.cancel"></button>Internal Card Slots
When Claude redesigns templates or generated card containers, preserve these internal semantics where that card exists:
The shown <template>, <article>, <span>, and <button> tags are examples only. Claude may change the internal tags and nesting as long as Codex can still find the same data-lg-slot and data-lg-action markers.
<template data-lg-hook="feedTemplate">
<article>
<span data-lg-slot="feed.avatar"></span>
<span data-lg-slot="feed.title"></span>
<span data-lg-slot="feed.meta"></span>
<button data-lg-action="feed.kudos"></button>
</article>
</template>
<template>
<article>
<span data-lg-slot="workout.set.entryLabel"></span>
</article>
</template>
<button data-lg-action="workout.set.add"></button>
<span data-lg-slot="workout.set.entryLabel"></span>Codex Handoff Style
When Codex asks Claude for design:
- Describe only functional requirements and states.
- Do not prescribe spacing, exact layout, card shape, palette, or hierarchy unless the user explicitly decided it.
- Include data shape, states, and stress data.
- Include the
data-lg-*hooks needed by the screen. - Ask Claude for complete replacement HTML/CSS for that screen.
- Do not include static fixture HTML/CSS or current app layout as a reference unless the user explicitly asks for that exact visual direction.
Implementation Source
- Current React app source:
src/react/ - Functional selector contract:
src/react/contracts/designContract.js - Current integration entry:
index.html - Supabase/data bridge:
src/react/services/barbelicApi.js - Web app manifest:
public/manifest.webmanifest - Offline service worker support: removed for now; restore separately if needed
The old vanilla frontend folders were removed. Do not use src/app, src/core, src/features, src/mobile, src/desktop, src/dom, top-level css, or top-level app.js as design or implementation references.