Skip to content

fix(opencode): read OpenCode v2 usage from session_v2/session_message tables #1644

Description

@amirh-amini

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 the session and message tables.

OpenCode v2 stores its data in the same database, however, in two new tables:

  • session_v2 for sessions, with cost and tokens_input/output/cache_read/cache_write directly on the row

  • session_message for messages, with id/session_id in columns and payload JSON in data, but only type='assistant' rows carry tokens and cost.

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)

  • Check whether the v2 tables (session_v2, session_message) exist in the database. If not, nothing needs to change.
  • If they exist, read session_message rows with type='assistant' for usage, and session_v2 for ccusage opencode session.
  • Extend OpenCodeMessage in parser.rs to accept the v2 payload shape.
  • Union both sources and dedup by message id.

Notes:

  • Log a debug-level count when v2 rows exist but produce no entry, in case the beta changes shape.

I'm happy to implement this myself.

Activity

  1. pullfrog commented on Aug 26, 2026

    @pullfrog
    Contributor

    Assessment

    This issue is actionable. The current OpenCode adapter only queries the legacy message table in rust/adapters/opencode/src/loader.rs and parses the v1 top-level payload fields in rust/adapters/opencode/src/parser.rs; it has no path for session_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 v2 session table alongside session_message and has no literal session_v2 table. The implementation should detect the actual tables/columns rather than assuming one name, while retaining legacy session/message compatibility.

    Proposed Plan

    1. 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.

    2. Add v2 database loading in loader.rs. Keep the legacy message query, add a session_message query restricted to type = 'assistant', and pass the row id and session_id separately from the JSON payload. Reuse the existing date-window pushdown plus authoritative payload filtering, with the v2 time_created/data.time.created shape handled explicitly. Preserve the existing JSON-file fallback and source ordering.

    3. Normalize both payload versions in parser.rs. Extend the source-local types to accept v1 fields and the v2 nested model.id/model.providerID shape. 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 existing extra_total_tokens convention rather than silently losing or double-counting it.

    4. Integrate v2 session data without polluting other reports. Use session_message entries for daily, weekly, monthly, and ordinary session aggregation. If the v2 session table is required for ccusage opencode session metadata or aggregate-only sessions, carry that information through a session-specific metadata/aggregate path in report.rs instead of adding aggregate session rows to LoadedEntry, which would inflate date totals and double-count message usage. Preserve legacy session behavior and parent/session identifiers where available.

    5. 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 opencode and the repository Rust formatting/check recipes.

    6. Update source documentation if the confirmed schema changes the user-visible data-source description. At minimum review rust/adapters/opencode/src/README.md and docs/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

    Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Implement plan ➔ | View workflow run | via Pullfrog | Using GPT Luna (free via Pullfrog for OSS) | 𝕏

  2. github-actions commented on Aug 26, 2026

    @github-actions
    Contributor

    This 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 replies lgtm, your future issues and PRs will stay open.

    See CONTRIBUTING.md.

  3. amirh-amini commented on Aug 27, 2026

    @amirh-amini
    ContributorAuthor

    @ryoppippi can I work on this?

  4. ryoppippi commented on Aug 27, 2026

    @ryoppippi
    Member

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

  5. pullfrog commented on Aug 27, 2026

    @pullfrog
    Contributor

    Triage: priority:medium.

    This is a real, unresolved bug. The current adapter reads legacy message rows, 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.

    Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | via Pullfrog | Using GPT Luna (free via Pullfrog for OSS) | 𝕏

  6. github-actions commented on Aug 28, 2026

    @github-actions
    Contributor

    Pullfrog 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.

  7. ryoppippi commented on Aug 31, 2026

    @ryoppippi
    Member

    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 main implementation covers this request. This item is kept for history and does not need to be reopened.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority:mediumA normal bug or meaningful improvement.triage:resolvedResolved by a later change or current implementation.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions