CodeNomad/AGENTS.md
Pascal André bbbc5e3ff9
merge(dev): resolve mission integration conflicts
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.
2026-10-01 18:49:47 +02:00

31 KiB
Raw Blame History

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.css if a shared pattern is needed.
  • Keep aggregate entry files (e.g., src/styles/controls.css, messaging.css, panels.css) lean—they should only @import feature-specific subfiles located inside src/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 from src/styles/components/window.css for 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.tsx with shared window chrome. Transient popups such as transcript filters dismiss on outside interaction and have no close button.
  • Authentication recovery uses lib/auth-recovery.ts and components/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 in styles/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-toggle with aria-expanded/aria-controls. Keep search state scoped to its instance/session and close it when that view becomes inactive.
  • The composer reserves /btw for native session.generate, outside ordinary prompt/command submission. Its ephemeral question/answer window uses DismissibleWindow and styles/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. See dev-docs/SESSION_HISTORY_QUERIES.md for scope, snapshot and cleanup semantics.
  • Keep agent, model, and thinking controls in the composer footer via PromptContextControls; adapt that footer with the named prompt-composer container 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 in styles/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.ts observes the conversation and its intersection with visualViewport, 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 in window-state.ts; Tauri uses window_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 share prompt-input/useDeviceAttachments.ts for serialized budgets and epoch-based draft/focus fencing; keep lifecycle and read logic out of prompt-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.css geometry), 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-radius is an alias). Register badge variants in styles/components/badges.css; use .badge-shape for utility-styled labels rather than adding a local radius.
  • The message-content popup and Chat settings share components/transcript-visibility.ts and the semantic icons from components/message-content-icons.ts; tool presentation metadata lives independently of renderers in components/tool-call/tool-presentation.ts. Popup styles live in styles/components/transcript-filters.css.
  • Tool-result images retain native state.content and render through the shared components/tool-call/output-images.tsx surface, including MCP and specialized tools. Keep image bytes out of text projections (copy/search/speech); image styles live in styles/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 the session-center container 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 in styles/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 through stores/timeline-previews.ts; never mount whole message/tool cards or fetch transcript windows for hover. Keep the viewport-bounded surface in styles/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 in dev-docs/PALETTE_SOURCES.md. Keep selection independent of participant identity, and keep transcript/composer surfaces distinct. Run palette-quality.test.ts and 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-settings container. Swatch styles live in styles/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-overlay for 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.tsx and styles/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.tsx and the shared .disclosure-chevron. Keep disclosure/selection/reader identities in the native per-window layout via stores/mission-view-state.ts, independent of refreshed snapshot object identity. Long mission content uses components/mission-reader.tsx above the transcript; its chrome follows .window-*. Mission styles remain under styles/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 MissionReadButton for objective/brief/report/change readers; keep detail excerpts to one line. mission-graph.tsx draws only declared task dependencies, including completed/retired work, from measured row geometry; graph styles live in styles/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. See dev-docs/MISSIONS.md; validate with the isolated scripts/test-missions-native.mjs fixture.

  • 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 cleanupTarget RPC 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 FileRowActions with a pinned eye using the shared icon-toggle active state; secondary actions use whole-row overflow measurements. Keep selection beneath the entire row including controls and rollover in styles/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 in styles/panels/git-history.css, row actions in styles/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.tsx chooses 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. See dev-docs/FILES_PANEL.md for 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. Run node scripts/test-tauri-input-deadlock.mjs --baseline on Windows when changing it. See dev-docs/TAURI_WINDOWS_INPUT_DEADLOCK.md for 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. Run node scripts/test-tauri-macos-window.mjs --baseline in a graphical macOS session and retain the ARM64 CI regression. See dev-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 upgrade through opencode-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 isolated scripts/test-opencode-upgrade-native.mjs fixture.

  • 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-availability instruction 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 with scripts/test-git-degraded-native.mjs using 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.ts and 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/opencode tree 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 in opencode-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: native location.reload rebuilds 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. See dev-docs/OPENCODE_V2_POST_BETA.md for version boundaries and isolated validation evidence.

  • A selected CLI's service status can report stopped for a live older daemon. Preserve the bounded, read-only registration fallback in workspaces/native-service-registration.ts and 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's config.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. See dev-docs/SESSION_ENVIRONMENT.md.

  • One bundled codenomad.automation V2 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. See dev-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.get global discovery directory, including reconnects. Never derive a running daemon's roots from backend/startup environment or CLI debug 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.md for 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.ts and the native OpenCode worktree API. CodeNomad supplies the .codenomad/worktrees default, 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 through scripts/test-opencode-location-native.mjs with an isolated CLI and tests/browser/worktrees.test.ts for 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.worktreesChanged refreshes 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/; see dev-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();) and tGlobal(...) in stores/non-component code.
    • Implementation: packages/ui/src/lib/i18n/index.tsx
  • Where messages live: packages/ui/src/lib/i18n/messages/<locale>/ as TypeScript objects ("flat.dot.keys": "string").
    • Each locale has an index.ts that merges message parts; duplicate keys throw at build time.
    • Merge helper: packages/ui/src/lib/i18n/messages/merge.ts
  • Adding a new string: add it to the appropriate .../messages/en/*.ts part 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.other and choose in code.
  • Adding a new language: add a new messages/<locale>/ folder + index.ts, register it in packages/ui/src/lib/i18n/index.tsx, and add it to the language picker in packages/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.json is migration input only).
  • Avoid English-only paths: do not import enMessages directly in feature code; always go through t(...) 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 edit tool for modifying existing files; prefer it over other editing methods.
  • Use the write tool only when creating new files from scratch.
  • Browser rendering regressions live in packages/ui/tests/browser/, with deterministic HTTP fixtures beside them in fixtures/. 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(...) in src/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.tsx computes 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/ui after npx playwright install chromium. CODENOMAD_BROWSER_PATH optionally 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.