Skip to content

feat(opencode): add upstream HttpApi backend route coverage - #1416

Merged
Astro-Han merged 3 commits into
devfrom
codex/i936-upstream-httpapi-parity
Jun 19, 2026
Merged

feat(opencode): add upstream HttpApi backend route coverage#1416
Astro-Han merged 3 commits into
devfrom
codex/i936-upstream-httpapi-parity

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

Adds local ProductionApi coverage for three upstream HttpApi backend JSON routes that have clear PawWork semantics:

  • GET /experimental/capabilities
  • GET /project/:projectID/directories
  • GET /pty/shells

Also classifies the remaining upstream-only candidates without local product semantics as explicitly deferred in the route inventory harness, while keeping retired /question routes out of local OpenAPI coverage.

Why

Issue #936 is migrating backend routes to the Effect HttpApi surface. The latest upstream inventory still had a small set of upstream HttpApi routes that were neither local ProductionApi routes nor documented local exceptions. This PR closes the safe backend parity gap and leaves code-backed inventory classifications for the routes that should not be locally implemented yet.

Related Issue

Related to #936.

Human Review Status

Pending

Review Focus

Please focus on whether the three newly exposed HttpApi routes map to the lowest correct local layer, and whether the deferred inventory classifications are narrow enough to avoid hiding real migration work.

Risk Notes

The /pty/shells route touches host shell discovery on macOS, Linux, and Windows by reusing the local shell helper; it avoids spawning shells and only checks candidate paths. The PR also updates generated OpenAPI and v2 SDK output to match ProductionApi. The visible UI check is skipped because no UI or copy changed.

How To Verify

packages/opencode focused server tests: 63 passed across route inventory, experimental, project, pty, and OpenAPI source tests
route inventory hermetic check: after git fetch origin dev made FETCH_HEAD point at the PawWork dev tree, route-inventory-harness.test.ts still passed 26 tests
packages/opencode typecheck: passed with GOMAXPROCS=2 bun run typecheck
packages/sdk/js typecheck: passed with bun run typecheck
git diff --check: passed
route inventory spot check: the three implemented routes are local-httpapi-upstream-only; formatter/control-plane/copy/background remain explicitly-deferred; retired question routes remain onlyHttpApi
fresh-eye review: no P0/P1; P2 hermetic inventory assertion issue fixed in f9aeee9c78

Screenshots or Recordings

Not applicable: no visible UI changes.

Checklist

How to use this checklist:

  • Tick a box by replacing [ ] with [x]. Do not edit, add, or remove items.
  • The bot-applied label items can only be honestly ticked AFTER the PR is opened and the labeler / priority-triage bots have run — return to the PR description and tick them then.
  • Most items are required. The few that are conditional are explicitly marked (conditional); for those, leave unticked if they truly do not apply and explain why in Risk Notes. All other items must be ticked before requesting human review.
  • Type label — this PR carries exactly one of bug, enhancement, task, documentation. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this.
  • Routing labels — this PR carries at least one of app, ui, platform, harness, ci. The labeler bot assigns these on PR open based on changed paths. Confirm the bot's choice (or override if wrong), then tick this.
  • Priority label — this PR carries exactly one of P0, P1, P2, P3. The priority-triage bot suggests one on PR open. Confirm or override, then tick this.
  • Human Review Status above is set to Pending, Approved by @<reviewer>, or Not required: <reason> (default is Pending; "not required" is restricted to bot-authored low-risk PRs).
  • I linked the related issue, or stated in Summary why there is no issue.
  • I described the review focus and any meaningful risks.
  • I replaced the example block in How To Verify with the real verification steps and the key result for each.
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope.
  • (conditional) I manually checked visible UI or copy changes when needed, with screenshots or recordings. Leave unticked only if no visible UI or copy changed.
  • (conditional) I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes. Leave unticked only if no platform/packaging surface was touched.
  • (conditional) I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant. Leave unticked only if none of those surfaces was touched.
  • I reviewed the final diff for unrelated changes and suspicious dependency changes.
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English.

@Astro-Han Astro-Han added P2 Medium priority upstream Tracked upstream or vendor behavior harness Model harness, prompts, tool descriptions, and session mechanics task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work labels Jun 19, 2026

@github-actions github-actions 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.

