RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/AGENTS.md/nexu-io/open-design

AGENTS.md

AGENTS.md
AGENTS.mdroot

Quality

74/100

Scores the file, not the repository.

Length

5,214 words

35 headings · 4 code blocks

Repository

83k

— · pushed 0 days ago

Last changed

3 days ago

First indexed 3 days ago.
nexu-io/open-design/AGENTS.mdRawGitHub
1# Directory guide
2 
3This file is the single source of truth for agents entering this repository. Read this file first; after entering `apps/`, `packages/`, `tools/`, or `e2e/`, read that layer's `AGENTS.md` for module-level details. Do not copy module details back into the root file; root stays focused on cross-repository boundaries, workflow, and commands.
4 
5## Core documentation index
6 
7- Product and onboarding: `README.md`, `docs/i18n/README.zh-CN.md`, `QUICKSTART.md`.
8- Contribution and environment: `CONTRIBUTING.md`, `docs/i18n/CONTRIBUTING.zh-CN.md`.
9- Architecture and protocols: `docs/architecture.md`, `docs/skills-protocol.md`, `docs/agent-adapters.md`, `docs/modes.md`.
10- Historical product baseline: `docs/spec.md`, `docs/roadmap.md` (both explicitly archived; do not treat their dated decisions as current behavior).
11- References and current plans: `docs/references.md`, `docs/code-review-guidelines.md`, `specs/current/maintainability-roadmap.md`, `specs/current/ci.md` (CI scope confidence methodology — required before changing confidence or guard fields in `scripts/scopes.ts`).
12- Directory-level agent guidance: `.github/AGENTS.md`, `apps/AGENTS.md`, `packages/AGENTS.md`, `tools/AGENTS.md`, `e2e/AGENTS.md`.
13- Packaged auto-update architecture and high-confidence local harness: read `tools/pack/AGENTS.md` section "Packaged auto-update architecture and harness" before touching packaged updater code, release-channel identity, installer behavior, or updater UI.
14- Packaged build cache contract: `tools/pack/CACHE.md` (determinant rules, materialization-time parameters, confidence grading — required before changing any build-cache node key).
15 
16## Workspace directories
17 
18- Workspace packages come from `pnpm-workspace.yaml`: `apps/*`, `packages/*`, `tools/*`, and `e2e`.
19- Top-level content directories: `skills/` (functional skills the agent invokes mid-task — utilities, briefs, packagers; see `skills/AGENTS.md`), `design-templates/` (rendering catalogue: decks, prototypes, image/video/audio templates; see `design-templates/AGENTS.md` and `specs/current/skills-and-design-templates.md`), `design-systems/` (brand `DESIGN.md` files), `craft/` (universal brand-agnostic craft rules a skill can opt into via `od.craft.requires`), `mocks/` (replay-based mock CLIs for `opencode`/`claude`/`codex`/`gemini`/`cursor-agent`/`deepseek`/`qwen`/`grok`, the ACP family `devin`/`hermes`/`kilo`/`kimi`/`kiro`/`vibe`, and the AMR `vela` CLI (login + models + ACP), built from anonymized Langfuse traces — PATH-overlay drop-in for tests and self-validation; see `mocks/README.md`).
20- `apps/web` is the Next.js 16 App Router + React 18 web runtime; do not restore `apps/nextjs`.
21- `apps/daemon` is the local privileged daemon and `od` bin. It owns `/api/*`, agent spawning, skills, design systems, artifacts, and static serving.
22- `apps/desktop` is the Electron shell; it discovers the web URL through sidecar IPC.
23- `apps/packaged` is the thin packaged Electron runtime entry; it starts packaged sidecars and owns the `od://` entry glue only.
24- `apps/landing-page` is the standalone static Astro marketing and public catalog site. It reads repository content at build time and is not part of the daemon/web product runtime.
25- `packages/contracts` is the pure TypeScript web/daemon app contract layer.
26- `packages/sidecar-proto` owns the Open Design sidecar business protocol; `packages/sidecar` owns the generic sidecar runtime; `packages/platform` owns generic OS process primitives.
27- `tools/dev` is the local development lifecycle control plane.
28- `tools/pack` is the local packaged build/start/stop/logs control plane, packaged updater harness, installer identity/registry validation surface, and mac beta release artifact preparation surface.
29- `tools/serve` is the local fixture-service control plane; first service is `tools-serve start updater` for deterministic updater metadata and artifacts.
30- `tools/release` owns release metadata, storage publishing, release reports, and notification-facing data contracts; packaged artifact construction and smoke testing remain in `tools/pack`.
31- `e2e` owns user-level end-to-end smoke tests and Playwright UI automation; read `e2e/AGENTS.md` before editing its tests or commands.
32 
33## Inactive or placeholder directories
34 
35- `apps/nextjs` and `packages/shared` have been removed; do not recreate or reference them.
36- Local runtime data, `.tmp/`, Playwright reports, and agent scratch directories must stay out of git. For daemon-managed data paths, read and follow **Daemon data directory contract** below; do not restate or improvise path conventions elsewhere.
37 
38# Development workflow
39 
40## Environment baseline
41 
42- Runtime target is Node `~24` and `pnpm@10.33.2`; use Corepack so the pnpm version pinned in `package.json` is selected.
43- New project-owned entrypoints, modules, scripts, tests, reporters, and configs should default to TypeScript.
44- Residual JavaScript is limited to generated output, vendored dependencies, explicitly documented compatibility build artifacts, and the allowlist in `scripts/guard.ts`.
45 
46## Windows native
47 
48- macOS, Linux, and WSL2 are the primary supported paths. Windows native is best-effort — file an issue if it doesn't work.
49- Historical Windows-specific friction is documented in closed issues #10, #96, #100, #203, and #315; check the issue tracker for the current state before filing new reports.
50- Install Node 24. Either `winget install OpenJS.NodeJS.LTS` (currently Node 24.x) or download from https://nodejs.org. After install, verify with `node --version` — the WinGet LTS pointer rolls to the next major in October 2026, so re-verify if you re-run the install command later. Do not use Node 22 — see FAQ.
51- `corepack enable` fails with EPERM on Windows (cannot write shims to `Program Files`). Use `npm install -g pnpm@10.33.2` instead.
52- `better-sqlite3` has no prebuilt binary for win32/Node 24; `pnpm install` will compile it from source via node-gyp (~2 min). Requires Visual Studio Build Tools 2022 or newer. This is expected — not a sign of version incompatibility.
53- For `tools-dev` start/stop/status usage, see "Local lifecycle" below.
54 
55## Local lifecycle
56 
57- Use `pnpm tools-dev` as the only local development lifecycle entry point.
58- Do not add or restore root lifecycle aliases: `pnpm dev`, `pnpm dev:all`, `pnpm daemon`, `pnpm preview`, or `pnpm start`.
59- Ports are governed by `tools-dev` flags: `--daemon-port` and `--web-port`.
60- `tools-dev` exports `OD_PORT` for the web proxy target and `OD_WEB_PORT` for the web listener; do not use `NEXT_PORT`.
61 
62## Daemon data directory contract
63 
64This section is the only repository-wide source of truth for daemon-managed
65data paths. Every README, guide, deployment note, and operational handoff that
66mentions daemon data paths must point here instead of restating the rules.
67 
68This boundary is strict. Do not introduce concrete filesystem examples for the
69daemon data directory, recommended data directory, shared data directory,
70deployment mount, or example data directory. If existing code exposes a legacy
71fallback, treat it as implementation detail or a known escape candidate, not as
72a documentation pattern to copy. If a change needs a data-path rule that is not
73covered here, request a core-maintainer decision in the PR instead of inventing
74a new convention.
75 
76The daemon has one active data-root truth source:
77 
78- On daemon startup, `apps/daemon/src/server.ts` resolves `OD_DATA_DIR` into
79 `RUNTIME_DATA_DIR`.
80- All daemon-owned data paths must derive from `RUNTIME_DATA_DIR` or from a
81 constant derived from it, such as `PROJECTS_DIR` or `ARTIFACTS_DIR`.
82- `PROJECTS_DIR` is the managed-project root. Imported-folder projects are the
83 explicit exception: they use `metadata.baseDir` for the user-selected
84 external workspace.
85- `ARTIFACTS_DIR`, SQLite, app config, memory, MCP config/tokens, automation
86 state, plugin state, connector credentials, generated files, logs owned by
87 sandbox mode, and agent runtime homes are daemon data and must remain under
88 the resolved daemon data root unless this file names a specific exception.
89- Agent subprocesses receive the resolved daemon data root as `OD_DATA_DIR`.
90 They must inherit the daemon's truth source instead of guessing their own
91 data path.
92 
93Development propagation:
94 
95- `tools-dev` owns sidecar runtime/log/ipc namespacing.
96- `tools-dev --namespace <name>` does not, by itself, define daemon data
97 isolation.
98- A development run that needs an isolated daemon data root must pass
99 `OD_DATA_DIR` into the daemon process environment. After that, the daemon
100 resolves it once and all daemon data paths flow from `RUNTIME_DATA_DIR`.
101 
102Packaged propagation:
103 
104- `tools-pack` / `apps/packaged` own packaged channel and namespace layout.
105- Packaged code resolves the final namespace-scoped daemon data root before
106 spawning the daemon.
107- The packaged daemon receives that final data root as `OD_DATA_DIR`; daemon
108 code must not infer packaged data paths from app names, Electron `userData`,
109 ports, channel names, or namespace names.
110 
111Sanctioned exceptions:
112 
113- `OD_MEDIA_CONFIG_DIR` is a narrow override for `media-config.json` only. It
114 is not a second daemon data root.
115- `OD_LEGACY_DATA_DIR` is a migration source for legacy data import only. It is
116 not an active daemon data root.
117- External tool homes such as `CODEX_HOME` are integration inputs, not daemon
118 data roots. The daemon must not describe them as Open Design runtime data.
119- Agent/project-cwd skill staging aliases are not daemon data roots.
120- Manifest metadata keys and CSS identifiers are semantic namespaces, not
121 filesystem path conventions.
122 
123Known escape candidates that must not be reused:
124 
125- Module-level defaults that point at a cwd-relative legacy data directory.
126- Helper defaults such as `defaultRegistryRoots()` that recompute a data root
127 from `process.env.OD_DATA_DIR` or a cwd fallback instead of receiving
128 `RUNTIME_DATA_DIR`.
129- `openDatabase(projectRoot)` calls that rely on its fallback instead of
130 passing the resolved data root.
131- Script help text or examples that suggest concrete legacy data directories.
132 
133Do not extend these escape patterns. When a fix is obvious, route the path
134through `RUNTIME_DATA_DIR` or an explicit data-root argument. When it is not
135obvious, block the PR and request core-maintainer guidance.
136 
137## Root command boundary
138 
139- Keep root scripts reserved for true repo-level checks and tools control-plane entrypoints: `pnpm guard`, `pnpm typecheck`, `pnpm tools-dev`, `pnpm tools-pack`, and `pnpm tools-serve`.
140- Do not add root aggregate `pnpm build` or `pnpm test` aliases. Build/test commands must stay package-scoped (`pnpm --filter <package> ...`) or tool-scoped (`pnpm tools-pack ...`).
141- Do not add root e2e aliases; e2e package commands and ownership rules live in `e2e/AGENTS.md`.
142 
143## GitHub automation boundary
144 
145Read `.github/AGENTS.md` before editing `.github/workflows/`, `.github/scripts/`, `.github/actions/`, PR follow-on automation, `workflow_run` trusted writes, CI handoff artifacts, or the workflow topology checks that guard those surfaces.
146 
147CI-related GitHub automation uses a two-layer architecture:
148 
149- Business layer workflows own product or validation decisions. `ci.yml` is the main low-privilege PR, merge-queue, and manual validation workflow. It detects scope, runs checks, and produces typed handoff artifacts.
150- Atomic capability workflows own reusable trusted operations. `comment.atom.yml` publishes pure text PR comments, `autofix.atom.yml` applies same-repository patches, and `report.atom.yml` materializes advanced comments that need trusted dependencies, secrets, or report generation before upsert.
151 
152Do not add a new business-named follow-on workflow such as `foo.comment.atom.yml` or `bar.autofix.atom.yml` without first trying to express the flow as a `ci.yml` producer plus the existing `comment`, `autofix`, or `report` capability. Keep artifact naming, storage layout, and parser behavior centralized in `.github/scripts/handoff.py`; do not let individual workflows invent parallel handoff conventions.
153 
154## Release channel model
155 
156- `beta` is the daily R&D/development validation channel. It is optimized for fast development feedback and is not part of the stable promotion gate.
157- `prerelease` is the internal validation channel for stable delivery. Stable releases remain gated by validated prerelease artifacts.
158- `preview` is an independent early-access channel with stable-like release rigor. It should use preview versions such as `X.Y.Z-preview.N`, publish to the `preview` R2 channel, publish updater feeds under `preview/latest`, and follow stable's platform policy including the existing optional Linux enablement.
159- `stable` is the formal delivery channel. Do not make stable promotion depend on preview; stable continues to depend on prerelease only.
160- Public packaged app identity must stay channel-distinct: stable uses `Open Design`, beta uses `Open Design Beta`, prerelease uses `Open Design Prerelease`, and preview uses `Open Design Preview`. Do not ship beta, prerelease, or preview mac DMGs whose drag-install app bundle is `Open Design.app`.
161- Windows beta updater validation must use the real beta namespace `release-beta-win`; otherwise a local beta-like namespace can create a separate uninstall registry key while looking like the same `Open Design Beta` app. See `tools/pack/AGENTS.md` for the architecture map and high-confidence acceptance harness.
162 
163## Boundary constraints
164 
165- Tests under `apps/`, `packages/`, and `tools/` live in a package/app/tool-level `tests/` directory sibling to `src/`; keep `src/` source-only and do not add new `*.test.ts` or `*.test.tsx` files under `src/`. Playwright UI automation belongs to `e2e/ui/`, not app packages.
166- App packages must not import another app's private `src/` or `tests/` implementation as a shared helper. In particular, `apps/web/**` must not import `apps/daemon/src/**`; web/daemon integration belongs behind HTTP APIs, `packages/contracts`, and app-local provider boundaries.
167- Cross-app, cross-runtime, or repository-resource consistency checks belong in `e2e/tests/` when they need to observe more than one app/package boundary; promote reusable logic to a pure package instead of borrowing another app's private source.
168- Keep shared API DTOs, SSE event unions, error shapes, task shapes, and example payloads in `packages/contracts`; update contracts before wiring divergent web/daemon request or response shapes.
169- Keep `packages/contracts` pure TypeScript and free of Next.js, Express, Node filesystem/process APIs, browser APIs, SQLite, daemon internals, and sidecar control-plane dependencies.
170- Keep project-owned entrypoints, modules, scripts, tests, reporters, and configs TypeScript-first; generated `dist/*.js` is runtime output, and source edits belong in `.ts` files.
171- New `.js`, `.mjs`, or `.cjs` files need an explicit generated/vendor/compatibility reason and must pass `pnpm guard`.
172- App business logic must not know about sidecar/control-plane concepts. Keep sidecar awareness in `apps/<app>/sidecar` or the desktop sidecar entry wrapper.
173- Shared web/daemon app contracts belong in `packages/contracts`; that package must not depend on Next.js, Express, Node filesystem/process APIs, browser APIs, SQLite, daemon internals, or the sidecar control-plane protocol.
174- Sidecar process stamps must have exactly five fields: `app`, `mode`, `namespace`, `ipc`, and `source`.
175- Orchestration layers (`tools-dev`, `tools-pack`, packaged launchers) must call package primitives; do not hand-build `--od-stamp-*` args or process-scan regexes.
176- Packaged runtime paths must be namespace-scoped and independent from daemon/web ports; ports are transient transport details only.
177- Default runtime files live under `<project-root>/.tmp/<source>/<namespace>/...`; POSIX IPC sockets are fixed at `/tmp/open-design/ipc/<namespace>/<app>.sock`.
178 
179## Capability exposure (UI/CLI dual-track)
180 
181Every user-facing capability must be reachable through both the web UI **and** the `od` CLI (`apps/daemon/src/cli.ts`). Shipping a feature with only one of the two surfaces is a regression.
182 
183- The CLI is the embeddability contract. External agents (hermes-agent, openclaw, custom Slack/Discord bots, packaged runtimes invoked from another shell) drive Open Design through `od` subcommands — they do not render the web UI. If a capability is UI-only, it cannot be composed into those external agents.
184- Both surfaces must call the same `/api/*` endpoints; do not let the CLI talk to one shape and the UI to another. The daemon HTTP layer is the single source of truth, with `packages/contracts` carrying the shared DTOs.
185- The CLI form must support `--json` for machine-readable output and accept long-form prompts via `--prompt-file <path|->`, so jobs that pipe through `xargs`, `jq`, and `<heredoc` stay clean.
186- Adding a new capability is a three-step closure: HTTP endpoint in `apps/daemon/src/*-routes.ts` (with a contract type in `packages/contracts/src/api/`), UI surface in `apps/web/src/`, and `od <capability>` subcommand in `apps/daemon/src/cli.ts` registered through `SUBCOMMAND_MAP`. Land all three in the same PR; do not stage them across PRs.
187- The PR template's Surface area checklist must reflect *both* surfaces. If you ticked UI, tick CLI too — and vice-versa — or explain in the PR body why the missing surface is genuinely not applicable (e.g. an internal-only daemon health probe). "I'll do the CLI later" is not a valid reason.
188- Existing reference points: `od automation …` mirrors the Automations tab against `/api/routines`; `od plugin …`, `od ui …`, `od project …`, `od media …`, `od mcp …`, `od research …` follow the same shape. Copy that pattern for new capabilities.
189 
190## Git commit policy
191 
192- Git commits must not include `Co-authored-by` trailers or any other co-author metadata.
193 
194## Pull request expectations
195 
196- Opening a PR uses `.github/pull_request_template.md`; fill every section, not just the title.
197- "Why" must answer both the author's use case (what made you write this PR) and the pain being addressed (user problem, technical debt, prod issue, or unblocker), not just a one-line restatement of the title.
198- "What users will see" describes the change from a user's perspective — what they click, what new thing appears, what default behavior changed — not from a code perspective.
199- The Surface area checklist must reflect actual surfaces touched; check every box that applies, including extension points (`skills/`, `design-systems/`, `design-templates/`, `craft/`), CLI flags, env vars, i18n keys, and new root `package.json` dependencies.
200- If any UI surface is checked, attach screenshots showing the entry point — where users discover the change — not just the feature in isolation; before/after is best for behavior changes.
201- For bug-fix PRs, link the red-spec test that reproduces the bug and confirm it went red on `main` and green on the branch, per the `Bug follow-up workflow` section above.
202- `CONTRIBUTING.md` covers PR scope, title format, dependency policy, and the issue-first rule for non-trivial features; `docs/code-review-guidelines.md` is the reviewer-facing complement.
203 
204## Code review guide
205 
206- Use `docs/code-review-guidelines.md` as the repository-wide review standard. That document is the operational guide; this `AGENTS.md` is the source of truth when the two disagree.
207- Walk reviews top-down through `docs/code-review-guidelines.md`: Product relevance test → forbidden surfaces → ownership/scope → matching lane → checklist → comments → approval bar.
208- Pick the matching review lane: default code/tests, contract and protocol changes, design-system additions, skill additions, or craft additions.
209- Before reviewing changes under `apps/`, `packages/`, `tools/`, or `e2e/`, read that directory's `AGENTS.md` and apply its local boundaries.
210- Blocking review feedback should focus on correctness, security/secrets, data integrity, repository boundary violations, contract/migration breakage, missing required validation, or high-risk maintainability issues.
211- Only maintainers may close a PR instead of requesting changes, and only when the change is not salvageable on the existing branch (wrong target product, foreign test harness, DOM/API assumptions absent from this repo, or scripts that conflict with lifecycle rules).
212 
213## PR-duty tooling
214 
215This repository no longer ships a maintainer PR-duty control plane. The former
216`pnpm tools-pr` workflow has moved to the standalone `PerishCode/duty` project
217so personal review-lane automation does not become product workspace
218maintenance surface. Do not recreate `tools/pr`, `@open-design/tools-pr`, or a
219root `pnpm tools-pr` script without a new explicit maintainer decision.
220 
221## Agent runtime conventions
222 
223- `RuntimeAgentDef.promptInputFormat` selects how the daemon writes the prompt to a child's stdin. The default `'text'` writes the composed prompt and ends stdin immediately. `'stream-json'` wraps the prompt as one JSONL `user` message and KEEPS stdin open so the daemon can stream further user messages back in mid-turn. Claude (`apps/daemon/src/runtimes/defs/claude.ts`) ships `'stream-json'` together with `--input-format stream-json` as generic mid-turn input infrastructure; the daemon closes stdin once the turn terminates cleanly. Every other agent stays on `'text'`.
224- `apps/daemon/src/server.ts` tracks `run.stdinOpen` on the run object. `applyClaudeStreamJsonRunBookkeeping` closes stdin (and records `turnCompletedCleanly`) when a `turn_end` (or `usage`) event arrives with a non `tool_use` `stop_reason`. The `tool_use` stop reason means the model paused mid tool (waiting on claude-code's internal runner); closing stdin there would truncate the follow up response.
225- `claude-stream.ts` emits the `turn_end` event AFTER iterating the assistant message's content blocks, not before, so the daemon sees the final `stop_reason` and every tool_use of the turn before deciding whether to close stdin.
226- The host asks the user clarifying questions through the `<question-form>` artifact (see "Asking the user questions" below), NOT through a stdin-injected `tool_result`. There is no `AskUserQuestion` tool wiring, no `/api/runs/:id/tool-result` endpoint, and no host-answer return path; the stream-json input skeleton is retained only as generic infrastructure.
227 
228## Asking the user questions
229 
230- There is exactly one mechanism for clarifying user intent: the `<question-form>` markdown artifact the model emits inline. `AssistantMessage.tsx` renders `QuestionFormView` directly inside the originating assistant message, and answers flow back as the next user message (`formatFormAnswers` in `apps/web/src/artifacts/question-form.ts` → `POST /api/chat`). There is no separate Questions tab or native tool card.
231- `<question-form>` is valid on ANY turn, not just turn-1 discovery. Use it for turn-1 discovery briefs AND for mid-conversation clarification (e.g. an ambiguous annotation). The system-prompt guidance lives in `apps/daemon/src/prompts/system.ts` and `discovery.ts`; the API/BYOK-mode wording is mirrored through `packages/contracts/src/prompts/system.ts`.
232- `run-artifacts.ts:runAskedUserQuestion` powers the `run_finished.asked_user_question` analytics signal by scanning the run's streamed text for a `<question-form` marker (reassembled across `text_delta` chunks), not by detecting any tool call.
233 
234## Chat UI conventions
235 
236- `apps/web/src/components/file-viewer-render-mode.ts` decides URL-load vs srcDoc for HTML previews. Bridges (deck, comment/inspect selection, palette, edit, tweaks) can ONLY inject through the srcDoc path. Add a new disqualifier to `UrlLoadDecision` whenever a feature needs a srcDoc-only bridge; pass it from `FileViewer.tsx` based on a source-content heuristic where appropriate (e.g. `hasTweaksTemplate`). The host keeps both iframes mounted simultaneously and swaps CSS visibility so toggling render mode does not cause an iframe reload flash; `iframeRef.current` stays aligned with the active iframe via `useEffect`. Receive filters use `isOurIframe(ev.source)` to accept messages from either iframe but signals that should ONLY come from the active iframe (e.g. `od:tweaks-available`) re-check `ev.source === iframeRef.current?.contentWindow`.
237- TodoWrite UI pins one canonical task list above the chat composer via `PinnedTodoSlot` in `ChatPane.tsx`. The slot reads the latest TodoWrite snapshot across the conversation through `latestTodoWriteInputFromMessages` (`apps/web/src/runtime/todos.ts`). `AssistantMessage.stripTodoToolGroups` removes any TodoWrite tool groups from per message rendering so there is exactly one TodoCard on screen. The progress count includes both `completed` and `in_progress` items (1/4 reads "one underway" not "zero finished"). Dismissal via the Done button is keyed on the snapshot's JSON, so a fresh TodoWrite from the agent automatically re shows the card. `PinnedTodoSlot` sits OUTSIDE the `.chat-log` scroll container, so auto-scroll requires explicit coverage: `ChatPane`'s `ResizeObserver` accepts a `containerRef` from `PinnedTodoSlot` and observes that element directly, and a pane-level `MutationObserver` (`childList: true` on the chat pane ancestor) re-syncs that observation whenever the slot mounts or unmounts as new TodoWrite snapshots arrive.
238- Clarifying questions render through the `<question-form>` artifact directly inside the chat — see "Asking the user questions" above.
239- Tool group rendering uses `dedupeSnapshotToolRetries` to collapse `TodoWrite` snapshots (only the most recent call survives, since each call is a state replace). `SNAPSHOT_TOOL_NAMES` lists the snapshot-style tools; non-snapshot tools pass through untouched.
240 
241## Web CSS ownership
242 
243- `apps/web/src/index.css` is an import-only cascade entrypoint. Do not add selectors or declarations there; add imports only when a truly global stylesheet is needed, and keep import order intentional.
244- Shared global styles belong in `apps/web/src/styles/`: design tokens, base/reset rules, primitives, app-shell layout, and legacy cross-component selectors that cannot safely be scoped yet. Keep domain-level global files grouped by owner (for example `styles/viewer/` and `styles/workspace/`) instead of adding more large files directly under `styles/`.
245- New component-owned UI styles should default to CSS Modules next to the component (`Component.module.css`) instead of expanding global stylesheets. This is preferred for isolated components, panels, menus, drawers, toolbars, cards, and form sections.
246- When touching an existing component with nearby global styles, prefer migrating that component's local selectors to a CSS Module as part of the change if it is small and testable. Do not mix a large mechanical move with behavior/styling changes in the same patch.
247- Keep global class names only for deliberate shared contracts: reusable primitives, theme hooks, third-party/content styling, cross-component layout, or selectors that rely on global cascade/specificity. Document any new global selector group with its owning feature.
248- CSS refactors must preserve cascade semantics. For mechanical splits, verify expanded import content/order matches the previous stylesheet; for CSS Module migrations, validate the affected UI path with `pnpm --filter @open-design/web typecheck` and a focused build/test or visual check when practical.
249 
250## Web component reuse
251 
252- New `apps/web` UI should reuse shared primitives from `@open-design/components` when one exists instead of styling plain HTML elements directly. For example, use `Button` for app buttons and `VisuallyHidden` for screen-reader-only text/status content.
253- Do not add new raw primitive classes such as `primary`, `primary-ghost`, `ghost`, `subtle`, `icon-btn`, or `sr-only` for new UI. Those classes are legacy compatibility surface for existing markup until it is migrated.
254- If a needed primitive is missing, prefer adding a small focused primitive to `packages/components` with colocated CSS Modules, then consume it from the app. Keep product-specific layout and workflow styling in the app, not in `packages/components`.
255- Keep semantic plain HTML when it is content markup or a specialized control that the shared package does not model yet; do not force a migration that would hide native behavior or make a custom widget harder to reason about.
256- `apps/web` transpiles `@open-design/components` from source during dev, so component and CSS Module edits should work through the normal web dev loop without rebuilding the package.
257 
258## i18n keys
259 
260- `apps/web/src/i18n/types.ts` is the typed `Dict`; every key must be defined in all 19 locale files under `apps/web/src/i18n/locales/*.ts` (`ar`, `de`, `en`, `es-ES`, `fa`, `fr`, `hu`, `id`, `it`, `ja`, `ko`, `pl`, `pt-BR`, `ru`, `th`, `tr`, `uk`, `zh-CN`, `zh-TW`). Add the key to `types.ts` first; missing translations produce a typecheck error.
261 
262## UI animation philosophy
263 
264- Default ease-out for UI transitions: `cubic-bezier(0.23, 1, 0.32, 1)`. Built-in `ease` is too weak; `ease-in` is forbidden for UI elements because it feels sluggish.
265- Asymmetric durations: enter around 200ms, exit around 140ms. Exit reads as decisive because the user has already chosen to dismiss.
266- Accordion expand and collapse uses `grid-template-rows: 0fr -> 1fr` (modern auto height pattern). Pair with opacity fade and the easing above. The shared `.accordion-collapsible` + `.accordion-collapsible-inner` class pair (defined in `apps/web/src/index.css`) is the canonical implementation; reuse it for new disclosure UI.
267- Never animate from `transform: scale(0)`. Start from `scale(0.9)` or higher with `opacity: 0`.
268- For elements that show conditionally, keep them mounted and toggle a CSS class (e.g. `.chat-jump-btn-active`). React unmounts skip the exit transition entirely.
269 
270## Validation strategy
271 
272- Before adding, repairing, or optimizing tests, follow
273 [`docs/testing/test-efficiency.zh-CN.md`](docs/testing/test-efficiency.zh-CN.md)
274 for completion signals, virtual-clock usage, isolation, and performance
275 validation.
276- After package, workspace, or command-entry changes, run `pnpm install` so workspace links and generated dist entries stay fresh.
277- For agent-stream / parser changes (`apps/daemon/src/runtimes/claude-stream.ts`, `json-event-stream.ts`, `qoder-stream.ts`, etc.), replay a recorded session through the mock CLIs in `mocks/` to verify event shapes round-trip without burning provider budget. PATH-overlay activation: `export PATH="$PWD/mocks/bin:$PATH" OD_MOCKS_TRACE=<8-char-id> OD_MOCKS_NO_DELAY=1`. See `mocks/README.md` for the trace catalog and selection knobs.
278- Treat every `pnpm-lock.yaml` change that affects Nix packaging as requiring a Nix pnpm deps hash refresh when you maintain the flake. `nix/pnpm-deps.nix` is a generated lock artifact; use `pnpm nix:update-hash` then re-run `nix flake check --print-build-logs --keep-going` locally. Standalone `.github/workflows/nix.yml` runs flake check when nix/lock inputs change; it is **not** part of core `ci.yml` / `Validate workspace` / merge queue. Docker image smoke/publish lives only in `.github/workflows/docker-image.yml` and is likewise outside the merge gate.
279- Before marking regular work ready, run at least `pnpm guard` and `pnpm typecheck`, plus the package-scoped tests/builds that match the files changed. Do not use or add root `pnpm test`/`pnpm build` aliases.
280- For local web runtime loops, prefer `pnpm tools-dev run web --daemon-port <port> --web-port <port>`.
281- For e2e tests that need a tools-dev daemon/web runtime, use the shared tools-dev harness under `e2e/lib/tools-dev/` and the framework suite adapters (`e2e/lib/playwright/suite.ts`, `e2e/lib/vitest/suite.ts`). Do not hand-spawn `tools-dev` from test cases or duplicate lifecycle helpers under framework-specific folders.
282- Playwright UI tests must import `test`/`expect` from `@/playwright/suite`, not directly from `@playwright/test`; type-only imports from `@playwright/test` remain fine. The suite owns one isolated tools-dev daemon/web/data root per Playwright worker. Do not add a shared-runtime fallback; set Playwright workers to `1` when constrained.
283- Playwright suite code must not own workspace prebuild policy. CI and callers keep the existing prebuild steps; `tools-dev` daemon freshness checks are only a fallback guard.
284- On a GUI-capable machine, validate desktop by running `pnpm tools-dev`, then `pnpm tools-dev inspect desktop status`.
285- Stamp/namespace changes must validate two concurrent namespaces and run desktop `inspect eval` plus `inspect screenshot` for each namespace.
286- Path/log changes must run `pnpm tools-dev logs --namespace <name> --json` and confirm log paths are under `.tmp/tools-dev/<namespace>/...`.
287 
288## Bug follow-up workflow
289 
290The following is a working playbook for routine bug follow-ups, distilled from recent practice. Treat it as a default action shape, not a contract — production reality always has edges these bullets can't anticipate, so use judgment when the situation doesn't fit cleanly.
291 
292- **Lead with a red spec.** Default to encoding the bug as a falsifiable test that goes red before any source change, so the fix is anchored in observable behavior rather than source-code intuition. If a red spec can't be written cheaply, that's usually a signal to clarify scope rather than push forward on a guess.
293- **Try the cheapest layer first.** Reach for the lightest test layer that can still see the symptom (e2e Vitest at the daemon HTTP boundary → app-local Vitest → Playwright UI → platform-native harnesses), and drop down only when the cheaper layer can't.
294- **Hold the spec's scope.** Defects discovered outside the bug's described boundary belong in a follow-up — their own red spec, their own PR — not in this fix. List them in the PR body's "Adjacent issues" section with the rationale and move on.
295- **Let the fix read as an invariant.** Prefer a named helper whose docblock describes what must hold over a bolt-on `if` guard with apologetic history-comments. The call site should read as intent.
296- **Diff against the baseline.** When neighboring suites have pre-existing failures, stash or check out upstream before claiming "no new failures."
297- **Link the issue from the PR body.** Use `Fixes #N` / `Closes #N` / `Resolves #N` so the issue auto-closes on merge and the release-time reverse lookup (`gh issue view N --json closedByPullRequestsReferences` → `git tag --contains <merge sha>`) actually has a chain to follow. The repo's PR template prompts for this; deleting the prompt is fine when the PR genuinely closes nothing.
298- **Stage human verification for visible bugs.** When the symptom needs an eye to confirm — UI, platform-native behavior, animations, race conditions a unit test can't see — green specs alone aren't acceptance. Stand up a buggy-vs-fix comparison the reviewer can drive themselves (typical shape: two namespaced runtimes, one on `main`, one on the fix branch), and seed any required data only through production HTTP APIs; source-level test backdoors invalidate the verification because they prove a fake flow rather than the real one.
299 
300For a worked example of one full loop (red e2e spec → fix → green), see `e2e/tests/dialog/stop-reconciles-message.test.ts` (issue #135).
301 
302# Common commands
303 
304```bash
305pnpm install
306pnpm nix:update-hash
307pnpm tools-dev
308pnpm tools-serve start updater
309pnpm tools-dev start web
310pnpm tools-dev run web --daemon-port 17456 --web-port 17573
311pnpm tools-dev status --json
312pnpm tools-dev logs --json
313pnpm tools-dev inspect desktop status --json
314pnpm tools-dev inspect desktop screenshot --path /tmp/open-design.png
315pnpm tools-dev stop
316pnpm tools-dev check
317```
318 
319```bash
320pnpm guard
321pnpm typecheck
322```
323 
324```bash
325pnpm --filter @open-design/web typecheck
326pnpm --filter @open-design/web test
327pnpm --filter @open-design/web build
328pnpm --filter @open-design/daemon test
329pnpm --filter @open-design/daemon build
330pnpm --filter @open-design/desktop build
331pnpm --filter @open-design/tools-dev build
332pnpm --filter @open-design/tools-pack build
333pnpm --filter @open-design/tools-serve build
334```
335 
336```bash
337pnpm tools-pack mac build --to all
338pnpm tools-pack mac install
339pnpm tools-pack mac cleanup
340pnpm tools-pack win build --to nsis
341pnpm tools-pack win install
342pnpm tools-pack win cleanup
343pnpm tools-pack linux build --to appimage
344pnpm tools-pack linux install
345pnpm tools-pack linux build --containerized
346```
347 
348# FAQ
349 
350## Why is there no root `pnpm dev` / `pnpm start`?
351 
352To avoid starting daemon, web, and desktop through inconsistent env, port, namespace, or log paths. All local lifecycle flows must go through `pnpm tools-dev`.
353 
354## Why should `apps/nextjs` not be restored?
355 
356The current web runtime is `apps/web`. The historical `apps/nextjs` layout has been removed from the active repo shape; restoring it would reintroduce duplicate app boundaries and stale scripts.
357 
358## How does desktop discover the web URL?
359 
360Desktop queries runtime status through sidecar IPC. The web URL comes from `tools-dev` launch status, not from desktop guessing ports or reading web internals.
361 
362## How are sidecar-proto, sidecar, and platform split?
363 
364`@open-design/sidecar-proto` owns Open Design app/mode/source constants, namespace validation, stamp fields/flags, IPC message schema, status shapes, and error semantics. `@open-design/sidecar` provides only generic bootstrap, IPC transport, path/runtime resolution, launch env, and JSON runtime files. `@open-design/platform` provides only generic OS process stamp serialization, command parsing, and process matching/search primitives, consuming the proto descriptor.
365 
366## When is `pnpm install` required?
367 
368Run `pnpm install` after changing package manifests, workspace layout, command entrypoints, bin/link-related content, or after adding/removing workspace packages.
369 
370## Can I use Node 22 instead of Node 24?
371 
372No. `package.json#engines` specifies `node: "~24"`, which is the only supported runtime. The current lockfile pins `better-sqlite3@11.10.0`; on Windows it has no prebuilt binary for Node 24 and is built from source via node-gyp (see the Windows native section). Older Node versions are not tested and may hit lockfile or dependency incompatibilities.
373 

Commands it names

  • pnpm install
  • pnpm nix:update-hash
  • pnpm tools-dev
  • pnpm tools-serve start updater
  • pnpm tools-dev start web
  • pnpm tools-dev run web --daemon-port 17456 --web-port 17573
  • pnpm tools-dev status --json
  • pnpm tools-dev logs --json
  • pnpm tools-dev inspect desktop status --json
  • pnpm tools-dev inspect desktop screenshot --path /tmp/open-design.png
  • pnpm tools-dev stop
  • pnpm tools-dev check
  • pnpm guard
  • pnpm typecheck
  • pnpm --filter @open-design/web typecheck
  • pnpm --filter @open-design/web test
  • pnpm --filter @open-design/web build
  • pnpm --filter @open-design/daemon test
  • pnpm --filter @open-design/daemon build
  • pnpm --filter @open-design/desktop build
  • pnpm --filter @open-design/tools-dev build
  • pnpm --filter @open-design/tools-pack build
  • pnpm --filter @open-design/tools-serve build
  • pnpm tools-pack mac build --to all
  • pnpm tools-pack mac install
  • pnpm tools-pack mac cleanup
  • pnpm tools-pack win build --to nsis
  • pnpm tools-pack win install
  • pnpm tools-pack win cleanup
  • pnpm tools-pack linux build --to appimage
  • pnpm tools-pack linux install
  • pnpm tools-pack linux build --containerized
  • pnpm-workspace.yaml
  • pnpm@10.33.2
  • node --version
  • npm install -g pnpm@10.33.2
  • pnpm dev
  • pnpm dev:all
  • pnpm daemon
  • pnpm preview

Sections

  • Directory guide
  • Core documentation index
  • Workspace directories
  • Inactive or placeholder directories
  • Development workflow
  • Environment baseline
  • Windows native
  • Local lifecycle
  • Daemon data directory contract
  • Root command boundary
  • GitHub automation boundary
  • Release channel model
  • Boundary constraints
  • Capability exposure (UI/CLI dual-track)
  • Git commit policy
  • Pull request expectations
  • Code review guide
  • PR-duty tooling
  • Agent runtime conventions
  • Asking the user questions
  • Chat UI conventions
  • Web CSS ownership
  • Web component reuse
  • i18n keys
  • UI animation philosophy
  • Validation strategy
  • Bug follow-up workflow
  • Common commands
  • FAQ
  • Why is there no root `pnpm dev` / `pnpm start`?
  • Why should `apps/nextjs` not be restored?
  • How does desktop discover the web URL?
  • How are sidecar-proto, sidecar, and platform split?
  • When is `pnpm install` required?
  • Can I use Node 22 instead of Node 24?

What it covers

setuptestcode-stylearchitecturetesting-strategygit-prsecurityapiuideploymentmonorepoagent-behaviourdocs

Stack — with the evidence

typescript

(1.00)

node

(0.95)

vitest

(0.95)

playwright

(0.95)

monorepo

(0.85)

pnpm

(0.85)

react

(0.70)

nextjs

(0.70)

astro

(0.70)

express

(0.70)

tailwind

(0.70)

aws

(0.70)

desktop-app

(0.70)

javascript

(0.60)

kubernetes

(0.60)

github-actions

(0.60)

vercel

(0.60)

Format

AGENTS.md

A plain-markdown README for coding agents, deliberately unopinionated: no frontmatter, no globs, no vendor keys. That minimalism is why it became the one file a dozen different agents will read, and why it carries the least per-file targeting power of any format here.

What the corpus says about it

Repository

Owner
nexu-io
Language
—
License
—
Archived
no

All configs in this repo

Also in nexu-io/open-design

Diff this repo’s formats

One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?

The other instruction files in this repository
RepositoryFormatStackCoversScoreChanged
nexu-io/open-designplugins/AGENTS.md · 83kAGENTS.mdtypescriptnode+15stylearchsecuritydo-not68/1003 days ago
nexu-io/open-design.github/AGENTS.md · 83kAGENTS.mdtypescriptmonorepo+15stylearchgitapi+383/1003 days ago
nexu-io/open-designapps/AGENTS.md · 83kAGENTS.mdtypescriptplaywright+15testarchmonorepo90/1003 days ago
nexu-io/open-designapps/daemon/AGENTS.md · 83kAGENTS.mdtypescriptvitest+15teststylearchtesting-strategy+486/1003 days ago
nexu-io/open-designapps/daemon/src/critique/AGENTS.md · 83kAGENTS.mdtypescriptnode+15archtesting-strategymonorepo52/1003 days ago
nexu-io/open-designapps/landing-page/AGENTS.md · 83kAGENTS.mdtypescriptastro+16apideploymentmonorepo82/1003 days ago
nexu-io/open-designapps/packaged/AGENTS.md · 83kAGENTS.mdtypescriptvitest+15monorepodo-not54/1003 days ago
nexu-io/open-designapps/web/src/components/Theater/AGENTS.md · 83kAGENTS.mdtypescriptvitest+15testarchmonorepo72/1003 days ago
nexu-io/open-designdesign-systems/_schema/AGENTS.md · 83kAGENTS.mdtypescriptnode+15archtesting-strategyapi58/1003 days ago
nexu-io/open-designdesign-templates/AGENTS.md · 83kAGENTS.mdtypescriptnode+15apiui43/1003 days ago
nexu-io/open-designe2e/AGENTS.md · 83kAGENTS.mdtypescriptvitest+15teststylearchtesting-strategy+393/1003 days ago
nexu-io/open-designpackages/AGENTS.md · 83kAGENTS.mdtypescriptnode+15archdependenciesmonorepo86/1003 days ago
nexu-io/open-designskills/AGENTS.md · 83kAGENTS.mdtypescriptnode+15no sections39/1003 days ago
nexu-io/open-designtools/AGENTS.md · 83kAGENTS.mdtypescriptplaywright+15testing-strategy82/1003 days ago
nexu-io/open-designtools/pack/AGENTS.md · 83kAGENTS.mdtypescriptvitest+16styletesting-strategyperformancedeployment+185/1003 days ago
nexu-io/open-designtools/serve/AGENTS.md · 83kAGENTS.mdtypescriptvitest+15do-not32/1003 days ago
Diff against plugins/AGENTS.md Diff against .github/AGENTS.md Diff against apps/AGENTS.md Diff against apps/daemon/AGENTS.md Diff against apps/daemon/src/critique/AGENTS.md Diff against apps/landing-page/AGENTS.md Diff against apps/packaged/AGENTS.md Diff against apps/web/src/components/Theater/AGENTS.md Diff against design-systems/_schema/AGENTS.md Diff against design-templates/AGENTS.md Diff against e2e/AGENTS.md Diff against packages/AGENTS.md Diff against skills/AGENTS.md Diff against tools/AGENTS.md Diff against tools/pack/AGENTS.md Diff against tools/serve/AGENTS.md

Similar configs

Same format, overlapping stack, ranked by quality.

Same format, overlapping stack, ranked by quality
RepositoryFormatStackCoversScoreChanged
n8n-io/n8npackages/@n8n/agents/AGENTS.md · 199kAGENTS.mdtypescriptlangchain+16buildteststylearch+3100/1003 days ago
TryGhost/Ghoste2e/AGENTS.md · 55kAGENTS.mdtypescriptjavascript+12setupteststylearch+2100/1003 days ago
SkeneTechnologies/skene-cookbookAGENTS.md · 51AGENTS.mdpythoneslint+4setupbuildtestlint-format+7100/1002 days ago
mui/material-uiAGENTS.md · 99kAGENTS.mdtypescriptjavascript+13setupbuildtestlint-format+9100/1003 days ago
aaif-goose/gooseAGENTS.md · 52kAGENTS.mdrusttypescript+2setupbuildtestlint-format+6100/1003 days ago
duckduckgo/content-scope-scriptsspecial-pages/AGENTS.md · 70AGENTS.mdtypescriptjavascript+5buildteststylearch+3100/1003 days ago
trick77/agents-md-syncAGENTS.md · 2AGENTS.mdtypescriptnode+4setupbuildteststyle+5100/1003 days ago
code-yeongyu/oh-my-openagentpackages/web/AGENTS.md · 67kAGENTS.mdtypescriptbun+10setupbuildtestlint-format+6100/1002 days ago
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack