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
@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
paramsobject returns the first page of sessions."
cwd: "Filter sessions by working directory. Must be an absolute path. Only sessions with a matchingcwdare returned."
Actual / root cause
-
Empty
paramsis not unfiltered.Session.listalways 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.idcomes fromProjectV2.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 sharedID.globalbucket (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. -
cwdis treated as a boolean, not a filter value. Even when the ACP layer forwardsparams.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 : undefinedAny truthy
directory/cwdis replaced withInstanceState.directory(the running instance's own directory) before the equality filter runs. Sosession/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 (
cwdomitted): return sessions across all known projects/directories, not just the launch instance's project. - When
cwdis provided: filter by exact equality againstSessionTable.directory/cwd, using the client-supplied value — notInstanceState.directory.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.