Suggested priority: P2 (includes non-doc, non-test paths outside the low-risk bucket).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Astro-Han, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 34 minutes and 4 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 83d9d9ff-e841-4453-81c9-dc48dcee7bd7

📥 Commits

Reviewing files that changed from the base of the PR and between fd4715c and b50002d.

📒 Files selected for processing (7)
  • packages/opencode/script/route-inventory.ts
  • packages/opencode/src/cli/cmd/generate.ts
  • packages/opencode/src/shell/shell.ts
  • packages/opencode/test/server/openapi-generation-source.test.ts
  • packages/opencode/test/server/route-inventory-harness.test.ts
  • packages/opencode/test/shell/shell.test.ts
  • packages/sdk/openapi.json
📝 Walkthrough

Walkthrough

Three new GET endpoints are added to the HTTP API: /experimental/capabilities (returns backgroundSubagents: false), /project/:projectID/directories (returns project worktree and sandbox directories), and /pty/shells (returns available system shells via a new Shell.list() implementation). The OpenAPI spec, route-inventory classifier, and tests are updated accordingly.

Changes

New HTTP API Endpoints: capabilities, directories, shells

Layer / File(s) Summary
Shell.Item type and list() implementation
packages/opencode/src/shell/shell.ts
Adds exported Item type and list() async function backed by resolved(), item(), win(), and unix() internal helpers that enumerate and validate platform shell candidates.
New schemas and route declarations
packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts, packages/opencode/src/server/routes/instance/httpapi/groups/project.ts, packages/opencode/src/server/routes/instance/httpapi/groups/pty.ts
Defines CapabilitiesResponse, ProjectDirectory, and ShellItem schemas; extends ExperimentalPaths with capabilities; registers three new GET endpoints in ExperimentalApi, ProjectApi, and PtyApi with OpenAPI annotations.
Raw route handlers
packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts, packages/opencode/src/server/routes/instance/httpapi/handlers/project.ts, packages/opencode/src/server/routes/instance/httpapi/handlers/pty.ts
Adds handleRaw implementations: capabilities returns a fixed { backgroundSubagents: false } payload; directories fetches project info and sandbox dirs, filters the root entry, maps to { directory }; shells calls Shell.list() and serializes results.
OpenAPI spec and route inventory classification
packages/sdk/openapi.json, packages/opencode/script/route-inventory.ts
Adds all three new endpoint definitions to the OpenAPI JSON spec; extends the route-inventory script with four new explicitlyDeferred patterns and a new local-httpapi-upstream-only classification branch.
Endpoint and inventory tests
packages/opencode/test/server/experimental-routes.test.ts, packages/opencode/test/server/project-routes.test.ts, packages/opencode/test/server/pty-routes.test.ts, packages/opencode/test/server/route-inventory-harness.test.ts
Adds OpenAPI contract assertions and integration handler tests for all three new endpoints; adds route-inventory harness tests for the local-httpapi-upstream-only and explicitly-deferred classifications.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Astro-Han/pawwork#949: Introduced the route-inventory harness and classification logic that this PR extends with new patterns and the local-httpapi-upstream-only branch.
  • Astro-Han/pawwork#1382: Also extends experimental.ts group and handlers with new experimental HttpApi endpoints, directly adjacent to the new /experimental/capabilities route added here.
  • Astro-Han/pawwork#1384: Modifies the PTY HTTP API group and handlers, overlapping with the new GET /pty/shells endpoint and PTY route-inventory coverage added here.

Suggested labels

tech-debt

Poem

🐇 Hippity-hop, three new routes appear,
/capabilities, /directories, /shells — oh dear!
The rabbit lists shells from /etc/shells with care,
Filters out / and maps what is there.
Background subagents? False for now, it would seem —
But soon, little bunny, we'll chase that big dream! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding upstream HttpApi backend route coverage to the local ProductionApi surface.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description is complete and well-structured, covering all required sections including Summary, Why, Related Issue, Human Review Status, Review Focus, Risk Notes, How To Verify, and a fully completed Checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/i936-upstream-httpapi-parity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/opencode/src/server/routes/instance/httpapi/groups/project.ts (1)

40-43: ⚡ Quick win

Use Schema.Class for ProjectDirectory.

