Add opencode-sandbox example - #23
Draft
opencolin wants to merge 2 commits into
Draft
Conversation
Documents enableOpenCode, a first-party Tenki feature the cookbook had no coverage of: it bakes the OpenCode CLI into the guest before the sandbox reports ready, so this example has no install step at all. Runs `opencode serve` against a cloned repo and exposes it on a public preview URL, so the same URL is both OpenCode's web UI (/app) and its JSON API. Measured gotchas are documented: port 7681 is reserved by Tenki's own ttyd console and cannot be exposed, --hostname 0.0.0.0 is required, and OPENCODE_SERVER_PASSWORD must be set or the server is open to the internet. verify.mjs asserts an unauthenticated request gets 401 before asserting the authenticated one returns the checkout, so the example cannot regress into publishing an unsecured agent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uz85xGA4zWSge1BtiDNnSN
run.mjs printed a preview URL and told you to open it in a browser, then `await using` terminated the sandbox as the scope ended — the URL 404'd before anyone could click it. Caught by running run.mjs for the first time. It now creates the sandbox without `await using`, holds the process open, and disposes on SIGINT, so the URL stays reachable until Ctrl-C. idleTimeoutMinutes: 30 reaps a sandbox that gets forgotten. Holding the loop open needs a ref'd handle: an unsettled top-level await makes Node exit 13 with "Detected unsettled top-level await". Dropping `await using` also drops the Node 24 requirement for this example; run.mjs now parses on Node 22. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uz85xGA4zWSge1BtiDNnSN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
32F7
div>
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CreateOptionshas shippedenableOpenCodeandopenCodeProviderfor a while and the cookbook has never mentioned either. This documents them.enableOpenCode: truebakes the OpenCode CLI into the guest before the sandbox reports ready, so unlike #20 and #22 this example has no install step at all. It startsopencode serveagainst a cloned repo and exposes it, so one public HTTPS URL is both OpenCode's web UI (/app) and its JSON API (/session,/agent,/project/current,/doc).Verification
Ran
node verify.mjslocally against the live API:Exit code 0, no model key needed. Asserts real values:
opencode --versionmatches semver (proving the bake, since nothing installs it), an unauthenticated request to the public URL returns exactly401, and the authenticated one returnsworktree: "/home/tenki/repo"withvcs: "git"— which only holds if the clone, the server, the gateway, and the auth are all working.Everything below was measured in a live sandbox
enableOpenCode: trueputsopencode1.17.20 at/usr/local/bin/opencode, and also starts attydconsole on port 7681.exposePort(7681)fails with[invalid_argument] port 7681 cannot be exposed as a preview— it's Tenki's own console. Any other port is fine; the example uses 4096.--hostname 0.0.0.0is required.opencode servedefaults to127.0.0.1, which the gateway can't reach.openCodeProvider: { apiKey, baseUrl }arrives in the guest as the env varsOPENCODE_API_KEYandOPENCODE_PROVIDER_BASE_URL— no config files are written.The security bit, which is why this PR is worth a careful read
Started without a password, the server logs
OPENCODE_SERVER_PASSWORD is not set; server is unsecuredand answers every caller. Combined withexposePort, that publishes an unauthenticated coding agent with a shell to the internet. I hit that in testing before writing a line of the example.So
run.mjsgenerates a random 24-byte password, andverify.mjsasserts the401before it asserts anything else, so the example cannot quietly regress into shipping an open agent. Auth is HTTP Basic (any username, that password); aBearertoken is rejected — both confirmed live.Scope
Adds one row to Developer tools, next to Claude Code and Codex. Touches nothing else outside
examples/opencode-sandbox/.Stacked on
examples/codex-sandbox(#22) → #21 → #20, since all four add a row to the root README table. Review order: #20 → #21 → #22 → this.Generated by Claude Code