Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .opencode/skills/codenomad-architecture-guide/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@ description: |
- OpenCode: read the three `sdk-*.md` references before changing client calls or service lifecycle.
- Desktop: read `references/desktop-conventions.md`.
- Developer Automation: read `../../../dev-docs/DEVELOPER_AUTOMATION.md`.
- Browser automation: read `../../../dev-docs/BROWSER_AUTOMATION.md`.

## Native OpenCode V2 Baseline

- The only OpenCode client dependency is the experimental `@opencode-ai/client@beta` protocol. Server and UI follow that dependency together; refresh the client lock before API audits or release validation. The runtime CLI is managed independently and startup has no exact version gate. The public `@opencode-ai/sdk` describes an alternative embedded host.
- Do not use `@opencode-ai/sdk`, `@opencode-ai/sdk/v2/client`, or `createOpencodeClient()`; follow installed `@opencode-ai/client` declarations.
- There is no legacy `packages/opencode-plugin/`. Do not restore the V1 compatibility runtime or add general plugin extension points. The reviewed Developer Automation adapter is the sole narrow exception; see `dev-docs/DEVELOPER_AUTOMATION.md`.
- There is no legacy `packages/opencode-plugin/`. Do not restore the V1 compatibility runtime or add general plugin extension points. The reviewed automation adapter shared by Developer Automation and native browser previews is the sole narrow exception; see `dev-docs/DEVELOPER_AUTOMATION.md` and `dev-docs/BROWSER_AUTOMATION.md`.
- The server uses the selected host or WSL CLI's official `service status`, `service start`, and `service get password` lifecycle to connect to one externally owned global OpenCode daemon. It owns no private port/database/registration/PID and never stops the daemon on backend shutdown. WSL requires Windows localhost forwarding and uses no cross-namespace PID operations.
- The UI uses generated Promise clients from `OpenCode.make()` through the CodeNomad proxy.
- OpenCode owns session APIs, native Forms, session Shell (`client.session.shell`), session instructions (`client.session.instructions.entry`), location-scoped background Shells, and interactive PTYs. Question request/reply/reject routes are compatibility-only; new interruption flows use `client.form.*`. The Status panel lists `client.shell.*` records, refreshes on Shell events/reconnect, displays native metadata, and supports ownership-checked removal. Interactive `client.pty.*` terminals remain separate.
- CodeNomad owns explicit Stop Workspace eviction, directory authorization, Git status/diff/stage/unstage/commit, Yolo persistence/auto-replies, and `/api/events`. Tab/window close only detaches local UI and never evicts.
- OpenCode owns the global daemon's standard state and database. Allowed configured environment variables apply only to `service start` for a missing daemon; an existing daemon is unchanged, and `OPENCODE_DB`/`XDG_STATE_HOME` ownership settings are ignored.
- Native desktop identity is channel plus config profile: one singleton process/backend per profile, multiple UUID windows, second-launch focus by default, and `--new-window` for another window. Stable/dev/non-default profiles isolate native state; OpenCode sessions/messages are shared while tabs/drafts/views are per-window.
- Client-state V3 is a per-window envelope over the V2 content-addressed partition graph with atomic publication/migration, ownership-fenced writes, and conservative post-commit GC. Native SideCar/browser previews are sandboxed without same-origin access; DOM comment inspection is web-only.
- Client-state V3 is a per-window envelope over the V2 content-addressed partition graph with atomic publication/migration, ownership-fenced writes, and conservative post-commit GC. Electron and Windows Tauri browser previews use hardened native child webviews; iframe previews remain sandboxed without same-origin access and DOM comment inspection is web-only.

## Package Map

Expand All @@ -47,7 +48,8 @@ description: |
- Git mutations: `packages/server/src/workspaces/git-mutations.ts`
- Yolo: `packages/server/src/permissions/`, `packages/server/src/server/routes/yolo.ts`
- Desktop hosts: `packages/electron-app/electron/main/`, `packages/electron-app/electron/preload/index.cjs`, `packages/tauri-app/src-tauri/src/`
- Developer Automation: `packages/server/src/opencode/automation-plugin.ts`, `packages/server/src/developer-cdp.ts`
- Automation bridge: `packages/server/src/opencode/automation-plugin.ts`, `packages/server/src/server/routes/automation-plugin.ts`
- Native browser previews: `packages/electron-app/electron/main/browser-controller.ts`, `packages/tauri-app/src-tauri/src/browser_controller.rs`, `packages/ui/src/lib/native/browser.ts`

