Skip to content

feat(usage): break down usage by project - #9015

Draft
saphid wants to merge 3 commits into
pingdotgg:mainfrom
saphid:saphid/usage-project-upstream
Draft

feat(usage): break down usage by project#9015
saphid wants to merge 3 commits into
pingdotgg:mainfrom
saphid:saphid/usage-project-upstream

Conversation

@saphid

@saphid saphid commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Usage totals show which provider and model spent the money, but not which project. When several workspaces share one environment, that's the question users actually have.

Depends on #9014. This branch contains #9014's commits (cf2474d602, 0f7cd7f00d) followed by this PR's single commit 80985a75ad. Review only the project increment. Merge #9014 first; the PR stays in draft until then.

How it works

  • Server. Claude and Codex transcripts already record each session's working directory. The scanner now keeps that cwd (Codex follows turn_context changes). At scan time it resolves the cwd against the environment's project list (ProjectionProjectRepository.listAll, which includes soft-deleted projects so their past spend stays attributed). The deepest workspace root wins. Each bucket is tagged project, outside, or unknown. Grok logs carry no folder, and a project-list read failure also yields unknown, never a misleading "outside".
  • Contract. UsageBucket gains optional project, projectId, and projectAttribution; USAGE_CONTRACT_VERSION goes 5 → 6. Older servers keep merging, and their buckets count as unknown attribution. The scan cache goes v3 → v4 so cached records carry their cwd; this costs one full rescan after upgrade.
  • Shared merge. mergeUsage rolls buckets up into projects, keyed per environment, so equal ids or titles on two servers stay separate. An optional projectFilter narrows every other figure. Session counts can't be split by project, so they're hidden while a filter is active. Fully unpriced projects reuse main's unpriced treatment (fix(usage): flag unpriced model activity instead of showing $0.00 #11021) instead of showing $0.00.
  • Web. The breakdown gains a Project view, ranked by the selected metric. A project picker (All projects / each project / Outside projects) narrows the page; "All projects" clears it.
  • Mobile. Not in this PR. Mobile totals still merge correctly with the v6 contract; the project view can follow separately.

Screenshots

Isolated dev server, synthetic Claude transcripts for two projects (Atlas, Beacon) plus work in an unregistered folder, 30-day window.

