OpenCode executor fork for the Pistachiorama sandbox (Spec 131/132)
Priority: high
This repo uses Bun as the runtime, package manager, and test runner.
- Use Bun-native APIs:
Bun.file(),Bun.serve(), etc. - Prefer
constoverlet; use ternaries over reassignment - Avoid
try/catch,any,else, unnecessary destructuring - Rely on type inference; avoid explicit annotations unless needed
- Use
tsgo --noEmitfor type checking (nottsc)
- Run tests from package directory, not repo root:
cd packages/opencode && bun test - Root
package.jsontest script intentionally errors — run per-package - No mocks — test actual implementation against real behavior
- Test timeout:
--timeout 30000(30 seconds) - Coverage:
bun test --coveragegenerates LCOV atcoverage/lcov.info
- Bun workspace monorepo —
bun installinstalls all packages - Use
bun add <pkg>to add dependencies (not npm/pnpm) bun.lockis the lockfile — commit it
bun run dev # From packages/opencode/
cd packages/opencode && bun test --timeout 30000
cd packages/opencode && bun test --coverage
bun turbo typecheck # All packages
cd packages/opencode && bunx tsgo --noEmit # Single package
bunx prettier --check . # Check
bunx prettier --write . # FixPriority: high
Never use any in TypeScript. Use specific types or unknown with type guards.
Prefer type inference over explicit annotations unless ambiguity would arise.
Priority: critical
- NEVER output API keys or secrets
- NEVER read or output .env file contents
- Reference secrets by env var name only (e.g.,
process.env.AXIOM_TOKEN) - Use .env.example for documentation
- Fly.io secrets are set via
fly secrets set— never committed
Priority: high
This fork adds a production HTTP server that Pistachiorama's sandbox uses for tool execution.
| File | Purpose |
|---|---|
packages/opencode/src/server/server.ts |
Hono app, CORS, auth, request logging |
packages/opencode/src/server/routes/tool-call.ts |
POST /session/:id/tool/call — direct tool execution |
packages/opencode/src/server/routes/session.ts |
Session CRUD, chat, abort |
packages/opencode/src/util/log.ts |
Custom logger (writes to stderr/file) |
packages/opencode/src/util/axiom.ts |
Axiom telemetry singleton (graceful no-op without AXIOM_TOKEN) |
- Runtime: Docker (multi-stage Bun build → Alpine)
- Platform: Fly.io app
pistachiorama-opencode, regionsjc,performance-2xVM - Port: 8080 (
opencode serve --port 8080 --hostname 0.0.0.0) - Registry:
registry.fly.io/pistachiorama-opencode - Auto-stop/start: Enabled — min 1 machine running (avoids cold starts)
- Docker build+push: On
v*tag push via.github/workflows/build-push.yml - Tests:
.github/workflows/test.ymlon PR/push todev - Type check:
.github/workflows/typecheck.ymlon PR/push todev - Lint:
.github/workflows/ci.ymlon PR/push todev(also hasci-passaggregation job)
The Pistachiorama Rust Durable Object connects server-to-server via fetch() — no browser in the loop. CORS is therefore irrelevant for the sandbox→OpenCode connection. The existing CORS config (localhost + opencode.ai domains) is correct and intentional.
- Default branch:
dev - All PRs target
dev - Never commit directly to
dev - Create worktrees for feature branches
Priority: high
Use Ubicloud runners for GitHub Actions, never ubuntu-latest for new workflows.
Default: ubicloud-standard-2 for most jobs.
Allowed variants:
ubicloud-standard-{2,4,8}— Standard x86ubicloud-standard-{4,8}-arm— ARM64 for cost savings
jobs:
example:
runs-on: ubicloud-standard-2 # NOT ubuntu-latestNote: No Windows or macOS Ubicloud runners — remove upstream Windows/macOS jobs when migrating workflows.