Plan for replacing instance Hono route implementations with Effect HttpApi while preserving behavior, OpenAPI, and SDK output during the transition.
src/server/routes/instance/httpapi/*.HttpApiGroup, schemas, handlers, and route-level middleware.httpapi/server.ts only composes groups, instance lookup, observability, and the web handler bridge.HttpApi replacements are default, tested, and represented in the SDK/OpenAPI pipeline.HttpApi if HttpApi is the wrong abstraction.OPENCODE_EXPERIMENTAL_HTTPAPI gates the bridge. Default behavior still uses Hono.server/routes/instance/index.ts before legacy Hono routes.hono-openapi SDK generation.HttpApi auth is independent of Hono auth.Authorization is attached in each route module, not centrally wrapped in server.ts.auth_token query parameter through HttpApiSecurity.apiKey.httpapi/server.ts using directory, workspace, and x-opencode-directory.Observability.layer is provided in the Effect route layer and deduplicated through the shared memoMap..zod only as compatibility for remaining Hono/OpenAPI surfaces.describeRoute entry.Use this checklist for each small HttpApi migration PR:
HttpApiGroup, route paths, DTO schemas, and handlers in src/server/routes/instance/httpapi/*.src/server/routes/instance/index.ts only inside the OPENCODE_EXPERIMENTAL_HTTPAPI block.InstanceState.context / InstanceState.directory inside HttpApi handlers instead of Instance.directory, Instance.worktree, or Instance.project ALS globals.Schema.Struct; use Schema.Class only when handlers return actual class instances..zod compatibility in place for SDK/OpenAPI generation.InstanceRoutes, not only the raw HttpApi web handler, when the route depends on auth or instance context.bun typecheck from packages/opencode, relevant bun run test:ci ... tests from packages/opencode, and ./packages/sdk/js/script/build.ts from the repo root.Use this checklist before deleting any Hono route implementation. A route being bridged is not enough.
HttpApi parity is complete for the route path, method, auth behavior, query parameters, request body, response status, response headers, and error status.OPENCODE_EXPERIMENTAL_HTTPAPI.HttpApi path and the fallback Hono path until the fallback is removed.HttpApi route as the source for that path.describeRoute, validator, and handler for that path are removed..zod compatibility on the canonical Effect Schema.HttpApi if raw Effect HTTP is a better fit.Hono can be removed from the instance server only after all mounted Hono route groups meet this checklist and server/routes/instance/index.ts no longer depends on Hono routing for default behavior.
For the experimental route group, port read-only JSON routes before mutations:
GET /console, GET /console/orgs, GET /tool/ids, GET /resource.GET /worktree only if the handler uses InstanceState.context instead of Instance.project.POST /console/switch, worktree create/remove/reset, and GET /session to separate PRs because they mutate state or have broader pagination/session behavior.Schema.Struct(...).annotate({ identifier }) for named OpenAPI refs when handlers return plain objects.Schema.Class only when the handler returns real class instances or the constructor requirement is intentional.Schema.Struct unless a named SDK type is useful.Before porting more routes, cover the bridge behavior that every route depends on.
HttpApi bridge, not just HttpApiBuilder.layer directly.auth_token success, missing credentials, and bad credentials.directory and x-opencode-directory instance selection.HttpApi groups.Create a route inventory from the actual Hono registrations and classify each route.
Statuses:
bridged: served through the HttpApi bridge when the flag is on.implemented: HttpApi group exists but is not mounted through Hono.next: good JSON candidate for near-term porting.later: portable, but needs schema/service cleanup first.special: SSE, websocket, streaming, or UI bridge behavior that likely needs raw Effect HTTP rather than HttpApi.Port remaining JSON routes in small batches.
Good near-term candidates:
GET /path, GET /vcs, GET /vcs/diff, GET /command, GET /agent, GET /skill, GET /lsp, GET /formatterPOST /instance/disposeKeep large or stateful groups for later:
sessionsyncHono routes cannot be deleted while hono-openapi is the source of SDK generation.
Required before route deletion:
HttpApi for ported routes.dev for every route group deletion.After JSON parity and SDK generation are covered:
Delete Hono routes group-by-group after each group meets the deletion criteria.
Deletion criteria:
HttpApi route is mounted by default.After deleting a group:
.route(...) registration from instance/index.ts.Special routes need explicit designs before Hono can disappear completely.
event: SSEpty: websockettui: UI/control bridge behaviorsession endpointsUse raw Effect HTTP routes where HttpApi does not fit. The goal is deleting Hono implementations, not forcing every transport shape through HttpApi.
| Area | Status | Notes |
|---|---|---|
question |
bridged |
GET /question, reply, reject |
permission |
bridged |
list and reply |
provider |
bridged |
list, auth, OAuth authorize/callback |
config |
bridged |
read, providers, update |
project |
bridged |
list, current, git init, update |
file |
bridged partial |
find text/file/symbol, list/content/status |
mcp |
bridged partial |
status, add, connect/disconnect; OAuth remains |
workspace |
bridged partial |
adaptor/list/status; create/remove/session-restore remain |
| top-level instance routes | bridged |
path, vcs, command, agent, skill, lsp, formatter, dispose |
| experimental JSON routes | bridged partial |
console reads, tool ids, worktree list/mutations, resource list; global session list remains later |
session |
later/special |
large stateful surface plus streaming |
sync |
later |
process/control side effects |
event |
special |
SSE |
pty |
special |
websocket |
tui |
special |
UI bridge |
This checklist tracks bridge parity only. Checked routes are available through the experimental HttpApi bridge; Hono deletion is tracked separately by the deletion checklist above.
POST /instance/dispose - dispose active instance after response.GET /path - current directory and worktree paths.GET /vcs - current VCS status.GET /vcs/diff - VCS diff summary.GET /command - command catalog.GET /agent - agent catalog.GET /skill - skill catalog.GET /lsp - LSP status.GET /formatter - formatter status.GET /config - read config.PATCH /config - update config and dispose active instance after response.GET /config/providers - config provider summary.GET /project - list projects.GET /project/current - current project.POST /project/git/init - initialize git and reload active instance after response.PATCH /project/:projectID - update project metadata.GET /provider - list providers.GET /provider/auth - list provider auth methods.POST /provider/:providerID/oauth/authorize - start provider OAuth.POST /provider/:providerID/oauth/callback - finish provider OAuth.GET /question - list questions.POST /question/:requestID/reply - reply to question.POST /question/:requestID/reject - reject question.GET /permission - list permission requests.POST /permission/:requestID/reply - reply to permission request.GET /find - text search.GET /find/file - file search.GET /find/symbol - symbol search.GET /file - list directory entries.GET /file/content - read file content.GET /file/status - file status.GET /mcp - MCP status.POST /mcp - add MCP server at runtime.POST /mcp/:name/auth - start MCP OAuth.POST /mcp/:name/auth/callback - finish MCP OAuth callback.POST /mcp/:name/auth/authenticate - run MCP OAuth authenticate flow.DELETE /mcp/:name/auth - remove MCP OAuth credentials.POST /mcp/:name/connect - connect MCP server.POST /mcp/:name/disconnect - disconnect MCP server.GET /experimental/console - active Console provider metadata.GET /experimental/console/orgs - switchable Console orgs.POST /experimental/console/switch - switch active Console org.GET /experimental/tool/ids - tool IDs.GET /experimental/tool - tools for provider/model.GET /experimental/worktree - list worktrees.POST /experimental/worktree - create worktree.DELETE /experimental/worktree - remove worktree.POST /experimental/worktree/reset - reset worktree.GET /experimental/session - global session list.GET /experimental/resource - MCP resources.GET /experimental/workspace/adaptor - list workspace adaptors.POST /experimental/workspace - create workspace.GET /experimental/workspace - list workspaces.GET /experimental/workspace/status - workspace status.DELETE /experimental/workspace/:id - remove workspace.POST /experimental/workspace/:id/session-restore - restore session into workspace.POST /sync/start - start workspace sync.POST /sync/replay - replay sync events.POST /sync/history - list sync event history.GET /session - list sessions.GET /session/status - session status map.GET /session/:sessionID - get session.GET /session/:sessionID/children - get child sessions.GET /session/:sessionID/todo - get session todos.POST /session - create session.DELETE /session/:sessionID - delete session.PATCH /session/:sessionID - update session metadata.POST /session/:sessionID/init - run project init command.POST /session/:sessionID/fork - fork session.POST /session/:sessionID/abort - abort session.POST /session/:sessionID/share - share session.GET /session/:sessionID/diff - session diff.DELETE /session/:sessionID/share - unshare session.POST /session/:sessionID/summarize - summarize session.GET /session/:sessionID/message - list session messages.GET /session/:sessionID/message/:messageID - get message.DELETE /session/:sessionID/message/:messageID - delete message.DELETE /session/:sessionID/message/:messageID/part/:partID - delete part.PATCH /session/:sessionID/message/:messageID/part/:partID - update part.POST /session/:sessionID/message - prompt with streaming response.POST /session/:sessionID/prompt_async - async prompt.POST /session/:sessionID/command - run command.POST /session/:sessionID/shell - run shell command.POST /session/:sessionID/revert - revert message.POST /session/:sessionID/unrevert - restore reverted messages.POST /session/:sessionID/permissions/:permissionID - deprecated permission response route.GET /event - SSE event stream; replace with raw Effect HTTP, not HttpApi.GET /pty - list PTY sessions.POST /pty - create PTY session.GET /pty/:ptyID - get PTY session.PUT /pty/:ptyID - update PTY session.DELETE /pty/:ptyID - remove PTY session.GET /pty/:ptyID/connect - PTY websocket; replace with raw Effect HTTP/websocket support.POST /tui/append-prompt - append prompt.POST /tui/open-help - open help.POST /tui/open-sessions - open sessions.POST /tui/open-themes - open themes.POST /tui/open-models - open models.POST /tui/submit-prompt - submit prompt.POST /tui/clear-prompt - clear prompt.POST /tui/execute-command - execute command.POST /tui/show-toast - show toast.POST /tui/publish - publish TUI event.POST /tui/select-session - select session.GET /tui/control/next - get next TUI request.POST /tui/control/response - submit TUI control response.Prefer smaller PRs from here so route behavior and SDK/OpenAPI fallout stays reviewable.
PATCH /project/:projectID.HttpApi JSON route slices.HttpApi routes into Hono behind OPENCODE_EXPERIMENTAL_HTTPAPI.auth_token as a query security scheme.