close
Skip to content

feat(opencode-workspaces-plugin): add Daytona workspace adaptor plugin for OpenCode - #38

Merged
mislavivanda merged 1 commit into
daytona:mainfrom
jamesmurdza:feat/opencode-workspaces-plugin
Aug 13, 2026
Merged

feat(opencode-workspaces-plugin): add Daytona workspace adaptor plugin for OpenCode#38
mislavivanda merged 1 commit into
daytona:mainfrom
jamesmurdza:feat/opencode-workspaces-plugin

Conversation

@jamesmurdza

@jamesmurdza jamesmurdza commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Description

Adds apps/opencode-workspaces-plugin: an OpenCode plugin that provisions Daytona sandboxes as remote workspaces via OpenCode's experimental workspace-adaptor API.

This PR was originally ported from daytonaio/daytona#4504, with Nx build config replaced by the standalone npm layout used elsewhere in this repo, and fixing several issues in the original plugin. It is not published and does not change packages/opencode-plugin.

This app has extensive test coverage, including end-to-end tests that run a full user flow in the actual OpenCode TUI with the plugin installed.

Upstream bugs in OpenCode

To make this PR work, two PRs were raised in OpenCode:

These PRs have both been merged and shipped.

Related issue(s)

Scope

  • This PR touches no more than one package/app (release routing is by changed file path).
  • The PR title follows Conventional Commits
    (e.g. feat(pi-extension): ..., fix(adk-plugin): ...) — it becomes the squash-commit
    message that release-please reads.

Checks

  • I ran the affected package's lint/build/test locally and they pass.
  • I updated documentation where relevant.

Legal

  • Every commit is signed off for the
    DCO (git commit -s); the sign-off matches the
    commit author.
    1 of 15 commits signed off — needs git rebase --signoff main.
  • I agree to the
    Contributor License Agreement.
    On my first PR, the CLA assistant will comment and I will reply to sign (once).

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA. ✅ Thank you!
Posted by the CLA Assistant Lite bot.

@jamesmurdza

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Aug 5, 2026
@jamesmurdza
jamesmurdza force-pushed the feat/opencode-workspaces-plugin branch from a256e9e to 19edfc0 Compare August 8, 2026 13:59
@jamesmurdza jamesmurdza changed the title (opencode-workspaces-plugin): add Daytona workspace adaptor plugin for OpenCode feat(opencode-workspaces-plugin): add Daytona workspace adaptor plugin for OpenCode Aug 8, 2026
@jamesmurdza
jamesmurdza marked this pull request as ready for review August 8, 2026 14:08
@jamesmurdza
jamesmurdza requested review from a team and mislavivanda as code owners August 8, 2026 14:08

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 13 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread apps/opencode-workspaces-plugin/test/integration.test.ts
Comment thread apps/opencode-workspaces-plugin/.opencode/plugin/daytona/index.ts Outdated
Comment thread apps/opencode-workspaces-plugin/test/integration.test.ts
@mislavivanda

mislavivanda commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

@jamesmurdza Reviewed the full source and live-tested everything against real Daytona sandboxes (5
workspaces created/destroyed over the session, zero leaks — the partial-create cleanup
demonstrably deletes its sandbox on failure). Typecheck, plugin, and integration suites are
green; the e2e TUI suite passes too, with one environment caveat documented below. Solid
work overall — the create() error path, the bounded health polls, and the log-based test
sweeps all held up under deliberate abuse.

A few requests before merge, all small:

1. Normalize "adaptor" → "adapter"

The upstream API spells it adapter everywhere (WorkspaceAdapter,
/experimental/workspace/adapter, workspace.adapter.list()); the PR mixes both variants,
sometimes in the same file (README's "Adaptor registration" section curls
/workspace/adapter three lines later). Occurrences: daytona/index.ts lines 7, 192
(variable), 360–361; plugin/index.ts line 8; plugin README lines 95, 97, 171, 183;
integration.test.ts line 131; root README table row. Verified the rename typechecks and
tests still pass.

2. README: "Running the e2e on any machine" section

The e2e drives the real TUI, so it inherits the developer's shell and global opencode
config — and fails on machines that differ from a vanilla setup. Both failure modes are
fixable purely via environment, no test changes needed. Verified on a machine where the
test fails as written and passes with:

SHELL=/bin/sh XDG_CONFIG_HOME=$(mktemp -d) npm test -- test/e2e-tui.test.ts