ProjectDirectory is a multi-field schema and should follow the repo convention with Schema.Class instead of Schema.Struct.

Suggested refactor
-const ProjectDirectory = Schema.Struct({
-  directory: Schema.String,
-  strategy: Schema.optionalKey(Schema.String),
-})
+class ProjectDirectory extends Schema.Class<ProjectDirectory>("ProjectDirectory")({
+  directory: Schema.String,
+  strategy: Schema.optionalKey(Schema.String),
+}) {}

As per coding guidelines, "Use Schema.Class for multi-field data in Effect schemas".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/server/routes/instance/httpapi/groups/project.ts`
around lines 40 - 43, The ProjectDirectory schema definition uses Schema.Struct
for a multi-field schema, but repository conventions require using Schema.Class
instead. Replace Schema.Struct with Schema.Class in the ProjectDirectory
definition that contains the directory and strategy fields to align with the
Effect schema coding guidelines for multi-field data structures.

Source: Coding guidelines

packages/opencode/src/server/routes/instance/httpapi/groups/pty.ts (1)

45-49: ⚡ Quick win

Prefer Schema.Class for ShellItem.

ShellItem is multi-field and should use Schema.Class per the Effect schema conventions in this repo.

Suggested refactor
-const ShellItem = Schema.Struct({
-  path: Schema.String,
-  name: Schema.String,
-  acceptable: Schema.Boolean,
-})
+class ShellItem extends Schema.Class<ShellItem>("ShellItem")({
+  path: Schema.String,
+  name: Schema.String,
+  acceptable: Schema.Boolean,
+}) {}

As per coding guidelines, "Use Schema.Class for multi-field data in Effect schemas".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/server/routes/instance/httpapi/groups/pty.ts` around
lines 45 - 49, The ShellItem definition currently uses Schema.Struct but should
be refactored to use Schema.Class since it contains multiple fields. Change the
ShellItem definition from using Schema.Struct to Schema.Class while keeping all
three field definitions (path as Schema.String, name as Schema.String, and
acceptable as Schema.Boolean) exactly as they are structured currently.

Source: Coding guidelines

packages/opencode/src/server/routes/instance/httpapi/handlers/project.ts (1)

70-83: ⚡ Quick win

Prefer a named Effect.fn for the new directories handler flow.

This new route path is currently anonymous (Effect.gen(...) inline). Using Effect.fn("ProjectHttpApi.directories") here keeps traces and debugging labels consistent with the repo’s Effect conventions.

Suggested refactor
-    .handleRaw("directories", (ctx) =>
-      Effect.gen(function* () {
+    const directories = Effect.fn("ProjectHttpApi.directories")(function* (ctx: { params: { projectID: string } }) {
         const projectInfo = yield* Project.Service.use((svc) => svc.get(ProjectID.make(ctx.params.projectID)))
         if (!projectInfo)
           return yield* projectFailure(new NotFoundError({ message: `Project not found: ${ctx.params.projectID}` }))
         const directories = yield* Project.Service.use((svc) => svc.sandboxes(projectInfo.id))
         const result = [projectInfo.worktree, ...directories]
           .filter((directory) => directory !== "/")
           .map((directory) => ({ directory }))
         return HttpServerResponse.jsonUnsafe(result)
-      }).pipe(
+      })
+
+    return handlers
+      .handleRaw("directories", (ctx) =>
+        directories(ctx).pipe(
           Effect.catch(projectFailure),
           Effect.catchDefect(projectFailure),
-      ),
-    ),
+        ),
+      )

