Repository navigation
fix(opencode): read OpenCode v2 usage from session_v2/session_message tables #1644
Description
Activity
pullfrog commented
on Aug 26, 2026 pullfrogboton Aug 26, 2026 – with PullfrogContributorMore actionsAssessment
This issue is actionable. The current OpenCode adapter only queries the legacy
messagetable inrust/adapters/opencode/src/loader.rsand parses the v1 top-level payload fields inrust/adapters/opencode/src/parser.rs; it has no path forsession_message, so v2 assistant usage is currently invisible. The existing DB/file ID deduplication is a useful foundation for the requested cross-source deduplication.One schema detail needs to be confirmed before implementation: the issue calls the new session table
session_v2, while the current upstream OpenCode beta schema I inspected uses a v2sessiontable alongsidesession_messageand has no literalsession_v2table. The implementation should detect the actual tables/columns rather than assuming one name, while retaining legacysession/messagecompatibility.Proposed Plan
-
Confirm and isolate the schemas. Establish a representative v1/v2 SQLite fixture and verify the physical session table name, column types, timestamp units, and whether v2 session rows are needed only for metadata or also for sessions lacking usable assistant messages. Detect optional tables before preparing queries so v1-only databases remain unchanged and beta schema drift fails open with debug diagnostics.
-
Add v2 database loading in
loader.rs. Keep the legacymessagequery, add asession_messagequery restricted totype = 'assistant', and pass the rowidandsession_idseparately from the JSON payload. Reuse the existing date-window pushdown plus authoritative payload filtering, with the v2time_created/data.time.createdshape handled explicitly. Preserve the existing JSON-file fallback and source ordering. -
Normalize both payload versions in
parser.rs. Extend the source-local types to accept v1 fields and the v2 nestedmodel.id/model.providerIDshape. Allow loader-supplied IDs and session IDs to fill fields absent from v2 JSON, retain positive stored costs and existing pricing fallback behavior, and ignore non-usage/malformed/zero-token rows. Decide the treatment of any v2 reasoning field against the existingextra_total_tokensconvention rather than silently losing or double-counting it. -
Integrate v2 session data without polluting other reports. Use
session_messageentries for daily, weekly, monthly, and ordinary session aggregation. If the v2 session table is required forccusage opencode sessionmetadata or aggregate-only sessions, carry that information through a session-specific metadata/aggregate path inreport.rsinstead of adding aggregate session rows toLoadedEntry, which would inflate date totals and double-count message usage. Preserve legacy session behavior and parent/session identifiers where available. -
Add regression coverage. Extend parser tests for both payload shapes and loader fixture tests for v1-only, v2-only, mixed databases, missing optional tables, assistant filtering, date bounds, malformed rows, and duplicate IDs across legacy/v2/file sources. Add session-report assertions plus focused JSON/table snapshot coverage for totals and model/token/cost fields. Validate with
cargo test -p ccusage opencodeand the repository Rust formatting/check recipes. -
Update source documentation if the confirmed schema changes the user-visible data-source description. At minimum review
rust/adapters/opencode/src/README.mdanddocs/guide/opencode/index.md, which currently describe the legacy JSON layout and do not explain the v2 SQLite tables. No CLI option or schema artifact change is expected.
No implementation changes have been made; the worktree remains clean.
Task list (3/3 completed)
- Read repository guidance and issue context
- Trace OpenCode v1 and v2 storage/reporting code and tests
- Assess actionability and publish an implementation plan
|⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to@v0or keep the SHA fresh with Dependabot | Implement plan ➔ | View workflow run | via Pullfrog | UsingGPT Luna(free via Pullfrog for OSS) | 𝕏-
github-actions commented
on Aug 26, 2026 on Aug 26, 2026 – with GitHub ActionsContributorMore actionsThis issue was auto-closed. Issues from new contributors are auto-closed by default.
Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.
Keep the issue short, concrete, and written in your own voice.
If a maintainer replies
lgtmi, your future issues will stay open. If a maintainer replieslgtm, your future issues and PRs will stay open.See CONTRIBUTING.md.
@ryoppippi can I work on this?
@pullfrog Triage this issue using the repository standing issue-triage instructions. Inspect the full issue body, comments, current main branch, and related issues or pull requests. Choose exactly one priority label. If the issue is clearly unresolved and is priority:critical or priority:high with safe and well-scoped requirements, implement it and open a focused pull request. Otherwise, only triage it. Keep the explanation short and use simple English.
Reacted by pullfrog- addedpriority:mediumA normal bug or meaningful improvement.A normal bug or meaningful improvement.
on Aug 27, 2026 pullfrog commented
on Aug 27, 2026 pullfrogboton Aug 27, 2026 – with PullfrogContributorMore actionsTriage:
priority:medium.This is a real, unresolved bug. The current adapter reads legacy
messagerows, so OpenCode v2 usage can be missed. I am not opening a PR because the exact v2 schema and the required session-report behavior still need confirmation. A representative database or confirmed table/column details would make implementation safer. |⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to@v0or keep the SHA fresh with Dependabot | View workflow run | via Pullfrog | UsingGPT Luna(free via Pullfrog for OSS) | 𝕏github-actions commented
on Aug 28, 2026 on Aug 28, 2026 – with GitHub ActionsContributorMore actionsPullfrog triage: priority:medium
A maintainer explicitly requested an implementation attempt. Clear, repository-scoped OpenCode compatibility bug with concrete affected tables, deduplication requirements, and implementation intent. The exact beta schema and session-report behavior still need maintainer confirmation, so no PR should be created yet.
Decision: kept open; Pullfrog will attempt a focused implementation PR.
- addedtriage:resolvedResolved by a later change or current implementation.Resolved by a later change or current implementation.
on Aug 31, 2026 Historical audit: this discussion was auto-closed by the legacy contributor gate. That closure did not assess technical importance.
Audit result: resolved. A later merged change or the current
mainimplementation covers this request. This item is kept for history and does not need to be reopened.

What do you want to change?
Extend the OpenCode adapter to also read the new tables that OpenCode v2 (npm dist-tag
beta) writes, while keeping the legacy tables working for v1 installs, without double-counting messages that exist in both.OpenCode v1 stores its data in
~/.local/share/opencode/opencode.db, in thesessionandmessagetables.OpenCode v2 stores its data in the same database, however, in two new tables:
session_v2for sessions, withcostandtokens_input/output/cache_read/cache_writedirectly on the rowsession_messagefor messages, withid/session_idin columns and payload JSON indata, but onlytype='assistant'rows carrytokensandcost.Why?
ccusage cannot detect sessions created by OpenCode v2 beta. For sessions initiated in v1 and later continued in v2, ccusage sees only the messages written in v1, but every new message written from v2 stays invisible.
Since v2 is the beta channel on its way to becoming the default, this will eventually affect every OpenCode user on ccusage.
How? (optional)
session_v2,session_message) exist in the database. If not, nothing needs to change.session_messagerows withtype='assistant'for usage, andsession_v2forccusage opencode session.OpenCodeMessageinparser.rsto accept the v2 payload shape.Notes:
I'm happy to implement this myself.