Skip to content
Merged
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: 3 additions & 7 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,9 @@ jobs:
node --import tsx scripts/test-subagent-depth-settings-native.mjs $cli
if ($LASTEXITCODE) { exit $LASTEXITCODE }
}
# Settings → Providers → Images: contract detection on both runtimes,
# native acceptance and hot reload of the written values on the latest.
if ('${{ matrix.runtime }}' -eq 'latest') {
node --import tsx scripts/test-image-settings-native.mjs $cli --expect-supported
} else {
node --import tsx scripts/test-image-settings-native.mjs $cli
}
# Settings → Providers → Images: default-on generation, native acceptance
# and hot reload of the written values.
node --import tsx scripts/test-image-settings-native.mjs $cli
if ($LASTEXITCODE) { exit $LASTEXITCODE }
# Design agent and skills copied into a project's .opencode/: native
# discovery, notices kept out of model text, skills unlisted but loadable.
Expand Down
2 changes: 1 addition & 1 deletion .opencode/skills/codenomad-architecture-guide/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ description: |

## Native OpenCode V2 Baseline

- Runtime requirements live in `opencode/runtime-support.ts`: OpenCode 2.1.2 is the minimum, required by Code Mode's JavaScript job ordering (reproduced by `scripts/test-codemode-jobs-native.mjs`) and the `native`/`metadata.keepID` replay contract consumed by the pinned client reducer; 2.2.1 is the recommendation. Each blocking requirement needs demonstrated API/behavior evidence; distinguish technically incompatible, recommended/tested and unverified versions. Shared-daemon restart is explicit and uses the native-parent launch bridge. See `dev-docs/OPENCODE_COMPATIBILITY.md` for the version boundaries and `dev-docs/OPENCODE_RUNTIME_SETUP.md` for setup, installation and admission.
- Runtime requirements live in `opencode/runtime-support.ts`: OpenCode 2.2.3 is the minimum and the recommendation, required by the `experimental_image_generate` image tool contract (upstream #60258) that the Images gallery, Design agent and Images settings consume; it also provides Code Mode's JavaScript job ordering (`scripts/test-codemode-jobs-native.mjs`) and the `native`/`metadata.keepID` replay contract consumed by the pinned client reducer. Each blocking requirement needs demonstrated API/behavior evidence; distinguish technically incompatible, recommended/tested and unverified versions. Shared-daemon restart is explicit and uses the native-parent launch bridge. See `dev-docs/OPENCODE_COMPATIBILITY.md` for the version boundaries and `dev-docs/OPENCODE_RUNTIME_SETUP.md` for setup, installation and admission.

- Server and UI pin the official `@opencode/client@2.1.0` together; native plugins pin `@opencode/plugin@2.1.0` for authoring and use `packages/server/scripts/native-plugin-build.mjs` to keep Effect/public SDK modules external. The daemon supplies their runtime instances. The canonical server-info client is `server.info()`, adapted to the authenticated discovered route. Review official V2 docs, installed declarations, generated wire paths and native integration tests when upgrading. Never infer a minimum from the latest publication or dependency pin alone. Update `dev-docs/OPENCODE_COMPATIBILITY.md` in place and retain detailed evidence in PR/CI logs. The runtime CLI is managed independently.
- Do not use `@opencode-ai/sdk`, `@opencode-ai/sdk/v2/client`, or `createOpencodeClient()`; follow installed `@opencode/client` declarations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

CodeNomad server and UI pin `@opencode/client@2.1.0`. The runtime CLI is managed independently; startup validates authenticated loopback `/api/info`, then (only to identify an outdated daemon) `/api/status`, then `/api/health`, advancing only on HTTP 404 with the same endpoint, credentials and deadline. Each response has its own validated schema and a 64 KiB bound. The shared transport forwards canonical `server.info()` unchanged. Review official V2 docs, installed declarations, generated routes and native regression tests together when upgrading.

Runtime requirements live in `packages/server/src/opencode/runtime-support.ts`: minimum 2.1.2 (Code Mode JavaScript job ordering and the `native`/`metadata.keepID` replay contract), with the recommendation tracked separately. Native builds share the daemon's Effect/public SDK instead of bundling a second runtime. The shared connection binds authenticated runtime identity, the canonical client and forwarding transport. Admission precedes functional requests/plugin provisioning; unlisted custom/prerelease/future labels require authenticated bounded API recognition. Never add operation-specific retry fallbacks. See `dev-docs/OPENCODE_COMPATIBILITY.md` for the version boundaries and `dev-docs/OPENCODE_RUNTIME_SETUP.md` for admission.
Runtime requirements live in `packages/server/src/opencode/runtime-support.ts`: minimum 2.2.3 (the `experimental_image_generate` image tool contract, Code Mode JavaScript job ordering and the `native`/`metadata.keepID` replay contract), with the recommendation (currently the same version) tracked separately. Native builds share the daemon's Effect/public SDK instead of bundling a second runtime. The shared connection binds authenticated runtime identity, the canonical client and forwarding transport. Admission precedes functional requests/plugin provisioning; unlisted custom/prerelease/future labels require authenticated bounded API recognition. Never add operation-specific retry fallbacks. See `dev-docs/OPENCODE_COMPATIBILITY.md` for the version boundaries and `dev-docs/OPENCODE_RUNTIME_SETUP.md` for admission.

The Promise client preserves the full `baseUrl` path prefix. Forward its generated URL unchanged through `createInstanceFetch`; remove the proxy prefix only when classifying reads for scheduling. Declared API errors are `Error` instances retaining their native `_tag`/data fields. Client errors retain structured `reason`/`cause`, and their `message` may add status, content type or cause detail: classify by structured fields, never exact message text.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- Native routes are `/api/*`; CodeNomad exposes them only through the authorized `/workspaces/:id/instance` proxy.
- That proxy is an explicit method/path allowlist: expose each new upstream API only after review.
- Proxy authorization and forwarding share one acquired connection. A stale generation must be rejected at actual HTTP dispatch, including after asynchronous body preparation; late streams cannot invalidate a replacement connection.
- The technical minimum is 2.1.2 for Code Mode's JavaScript job ordering and the `native` replay and `metadata.keepID` compaction shapes consumed by the pinned client reducer; the recommendation is independent. Plugins use host-owned Effect/public SDK modules through the shared native build settings. Unknown version labels, prereleases and future majors undergo bounded authenticated API recognition, including session environment support. Native `session.inbox.enqueued` has its own shape: its timestamp lives in event metadata, unlike an HTTP inbox record.
- The technical minimum is 2.2.3 for the `experimental_image_generate` image tool contract (upstream #60258: tool, permission action, job type and notice `metadata.source` share that name; on unless `experimental.image_generate` is `false`), alongside Code Mode's JavaScript job ordering and the `native` replay and `metadata.keepID` compaction shapes consumed by the pinned client reducer; the recommendation is a separate constant, currently the same version. Plugins use host-owned Effect/public SDK modules through the shared native build settings. Unknown version labels, prereleases and future majors undergo bounded authenticated API recognition, including session environment support. Native `session.inbox.enqueued` has its own shape: its timestamp lives in event metadata, unlike an HTTP inbox record.
- Never retry a write using another contract after a 400/404/transport failure. Keep the setup/recovery path distinct from functional transport and never replay prompts.

## Location Is Authority
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Then open a pull request on GitHub targeting the `dev` branch.

### OpenCode V2 Boundaries

- Server and UI pin `@opencode/client@2.1.0`; native plugins pin `@opencode/plugin@2.1.0` for authoring but resolve Effect and the public SDK from the daemon at runtime. Upgrade pins together with the lockfile and isolated native validation. The runtime CLI is managed independently; its demonstrated minimum and recommended/tested versions remain separate constants in `packages/server/src/opencode/runtime-support.ts` (minimum 2.1.2 for Code Mode's reproduced JavaScript job-ordering defect on 2.1.0/2.1.1, recommended 2.2.1; the native replay contract dates from 2.1.0). A build pin alone is never a runtime requirement, and unfamiliar newer/custom labels retain authenticated contract recognition. Review current OpenCode documentation, installed declarations, and proxy/API parity whenever the client contract changes.
- Server and UI pin `@opencode/client@2.1.0`; native plugins pin `@opencode/plugin@2.1.0` for authoring but resolve Effect and the public SDK from the daemon at runtime. Upgrade pins together with the lockfile and isolated native validation. The runtime CLI is managed independently; its demonstrated minimum and recommended/tested versions remain separate constants in `packages/server/src/opencode/runtime-support.ts` (both currently 2.2.3: the minimum for the `experimental_image_generate` image tool contract of upstream #60258, consumed by the Images gallery, Design agent and Images settings, and the recommendation). A build pin alone is never a runtime requirement, and unfamiliar newer/custom labels retain authenticated contract recognition. Review current OpenCode documentation, installed declarations, and proxy/API parity whenever the client contract changes.
- Upgrade references: [OpenCode V2 changelog](https://opencode.ai/changelog) (GitHub Releases list V1), the exact release tags (`vX.Y.Z`) or published npm packages for source/declaration deltas, [OpenCode V2 documentation](https://opencode.ai/v2/docs/), and `node_modules/@opencode/client/dist/promise/`.
- `packages/server/src/workspaces/opencode-service.ts` 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 daemon. CodeNomad owns no private port, database, registration, or daemon PID and never stops the daemon on backend shutdown.
- WSL requires Windows localhost forwarding and runs the Linux CLI lifecycle inside the distribution; never inspect or signal Linux PIDs from Windows.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ npx @neuralnomads/codenomad-dev --password "your-password" --launch

## OpenCode V2 and upgrading from 0.19.x

CodeNomad **1.0.0 requires OpenCode V2**: **2.1.2 minimum, 2.2.1 recommended**, including the Code Mode JavaScript job-ordering fix. OpenCode V1 and the former V2 beta protocol are not supported. The current requirements are maintained in [`runtime-support.ts`](packages/server/src/opencode/runtime-support.ts).
CodeNomad **1.0.0 requires OpenCode V2**: **2.2.3, both minimum and recommended**, for the image generation tool used by the Images settings and the Design extension. OpenCode V1 and the former V2 beta protocol are not supported. The current requirements are maintained in [`runtime-support.ts`](packages/server/src/opencode/runtime-support.ts).

- **One shared OpenCode service** owns sessions and messages. Closing a CodeNomad tab, window, or backend leaves that service running. Desktop tabs, drafts, and layout are restored separately for each window.
- **Use an existing CLI or install from CodeNomad.** Executables on `PATH` are preferred; the setup screen also supports a selected executable and a shared user npm installation. The former private CodeNomad OpenCode installation is no longer used.
Expand Down Expand Up @@ -166,7 +166,7 @@ Add SideCar as:

## Requirements

- **[OpenCode V2](https://opencode.ai/v2/docs/)** — 2.1.2 minimum and 2.2.1 recommended for CodeNomad 1.0.0. Install/select it through desktop setup or provide a compatible CLI on the server host.
- **[OpenCode V2](https://opencode.ai/v2/docs/)** — 2.2.3, both minimum and recommended for CodeNomad 1.0.0. Install/select it through desktop setup or provide a compatible CLI on the server host.
- **[Git](https://git-scm.com/downloads)** — a prerequisite for full functionality (repository identity, Git operations and worktrees). Git must be executable in the CodeNomad backend's `PATH`; it is not bundled with the desktop installers.
- **Node.js and npm** — required for the standalone npm server and source builds, bundled with desktop releases. Use **Node.js 24 LTS**; development and release builds use the version in [`.node-version`](.node-version) (currently 24.20.0).

Expand Down
28 changes: 18 additions & 10 deletions dev-docs/OPENCODE_COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,24 @@ view; release notes are at [opencode.ai/changelog](https://opencode.ai/changelog
(GitHub Releases cover V1 only). Keep results in the PR and CI logs, never as
per-version sections here.

Minimum runtime **2.1.2**, recommended **2.2.1** (`runtime-support.ts`), with
**2.1.0** client/plugin pins. Earlier native Code Mode breaks JavaScript
run-to-completion (lost shared updates, async caller resumed before its first await);
`scripts/test-codemode-jobs-native.mjs` keeps the red/green regression, run in
CI against minimum and latest. The pinned 2.1 reducer consumes the replay
contract (below), so 2.0.x daemons are refused with `native_contract`. Plugins
share the host Effect 4.0.1/Schema runtime. Unlisted/prerelease/custom/future
labels undergo authenticated contract recognition; missing canonical APIs,
session environment or the replay shape give a concrete reason. OpenCode 2.1
reads older stored data.
Minimum and recommended runtime **2.2.3** (`runtime-support.ts`), with
**2.1.0** client/plugin pins. The minimum carries the image tool contract of
upstream [#60258](https://github.com/anomalyco/opencode/pull/60258), consumed by
the Images gallery, the Design agent and skills and the Images settings: one
name, `experimental_image_generate`, for the tool, its permission action, its job
type and its completion notices' `metadata.source` (`IMAGE_TOOL` in
`session-pruning/assets-gallery-proof.ts`), and the tool offered while an image
model is available unless `experimental.image_generate` is `false`
(`image-settings.ts` reads it that way). Notices wrap their text in
`<image id="…" state="…">`; the gallery reads the `Saved image: <path> (` line.
The minimum also provides the replay contract (below) consumed by the pinned 2.1
reducer and Code Mode JavaScript run-to-completion, whose regression
`scripts/test-codemode-jobs-native.mjs` runs in CI against minimum and latest.
Daemons below the minimum are refused with `native_contract`. Plugins share the
host Effect 4.0.6/Schema runtime. Unlisted/prerelease/custom/future labels
undergo authenticated contract recognition; missing canonical APIs, session
environment or the replay shape give a concrete reason. OpenCode reads older
stored data.

### Native Codex subscription usage

Expand Down
2 changes: 1 addition & 1 deletion dev-docs/PANEL_EXTENSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ await codenomad.preferences.set({ imagesPerTurn: 3 }) // "saved" | "too-large" |

- **Status** reads the session's Location (without a displayed conversation, the
instance's current Location): generation from `experimental.image_generate` in the
daemon schema and its effective value (`opencode/image-settings.ts`), image models
daemon schema and its effective value, on unless `false` (`opencode/image-settings.ts`), image models
from the Location's image catalog, the Design agent's content mark
(`opencode/design/status.ts`), and whether the effective chat model (session,
else its agent's when available, else the native default) lists an `image*`
Expand Down
12 changes: 6 additions & 6 deletions dev-docs/SESSION_PRUNING_RPC.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ stops before the revert boundary (`id < revert.messageID`).

- `images({ sessionID, cursor?, prompts? })` lists, newest first, one `image` entry
per image file (`image/png|jpeg|gif|webp|avif`) of a `read` tool part and one
`generation` entry per `image_generate` part, in part and file order. A page holds
`generation` entry per `experimental_image_generate` part, in part and file order. A page holds
at most 32 assistant messages, 32 MiB of stored JSON (each row size-checked
before it loads; a row over 16 MiB gives `blocked: limit`), 64 entries and 1 MiB
serialized. Every admitted row is emitted before the cursor advances: a row the
Expand All @@ -105,13 +105,13 @@ decoded by SQLite only for rows of at most 64 KiB. A read of file `F` over
undecoded row is dated at or before the read's end, the scan covers the item's whole
range (its message and the 31 before it, within 32 MiB, unless the session starts
sooner; a range an oversized row or the scan budget cuts proves nothing), exactly one
`image_generate` call that may write `F` in that range started before that end, it
`experimental_image_generate` call that may write `F` in that range started before that end, it
completed with a `jobID` before the read began, its single
decoded notice names `F` between the call's start and the read's start, and no
other completed notice names `F` from then until the read's end. Parents of a proven
call follow the same rule over the generation's own interval. Only a `completed`
`image_generate` part with `metadata.path` names the file it writes (that stem);
every other `image_generate` part (streaming, running, errored or completed without
`experimental_image_generate` part with `metadata.path` names the file it writes (that stem);
every other `experimental_image_generate` part (streaming, running, errored or completed without
`metadata.path`) may write any file, so it leaves every proof and reference it could
affect unverifiable. Relative read names and parent references resolve lexically against the session directory in the daemon's
path style (Windows without case); one outside the location has no label and no
Expand All @@ -131,7 +131,7 @@ notice naming the file after it (`changed`). A generation target is also refused
its file, started before its notice (or at an unknown time) in the item's range or
later, lacks a completion time or a decoded notice of its own.

Consumed contracts: `read` tool `state.content` files, `image_generate` parts
Consumed contracts: `read` tool `state.content` files, `experimental_image_generate` parts
(`state.status`, `state.input.prompt|images`, `state.metadata.path` as the stem, `jobID`, `model`,
`time.ran|completed`) and its synthetic notices (`metadata.source|jobID|state|path`,
text `Saved image: <file> (`). A change leaves generations `unknown` and images
Expand Down Expand Up @@ -208,7 +208,7 @@ whose ref and blob the prune releases), the Images conversation (one creation fo
concurrent opens from two clients, a newer marked child, deletion, another location,
restart) and gallery membership on that stored tool file. Unit tests cover rollback
and client projection/read races; the gallery tests replay their proof mutations on
copies of two OpenCode 2.2.1 Images transcripts, with and without media blobs
copies of two Images transcripts in the OpenCode 2.2.3 format, with and without media blobs
(`assets-gallery-fixture.json`).
`scripts/test-design-companion-native.mjs` drives an Images conversation end to end with a
scripted chat model and a fake image model on the shipped bundle: two series of read images
Expand Down
Loading
Loading