diff --git a/AGENTS.md b/AGENTS.md index dccb27b..e95efb5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,9 @@ # AGENTS +Read this file together with `DESIGN.md`. +`AGENTS.md` is the engineering and ownership source of truth. +`DESIGN.md` is the visual and component-aesthetics source of truth. + ## Purpose `mini-stim` is now a small, local-first single-person AI chat prototype. @@ -61,7 +65,7 @@ mini-stim/ │ ├── contracts/ # generated OpenAPI schema/types │ ├── mqueue/ # browser transport/event projection over contracts + SSE │ ├── hooks/ # React provider + atomic hooks over mqueue -│ └── components/ # reusable UI primitives/compositions used by client +│ └── components/ # reusable UI atoms/patterns consumed by client ├── docs/ └── .task/ # local task memory, ignored by git ``` @@ -116,8 +120,132 @@ plane and must stay limited to cell lifecycle facts. fallbacks or exploring unrelated environment workarounds unless the user asks. - Keep hard cuts acceptable. Add compatibility only for a real external surface. +## Browser Automation Rules + +Treat browser automation as a persistent working surface, not a disposable +subprocess. + +- Browser automation policy follows the current official `@playwright/cli` + documentation surface, not ad hoc local muscle memory from older installs. +- A working browser surface assumes a modern `@playwright/cli` with named + sessions via `-s=` and session management via `list`, `close`, + `close-all`, `kill-all`, and `delete-data`. +- Start browser work by checking `playwright-cli --version` when session + behavior looks unfamiliar. If the installed CLI does not match the current + documented command surface, treat that as environment drift and report it + directly instead of burning time on exploratory command permutations. +- Prefer reusing the current `playwright-cli` session and tab instead of + stopping/restarting or closing/reopening the browser. +- If the target page needs to refresh, prefer `playwright-cli reload`. +- If the task needs a different page in the same working surface, prefer + `playwright-cli -s= open ` or `playwright-cli goto ` on the + active session/tab instead of tearing the session down first. +- Only stop, restart, or delete a browser session when the current session is + unusable, isolated state is explicitly required, or the user asks for a fresh + browser context. +- Avoid unnecessary browser restarts because they destroy the current window + shape, tab arrangement, and other user-adjusted visual context. + +For routine local iteration, the primary `playwright-cli` session name is +`mini-stim`. Do not fall back to the default session for ordinary work unless +the named session is unusable. + +`playwright-cli` cold start is `mini-stim-session-first`, not help-first, +restart-first, or new-session-first. + +`working-surface check` is the standard phrase for cold-starting or revalidating +the local runtime/browser surface before discussing concrete edits. It means: + +- verify the installed `playwright-cli` command surface before using browser + session commands when there is any sign of version drift +- verify `sidecar` health first +- recover the runtime only if cells are unhealthy +- read the current `web.port` from the active namespace store +- reuse the routine `playwright-cli` session `mini-stim` +- open the current local web URL and take a fresh snapshot so everyone is + looking at the same live surface + +Normal local web startup path: + +```bash +playwright-cli --version +sidecar status --config sidecar.toml +sidecar stop --config sidecar.toml # only if runtime/cells are unhealthy +sidecar start --config sidecar.toml # only if runtime/cells are unhealthy +cat .tmp/sidecar//client/web.port +playwright-cli -s=mini-stim open http://127.0.0.1: --headed +playwright-cli -s=mini-stim snapshot +``` + +Only deviate from that path when the current session is unusable or the task +explicitly requires isolated browser state. If the installed CLI does not +support this command surface, stop and report the version drift instead of +guessing alternate syntax. + +Normal `playwright-cli` shutdown path: + +```bash +playwright-cli -s=mini-stim close # stop the routine session cleanly +playwright-cli close-all # stop all sessions when broader cleanup is intended +playwright-cli kill-all # only for stale/zombie browser processes +playwright-cli -s= delete-data # only after close, and only if session data should be removed +``` + +Do not kill the underlying browser process directly unless there is no cleaner +recovery path left. + +For `playwright-cli`, treat the following as the normal hot path: + +- start with the routine `mini-stim` session for ordinary local iteration +- use additional named sessions only when the task truly needs separate + cookies/storage or parallel browser contexts +- prefer semantic session names when extra named sessions are required +- use `-s=` with `open`, `snapshot`, `click`, `fill`, `press`, `reload`, + `tab-list`, and `tab-select` as the default interactive workflow +- resnapshot after significant page changes instead of guessing stale refs +- use `tab-new` only when the task benefits from a second live tab; otherwise + keep work in the current tab +- use `list` to inspect existing sessions before creating extra ones if + session state is unclear +- if the current page is simply stale, prefer `reload` over re-`open`ing unless + the URL itself must change +- clean up sessions only when the task is complete or stale state is clearly + harmful; do not treat cleanup as the default first move + ## Frontend Package Boundary +The frontend design-system asset model is explicit: + +- `packages/components/src/atoms` + owns business-blind primitives, low-level layout/control capabilities, token + consumption, and SCSS for those primitives. +- `packages/components/src/patterns` + owns business-blind but higher-level hard-coded composition templates. A + pattern is not a page component and not a product concept; it is a reusable + structural solution for a recurring, high-constraint UI problem. +- `apps/client/soma/web/src/components` + owns product-semantic assembly such as session rails, transcript item views, + composer instances, and other `mini-stim`-specific compositions built from + hooks plus component-system assets. + +Treat `patterns` as a first-class asset layer, not as a documentation-only +idea and not as an accidental pile of "slightly larger atoms". + +- A pattern must stay business-blind. + It may encode structural relationships, surface layering, spacing rhythm, + fixed-vs-fluid layout logic, label/status clustering, and similar reusable + composition rules. + It must not encode product concepts such as `session`, `conversation`, + `assistant`, `tool result`, or `mini-stim`. +- A mature pattern should be hard-coded in `packages/components`, with code as + the primary truth. +- `DESIGN.md` may temporarily carry provisional patterns that are not yet ready + to hard-code, but that is a staging area, not the long-term home of mature + pattern behavior. +- If a local UI problem is sufficiently constrained that the correct atom + combination is effectively unique, treat that as a pattern-discovery signal. + Do not keep re-solving that problem in `web`. + - Keep the frontend split strict even though everything ships from one repo. - `packages/contracts` owns generated OpenAPI clients and DTOs only. - `packages/mqueue` owns browser-facing HTTP calls, SSE wiring, stream merge, @@ -125,15 +253,25 @@ plane and must stay limited to cell lifecycle facts. - `packages/hooks` owns React context/providers and atomic hooks over `mqueue`. It is the only stateful integration layer the web app should consume. -- `packages/components` owns reusable presentational UI primitives and small - compositions. It should stay transport-agnostic and product-light. +- `packages/components` owns reusable presentational UI primitives and + hard-coded business-blind patterns. It should stay transport-agnostic and + product-light. - `apps/client/soma/web` owns route/page assembly, product-specific layout, and composer/transcript/session UX built from hooks and components. - Web app code must not call raw `fetch`, construct `EventSource`, import `@mini-stim/contracts`, or reach into sidecar/browser globals directly. - If a UI pattern is reusable across multiple client surfaces or would - otherwise cause page-level CSS/control duplication, move it into - `packages/components` instead of re-implementing it in `web`. + otherwise cause repeated atom soup or page-level CSS/control duplication, + move it into `packages/components`, usually as a `pattern`, instead of + re-implementing it in `web`. +- When deciding where a UI change belongs, use this ladder: + - token issue -> theme/tokens + - primitive capability issue -> `atoms` + - recurring high-constraint composition issue -> `patterns` + - product semantics / content assembly issue -> `web` +- Do not skip the `patterns` layer merely because a layout can technically be + assembled from atoms. The question is not "can atoms express this?" but + "should `web` have to re-decide this structure?" - If logic is about transport, replay, stream state, or event normalization, it belongs below `web`, usually in `mqueue` or `hooks`, not inside React pages. - Do not create a fake package/release process inside the repo. Keep the diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..54c01ad --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,566 @@ +# mini-stim Design System + +This file is the visual source of truth for `mini-stim`. + +It exists to turn broad design inspiration into a stable local design system + that agents can apply repeatedly without re-deciding taste on every task. + +`AGENTS.md` defines ownership and engineering boundaries. +`DESIGN.md` defines visual boundaries, component aesthetics, and the rules that + convert outside inspiration into reusable internal UI language. + +## 1. Design intent + +`mini-stim` is a focused work surface for a local-first AI chat product. + +It should feel: + +- calm +- readable +- tool-like +- intentional +- slightly refined, but never ornamental + +It should not feel: + +- like a marketing page +- like a social chat app +- playful, cute, or overly brand-heavy +- glossy enterprise dashboard noise +- editorial-for-editorial's-sake + +The interface is for sustained reading and iterative work. Visual choices must +reduce fatigue before they add personality. + +## 2. Long-term system goal + +External references are inspiration, not templates. + +When a strong design reference is found, we do not copy page structure or + ad hoc colors into `web`. We extract the durable visual idea and translate it + into: + +- tokens +- atom capabilities +- surface rules +- typography roles +- spacing and border behavior + +Only after that translation should the idea appear in product UI. + +This is how visual taste becomes a maintainable system instead of a sequence of + one-off page edits. + +## 3. Templates, creativity, and patterns + +Template use and creativity are orthogonal. + +Templates are not the opposite of creative work. +They are the normal way to solve a problem once its constraints are clear +enough that the correct structure becomes stable. + +In `mini-stim`: + +- creativity is used to choose, revise, extend, or delete patterns +- templates are used to solve recurring, high-constraint local UI problems +- patterns are the formal system asset that carries those templates + +This means: + +- we do not treat every local UI problem as a fresh composition exercise +- we do not reject a near-unique structural solution just to preserve the + appearance of originality +- we do not confuse repeated, mature layout practice with a lack of design + judgment + +When a local UI problem becomes structurally obvious, the correct action is +usually to recognize the pattern and encode it, not to improvise again. + +## 4. Pattern layer + +`mini-stim` recognizes a layer between low-level design-system primitives and +product-specific components. + +That layer is `patterns`. + +Patterns are: + +- business-blind +- structurally opinionated +- reusable +- allowed to be hard-coded +- subject to revision, expansion, and deletion + +Patterns are not: + +- page-local implementation tricks +- product-semantic components +- permanent rules frozen forever +- just documentation with no code representation + +The intended hierarchy is: + +1. tokens +2. atoms +3. patterns +4. product components + +Patterns sit above atoms because they express recommended composition logic. +Patterns sit below product components because they must not encode product +meaning. + +For example, a pattern may express: + +- fluid primary region + fixed action region +- label stack + trailing status cluster +- header + scroll body + pinned footer +- primary content + secondary meta line + +It should not express: + +- session rail item +- assistant transcript card +- mini-stim composer + +Those are product-semantic usages of more general patterns. + +## 5. Pattern lifecycle + +Patterns are design assets, not sacred artifacts. + +They may be: + +- added +- modified +- expanded +- simplified +- deprecated +- deleted + +The design question is not whether a pattern should stay untouched forever. +The design question is whether the current recurring problem is better served by +reusing an existing pattern, revising one, or creating a new one. + +The default storage rule is: + +- mature patterns belong in code +- `DESIGN.md` explains pattern philosophy and indexes pattern assets +- `DESIGN.md` may temporarily hold provisional patterns that are not yet ready + to hard-code + +`DESIGN.md` is not the permanent home of mature pattern behavior. +If a pattern is stable enough to trust, the preferred outcome is to encode it +in `packages/components`. + +## 6. Current aesthetic direction + +The current direction is: + +- cool neutral workspace base +- low-noise panels and surfaces +- one restrained accent color +- strong readability over dramatic contrast +- subtle depth through value separation, not heavy shadowing + +The closest useful inspiration pattern is: + +- disciplined neutral surfaces +- clear typographic hierarchy +- sparse accent usage +- light borders and soft separation + +The wrong takeaway from editorial references is warm paper nostalgia. +The right takeaway is restraint, hierarchy, and accent discipline. + +## 7. Color philosophy + +### Base rule + +Use mostly neutral colors. + +The UI should be built from: + +- canvas +- panel +- subtle panel +- surface +- muted text +- light border +- one accent +- success / warning / danger support tones + +### Accent rule + +Use one primary accent family at a time. + +Accent exists to mark: + +- primary action +- selection +- authored/account-side emphasis +- focus states where appropriate + +Accent must not be sprayed across the interface. If everything is emphasized, + nothing is emphasized. + +### Contrast rule + +Prefer: + +- light or mid-light surfaces with dark text + +Avoid: + +- large deep-color surfaces with white text for reading-heavy content + +Dark-on-light is the default reading mode. +Inverse surfaces should be rare and must justify themselves. + +### Temperature rule + +Default product temperature is slightly cool-neutral. + +Do not drift into: + +- yellowed paper +- sepia +- muddy beige +- green-gray murk + +Warm accents may exist, but the workspace itself should remain clear and clean. + +## 8. Surface hierarchy + +The product should read as a stack of clear working layers: + +1. canvas +2. panel +3. surface +4. emphasized surface +5. feedback surface + +Those layers should differ primarily by: + +- lightness +- border strength +- occasional tint + +Not by: + +- large shadow jumps +- excessive gradients +- arbitrary color shifts + +Shadows should be minimal. Borders and tonal separation do most of the work. + +## 9. Typography roles + +Typography has distinct jobs. + +### Heading + +Use for: + +- page titles +- section titles +- key chat context labels + +It should feel compact, confident, and quiet. Not theatrical. + +### Body + +Use for: + +- messages +- descriptive copy +- empty states +- system notes + +Body text is the product's main workload. Readability wins over personality. + +### Meta + +Use for: + +- timestamps +- connection state +- small labels +- supporting status copy + +Meta text should step back without becoming low-contrast mush. + +### Mono + +Use for: + +- structured payloads +- tool arguments/results +- machine-readable fragments + +Mono is not a theme. It is a utility lane. + +## 10. Component translation rules + +Visual language must land in the component system, not in page-local styling. + +### Atoms + +Atoms are business-blind. + +They own: + +- visual primitives +- layout primitives +- form controls +- surface treatments +- token consumption +- their own SCSS + +They do not own product concepts like: + +- session +- message +- tool call +- assistant +- transcript + +Atoms should answer questions like: + +- what surface tones exist +- what padding/radius/typography roles exist +- how low-level layout primitives behave +- how controls expose state and affordance + +They should not answer recurring high-level composition questions that already +have a stable structural solution. + +### Patterns + +Patterns are business-blind hard-coded composition templates. + +They own: + +- recurring high-constraint layout solutions +- recommended structural combinations of atoms +- reusable information hierarchy templates +- stable local surface/lane relationships + +They do not own: + +- transport logic +- page routing +- product semantics +- one-off page composition + +If a UI problem repeatedly causes `web` to compose the same atoms in nearly the +same way, stop and consider whether that structure is actually a missing +pattern. + +### Web business components + +Business components may compose atoms and patterns into: + +- session rail rows +- transcript items +- composer blocks +- tool result views + +They may express product meaning, but they must not invent local visual rules +when those rules already belong in atoms or patterns. + +### Web CSS rule + +`apps/client/soma/web` should not become a styling escape hatch. + +If `web` appears to need CSS, assume atom expressiveness is missing. +Add or refine atom/pattern capability instead of patching page-local styles. + +## 11. Pattern index and provisional storage + +This file also acts as the pattern index. + +Use the following interpretation: + +- hard-coded pattern + the pattern is implemented in `packages/components` and code is the primary + truth +- provisional pattern + the pattern has been identified and should be remembered, but is not yet + stable enough or enabled enough to hard-code +- deprecated pattern + the pattern should no longer guide new work and should be removed or replaced + +When a provisional pattern is recorded here, include: + +- status +- constraints +- intended structural shape +- why it is not yet hard-coded +- what would trigger promotion into code + +Current index: + +### Hard-coded patterns + +#### FieldActionLayout + +- status: hard-coded +- intent: + - one fluid primary region + - one fixed-width secondary action region + - one shared control body without page-local layout improvisation +- code location: + - `packages/components/src/patterns/FieldActionLayout/FieldActionLayout.tsx` + - `packages/components/src/patterns/FieldActionLayout/FieldActionLayout.scss` +- current product usage: + - the `mini-stim` chat composer is the first pilot consumer +- notes: + - this pattern is intentionally business-blind + - it captures a recurring layout solution, not a chat-specific component + +### Provisional patterns + +None currently tracked. + +## 12. Message styling rules + +Messages should be visually distinct by role, but still belong to one family. + +### Account-side messages + +- may use the accent family +- should remain highly readable +- should prefer tinted light surfaces with dark text over saturated dark blocks + +### Assistant-side messages + +- should be the quiet default reading surface +- should not compete with account messages + +### System messages + +- may use a soft warning/editorial tint +- should feel special but not alarming + +### Tool blocks + +- may use a soft success/utility tint +- should feel structured and inspectable +- code/payload areas should remain mono and neutral enough for scanning + +## 13. Motion and interaction + +Motion should be sparse and useful. + +Use motion for: + +- hover clarity +- focus reinforcement +- state transition smoothness + +Do not use motion for: + +- ornament +- bounce +- personality signaling + +The interface should feel responsive, not animated. + +## 14. Background and atmosphere + +The product may have a small amount of atmosphere, but it must stay behind the + work. + +Allowed: + +- faint tonal variation +- extremely subtle cool ambient gradients +- almost invisible texture + +Not allowed: + +- obvious paper texture +- strong noise overlays +- decorative illustration language in the work surface + +If a background effect is noticeable before the content is noticeable, it is +too strong. + +## 15. Borrowing from external references + +When studying another project, extract only stable principles such as: + +- accent discipline +- hierarchy +- spacing rhythm +- border weight +- typography role separation +- panel layering + +Do not directly copy: + +- brand palettes +- hero-page treatments +- editorial gimmicks +- warm/cold bias without product fit + +The question is never "How do we make mini-stim look like that project?" + +The question is: + +"What visual rule from that project is durable enough to become a token, atom, + or pattern capability here?" + +## 16. Review heuristics + +A visual change is likely correct when: + +- readability improves +- hierarchy gets clearer +- fewer colors carry more meaning +- the change can be explained through tokens, atoms, or patterns +- another screen could reuse the same rule + +A visual change is likely wrong when: + +- it only works in one page context +- it introduces a new special-case color without a system reason +- it depends on `web`-local CSS +- it makes reading harder to gain personality +- it copies a reference surface without translating its logic +- it leaves a recurring high-constraint local structure trapped in page-level + JSX instead of promoting it to a reusable pattern + +## 17. Near-term direction for mini-stim + +Near-term refinement should focus on: + +- better neutral layering +- more stable accent usage +- clearer meta typography +- improved transcript readability +- stronger atom capabilities for shell/layout/surfaces +- extracting the first true business-blind hard-coded patterns from recurring + chat/workspace structures + +Not on: + +- decorative flourishes +- multi-accent exploration +- dark mode expansion before the light mode language is stable +- high-brand marketing aesthetics inside the working chat surface + +## 18. Maintenance rule + +When `mini-stim` gains new visual capabilities, update this file if the change +alters: + +- the aesthetic direction +- the pattern philosophy or layer boundary +- the interpretation of accent usage +- the allowed surface hierarchy +- the boundary between inspiration and system +- the default readability rules + +This file should stay opinionated, compact, and durable. +It is not a changelog and not a moodboard. diff --git a/apps/client/soma/web/src/App.tsx b/apps/client/soma/web/src/App.tsx index 1597f8b..736c464 100644 --- a/apps/client/soma/web/src/App.tsx +++ b/apps/client/soma/web/src/App.tsx @@ -1,5 +1,5 @@ import { useMemo, useState } from "react"; -import { AppRoot } from "@mini-stim/components"; +import { AppRoot, Grid, GridItem } from "@mini-stim/components"; import { useMessageConnection, useSelectedSessionId, @@ -68,8 +68,9 @@ export function App() { } return ( - + + - } - main={ + + - } - /> + + + ); } diff --git a/apps/client/soma/web/src/components/ChatHeader.tsx b/apps/client/soma/web/src/components/ChatHeader.tsx index 2a4dd78..6573700 100644 --- a/apps/client/soma/web/src/components/ChatHeader.tsx +++ b/apps/client/soma/web/src/components/ChatHeader.tsx @@ -3,6 +3,8 @@ import { Heading, Inline, Pane, + Stack, + Text, } from "@mini-stim/components"; export function ChatHeader(props: { @@ -12,14 +14,20 @@ export function ChatHeader(props: { title: string; }) { return ( - - - - {props.title} - + + + + SESSION + + {props.title} + + - {props.busy ? Sending : null} - {props.selectedSessionId ? {props.connection} : null} + + {props.busy ? "sending" : "idle"} + + {props.selectedSessionId ? {props.connection} : null} + {!props.selectedSessionId ? new : null} diff --git a/apps/client/soma/web/src/components/ChatShell.tsx b/apps/client/soma/web/src/components/ChatShell.tsx index 0d3d18c..542c15c 100644 --- a/apps/client/soma/web/src/components/ChatShell.tsx +++ b/apps/client/soma/web/src/components/ChatShell.tsx @@ -1,4 +1,4 @@ -import { Notice, Pane, Stack, Text } from "@mini-stim/components"; +import { GridRows, Notice, Pane, Stack, Text } from "@mini-stim/components"; import { ChatHeader } from "./ChatHeader"; import { Composer } from "./Composer"; @@ -17,7 +17,7 @@ export function ChatShell(props: { }) { return ( - + - {props.error ? ( - - - {props.error} - + + {props.error ? ( + + + {props.error} + + + ) : null} + + - ) : null} - - - - + + ); } diff --git a/apps/client/soma/web/src/components/Composer.tsx b/apps/client/soma/web/src/components/Composer.tsx index 9fd930e..b0f7db5 100644 --- a/apps/client/soma/web/src/components/Composer.tsx +++ b/apps/client/soma/web/src/components/Composer.tsx @@ -1,4 +1,4 @@ -import { IconButton, Inline, TextArea } from "@mini-stim/components"; +import { Button, FieldActionLayout, TextArea } from "@mini-stim/components"; export function Composer(props: { disabled?: boolean; @@ -13,21 +13,29 @@ export function Composer(props: { props.onSubmit(); }} > - + + Send + + )} + >