## Rules

Expand All @@ -67,7 +69,7 @@ description: |
| Public `@opencode-ai/sdk` examples | Installed experimental `@opencode-ai/client` declarations |
| One `opencode serve` per workspace | One externally owned global daemon through the official CLI lifecycle |
| Per-worktree clients/processes | Root proxy client plus native location/directory inputs |
| Reintroducing the V1 `packages/opencode-plugin` or general server plugin/background-process paths | Native OpenCode APIs; the reviewed Developer Automation adapter only for desktop feedback |
| Reintroducing the V1 `packages/opencode-plugin` or general server plugin/background-process paths | Native OpenCode APIs; the reviewed automation adapter only for desktop feedback and browser previews |
| OpenCode APIs for stage/commit/Yolo policy | CodeNomad routes and managers |
| Hardcoded UI strings | `t()` / `tGlobal()` and every locale |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- Use `OpenCodeSharedService` in `packages/server/src/workspaces/opencode-service.ts`.
- Keep one shared-service adapter and one event subscription for all workspaces. Use the selected host or WSL CLI's official status/start/password lifecycle, own no private service state/PID, and never stop the externally owned global daemon on backend shutdown.
- Model workspaces with native `LocationRef`/directories in `packages/server/src/workspaces/manager.ts`.
- Never spawn or stop OpenCode per workspace and never add general plugin installation/packaging. Developer Automation's reviewed, execution-gated adapter is the sole exception; definitions are global until OpenCode supports dynamic location-scoped registration.
- Never spawn or stop OpenCode per workspace and never add general plugin installation/packaging. The reviewed, execution-gated adapter shared by Developer Automation and browser previews is the sole exception; definitions are global until OpenCode supports dynamic location-scoped registration.
- Explicit Stop Workspace evicts the location; ordinary UI close never calls workspace deletion. WSL requires localhost forwarding and no cross-namespace PID operations.
- Leave global service state/database ownership to OpenCode. Pass allowed environment only when starting a missing daemon; leave an existing daemon unchanged and ignore `OPENCODE_DB`/`XDG_STATE_HOME`.

Expand Down Expand Up @@ -45,6 +45,6 @@
- CodeNomad SSE: `packages/server/src/server/routes/events.ts`
- Git reads/mutations: `packages/server/src/workspaces/git-status.ts`, `git-mutations.ts`
- Yolo: `packages/server/src/permissions/`, `packages/server/src/server/routes/yolo.ts`
- Developer Automation: `packages/server/src/opencode/automation-plugin.ts`, `packages/server/src/server/routes/automation-plugin.ts`
- Developer and browser automation: `packages/server/src/opencode/automation-plugin.ts`, `packages/server/src/server/routes/automation-plugin.ts`

Deleted paths such as `packages/server/src/workspaces/runtime.ts`, `packages/server/src/background-processes/`, `packages/server/src/plugins/`, and `packages/opencode-plugin/` are not valid extension points.
30 changes: 30 additions & 0 deletions dev-docs/BROWSER_AUTOMATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Browser Automation

CodeNomad exposes `codenomad.browser` for controlling the visible web preview attached to the current OpenCode session. The supported actions are `open`, `navigate`, `snapshot`, `click`, `type`, and `screenshot`.

## Shared Bridge

Browser control extends the Developer Automation adapter instead of installing another plugin or listener:

- `packages/server/src/opencode/automation-plugin.ts` installs the single `codenomad-automation.ts` OpenCode plugin and publishes one loopback registration.
- `packages/server/src/server/routes/automation-plugin.ts` serves the existing `/api/opencode-plugin/automation` endpoint with the existing per-process token.
- `browser-claim` verifies that exactly one CodeNomad instance owns the session before an `open` action asks the UI to create a preview.
- `browser-probe` also requires a visible native preview registered to that session.
- `browser-execute` validates the browser action and forwards `browser.probe` or `browser.execute` over the existing fenced native-parent request channel.

The bridge remains loopback-only, token-authenticated, bounded, and session-location gated. The removed V1 plugin runtime and browser-specific bridge routes are not part of this design.

## Native Hosts

Electron uses a hardened `<webview>` with per-session storage. Attachment verifies guest ownership, allows only credential-free HTTP(S) URLs, denies permissions and downloads, and uses Chromium accessibility/CDP commands for snapshots and actions.

Windows Tauri uses a child webview owned by the local application window. Commands, capabilities, navigation checks, bounds, visibility, and storage are managed by `browser_controller.rs`. Other Tauri platforms continue to use the existing iframe preview and do not advertise native browser automation.

The UI routes an autonomous open request to the one loaded instance containing the session, claims the request for one local window, selects that session, and opens its preview. Hidden or duplicate targets are rejected rather than selected implicitly.

## Focused Validation

- Server: `automation-plugin.test.ts` and `routes/automation-plugin.test.ts`
- Electron: `browser-controller.test.ts`, `browser-webview-security.test.ts`, preload tests
- Tauri: `browser_controller.rs` tests plus command capability generation
- UI: `browser-frame-security.test.ts` and `lib/native/browser.test.ts`
2 changes: 1 addition & 1 deletion dev-docs/DEVELOPER_AUTOMATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The small automation adapter registers these definitions with OpenCode:

OpenCode plugin setup is currently one-shot, so definitions are visible in unrelated locations. Calls remain inert unless the bridge verifies that the current session location is owned by the active CodeNomad instance.

The adapter is intentionally narrower than the removed V1 plugin runtime. It does not own OpenCode lifecycle or state, spawn one daemon per workspace, or expose autonomous browser previews.
The adapter is intentionally narrower than the removed V1 plugin runtime. It does not own OpenCode lifecycle or state or spawn one daemon per workspace. Autonomous browser previews share its authenticated bridge and native transport but keep separate browser actions and host controllers; see [BROWSER_AUTOMATION.md](BROWSER_AUTOMATION.md).

## Trust Boundaries

Expand Down
4 changes: 4 additions & 0 deletions dev-docs/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Measured DEV-v2 growth analysis, maintainer position on test volume, ranked redu

Isolated Electron/Tauri developer runs, CDP feedback tools, lifecycle guarantees, and trust boundaries.

### [BROWSER_AUTOMATION.md](BROWSER_AUTOMATION.md)

Autonomous native browser previews, shared automation bridge routing, host security, and focused validation.

---

## Specification Documents
Expand Down
5 changes: 3 additions & 2 deletions dev-docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Electron and Tauri run one native singleton process and one CodeNomad backend pe

OpenCode sessions and messages remain shared through the global daemon. Window membership, tabs, drafts, view state, and native bounds are local to each UUID window. Client-state V3 is a per-window envelope over the V2 content-addressed partition graph: immutable partitions are prepared before atomic root publication, writes and migrations are fenced by current ownership, and garbage collection runs after publication while retaining every partition referenced by any window.

Previews use unguessable capabilities for HTTP and WebSocket traffic. Native previews route a token-scoped `.preview.localhost` origin to the pinned target; web clients use the equivalent path route. SideCar/browser frames remain opaque-origin sandboxes without `allow-same-origin`; preview element comments use a source-checked message bridge instead of parent DOM access.
Previews use unguessable capabilities for HTTP and WebSocket traffic. Electron and Windows Tauri local windows open HTTP(S) pages in hardened native child webviews with isolated storage; other clients use the existing capability-scoped iframe proxy. SideCar/browser iframes remain opaque-origin sandboxes without `allow-same-origin`; preview element comments use a source-checked message bridge instead of parent DOM access.

## API Boundaries

Expand Down Expand Up @@ -72,8 +72,9 @@ Current native events include session lifecycle/output events (`session.created`
| Yolo state, persistence and auto-accept | CodeNomad server |
| Browser SSE multiplexing | CodeNomad server |
| Developer Automation launch and CDP feedback | CodeNomad desktop hosts and authenticated automation adapter |
| Autonomous browser previews | CodeNomad desktop browser controllers and the same authenticated automation adapter |

Session Shell remains separate from background Shell and PTY management. The Status panel lists location-scoped native background Shells, refreshes on Shell events/reconnect, displays native metadata, and allows ownership-checked removal. Output requests preserve native cursor pagination. Interactive PTYs remain separate. `packages/opencode-plugin` and the server plugin/background-process paths remain deleted and must not be restored; Developer Automation is the only reviewed adapter exception.
Session Shell remains separate from background Shell and PTY management. The Status panel lists location-scoped native background Shells, refreshes on Shell events/reconnect, displays native metadata, and allows ownership-checked removal. Output requests preserve native cursor pagination. Interactive PTYs remain separate. `packages/opencode-plugin` and the server plugin/background-process paths remain deleted and must not be restored; the narrow automation adapter used by Developer Automation and browser previews is the only reviewed exception.

## Persistence

Expand Down
Loading
Loading