anomalyco / anomalyco/opencode

session/list doesn't conform to the ACP spec: empty params scopes to the launch project instead of all sessions, and cwd filter value is discarded

Open
#39,579 1 comment 0 reactions 1 assignee View on GitHub

@jlongster is already working on this.

Since Jul 29, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

Per the ACP session/list spec, an empty params object should return "the first page of sessions," and the optional cwd parameter should filter to "sessions with a matching cwd." In practice, opencode's ACP session/list handler does neither: it silently scopes to the git-derived "project" of wherever the agent process was launched, and discards any cwd value you actually pass.

Repro
$ pwd
/path/to/some-git-repo   # a git repo opencode has never seen before
$ opencode acp
{"jsonrpc":"2.0","id":1,"method":"session/list","params":{}}
{"jsonrpc":"2.0","id":1,"result":{"sessions":[]}}
$ pwd
/home/someuser   # not a git repo
$ opencode acp
{"jsonrpc":"2.0","id":1,"method":"session/list","params":{}}
{"jsonrpc":"2.0","id":1,"result":{"sessions":[ ... dozens of sessions with unrelated cwds,
  e.g. various temp directories and other unrelated project paths ... ]}}

Same method, same empty params, wildly different results depending on the literal directory the agent process happens to be started from — and neither result is "all sessions."

Expected (per spec)

"All parameters are optional. A request with an empty params object returns the first page of sessions."
cwd: "Filter sessions by working directory. Must be an absolute path. Only sessions with a matching cwd are returned."

Actual / root cause
  1. Empty params is not unfiltered. Session.list always scopes to the current instance's project id, with no way to opt out:

    // packages/opencode/src/session/session.ts:548-555
    const list = Effect.fn("Session.list")(function* (input?: ListInput) {
      const ctx = yield* InstanceState.context
      return yield* listByProject(db, { projectID: ctx.project.id, ...input })
    })
    

    ctx.project.id comes from ProjectV2.resolve() (packages/core/src/project.ts:110-122), which walks up from the server's own launch directory looking for a git repo. No repo → everything collapses into the shared ID.global bucket (explaining why a non-git launch directory returns a grab-bag of unrelated sessions from every prior non-git invocation). A repo found → a brand-new project id scoped to that repo, which starts out empty even though other sessions exist elsewhere.

  2. cwd is treated as a boolean, not a filter value. Even when the ACP layer forwards params.cwd (packages/opencode/src/acp/service.ts:251), the underlying HTTP handler ignores the actual value:

    // packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts:65
    const directory = ctx.query.directory ? yield* InstanceState.directory : undefined
    

    Any truthy directory/cwd is replaced with InstanceState.directory (the running instance's own directory) before the equality filter runs. So session/list { cwd: "/some/other/path" } never actually filters by /some/other/path — it filters by wherever the server itself started.

This looks like the REST endpoint was designed for opencode's own UI/CLI, where a server instance is pinned 1:1 to a workspace and "directory" is really just a "scope to my workspace" toggle — and the ACP bridge is reusing it as if it implemented the protocol's literal cwd filter, which it doesn't.

Suggested fix
  • Default (cwd omitted): return sessions across all known projects/directories, not just the launch instance's project.
  • When cwd is provided: filter by exact equality against SessionTable.directory/cwd, using the client-supplied value — not InstanceState.directory.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.