clawdis / ui
steipete/clawdis/ui/AGENTS.md
UI ownership rules here; repo-global architecture, proof, Git rules in root AGENTS.md. The Control UI and its plugin views use Solid 2 and native primitives. Lit and Web Awesome have been removed from these surfaces. Solid route modules expose renderSolid(props) from the existing lazy page import. The outlet mounts that renderer once and supplies live data, loaderPending, and presented props; loader updates must preserve page-local state. Keep page imports inside their route's component loader.
What's in it
- Control UI Guide
- Solid
- State Ownership And Async Results
- Session Roster Refresh
- Reload Performance
- i18n Rules
- CSS / Template Linting
- Stylesheet Policy
- Modal Completion Actions
- Gateway Coupling
- Build Chunking
- Live Verification
- Scope
- Visual Proof
# Control UI Guide
UI ownership rules here; repo-global architecture, proof, Git rules in root `AGENTS.md`.
## Solid
- Before writing, reviewing, or refactoring any Solid code here, read the [Solid skill](../.agents/skills/solid/SKILL.md) in full, the installed `node_modules/solid-js/CHEATSHEET.md` it points to, and the references it routes you to; for existing code, the [refactor checklist](../.agents/skills/solid/references/refactor-checklist.md). State ownership below still applies.
The Control UI and its plugin views use Solid 2 and native primitives. Lit and
Web Awesome have been removed from these surfaces.
Solid route modules expose `renderSolid(props)` from the existing lazy page import.
The outlet mounts that renderer once and supplies live `data`, `loaderPending`, and
`presented` props; loader updates must preserve page-local state. Keep page
imports inside their route's `component` loader.
## State Ownership And Async Results
- Gateway owns shared state; renderer copies = caches; views own presentation state. Reuse owning store/controller + Gateway contract for session, config, authorization decisions.
- Scope caches/requests to connection, agent, session. Before publishing: check owner + request generation; old results must not overwrite newer intent/another context.
- Optimistic updates: retain visible recovery state + reconcile with authority. Old requests must not roll back newer edits. Failed writes follow Gateway [target and outcome contract](../src/gateway/AGENTS.md#write-target-and-outcome), never renderer-selected fallback account/connection.
- Background updates may refresh scoped cache, never replace foreground selection/publish another context's state.
## Session Roster Refresh
- `src/lib/sessions/session-list-query.ts` owns held-window reconciliation. Lifecycle, participants, placement, patch/send/steer, run-start/settlement/capacity, title snapshots may skip list reads only with unchanged membership, lineage, pin/owner/archive facts + nondecreasing recency. Tree events: complete access-scoped `ancestorSessions` + any `ancestorSessionRefs`; references need held row's admitted content revision. Preserve each row's generation + field receipts. Certified nested rows own facts; only explicit null clearing receipts may fill omissions from envelope.
- Authoritative refreshes required: unknown rows, incomplete ancestor coverage, broad/catalog changes, Gateway-owned filters, failed reads, uncertain owner-prefix boundaries. Overlapping reads recheck later row receipts against their accepted membership; covered facts merge without trailing reads. Events never create filtered membership; only complete unfiltered active-only Current Work windows may admit certified full active rows below.
- Sidebar windows may exclude certified rows below a full recency window; owner-first overflow crossing into the shared page still needs authority. Involving-me members need current viewer ownership or participant receipts and explicit non-hidden state; bounded participants cannot prove non-membership or admit unseen members.
- Compact rows + bounded source attribution. Enrichment flags/global-or-unknown inclusion preserve membership when kind unchanged; dashboard filters need matching `hasBoard`/`boardFace` receipts. Gallery pagination extends shared managed window; load full settings from descriptors on demand. Child membership: Gateway retention owner's `childOwnerSessionKeys`. Parent-only events must certify complete child window; unheld ancestors need explicit exclusion or admitted reference resolved through connection row provenance.
- Cached lineage re-adoption changes presentation, not managed membership. Preserve fresh descriptor/event invalidation. Apply admitted descriptor rows immediately; incomplete ancestor coverage gets one paced coordinator refresh, never read per event.
- Unfiltered History/Current Work: apply admitted rows without list refetches. History's shared row-provenance owner retains field clocks, recap updates, clearing receipts; returned lists alone own membership. `excludeSubagents` ignores key-proven child exclusions only with complete access-scoped ancestor coverage; held parents/certified references still update. Missing held parents/supplied unheld ancestors need authority; named unheld parents absent from certified coverage may be invisible. Merge live facts on refresh, never replay/coalesce History packets. Missing initial membership needs catch-up; query/connection changes reset provenance. History: forward activity clocks required; preserve omitted recap enrichment; person/search filters retain authoritative refreshes.
- Current Work: coalesce only consecutive full active snapshots of one generation, retaining first receipt/latest tail. Partial events, references, terminal snapshots, other identities = FIFO barriers. Complete window below limit may admit certified active row with real session ID/kind, sampled after accepted list + generation retirement/liveness clocks; preserve Gateway cron-run exclusion. Truncated/full windows, conflicting generations, partial unknown rows, ambiguous settlement, incomplete-window removals need authority.
- Current Work: apply ancestor snapshots/references via shared reconciler; pending references retain prerequisite full-row receipts. Controller caps generation-coalesced fence records at 1,000; reconciler owns independent retirement, liveness-observation, generation-authority facts. Only retirement prunes stale returned rows. Fresh certified full rows may resolve older clocked liveness; unclocked observations/conflicting generations need list read. Query/connection changes clear records. Authoritative lists clear uncertainty + covered retirements before pending replay, preserving later retirements. Saturation blocks unseen admission until authoritative read restores bounded state.
- Healthy applied row traffic retains one fallback refresh after at least 60 seconds, including whole-query people/pulse facets. `src/lib/sessions/event-refresh-coordinator.ts` owns pacing + pending/trailing invalidation: sample four-to-five-second collection window once when armed; events cannot postpone it. After automatic refresh: wait three times its duration, bounded to five–15 seconds.
- Accepted local creates refresh observed list membership independently of primary reads/bootstrap. Create events skip coordinator collection/backoff but retain visibility, bootstrap admission, and queued navigation ownership; the Gateway still owns owner/involvement/search filtering. Other event invalidations retain coordinator pacing.
- Explicit refresh, filter/agent changes, reconnects, foreground replacement bypass backoff + absorb pending invalidation. Recheck visibility/current intent after background admission; hidden pages retain one catch-up until visible.
## Reload Performance
- Prove the bench executes the live hot function with `--cpu-profile` before measuring a fix; never mix profiled and unprofiled timings.
- Reload cost is main-thread render/reconcile triggered per Gateway message; JSON parse and transport are negligible. Measured no win or regressions (2026-10-15, Team-scale bench, quiet AWS, ≥7 interleaved pairs): socket worker/SharedWorker, delivery scheduling/chunking, batched boot RPC, V8 compile hints/chunk sizing, cached DOM shell replay. WebSocket permessage-deflate saves bytes on slow links, not render time. Retry only with new evidence.
- Cut work at its owner: memoize values read per item (`createMemo`), render reused UI as components rather than helper calls, keep row identity through placement/history/live updates, check cheap state before reading layout.
- Measure with `scripts/bench-control-ui-cold-load.ts` (long-task and render-pass probes) over several untraced runs; single DevTools traces inflate timing.
## i18n Rules
- Foreign `src/i18n/locales/*.ts` = stable source-owned lazy adapters; translations from canonical grouped `src/i18n/.i18n/*.tm.jsonl`. Never hand-edit translation memory, locale/fallback metadata unless targeted generated-output fix requested.
- English: `src/i18n/locales/en.ts`, static `en-agents.ts`, lazy `en-*.ts` registrars. `scripts/lib/control-ui-i18n-catalog.ts` owns ordered composition + raw source hashes for generation, verification, Vite; reads `.catalog` data without runtime registration. Wiring owners: `scripts/control-ui-i18n.ts`, `scripts/lib/control-ui-i18n-sync-plan.ts`, `ui/config/control-ui-locales.ts`, `ui/src/i18n/lib/{types,registry}.ts`.
- Register lazy English synchronously at each consumer, including Settings search before page load. Keep startup/shared copy eager; preserve shared `en` + sibling namespaces. Retain empty subtree anchors when extraction changes flattened order/grouped memory aliases. Never import host catalog owner into runtime.
- Source PRs: update English/adapters/wiring, run keyless `pnpm ui:i18n:baseline`, commit changed raw-copy baseline. Exclude fallback/locale metadata + translation memory: CI rejects mixed diffs except canonical `release/YYYY.M.PATCH` branches or detected complete canonical-memory migrations.
- Deterministic keyless `pnpm ui:i18n:verify`: English shape, runtime wiring, raw-copy drift in lint/changed-check UI. Foreign parity: post-merge bot + strict generated-output gate.
- Serialized `control-ui-locale-refresh`: translate after merge, open generated PR with exact-head auto-merge. Authenticated `pnpm ui:i18n:sync`: maintainer/release repair path; new keys require provider auth. Drift: workflow/release prep, never manual translation/merging generated outputs.
- `pnpm release:prep` syncs before freeze; `pnpm ui:i18n:check` = zero-fallback release/generated-output gate. `pnpm ui:i18n:report` = hardcoded-copy priorities + fallback metadata, not drift.
## CSS / Template Linting
- `pnpm lint`: Solid 2 oxlint rules on `ui/**/*.tsx` and TypeScript helpers in `src/lib/reactive/`, `src/components/solid/`, and `src/test-helpers/`; plain domain owners keep their own contracts. Follow the [Solid idioms](../.agents/skills/solid/references/idioms.md) for split effects, tracking, and lifecycle. `tools/solid-lint` isolates plugin tooling dependencies; corpus: `test/scripts/oxlint-solid.test.ts`.
- `pnpm lint:ui:styles` (included in lint): `ui/src` stylesheets via `config/stylelint.config.mjs`. Stylelint owns error rules; oxfmt owns formatting.
## Stylesheet Policy
- No universal targets/pseudo-elements after `:has()` compound, `:has()` with `::placeholder`, or descendants after sibling-relative `:has(+ …)` on repeated items. Use owner-set classes, named children, or subject custom property. No `:has()` subjects on `.shell`, `.content`, `.chat-thread`, `.chat-split-view`, `:root`, `html`, `body`, including modifiers, `:is()`/`:where()`, nested `&`: insertions restyle subtree; stylelint cannot resolve nesting.
- New-tab links/controls: pointer cursors; state-changing controls: default arrow.
- Colors: `src/styles/base.css` tokens (`color-no-hex`). Stated exemptions: token definitions, `lobster-pet.css` artwork, `--theme-chip-*` previews.
- `max-width` breakpoints: 400/560/640/768/900/1100/1320px + 932×500 landscape-phone compound. Round new thresholds up; new rungs require config comment + this rule updates.
- Duplicate selectors = errors; deliberate topic reopens need `stylelint-disable-next-line no-duplicate-selectors -- <reason>`.
- `node --import tsx scripts/audit-control-ui-dead-css.mts` advisory. Verify selectors before deleting; extend dynamic-stem detection, not allowlist.
- Nest CSS only while rewriting section; no conversion sweeps.
- No `@layer`: shared light-DOM CSS depends on import order/specificity + lazy page CSS. Reconsider only with computed-style parity across all routes on mocked dev server.
## Modal Completion Actions
- Place workflow completion actions last in `<openclaw-modal-actions>`, after content, status and validation errors. The native modal stylesheet owns right alignment, wrapping and label containment. Keep submit buttons inside their native form; no renderer or custom-element registration is needed. Caller styles own spacing, not competing alignment or mobile full-width rules. Header X/Expand and field-local controls are not completion actions. Scrollable panels respect `--openclaw-modal-height-limit` so the footer stays reachable. Set the intended width with `--openclaw-modal-width` on the native host and let child panels fill the shell instead of imposing a wider independent width.
## Gateway Coupling
- UI/Gateway ship as one install/version. Never older-Gateway method fallbacks/version-conditional UI behavior. `isGatewayMethodAdvertised` only gates config/plugin-dependent features.
- Handshake rejects Gateway-served same-origin skew. Exempt `pnpm ui:dev`, custom `gateway.controlUi.root`, cross-origin/connection-settings dialing remain unsupported for mismatch: no compat, visible failure at first missing method. Rejection at connect = separate server-owned product change.
## Build Chunking
- Generated `config/control-ui-boot-modules.json` records ready `/new` + `/chat` captures: fetched modules reachable from HTML/requested dynamic entries, static imports, dynamic imports resolving into fetched chunks. Keep route-exclusive/shared `control-ui-boot-*` groups separate in `config/control-ui-chunking.ts`; co-located chat-only code must stay out of New Session. `entries` lists requested dynamic entries; `config/control-ui-boot-preloads.ts` follows static dependencies into inert route preload templates activated by Gateway. CSS hints preload bytes without changing insertion order.
- Material boot-path changes: `pnpm ui:boot-manifest:gen`, then `pnpm ui:build` to verify grouped output. Generation: temporary build with measured groups disabled/inactive templates, preventing stale-capture feedback. Never hand-edit manifest.
## Live Verification
- Gateway serves `dist/control-ui`; source edits need `pnpm ui:build`. Before trusting live result: verify served `/assets/index-*.js` hash changed.
## Scope
- UI-specific rules here; root `AGENTS.md` owns repo-global workflow.
## Visual Proof
- Substantial UI design changes: follow [Control UI stress test](../.agents/skills/control-ui-e2e/SKILL.md#ui-stress-test); inspect states in HTML gallery + collect per-example feedback.
- Never capture the retired Discord invitation artwork. Mock/E2E harnesses default to `communityInvite: false`; compact Community entry scenarios opt in with `communityInvite: true`. Capture only the current entry and on-demand sheet, with synthetic content.
More agent context in steipete/clawdis
107 other files this repository gives its agents, the first 60 shown.
Skill
- agent-transcript.agents/skills/agent-transcript/SKILL.md
- auto-qa.agents/skills/auto-qa/SKILL.md
- autoreview.agents/skills/autoreview/SKILL.md
- channel-message-flows.agents/skills/channel-message-flows/SKILL.md
- clawdtributor.agents/skills/clawdtributor/SKILL.md
- claw-score.agents/skills/claw-score/SKILL.md
- clawsweeper.agents/skills/clawsweeper/SKILL.md
- control-ui-e2e.agents/skills/control-ui-e2e/SKILL.md
- crabbox.agents/skills/crabbox/SKILL.md
- discord-clawd.agents/skills/discord-clawd/SKILL.md
- discord-e2e.agents/skills/discord-e2e/SKILL.md
- discord-user-post.agents/skills/discord-user-post/SKILL.md
- discrawl.agents/skills/discrawl/SKILL.md
- gitcrawl.agents/skills/gitcrawl/SKILL.md
- graincrawl.agents/skills/graincrawl/SKILL.md
- notcrawl.agents/skills/notcrawl/SKILL.md
- openclaw-changelog-update.agents/skills/openclaw-changelog-update/SKILL.md
- openclaw-ci-limits.agents/skills/openclaw-ci-limits/SKILL.md
- openclaw-debugging.agents/skills/openclaw-debugging/SKILL.md
- openclaw-docker-e2e-authoring.agents/skills/openclaw-docker-e2e-authoring/SKILL.md
- openclaw-ghsa-maintainer.agents/skills/openclaw-ghsa-maintainer/SKILL.md
- openclaw-live-updater.agents/skills/openclaw-live-updater/SKILL.md
- openclaw-parallels-smoke.agents/skills/openclaw-parallels-smoke/SKILL.md
- openclaw-pr-maintainer.agents/skills/openclaw-pr-maintainer/SKILL.md
- openclaw-qa-testing.agents/skills/openclaw-qa-testing/SKILL.md
- openclaw-refactor-docs.agents/skills/openclaw-refactor-docs/SKILL.md
- openclaw-release-validation.agents/skills/openclaw-release-validation/SKILL.md
- openclaw-repair-sweep.agents/skills/openclaw-repair-sweep/SKILL.md
- openclaw-secret-scanning-maintainer.agents/skills/openclaw-secret-scanning-maintainer/SKILL.md
- openclaw-test-heap-leaks.agents/skills/openclaw-test-heap-leaks/SKILL.md
- openclaw-testing.agents/skills/openclaw-testing/SKILL.md
- openclaw-test-performance.agents/skills/openclaw-test-performance/SKILL.md
- openclaw-update.agents/skills/openclaw-update/SKILL.md
- parallels-discord-roundtrip.agents/skills/parallels-discord-roundtrip/SKILL.md
- plugin-sdk-impact.agents/skills/plugin-sdk-impact/SKILL.md
- proof-video.agents/skills/proof-video/SKILL.md
- prototype-openclaw-tui.agents/skills/prototype-openclaw-tui/SKILL.md
- pr-simplify.agents/skills/pr-simplify/SKILL.md
- release-openclaw-announcement.agents/skills/release-openclaw-announcement/SKILL.md
- release-openclaw-ci.agents/skills/release-openclaw-ci/SKILL.md
- release-openclaw-mac.agents/skills/release-openclaw-mac/SKILL.md
- release-openclaw-maintainer.agents/skills/release-openclaw-maintainer/SKILL.md
- release-openclaw-plugin-testing.agents/skills/release-openclaw-plugin-testing/SKILL.md
- security-triage.agents/skills/security-triage/SKILL.md
- slack-e2e.agents/skills/slack-e2e/SKILL.md
- slacrawl.agents/skills/slacrawl/SKILL.md
- solid.agents/skills/solid/SKILL.md
- tag-duplicate-prs-issues.agents/skills/tag-duplicate-prs-issues/SKILL.md
- technical-documentation.agents/skills/technical-documentation/SKILL.md
- telegram-e2e-userbot.agents/skills/telegram-e2e-userbot/SKILL.md
- test-audit.agents/skills/test-audit/SKILL.md
- update-team-server.agents/skills/update-team-server/SKILL.md
- verify-release.agents/skills/verify-release/SKILL.md
- 1passwordskills/1password/SKILL.md
- apple-notesskills/apple-notes/SKILL.md
Also found in 2 other repositories
The same file, byte for byte, in the weekly crawl of public GitHub.
- clawdbot/clawdbot392k
- moltbot/moltbot392k
Discussion
Talked about elsewhere, linking to steipete/clawdis
- Add clawdis repository as submodule
YouTube · maxzherman/elements · Jan 9, 2026
- Add clawdis repository as submodule
GitHub · maxzherman/elements · Jan 9, 2026
- macOS Swift Compiler Crash in OnboardingView+Wizard.swift
YouTube · openclaw/openclaw · 2 comments · Jan 3, 2026
- macOS Swift Compiler Crash in OnboardingView+Wizard.swift
GitHub · openclaw/openclaw · 2 comments · Jan 3, 2026
- Missing TypeScript Type Definitions for Discord Actions Config
YouTube · openclaw/openclaw · 1 comments · Jan 3, 2026
- Missing TypeScript Type Definitions for Discord Actions Config
GitHub · openclaw/openclaw · 1 comments · Jan 3, 2026
- Bug: Broken @mariozechner/pi-ai Patch After Upstream Update
YouTube · openclaw/openclaw · 1 comments · Jan 3, 2026
- Bug: Broken @mariozechner/pi-ai Patch After Upstream Update
GitHub · openclaw/openclaw · 1 comments · Jan 3, 2026
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