Before (#9014 head 0f7cd7f00d): model and day breakdowns only.

Before: Usage page with Model and Day breakdowns

After (80985a75ad): Project breakdown. The rows add up to the $36.04 headline, and unregistered work appears as "Outside projects".

After: Project breakdown with Beacon, Atlas and Outside projects

After, Atlas selected in the picker: headline, chart, totals and table all narrow to $12.23.

After: Atlas filter narrows the whole page

Verification

  • vp test run apps/server/src/usage/ apps/web/src/components/usage/ apps/web/src/state/usage.test.tsx packages/shared/src/usageMerge.test.ts packages/shared/src/usageFormat.test.ts: 17 files, 210 tests pass. New coverage: service-level attribution (project vs outside), unknown attribution on repository failure, the resolver's nesting/boundary/deleted-project rules, scan-cache cwd round trip, Codex cwd changes, and merge filtering/namespacing/unpriced projects.
  • Typecheck passes for t3, @t3tools/web, @t3tools/shared, @t3tools/contracts, @t3tools/mobile. vp lint and vp fmt pass on the touched files.
  • A cross-provider (Codex) review was skipped because Codex weekly quota was at 7%.

Rework note

This head replaces the earlier cumulative stack. The refresh-token cache bypass, retained refresh statuses, refresh error toasts/alerts, the segmented Input variant, and the three unshipped contract bumps (v6–v8) are gone. They weren't needed for project attribution; any that are still wanted belong in their own PRs.

Coordination trace: T3 thread 7227674d-e4cd-4b7a-b0d4-08e32d2e1e0e

Reworked with Claude Opus 5 in the Claude Code harness (via T3 Code).

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 1, 2026
Comment thread apps/web/src/components/usage/UsagePage.tsx Outdated
Comment thread apps/server/src/usage/usageScanCache.ts Outdated
Comment thread packages/shared/src/usageMerge.ts Outdated
Comment thread apps/web/src/components/usage/UsagePage.tsx Outdated
@saphid
saphid force-pushed the saphid/usage-project-upstream branch from 684786f to 117bf75 Compare September 1, 2026 11:12
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Sep 1, 2026
Comment thread apps/server/src/usage/usageTranscripts.ts
Comment thread apps/web/src/components/usage/UsageProviderChart.tsx Outdated
Comment thread docs/user/usage.md Outdated
Comment thread apps/server/src/usage/UsageService.ts
@saphid
saphid force-pushed the saphid/usage-project-upstream branch from 117bf75 to 867cc41 Compare September 1, 2026 11:27
Comment thread apps/web/src/components/usage/UsagePage.tsx Outdated
@saphid
saphid force-pushed the saphid/usage-project-upstream branch 2 times, most recently from a59e015 to 6ca946c Compare September 1, 2026 11:56
Comment thread apps/web/src/components/usage/UsagePage.tsx
@saphid
saphid force-pushed the saphid/usage-project-upstream branch 2 times, most recently from 79c9fc2 to eb2a16a Compare September 1, 2026 12:29
Comment thread apps/server/src/usage/usageTranscripts.ts
Comment thread apps/web/src/components/usage/UsagePage.tsx
@saphid
saphid force-pushed the saphid/usage-project-upstream branch from eb2a16a to 7178d4d Compare September 1, 2026 12:46
Comment thread packages/shared/src/usageMerge.ts Outdated
@saphid
saphid force-pushed the saphid/usage-project-upstream branch 2 times, most recently from 82b25d2 to dce69bb Compare September 1, 2026 13:13
Comment thread apps/web/src/components/usage/UsagePage.tsx Outdated
@saphid
saphid force-pushed the saphid/usage-project-upstream branch from dce69bb to 13d4b24 Compare September 1, 2026 13:23
Comment thread apps/web/src/components/usage/UsagePage.tsx Outdated
@saphid
saphid force-pushed the saphid/usage-project-upstream branch from 13d4b24 to da35181 Compare September 1, 2026 13:31
Comment thread apps/web/src/components/usage/UsagePage.tsx
@github-actions github-actions Bot removed the size:XL 500-999 changed lines (additions + deletions). label Sep 5, 2026
@github-actions github-actions Bot added the size:XXL 1,000+ changed lines (additions + deletions). label Sep 5, 2026
Comment thread apps/mobile/src/features/usage/UsageRouteScreen.tsx Outdated
Comment thread apps/mobile/src/features/usage/UsageRouteScreen.tsx Outdated
Comment thread apps/server/src/usage/UsageService.ts Outdated
Comment thread packages/contracts/src/usage.ts Outdated
Comment thread apps/web/src/state/usage.ts Outdated
saphid added a commit to saphid/t3code that referenced this pull request Sep 11, 2026
The Usage page can drill project, provider and model totals down to the
threads and subagents that produced them. The server maps provider
sessions and worktrees to T3 threads with bounded rows, and the web and
mobile clients filter by environment, project and provider ownership.

Includes the stacked usage time-range (pingdotgg#9014) and project-breakdown
(pingdotgg#9015) changes this feature builds on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
saphid added a commit to saphid/t3code that referenced this pull request Sep 11, 2026
Carries the cumulative content of pingdotgg#9014, pingdotgg#9015 and pingdotgg#9016, rebased onto
current main. This PR's own change is the following commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
saphid added a commit to saphid/t3code that referenced this pull request Sep 11, 2026
Price cache creation as its own estimated component in usage summaries,
the model/project/thread breakdowns and the daily thread chart, keeping
unknown cache-write cost unavailable rather than zero.

Carries the stacked usage work from pingdotgg#9014, pingdotgg#9015, pingdotgg#9016 and pingdotgg#9017, rebased
onto main and reconciled with upstream's per-model unpriced flag (pingdotgg#11021).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
saphid and others added 3 commits September 11, 2026 17:12
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Usage totals now split by the T3 project whose workspace root contains each
session's working directory. The server records the cwd from Claude and Codex
transcripts, resolves it against the project list at scan time, and tags each
bucket as project, outside, or unknown. The web Usage page gains a Project
breakdown and a project picker that narrows every figure on the page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@saphid
saphid force-pushed the saphid/usage-project-upstream branch from a3eb8de to 80985a7 Compare September 11, 2026 07:22
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant