Skip to content

Commit 2e271e8

Browse files
ryoppippiigorovh
andcommitted
docs(opencode): state the resumed-session rule and its residual undercount
Refs #2004 Co-authored-by: igorovh <[email protected]>
1 parent 2348866 commit 2e271e8

2 files changed

Lines changed: 2 additions & 2 deletions

File tree

‎docs/guide/opencode/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ The `claude-agent` provider runs Claude Code under the hood, so each turn is als
7777
ccusage matches OpenCode rows to Claude usage by Claude Code session, not by individual turn:
7878

7979
- **Daily, weekly, and monthly reports** skip an OpenCode `claude-agent` row when the Claude source counted usage from the same Claude Code session on the row's date, in the Claude source's timezone. Rows still count when the Claude Code log is gone, holds no usage for that day, holds only subagent usage, or falls outside the Claude source's date range.
80-
- **Session reports** skip every OpenCode `claude-agent` row whose Claude Code session the report includes, because the Claude session row holds all of that session's usage, including days outside the Claude source's date range. For a resumed or forked session, the row is skipped only when the session it continues is included too, since its repeated turns are counted there.
80+
- **Session reports** skip every OpenCode `claude-agent` row whose Claude Code session the report includes, because the Claude session row holds all of that session's usage, including days outside the Claude source's date range. A resumed or forked Claude Code session repeats earlier turns, which ccusage counts once under one of the sessions. A session with turns of its own in the report is always skipped. A session whose turns all live under other sessions is skipped only when every one of those is included. So when the report includes a fork but not the session it continues, a repeated turn that OpenCode logged under the fork is left out.
8181

8282
Because OpenCode dates a turn by when it started and Claude Code dates each model call, a turn that runs across midnight can be off in the daily family. It is counted twice when Claude has no usage from that session on the day the turn started. With `--until` on that day, the calls Claude logs after midnight are left out, even though OpenCode dates the whole turn on the earlier day. `ccusage opencode` always shows every `claude-agent` row.
8383

‎rust/adapters/opencode/src/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ SQLite databases are the primary source. Legacy JSON messages under `storage/mes
1616

1717
OpenCode v2 forks copy the parent's `session_message` rows with new ids but the same `seq`. When `session_v2.fork_session_id` and `fork_boundary` resolve against the parent's rows, fork rows at or below the last copied `seq` (the boundary for `through`, the parent's last row before it for `before`) are skipped as inherited history. The fork's `session_v2` counters start at zero and hold only fork-local usage, so they remain a valid session fallback. Unresolvable boundaries and pre-`seq` schemas keep every row.
1818

19-
The Claude Agent provider (`claude-agent`) runs Claude Code, which also writes its own transcript. Its v2 rows record that Claude Code session as `content[].native.sessionID`, which `load_entries_with_native_sessions` returns with each entry. Unified daily-family reports drop a row when the Claude source counted main-thread usage of that session on the row's date, in the Claude source's timezone and date range; session reports drop it when the report includes that Claude session, whose row holds all of its usage. When Claude deduplicated a resumed or forked session's copied turns into another session, the row's session counts as included only if every session holding its usage is included, so its own turns are never dropped uncounted. The usage is then priced by the resolved model ID rather than the `opus`/`sonnet` alias OpenCode stores. The match is per session or session day, not per turn: `native.messageID` is the transcript line `uuid`, and one OpenCode row sums several API calls, so rows do not map one-to-one to Claude entries. This relies on the transcript holding every main-thread turn OpenCode records for that session; it also holds turns OpenCode drops, such as interrupted steps saved with `tokens: null`. A row is dated by its turn's start while Claude dates each call, so in daily-family reports a turn that crosses midnight in the Claude source's timezone is counted by both sources when Claude has no usage of that session on the earlier day, and with `--until` on that day the calls Claude logs after midnight are left out although OpenCode dates the whole turn on the earlier day. Only v2 `session_message` rows can carry the link: OpenCode added the provider after moving to SQLite v2, so legacy JSON messages and the v1 `message` table hold no `claude-agent` rows. `ccusage opencode` keeps every row.
19+
The Claude Agent provider (`claude-agent`) runs Claude Code, which also writes its own transcript. Its v2 rows record that Claude Code session as `content[].native.sessionID`, which `load_entries_with_native_sessions` returns with each entry. Unified daily-family reports drop a row when the Claude source counted main-thread usage of that session on the row's date, in the Claude source's timezone and date range; session reports drop it when the report includes that Claude session, whose row holds all of its usage. A resumed or forked session repeats earlier turns, and Claude's dedup keeps each under one session, often the parent, since files are read in path order. A session with its own surviving main-thread usage counts as included exactly when the report includes it. A session whose usage all survives under other sessions counts as included only when every one of those is included. The residual error is an undercount: when a fork is reported without its parent, the fork's rows for repeated turns are dropped, though Claude counts those turns under the parent. Leaving the fork uncovered instead would double count its own turns, which are usually most of its rows, because OpenCode excludes its own fork copies. The usage is then priced by the resolved model ID rather than the `opus`/`sonnet` alias OpenCode stores. The match is per session or session day, not per turn: `native.messageID` is the transcript line `uuid`, and one OpenCode row sums several API calls, so rows do not map one-to-one to Claude entries. This relies on the transcript holding every main-thread turn OpenCode records for that session; it also holds turns OpenCode drops, such as interrupted steps saved with `tokens: null`. A row is dated by its turn's start while Claude dates each call, so in daily-family reports a turn that crosses midnight in the Claude source's timezone is counted by both sources when Claude has no usage of that session on the earlier day, and with `--until` on that day the calls Claude logs after midnight are left out although OpenCode dates the whole turn on the earlier day. Only v2 `session_message` rows can carry the link: OpenCode added the provider after moving to SQLite v2, so legacy JSON messages and the v1 `message` table hold no `claude-agent` rows. `ccusage opencode` keeps every row.
2020

2121
Token mapping:
2222

0 commit comments

Comments
 (0)