As per coding guidelines, packages/opencode/**/*.ts: “Use Effect.fn("Domain.method") for named/traced effects and Effect.fnUntraced for internal helpers...”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/server/routes/instance/httpapi/handlers/project.ts`
around lines 70 - 83, The handleRaw "directories" handler currently uses an
anonymous Effect.gen for its flow, which doesn't provide proper tracing labels.
Refactor this by extracting the Effect.gen logic into a named Effect.fn call
with the identifier "ProjectHttpApi.directories" to align with the repository's
Effect conventions for tracing and debugging. Replace the inline
Effect.gen(function* () { ... }) with Effect.fn("ProjectHttpApi.directories",
...) that generates the same effect chain, ensuring the error handling with
projectFailure is preserved in the pipe.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/src/shell/shell.ts`:
- Around line 95-99: The unix() function reads /etc/shells but doesn't properly
normalize lines before filtering. Currently it checks if line.trim() is truthy
in the filter condition but uses the original untrimmed line value, which
preserves whitespace padding and allows indented comments (lines with leading
whitespace before #) to be treated as valid shell candidates. Fix this by
trimming each line first, then checking if the trimmed line is truthy and
doesn't start with "#", so you filter on the actual trimmed value rather than
checking trimmed truthiness while keeping the untrimmed value. Additionally, add
a fallback return statement after the return statement with Array.from in case
the final parsed array is empty.

In `@packages/sdk/openapi.json`:
- Line 2751: The import statement in the code sample on line 2751 (and also on
lines 2801 and 3788) is missing the closing quote around the module name
"`@opencode-ai/sdk`". The import statement currently reads "import {
createOpencodeClient } from \"`@opencode-ai/sdk`\n" but should be "import {
createOpencodeClient } from \"`@opencode-ai/sdk`\"\n". Add the missing closing
double quote after the package name `@opencode-ai/sdk` in all three locations to
make the JavaScript import valid.

---

Nitpick comments:
In `@packages/opencode/src/server/routes/instance/httpapi/groups/project.ts`:
- Around line 40-43: The ProjectDirectory schema definition uses Schema.Struct
for a multi-field schema, but repository conventions require using Schema.Class
instead. Replace Schema.Struct with Schema.Class in the ProjectDirectory
definition that contains the directory and strategy fields to align with the
Effect schema coding guidelines for multi-field data structures.

In `@packages/opencode/src/server/routes/instance/httpapi/groups/pty.ts`:
- Around line 45-49: The ShellItem definition currently uses Schema.Struct but
should be refactored to use Schema.Class since it contains multiple fields.
Change the ShellItem definition from using Schema.Struct to Schema.Class while
keeping all three field definitions (path as Schema.String, name as
Schema.String, and acceptable as Schema.Boolean) exactly as they are structured
currently.

In `@packages/opencode/src/server/routes/instance/httpapi/handlers/project.ts`:
- Around line 70-83: The handleRaw "directories" handler currently uses an
anonymous Effect.gen for its flow, which doesn't provide proper tracing labels.
Refactor this by extracting the Effect.gen logic into a named Effect.fn call
with the identifier "ProjectHttpApi.directories" to align with the repository's
Effect conventions for tracing and debugging. Replace the inline
Effect.gen(function* () { ... }) with Effect.fn("ProjectHttpApi.directories",
...) that generates the same effect chain, ensuring the error handling with
projectFailure is preserved in the pipe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 832fc393-3bd5-495e-b631-14d1e7f0bd46

📥 Commits

Reviewing files that changed from the base of the PR and between dc4a521 and fd4715c.

⛔ Files ignored due to path filters (2)
  • packages/sdk/js/src/v2/gen/sdk.gen.ts is excluded by !**/gen/**
  • packages/sdk/js/src/v2/gen/types.gen.ts is excluded by !**/gen/**
📒 Files selected for processing (13)
  • packages/opencode/script/route-inventory.ts
  • packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts
  • packages/opencode/src/server/routes/instance/httpapi/groups/project.ts
  • packages/opencode/src/server/routes/instance/httpapi/groups/pty.ts
  • packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts
  • packages/opencode/src/server/routes/instance/httpapi/handlers/project.ts
  • packages/opencode/src/server/routes/instance/httpapi/handlers/pty.ts
  • packages/opencode/src/shell/shell.ts
  • packages/opencode/test/server/experimental-routes.test.ts
  • packages/opencode/test/server/project-routes.test.ts
  • packages/opencode/test/server/pty-routes.test.ts
  • packages/opencode/test/server/route-inventory-harness.test.ts
  • packages/sdk/openapi.json

Comment thread packages/opencode/src/shell/shell.ts
Comment thread packages/sdk/openapi.json Outdated
@Astro-Han
Astro-Han merged commit 20b388b into dev Jun 19, 2026
70 of 73 checks passed
@Astro-Han
Astro-Han deleted the codex/i936-upstream-httpapi-parity branch June 19, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work upstream Tracked upstream or vendor behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant