Integrate current dev while preserving the mission routes, durable execution controls and specialist cleanup. Retain native usage route dependencies and align local plugin dependencies and architecture guidance with OpenCode 2.0.21. Combine the workspace file reader with the mission reader in the central session surface. Explicit reader selection dismisses the competing preview without losing stored editor drafts or the composer. Extend the real-session browser regression to cover switching between both readers. Validate server and UI typechecks and all ten mission browser/i18n tests. Preserve the upstream Tao patch unchanged, including its original whitespace and provenance.
31 KiB
AGENT NOTES
Styling Guidelines
- Reuse the existing token & utility layers before introducing new CSS variables or custom properties. Extend
src/styles/tokens.css/src/styles/utilities.cssif a shared pattern is needed. - Keep aggregate entry files (e.g.,
src/styles/controls.css,messaging.css,panels.css) lean—they should only@importfeature-specific subfiles located insidesrc/styles/{components|messaging|panels}. - When adding new component styles, place them beside their peers in the scoped subdirectory (e.g.,
src/styles/messaging/new-part.css) and import them from the corresponding aggregator file. - Prefer smaller, focused style files (≈150 lines or less) over large monoliths. Split by component or feature area if a file grows beyond that size.
- Co-locate reusable UI patterns (buttons, selectors, dropdowns, etc.) under
src/styles/components/and avoid redefining the same utility classes elsewhere. - Use the shared
.window-*primitives fromsrc/styles/components/window.cssfor dialog, popover, and floating-window headers, toolbars, bodies, footers, titles, and actions. - Persistent utility windows and transcript-covering previews expose an upper-right close button in their existing top toolbar; do not add a dedicated row just for dismissal. Use
components/window-close-button.tsxwith shared window chrome. Transient popups such as transcript filters dismiss on outside interaction and have no close button. - Authentication recovery uses
lib/auth-recovery.tsandcomponents/auth-recovery-dialog.tsx: confirm CodeNomad auth status before showing an expired-login form, reconnect in place to preserve drafts, and never replay failed mutations. Its shared window styles live instyles/components/auth-recovery.css. - Persistent command/search utility windows use
components/dismissible-window.tsx: non-modal, no scrim, outside interactions keep them open, and explicit toggles use.icon-togglewitharia-expanded/aria-controls. Keep search state scoped to its instance/session and close it when that view becomes inactive. - The composer reserves
/btwfor nativesession.generate, outside ordinary prompt/command submission. Its ephemeral question/answer window usesDismissibleWindowandstyles/components/session-aside.css; cancellation and inactive/session transitions fence late results without interrupting the main session. - OpenCode settings keep executable selection first and runtime status, install/update and service actions directly inline. Only version details and troubleshooting are collapsed disclosures at the bottom of the runtime panel; log levels remain the final settings card. Share controls with the startup recovery dialog rather than routing settings through a separate management modal. Disclosure styles live in
styles/components/opencode-setup.css. - Full-history search/counts use the bundled pruning plugin's bounded queries, outside the transcript store. Current-session results and the global timeline navigate through bounded anchor windows; other-session previews fetch one native message only. Search/results/progress styles live in
styles/components/history-search.css. Seedev-docs/SESSION_HISTORY_QUERIES.mdfor scope, snapshot and cleanup semantics. - Keep agent, model, and thinking controls in the composer footer via
PromptContextControls; adapt that footer with the namedprompt-composercontainer rather than viewport-only breakpoints. - Composer context selectors and actions always share one row on desktop and touch; truncate selector labels rather than wrapping the footer. Dense conversation toolbar/footer controls use
--touch-target-size-compact; timeline markers use the compact control height rather than the global touch target. Toolbar touch spacing lives instyles/panels/session-toolbar-touch.css. Transcript filters join the header action overflow and anchor/focus back to that menu when collapsed. - Composer height limits use the same visible conversation height: minimum 8% (44 px floor), maximum 60% (never below that minimum). Width and draft length do not change the limits.
prompt-input/usePromptViewport.tsobserves the conversation and its intersection withvisualViewport, including keyboard resize/pan. Store manually chosen heights as proportions so the field itself follows viewport changes; migrate legacy pixel choices on the first valid measurement. Viewport-driven changes never overwrite the saved proportion; pointer and keyboard resize controls share the same limits and long drafts remain scrollable. - Browser preview retains its six original fixed templates (responsive, desktop, tablet portrait/landscape, mobile portrait/landscape), without a separate rotation button. Mobile templates automatically use native Android/Chromium touch emulation; iframe fallback changes dimensions only. Profiles share
packages/ui/src/lib/native/browser-emulation.json; only owned native guests may receive device overrides, and returning to dimensions clears them before reloading. Main local/remote desktop content minimums are 390 × 600 CSS pixels: multiply by application zoom, not monitor DPI, and round up native logical dimensions. Restore uses the saved zoom; keyboard/wheel/menu changes update constraints without shrinking larger windows, with monitor-work-area caps at extreme zoom. Electron handles outer-frame offsets inwindow-state.ts; Tauri useswindow_constraints.rs. Preferences and native preview children retain their separate sizing contracts. - Composer attachments use one native-device action and project-scoped
@references. Picker/drop/clipboard bytes shareprompt-input/useDeviceAttachments.tsfor serialized budgets and epoch-based draft/focus fencing; keep lifecycle and read logic out ofprompt-input.tsx. File listing/search validate the session directory through existing workspace ownership before reading a worktree or translated WSL root. - Session rows keep actions inline until their measured title, badges, and controls no longer fit. Keep responsive action styles in
styles/components/session-row-actions.css; hidden inline controls remain measurable but inert, and an open overflow menu stays mounted until dismissal. - Session hierarchy geometry lives in
styles/components/session-tree.css; connector axes follow the parent expander at every depth, including selection mode, RTL and touch layouts. - Session search/filter mode uses flat per-session results with an optional subsession switch; filters, sorting, worktree badges and selection use each result's own identity. Normal browsing retains the session hierarchy.
- Never use rounded corners in UI styling; keep corners square unless the user explicitly requests otherwise for a specific change.
- Explicit round exceptions: Yolo, MCP and plugin activation switches (shared
styles/components/switches.cssgeometry), overlay drawer navigation buttons, and floating message scroll buttons. Other chrome remains square. - Tags and numeric/context/token labels also use rounded geometry via
--chip-radius(--pill-radiusis an alias). Register badge variants instyles/components/badges.css; use.badge-shapefor utility-styled labels rather than adding a local radius. - The message-content popup and Chat settings share
components/transcript-visibility.tsand the semantic icons fromcomponents/message-content-icons.ts; tool presentation metadata lives independently of renderers incomponents/tool-call/tool-presentation.ts. Popup styles live instyles/components/transcript-filters.css. - Tool-result images retain native
state.contentand render through the sharedcomponents/tool-call/output-images.tsxsurface, including MCP and specialized tools. Keep image bytes out of text projections (copy/search/speech); image styles live instyles/messaging/tool-call/images.css. - Session timeline placement spans the transcript and composer via the session-owned mount; keep its rail layout in
styles/messaging/session-timeline-rail.css. Hide the rail and force conversation-header actions into their overflow menu below 420 CSS px of thesession-centercontainer on all platforms. Keep that width-only force separate from measured header density so trial layouts can expand again above the breakpoint; filters anchor and return focus to the visible menu. Docked drawers reserve a minimum conversation width of 390 CSS px before overlaying. The composer worktree selector becomes a compact arrow-only cell below 460 CSS px of that conversation container (not the remaining composer width); keep its accessible label and styles instyles/components/prompt-context-controls.css. Timeline visibility must not depend on measured header density, changing status controls or viewport height; preserve the saved visibility preference. - Timeline geometry uses the cached structural index independently of transcript/excerpt loading. Aggregate tool markers retain the outline's representative tool name so their icon does not fall back to
other; preserve that metadata through projection and persisted-index revalidation. Hover/focus previews render bounded Markdown, prefetch visible-nearby excerpts and prioritize the hovered marker throughstores/timeline-previews.ts; never mount whole message/tool cards or fetch transcript windows for hover. Keep the viewport-bounded surface instyles/messaging/timeline-preview.css. - Document any new styling conventions or directory additions in this file so future changes remain consistent.
- Soft palette families live in
packages/ui/src/lib/soft-color-schemes.ts, with references indev-docs/PALETTE_SOURCES.md. Keep selection independent of participant identity, and keep transcript/composer surfaces distinct. Runpalette-quality.test.tsand inspect real rendered captures when changing palette colors or their token mapping. - Palette settings follow the resolved appearance in Auto mode. Keep the picker, single-row square swatches and trailing actions aligned. Swatch names use tooltips and accessible input labels. At narrow card widths, scroll the swatch strip beside the picker and move actions below via the
palette-settingscontainer. Swatch styles live instyles/components/theme-scheme-swatches.css. - Appearance mode and the saved light/dark selections are independent (
lib/appearance-preferences.ts). Message/tool cards use the muted surface, inset output and the composer use the base canvas, and preferences use the same secondary surface as the main panels. Use--surface-hover-overlayfor a subtle local rollover; preserve selected backgrounds beneath that overlay instead of replacing them with a generic panel color. - Right-panel base-canvas button rollover overrides live in
styles/panels/control-hover.css; do not substitute the secondary surface merely to show hover. - V2 plugin activation controls use the shared rounded SUID switch geometry in
styles/components/switches.css. Present Global and Project as separate per-plugin columns so every mutation has an explicit scope. Cache display snapshots by instance and worktree directory, and refresh them only while the plugin surface is visible. - Keep the Plugins surface minimal: plugin names and Global/Project switches only. Put per-plugin source/status/target details in the name's hover/focus tooltip. Do not add general descriptions, inline explanations, target footers or success commentary. The compact Refresh icon occupies the name-column header and spins during loading and refresh; automatic updates still follow native events, reconnects and visible demand.
- Project and right-panel tabs share
components/tab-scroll.tsxandstyles/components/tab-scroll.css. Keep their native scrollbar above upright content without mirrored transforms, negative border overlaps or permanent compositing hints. Validate shared scrollbar styling and adjoining edges at fractional zoom in the browser and isolated Electron renderer fixtures (tests/browser/tab-chrome.test.ts). - Mission sections use
components/mission-disclosure.tsxand the shared.disclosure-chevron. Keep disclosure/selection/reader identities in the native per-window layout viastores/mission-view-state.ts, independent of refreshed snapshot object identity. Long mission content usescomponents/mission-reader.tsxabove the transcript; its chrome follows.window-*. Mission styles remain understyles/panels/mission-*.css. - Mission navigation uses top-level vertical rows with two-line objectives, semantic state colors, inline reader/coordinator/edit/delete actions and thin separators like the session list. Work initially opens before attention, Reports, Conversations and History; the latter three initially collapse. Use
MissionReadButtonfor objective/brief/report/change readers; keep detail excerpts to one line.mission-graph.tsxdraws only declared task dependencies, including completed/retired work, from measured row geometry; graph styles live instyles/panels/mission-graph.css.
Coding Principles
-
Missions ships through
DesktopPluginLifecycle("missions")and backend presence, with project-scoped native storage. Keep roles independent of native execution IDs. Persist explicit agent/model/variant selections and never switch a busy actor for a queued task. Mission prompt/report admission uses the authenticated desktop bridge, authoritative typed snapshot, ownership/connection/worktree fences and per-send profile environment. Seedev-docs/MISSIONS.md; validate with the isolatedscripts/test-missions-native.mjsfixture. -
A durable mission report and its coordinator notification are distinct. Recover only unacknowledged report notifications through the existing bridge with stable native message IDs and lifecycle fencing; never turn notification recovery into task dispatch or a workflow engine. An admission acknowledgement is not proof of model consumption or mission completion.
-
Optional mission specialist cleanup records immutable tombstone targets and per-session receipts. Use the authenticated bridge and authoritative
cleanupTargetRPC before native HTTP deletion; plugin contexts do not expose native session removal. Preserve coordinators, reused/shared/moved sessions and roots with descendants. Partial cleanup retries retain the original request identity and never become a background dispatcher. -
Mission Play starts/resumes through durable explicit lifecycle intent; Pause interrupts registered root actors and parks Mission notifications/dispatch, while Stop is terminal. Native acknowledgements have per-target receipts and explicit retries, with the same authenticated bridge, environment and ownership fences. Do not claim recursive subagent suspension or turn notification recovery into a control-action runner. Keep the single Play/Pause/Stop strip in
components/mission-lifecycle-controls.tsx. -
Workspace text remains editable in the central file reader (including Markdown source), with Save and Ctrl/Cmd+S. Keep dirty drafts in
components/workspace-file-editor.ts, scoped by instance/directory/path; invalidation must not replace them. Saves reread for external-change confirmation and pass the exact owned directory through the deletion-fenced filesystem write route. Images, binary content and historical diffs remain read-only. -
Files row selection never opens the central preview implicitly. All three modes reuse
FileRowActionswith a pinned eye using the sharedicon-toggleactive state; secondary actions use whole-row overflow measurements. Keep selection beneath the entire row including controls and rollover instyles/panels/control-hover.css. Changes keeps staged/unstaged disclosures with commit actions at the top of the staged section. Git image readers use exact bounded HEAD/index/worktree or parent/commit bytes, not current-file substitutes for historical content. -
The Files panel combines Workspace, Changes and Commits in one compact switch, initially on Workspace. Its lazy worktree tree preserves expanded folders while switching modes; tree styles live in
styles/panels/workspace-tree.css, Git navigation instyles/panels/git-history.css, row actions instyles/panels/file-row-actions.css. Workspace secondary actions are folder-specific (open, terminal, copy path) and file-specific (open, reveal, copy path). Changes rows carry explicit stage/unstage actions and drag between staged/unstaged drop zones. File/diff readers close with a trailing X; the unified/split switch shows the current layout with Columns/Rows iconography. All three modes are cache-first: directory listings, git status and commit history revalidate lazily on filesystem invalidation, mode activation or explicit refresh, never on every focus or expand.components/files-preview-view.tsxchooses the central editable Workspace reader or shared read-only diff reader above the composer. Worktree browsing never checks out a branch or moves a session. Historical reads use bounded worker Git commands behind existing worktree ownership checks. Workspace previews use the bounded directory-authorized preview route; Monaco tokenizers ship locally. Seedev-docs/FILES_PANEL.mdfor lifecycle, migration and validation. -
Tauri's Tao Windows input backport lives in
packages/tauri-app/vendor/; preserve upstream provenance and avoid message pumping under input mutexes. Runnode scripts/test-tauri-input-deadlock.mjs --baselineon Windows when changing it. Seedev-docs/TAURI_WINDOWS_INPUT_DEADLOCK.mdfor the captured failure and override removal criteria. -
Tao's macOS zoom getter must remain read-only: synchronous temporary style-mask changes on borderless windows generate geometry-event feedback and can starve startup navigation. Keep the exact upstream tao#1182 backport beside the Windows fix, with its provenance in
packages/tauri-app/vendor/README.md. Runnode scripts/test-tauri-macos-window.mjs --baselinein a graphical macOS session and retain the ARM64 CI regression. Seedev-docs/TAURI_MACOS_STARTUP.md; do not disable window persistence or change the application chrome as a workaround. -
Verified shared npm OpenCode installations at 2.0.15+ delegate version changes to native
upgradethroughopencode-update/native-upgrade.ts, with bundled npm scoped to the verified prefix. Native Windows image retention replaces the write preflight only on that path; first install, older migration and same-version repair retain direct npm/preflight. Never retry a failed native mutation via npm or restart the daemon implicitly. Validate with the isolatedscripts/test-opencode-upgrade-native.mjsfixture. -
Git is a full-functionality prerequisite, with directory-only degraded conversations when the backend cannot find Git. Only the explicitly opened physical folder is session authority in that mode; never infer sibling worktrees from native project IDs. Keep ancestor/descendant mutation identities covered by the deletion fence across Git availability changes. Inform agents through the owned native
codenomad.git-availabilityinstruction before prompts/custom commands, remove stale context after recovery, and keep this advisory separate from fail-closed environment synchronization. No blocking Git setup UI. Validate withscripts/test-git-degraded-native.mjsusing an isolated CLI/database and provider. -
OpenCode minimum requirements must follow demonstrated technical dependencies, never the latest published or solely tested version. Keep required, recommended/tested and unverified versions distinct in
opencode/runtime-support.tsand setup diagnostics. Validate authenticated daemon metadata/contract before client use/plugin provisioning. Setup uses bundled Node/npm for a shared user npm installation and prefers PATH. The retired private~/.local/share/codenomad/opencodetree must never be discovered or launched; ignore its receipts and saved selections without migrating or deleting it. Keep installer locking and Windows live-executable preflight inopencode-update/installation-lock.ts; register terminal PATH only on explicit installation. A running daemon restart is a separate explicit action. Configuration reload is also explicit: nativelocation.reloadrebuilds every loaded location and cancels pending Forms/permissions, so never use it as an automatic watcher fallback. Retire old wire translations without removing current identity/ownership checks. Seedev-docs/OPENCODE_V2_POST_BETA.mdfor version boundaries and isolated validation evidence. -
A selected CLI's
service statuscan reportstoppedfor a live older daemon. Preserve the bounded, read-only registration fallback inworkspaces/native-service-registration.tsand authenticate historical metadata before allowing start;ensure()repeats discovery. Native service lookup is separate from plugin-root discovery, which must still use the connected daemon'sconfig.get. Never write service registration/configuration files from the backend. -
Profile environment variables are applied server-side before each native session prompt, custom command or session shell request, after ownership and worktree-mutation admission. Build a complete execution-host snapshot with
workspaces/session-environment.ts; never send the profile environment through the browser or skip the per-send write using a cache. Reads and settings edits do not mutate native sessions. Keep native environment failures fail-closed and redact SDK request bodies. Seedev-docs/SESSION_ENVIRONMENT.md. -
One bundled
codenomad.automationV2 plugin uses native discovery and backend presence. All browser/developer tools are available without a Developer Mode toggle; native instrumentation starts with the desktop host. Loading, tool availability and execution targeting are separate: retain the authenticated bridge and session/window fences. Tauri preview children receive no application capabilities; primary-renderer reload must dispose them and final-window checks must count native windows. Seedev-docs/BROWSER_AUTOMATION.md. -
Developer UI tools target the inspected native window/run, not the currently selected project or conversation. Keep backend ownership discovery separate from UI focus; agents must be able to inspect and navigate back from another session themselves. Accessibility refs expire on document/target replacement, not merely on session selection. Browser previews retain their own session attachments.
-
Desktop automation and pruning provisioning follows the authenticated OpenCode connection and its
config.getglobal discovery directory, including reconnects. Never derive a running daemon's roots from backend/startup environment or CLIdebug paths. OpenCode watches the entire discovery root recursively: keep changing presence leases outside it, in the sibling.codenomad/<root-hash>/namespace. Retain existing outside-root storage; migrate inside-root storage while reading older backends' leases without writing there. WSL translates the daemon-reported paths through the selected distro only for filesystem access. Verify heartbeat stability with the isolated native automation fixture. -
Follow
dev-docs/CACHE_REFRESH_CONVENTIONS.mdfor display snapshots, coalesced trailing refreshes, stale-response fencing and authoritative mutation reads. Check existing feature semantics before adding another cache or refresh policy. -
The shared native event relay consumes upstream events before slow routing I/O. Preserve per-session/PTY/Shell and per-recipient FIFO, validated full-location ownership, invalidation/connection/workspace fences and bounded-backlog reconnect recovery. A slow recipient must not block another or the shared SDK subscriber. Validate with the relay regressions and isolated native location fixture.
-
Worktree discovery/create/remove use
workspaces/native-worktrees.tsand the native OpenCode worktree API. CodeNomad supplies the.codenomad/worktreesdefault, named-branch policy and verified family transactions. Git common-directory identity scopes the native inventory to the opened local repository; opaque worktree identifiers are separate from mutable branch labels. Validate throughscripts/test-opencode-location-native.mjswith an isolated CLI andtests/browser/worktrees.test.tsfor selector gestures. -
Worktree inventory snapshots live in
workspaces/worktree-inventory.ts: display reads serve cached data and lazily revalidate, directory authorization uses validated reads, and family transactions force fresh reads. Invalidation retains display data and fences pending scans;workspace.worktreesChangedrefreshes existing UI consumers after a changed snapshot is published. Keep selector opening independent of refresh completion and suppress duplicate selection events during inventory reconciliation. -
Worktree branch/HEAD annotations use one NUL-delimited Git worktree snapshot, intersected with native inventory and verified Git identities; effective checkout roots must respect Git configuration as well as administrative backlinks. Pending move targets belong to the store's instance/family request identity and survive selector navigation/remounts until native reconciliation settles.
-
Session pruning is a narrow V2 plugin/RPC exception under
packages/server/src/opencode/session-pruning/; seedev-docs/SESSION_PRUNING_RPC.md. Bundle it with the shared server for both desktop hosts and provision through normal native plugin discovery. RPC registrations follow backend presence; clean shutdown removes that backend's lease and crashes expire. Loading never deletes content. Deletion occurs only on an explicit pruning request, without an extra enable-write switch or beta-number gate. Keep generic RPC proxy access closed. Writes validate actual storage, a fresh daemon-storage identity challenge and the native durable execution claim inside a synchronous SQLite transaction. Run isolated native concurrency/payload and client-cache regressions; tests must never target the shared daemon or a user's database. -
Favor KISS by keeping modules narrowly scoped and limiting public APIs to what callers actually need.
-
Uphold DRY: share helpers via dedicated modules before copy/pasting logic across stores, components, or scripts.
-
Enforce single responsibility; split large files when concerns diverge (state, actions, API, events, etc.).
-
Prefer composable primitives (signals, hooks, utilities) over deep inheritance or implicit global state.
-
When adding platform integrations (SSE, IPC, SDK), isolate them in thin adapters that surface typed events/actions.
Multi-Language Support (i18n)
The UI uses a small custom i18n layer (no ICU/messageformat). When building features, never hardcode user-visible strings.
- Runtime API: use
useI18n()in components (const { t } = useI18n();) andtGlobal(...)in stores/non-component code.- Implementation:
packages/ui/src/lib/i18n/index.tsx
- Implementation:
- Where messages live:
packages/ui/src/lib/i18n/messages/<locale>/as TypeScript objects ("flat.dot.keys": "string").- Each locale has an
index.tsthat merges message parts; duplicate keys throw at build time. - Merge helper:
packages/ui/src/lib/i18n/messages/merge.ts
- Each locale has an
- Adding a new string: add it to the appropriate
.../messages/en/*.tspart file, then add the same key to each other locale’s corresponding file.- Missing translations fall back to English (and finally to the key), so gaps can be easy to miss.
- Interpolation: placeholders are simple
{name}replacements (word characters only). Avoid placeholders like{file-name}. - Pluralization: handle manually via separate keys like
something.one/something.otherand choose in code. - Adding a new language: add a new
messages/<locale>/folder +index.ts, register it inpackages/ui/src/lib/i18n/index.tsx, and add it to the language picker inpackages/ui/src/components/folder-selection-view.tsx. - Locale persistence: the selected locale is stored in app preferences (
locale) and persisted via the server config (default~/.config/codenomad/config.yaml;config.jsonis migration input only). - Avoid English-only paths: do not import
enMessagesdirectly in feature code; always go throught(...)so locale changes apply.
File Length Guidelines (Highlight Only)
We track file size as a refactoring signal. When you touch or create files, highlight oversized files so the team can plan refactors when time permits.
- Source files: warn after ~500 lines; target limit ~800 lines
- Test files: highlight after ~1000 lines
Behavior for agents:
- Do not refactor solely to satisfy these thresholds.
- When a change touches a file that exceeds the warning/limit, mention it in your final response and include the file path and approximate line count.
- When creating new files, aim to stay under the thresholds unless there's a clear reason.
Tooling Preferences
- Use the
edittool for modifying existing files; prefer it over other editing methods. - Use the
writetool only when creating new files from scratch. - Browser rendering regressions live in
packages/ui/tests/browser/, with deterministic HTTP fixtures beside them infixtures/. Exercise the real Solid components and native event dispatcher rather than reimplementing rendering logic. - Transcript rows retain pointer hit testing during virtualizer scrolling (
styles/messaging/virtual-follow-list.css), so nested code/tool scrollers and message controls receive gestures at their visible target. - Keep the global scrollbar-width default at zero specificity (
:where(...)insrc/index.css) so component visibility rules win. The timeline and transcript use the same standard native scrollbar: only marker rectangles narrow, icons and vertical spacing never shrink.components/timeline-virtual-list.tsxcomputes the timeline's exact extent from measured marker/gap primitives; never estimate hidden/offscreen rows. Manual rail browsing owns its position until an explicit transcript gesture. Native thumb drags retain ownership beyond the gesture timeout and defer window paging until release. Validate with the full stylesheet and real thumb gestures on mixed-height transcripts. - Run them with
npm run test:browser --workspace @codenomad/uiafternpx playwright install chromium.CODENOMAD_BROWSER_PATHoptionally selects an existing Chromium executable; it does not target the installed application or user sessions.
V2 Runtime Launch
- Native automation instrumentation starts automatically; no Developer Mode toggle or activation restart is required. Do not configure a fixed CDP port or a manual WebView2 profile.
- Rebuild Electron before calling
codenomad.act({ action: "restart" }). For Windows Tauri, stop and relaunch the release executable only when the linker cannot replace it; never stop the shared OpenCode daemon.
Commit Message Guidelines
- When creating commits, use detailed commit messages: a concise conventional-style subject followed by body paragraphs that explain the user-visible behavior change, the implementation approach, important edge cases or platform considerations, and the validation or test coverage added.
- Prefer messages that explain why the change exists and how regressions are prevented, not just a list of touched files.