Please add a short README subsection under Running Tests documenting this, with the why:

  • SHELL=/bin/sh — the test types cd … && opencode into a fresh tmux pane immediately
    after new-session; heavier shell inits (zsh + plugins) eat part of that line, so the
    TUI silently starts in the wrong directory (plugin log then shows worktree=<repo root>
    instead of the temp project). A plain sh pane has no init to race.
  • XDG_CONFIG_HOME=$(mktemp -d) — isolates ~/.config/opencode. With a custom default
    agent configured globally (e.g. an oh-my-opencode setup), the warped session's first
    prompt dies silently on the remote: session created, zero assistant output, zero tokens,
    $0.00, no error surfaced. Isolated A/B on the same machine: vanilla config → reply in
    ~1s; custom default agent → dead session. Auth lives under XDG_DATA, so provider keys
    still forward.
  • OPENCODE_SERVER_PASSWORD must be unset — all three suites poll /global/health
    unauthenticated and fail with opaque 401s when it's exported.

The custom-agent behavior itself looks like upstream workspace-API territory (remote can't
resolve host-only agents and swallows the prompt without an error) — worth filing as
feedback to the opencode team alongside the two PRs already linked in the description, and
worth a one-line "known limitation" note in this README.

3. Stale comment: the TUI-render "sync gap"

The e2e header (test/e2e-tui.test.ts:16–20) says OpenCode's global sync delivers state
counts but not message content, so the reply never renders in the host TUI and is only
logged informationally. On 1.18.15 the reply DOES render (the test itself prints "TUI
rendered the reply" now). Suggest updating the comment, and optionally promoting the
informational check to a hard assertion.

4. Minor / documentation

  • create() unconditionally overwrites the sandbox repo's opencode.json (index.ts:292–300)
    and strips committed .opencode/ from the upload (index.ts:263) — repos carrying their own
    opencode config lose it remotely. Fine as a v1 trade-off, but worth a README note (or
    merging instructions into an existing config later).
  • Only the last commit is uploaded (clone from worktree, --depth 1) — uncommitted changes
    don't travel. Worth one README sentence.
  • Provider credentials are forwarded into sandbox envVars (that's how the remote can call
    models) and are visible in the Daytona dashboard — inherent to the design, deserves a
    one-line note.
  • PR body is stale: it says "1 of 15 commits signed off", but all commits now carry matching
    Signed-off-by trailers.

On the cubic comments

  • Temp-dir Date.now() collision — agreed, mkdtemp is a strict improvement; please take it.
  • Unbounded create fetch — already bounded by bun's --timeout 180000 and the afterAll
    log-sweep exists precisely for hung creates; optional, and if added the bound should be
    generous (creates legitimately took 16–50s in live runs).
  • Shared plugin log between test files — the path is the plugin's fixed log which tests
    only read (append-only + per-file offsets, files run sequentially), so the described
    orphan scenario can't occur; making the plugin's log path env-configurable would be nice
    future polish but isn't needed for merge.

@jamesmurdza
jamesmurdza force-pushed the feat/opencode-workspaces-plugin branch from 6733206 to 34d859d Compare August 13, 2026 02:38
@jamesmurdza

Copy link
Copy Markdown
Contributor Author

@mislavivanda Thank you for the feedback. I've implemented all the changes except instead of documenting the second one (e2e test inherits the developer's shell and global opencode config) I updated the test so this doesn't happen.

Summary of changes:

  1. adaptor → adapter — normalized the spelling everywhere to match the upstream API
  2. Unique scratch dir per create() — replaced the Date.now()-based temp path with mkdtemp
  3. e2e reproducibility — rather than documenting a manual env incantation, the e2e now pins its own environment at the tmux spawn (SHELL=/bin/sh, a temp XDG_CONFIG_HOME, and OPENCODE_SERVER_PASSWORD unset).
  4. README Limitations note — documented three trade-offs: 1) only the last commit is uploaded (shallow clone), 2) a repo's own .opencode//opencode.json isn't carried over, and 3) provider credentials are forwarded into the sandbox env.

And (of course) I've run the test suite after these changes to make sure everything works.

…n for OpenCode

Adds `apps/opencode-workspaces-plugin`: an OpenCode plugin that provisions
Daytona sandboxes as remote workspaces via OpenCode's experimental
workspace-adapter API.

Ported from `daytonaio/daytona` `libs/opencode-plugin` @ `106ca0a3`, with the
Nx build config replaced by the standalone npm layout used elsewhere in this
repo. Marked private — not published. Does not change
`packages/opencode-plugin`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: James Murdza <james@jamesmurdza.com>
@jamesmurdza
jamesmurdza force-pushed the feat/opencode-workspaces-plugin branch from 34d859d to b7f1a07 Compare August 13, 2026 09:48
@mislavivanda
mislavivanda merged commit f858293 into daytona:main Aug 13, 2026
28 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants