Skip to content

Add Pi token usage provider - #3246

Open
Yuxin-Qiao wants to merge 34 commits into
steipete:mainfrom
Yuxin-Qiao:feat/pi-provider-tokscale
Open

Add Pi token usage provider#3246
Yuxin-Qiao wants to merge 34 commits into
steipete:mainfrom
Yuxin-Qiao:feat/pi-provider-tokscale

Conversation

@Yuxin-Qiao

@Yuxin-Qiao Yuxin-Qiao commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Add Pi as an opt-in local-history provider with its own menu, dashboard source, icon, widget choice, and documentation. Thanks @Yuxin-Qiao for the original implementation; the maintainer follow-up repairs the shared accounting and filesystem boundaries on this same PR.

Pi combines supported Anthropic and OpenAI Codex Pi/OMP session usage. Standalone Claude and unscoped Codex keep their existing inclusive reports. Combined Usage & Spend and Overview views instead select retained native-only values when a visible Pi source owns the same history, so every contribution is counted once. Native account-scoped Codex remains Pi-free. Pi is a local source, not an extra subscription.

The live-session and historical readers now share Pi root selection. Historical caches and publications carry root identity and completeness; explicit missing or invalid roots fail closed, absent default history is unavailable, and malformed/truncated/unsupported records cannot become falsely complete history. Project/global settings, custom agent directories, OMP profiles and eligible XDG roots have isolated regression coverage. A valid custom Pi settings directory does not require a companion OMP installation.

The icon uses a font-free transparent glyph so macOS template rendering retains the Pi mark. Documentation explains the assistant-message list-price estimator, unsupported billing components, standalone CLI behavior, and widget coverage limitations.

Maintainer verification

  • Candidate commit: 6f5e173d9020e6f49f73e34de615d5f4468a386a. The integration commit fa1ab1d9fe9427df40977ab1e6c872773468bd92 preserves the original contributor commit as a merge parent. Two small follow-ups fix Linux hashing imports and repeated cache persistence.
  • Integration-focused run on fa1ab1d9fe9 with the repository's canonical --no-parallel setting: 224 tests in 20 suites, plus four portable tests executed on macOS, passed. The production-view render test also passed. Coverage includes accounting/visibility, native accounts, root/cache contracts, backend/day-specific partial evidence, malformed records and boolean counters/timestamps, publication ownership, cached startup, and provider architecture.
  • Final make check: passed, zero violations across 2,045 Swift files.
  • Full make test on 6f5e173d902: passed all 963 selections across 81 groups in 1,976.1 seconds. Eighty groups passed initially; one cache-test group reached the normal 180-second limit and recovered when all twelve selections passed individually through the existing runner. There were no full-group retries, source/assertion changes, or deadline increases; non-timeout retries stayed disabled. Earlier interrupted candidate runs are not full-pass claims.
  • Independent source review: clean, no actionable P0–P2 findings after repairing the five accepted findings at their shared owners. The generated social-card PNG was visually reviewed separately from the complete source/test/documentation/SVG/HTML review.
  • The portability follow-up passed 69 focused tests and four portable tests on macOS, final make check, and a clean independent review of the four-line diff.
  • The first hosted CI run exposed an unconditional CryptoKit import on Linux. The existing Swift Crypto dependency is now selected there, matching the repository's established pattern. Replacement CI run 33123394523 builds on Linux, including a successful musl job, but its x64/ARM test jobs exposed a saved-cache reload failure. The x64 run executed 455 tests in 63 suites with four failed cache-coverage assertions; the corresponding in-memory parser assertions passed. Remaining obsolete jobs were canceled.
  • The cache follow-up replaces the manual file swap with one atomic write to the final cache path. It passed 61 focused tests and five portable tests on macOS, make check, explicit portable format/lint, and a clean independent review. The new regression reads the actual JSON after both first and replacement saves, checks changed values, and rejects stray temporary files. These macOS results are not a native Linux pass.
  • Final CI run 33124888635: all eight jobs passed on 6f5e173d9020e6f49f73e34de615d5f4468a386a, including native Linux x64/ARM64 builds, tests and CLI smoke checks, musl build, both macOS test shards, lint, and the aggregate gate. The cache repair is now verified on native Linux.

Tests use synthetic history, isolated stores, and Keychain/file-access safeguards. The rendered light/dark menus, dashboard, Overview and widget use production views and the same synthetic accounting fixture: standalone Claude $12/120K tokens, Pi $5/50K, combined $15/150K with native Claude $10/100K. Widget publication is also tested through the in-memory save boundary.

One earlier broad focused run used parallel execution and hit the dashboard test's 30-second wait while a main-actor architecture audit occupied roughly 32 seconds. With the repository's existing serial test setting, that same publication test passed in 1.8 seconds and the entire focused set passed. No deadline, assertion, or source change was made to hide the timeout.

These are offscreen render and publication proofs, not installed-app or installed WidgetKit proofs. All automated gates are green, but packaged runtime validation remains a maintainer-owned hold and this PR is not yet merged. No contributor change request is needed. No live account or credential probe, release, or installed-widget claim is included.

Focused verification command
env -u CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS \
  CODEXBAR_SUPPRESS_TEST_KEYCHAIN_ACCESS=1 \
  CODEXBAR_TEST_CODEX_FILE_ISOLATION=1 \
  CODEXBAR_TEST_RETRY_NON_TIMEOUT_FAILURES=0 LIVE_GEMINI_FETCH=0 \
  swift test --no-parallel --filter 'PiRecordValidationTests|PiPartitionCoverageTests|PiRootSelectionContractTests|PiHistoryCoverageTests|PiHistoryScopeLinuxTests|PiProviderTests|PiSessionCostScannerTests|PiSessionCostCompatibilityTests|PiSpendAccountingTests|PiPublicationTests|PiNativeAccountingTests|CostUsageFetcherTests|CostUsageFetcherCacheSnapshotTests|CostUsageFetcherUnknownModelPricingTests|OverviewSpendSummaryTests|SpendDashboardModelTests|SpendDashboardPublicationTests|ProviderArchitectureGatekeeperTests|ProviderIconResourcesTests|UsageStoreCachedTokenHydrationTests|PiFamilySessionTests.*custom session directories|MenuLayoutScreenshotRenderTests.test_renderPiAccountingProof'

The render test additionally used an owned temporary output directory through CODEXBAR_PI_PROOF_DIR.

Visual proof

All images contain synthetic data rendered through production views on integration commit fa1ab1d9fe9. Its final rerender is byte-identical to the inspected attachments. The subsequent Linux import and cache-write corrections change no rendering code or synthetic accounting values.

Dashboard before and after icon/source-label cleanup

Before: the first integrated render already includes the accounting repair, but incorrectly calls Pi a subscription and loses the template glyph. This is not the original contributor commit or an installed-app screenshot.

Dashboard before maintainer icon and source-label cleanup

After: the same synthetic amounts, with correct source labels and a visible Pi template glyph.

Dashboard after maintainer icon and source-label cleanup

Combined Overview and Pi cost-only widget in dark appearance

Combined Overview with one subscription and one local source

Pi cost-only production widget view with synthetic data

@clawsweeper

clawsweeper Bot commented Aug 27, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3732c325e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

let piDaily: CostUsageDailyReport = try await CostUsageScanExecutor.run { checkCancellation in
try PiSessionCostScanner.loadDailyReportCancellable(
// Provider-specific by design: this call reads Pi's local aggregate session ledger.
provider: .pi,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Deduplicate Pi spend from Claude totals

When Pi and Claude are both enabled with cost usage, this branch publishes Claude-priced Pi rows under Pi, while the existing loadLocalTokenScanResult path still merges those same rows into Claude at CostUsageFetcher.swift:726-740; SpendDashboardModel then sums provider totals at line 522, so Claude-backed Pi tokens and spend are counted twice. Assign these rows to only one dashboard source or explicitly deduplicate the overlap.

Useful? React with 👍 / 👎.


// Provider-specific by design: Pi has an independent aggregate token-cost history over its local JSONL logs.
if provider == .pi {
var piOptionsOnly = overridePiScannerOptions ?? PiSessionCostScanner.Options()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve configured Pi session roots

For users who relocate sessions through PI_CODING_AGENT_SESSION_DIR, PI_CODING_AGENT_DIR, Pi's sessionDir setting, or OMP profiles, constructing default options here ignores the supplied environment and scans only ~/.pi/agent/sessions and ~/.omp/agent/sessions. The existing root logic in PiFamilySessionScanner.swift:631-698 already recognizes these supported layouts, but the new token provider will report no sessions for them unless equivalent roots are passed into PiSessionCostScanner.Options.

Useful? React with 👍 / 👎.

@steipete steipete left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainer update

I have repaired items 1–3 directly on this PR, preserving @Yuxin-Qiao's contributor credit. The integration is in fa1ab1d9fe9427df40977ab1e6c872773468bd92, with Linux portability and cache-persistence follow-ups through 6f5e173d9020e6f49f73e34de615d5f4468a386a. Regression coverage now exercises disjoint combined totals, native account isolation, selected filesystem scope, cache identity, and incomplete history. Independent review is clean, and both native Linux build/test/smoke jobs pass.

Final verification and the remaining installed-app/widget proof are maintainer-owned. No further contributor changes are requested. The current commands, results, CI links, and proof limitations are recorded in the PR description; this review remains blocking until the remaining verification is complete.

Original source review — historical findings, now repaired

Thanks @Yuxin-Qiao. Reusing the existing scanner and provider descriptors is a sensible starting point, but this needs changes before merge. I checked c3732c3 against main b4694bd and followed the actual shared-spend callers.

  1. Prevent overlapping Claude/Pi totals. The new Pi report merges the Anthropic and OpenAI Codex Pi ledgers, while CostUsageFetcher still merges Anthropic Pi rows into Claude by default. UsageStore.loadTokenUsageSnapshot leaves that default enabled, and the shared spend model sums the distinct Claude and Pi source inputs. With both enabled and visible, the same Anthropic Pi event contributes twice. Native account-scoped Codex dashboard scans explicitly exclude Pi, so this is not a claim that every Codex view doubles usage. Define whether Pi is a non-additive view of the existing ledger or a disjoint additive source, and prove exactly-once combined totals with Pi plus Claude, including non-Pi Claude usage and source visibility changes. Hiding all Claude usage or subtracting aggregate totals would lose the required attribution.

  2. Honor the selected filesystem scope. The new fetcher branch does not pass its supplied environment into root resolution; default scanner options read the ambient user's .pi/.omp directories. Agent Sessions already recognizes configured Pi roots and supplied HOME, so relocated history can appear there but be absent from the new provider—or the provider can inspect the wrong default root. Resolve an explicit supported root context and tie cache identity to it. Cover configured versus ambient roots, supplied HOME and OMP profile boundaries using isolated fixtures; do not broaden scanning to every profile as a fallback.

  3. Do not claim established history without coverage evidence. The branch unconditionally sets historyCoverageIsEstablished: true, but the reused scanner returns empty discovery for some missing/unreadable roots and skips malformed/truncated records/read failures. Its report currently covers only the two recognized backends. Carry scan-completeness evidence into the snapshot and distinguish confirmed empty from unavailable/partial history. Add negative fixtures, not just an assertion that the flag is true. Keep this at the scanner/report boundary; it should not become another provider-specific publication workaround.

The submitted tests exercise the isolated aggregate and registration, not these combined-source and failure cases. This review is source-based; I have not run this PR's tests or independently verified its reported CI/runtime results. Once the accounting contract is settled and those regressions are covered, the cost-only menu/widget behavior still needs packaged runtime proof. Keeping the provider opt-in does not resolve the overlap or scope issues.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P1 Urgent regression or broken agent/channel workflow affecting real users now. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 27, 2026
@clawsweeper

clawsweeper Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed September 10, 2026, 5:31 PM ET / 21:31 UTC (Revision 42).

ClawSweeper review

What this changes

Adds an opt-in Pi local-history provider across the app, CLI, dashboard, and widget, with shared session discovery, cost accounting, cache validation, and regression tests.

Merge readiness

Blocked before merge - 8 items remain

This remains a distinct, maintainer-engaged addition absent from main and v0.58.0. The latest follow-up resolves several prior findings, but three concrete defects and incomplete runtime proof prevent a clean review.

Priority: P2
Reviewed head: c8fb54efb551b27cdf92db2a434f716967359643

Review scores

Measure Result What it means
Overall readiness 🦪 silver shellfish (2/6) Substantial implementation and regression coverage remain useful, but concrete defects and historical-only visual proof limit readiness.
Proof confidence 🦪 silver shellfish (2/6) Needs stronger real behavior proof before merge: The four inspected historical screenshots demonstrate synthetic presentation, but not this head's process discovery, persisted-cache reload, and publication behavior in a real setup. The captured body explicitly retains a maintainer-owned packaged-runtime hold; that owner should supply redacted runtime and upgrade evidence. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🦐 gold shrimp (3/6) 3 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs stronger real behavior proof before merge: The four inspected historical screenshots demonstrate synthetic presentation, but not this head's process discovery, persisted-cache reload, and publication behavior in a real setup. The captured body explicitly retains a maintainer-owned packaged-runtime hold; that owner should supply redacted runtime and upgrade evidence. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 9 items Repository policy: Read the complete root AGENTS.md. No nested AGENTS.md files or maintainer-notes directory were found. Applied provider isolation, focused validation, and Keychain safeguards; no builds or tests were executed under the read-only review contract.
Pinned introduction and review continuity: GitHub's comparison of the previous reviewed head with the current head confirms retained-root scope lookup, settings provenance keys, optional CWD handling for absolute session selectors, and hidden-source accounting changes. The corresponding source and focused regressions were inspected. Local git comparisons encountered unavailable promisor objects and HTTP 403; GitHub read-only comparisons supplied the relevant patches.
Still distinct from main: The provider enumeration on pinned main does not register Pi. Existing Pi/OMP contributions to Claude and Codex reports do not provide the proposed independently selectable Pi surface.
Findings 3 actionable findings [P2] Discard retained settings roots when the setting is removed
[P2] Preserve CWD-independent OMP profile selectors
[P2] Classify Pi separately from subscriptions
Security None None.

How this fits together

CodexBar reads local Pi and OMP session logs to estimate token usage and spend. Shared accounting feeds standalone provider reports and combined dashboards, where overlapping contributions must be counted once.

flowchart TD
  A[Settings and live processes] --> B[Resolve session directories]
  B --> C[Read Pi and OMP logs]
  C --> D[Validate and cache usage]
  D --> E[Separate native and Pi totals]
  E --> F[Standalone provider reports]
  E --> G[Combined dashboard and widget]
Loading

Before merge

  • Add real behavior proof - Needs stronger real behavior proof before merge: The four inspected historical screenshots demonstrate synthetic presentation, but not this head's process discovery, persisted-cache reload, and publication behavior in a real setup. The captured body explicitly retains a maintainer-owned packaged-runtime hold; that owner should supply redacted runtime and upgrade evidence. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Discard retained settings roots when the setting is removed (P2) - After a live Pi process caches a custom sessionDir, removing that property makes the resolver return a default root without the settings retention key. This check therefore keeps the old root alongside the default, continuing to include obsolete spend or leaving history incomplete if the old directory disappears. Track a settings selector that was inspected and cleared, so removal replaces its old root just as an A-to-B change does.
  • Preserve CWD-independent OMP profile selectors (P2) - A running omp --profile work process is discarded here when CWD lookup fails, even with an absolute HOME that lets the existing OMP resolver locate the profile. The downstream scan then loses the explicit selector and falls back to ambient discovery; a missing selected store can be treated as complete default history instead of unavailable. Retain resolvable profile contexts and allow them through the corresponding missing-CWD guard in the root resolver.
  • Classify Pi separately from subscriptions (P2) - The new Pi input uses the default native source kind, which publishCurrentState maps to .subscription. Overview therefore counts Claude plus Pi as two subscriptions, contrary to the intended local-history source behavior and the historical proof image. Add a local-source classification and update coverage counts accordingly. This was already visible at the previous reviewed head and was missed in the earlier review.
  • Resolve merge risk (P1) - Existing Claude and ambient Codex reports share the changed root and cache machinery, so incorrect scope transitions can alter their displayed totals even when Pi is not separately enabled.
  • Resolve merge risk (P1) - Fresh-install and upgrade behavior for cache version 9, retained roots, and existing cost preferences lacks current-candidate runtime evidence.
  • Resolve merge risk (P1) - The pinned GitHub context reports merge conflicts; no validated test merge is available.
  • Complete next step (P2) - Repair the three findings and resolve integration conflicts. The designated maintainer should add current-candidate runtime and fresh-install/upgrade evidence; screenshots or recordings are preferred for visible behavior, and terminal output or logs count for discovery and caching. Redact private paths, credentials, IP addresses, and other sensitive details. Update the PR body to trigger re-review; if needed, ask a maintainer to comment @clawsweeper re-review.

Findings

  • [P2] Discard retained settings roots when the setting is removed — Sources/CodexBarCore/PiSessionCostScanner.swift:501-507
  • [P2] Preserve CWD-independent OMP profile selectors — Sources/CodexBarCore/LocalAgentSessionScanner.swift:234-238
  • [P2] Classify Pi separately from subscriptions — Sources/CodexBar/SpendDashboardController.swift:341-345
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production and test delta Production +1,989/−307 lines; tests +2,070/−195 lines The stated discovery, accounting, and cache work explains the production growth, but extends the review boundary beyond registering one provider.

Merge-risk options

Maintainer options:

  1. Complete scope and upgrade validation (recommended)
    Repair selector retention and source classification, then verify existing Claude/Codex totals and preferences through fresh installation and upgrade before lifting the runtime hold.
  2. Keep the integration paused
    Retain the branch while its designated maintainer completes packaged-runtime validation and resolves integration conflicts.

Technical review

Best possible solution:

Preserve inclusive standalone reports while making Pi a correctly classified local source, with selector changes replacing obsolete roots and current-candidate upgrade proof confirming stable totals.

Do we have a high-confidence way to reproduce the issue?

Yes, source establishes focused triggers for the findings: remove a retained sessionDir setting, lose CWD lookup for an OMP profile process, or enable Pi in Overview. These paths were inspected, not executed.

Is this the best way to solve the issue?

The shared resolver and retained native projections are appropriate, but the implementation still mishandles selector removal and local-source classification; those repairs belong in the existing shared owners.

Full review comments:

  • [P2] Discard retained settings roots when the setting is removed — Sources/CodexBarCore/PiSessionCostScanner.swift:501-507
    After a live Pi process caches a custom sessionDir, removing that property makes the resolver return a default root without the settings retention key. This check therefore keeps the old root alongside the default, continuing to include obsolete spend or leaving history incomplete if the old directory disappears. Track a settings selector that was inspected and cleared, so removal replaces its old root just as an A-to-B change does.
    Confidence: 0.97
  • [P2] Preserve CWD-independent OMP profile selectors — Sources/CodexBarCore/LocalAgentSessionScanner.swift:234-238
    A running omp --profile work process is discarded here when CWD lookup fails, even with an absolute HOME that lets the existing OMP resolver locate the profile. The downstream scan then loses the explicit selector and falls back to ambient discovery; a missing selected store can be treated as complete default history instead of unavailable. Retain resolvable profile contexts and allow them through the corresponding missing-CWD guard in the root resolver.
    Confidence: 0.95
  • [P2] Classify Pi separately from subscriptions — Sources/CodexBar/SpendDashboardController.swift:341-345
    The new Pi input uses the default native source kind, which publishCurrentState maps to .subscription. Overview therefore counts Claude plus Pi as two subscriptions, contrary to the intended local-history source behavior and the historical proof image. Add a local-source classification and update coverage counts accordingly. This was already visible at the previous reviewed head and was missed in the earlier review.
    Confidence: 0.99
    Late finding: first raised on code an earlier review cycle already covered.

Overall correctness: patch is incorrect
Overall confidence: 0.95

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against c9f2eca8da03.

Labels

Label justifications:

  • P2: This is a useful provider addition with bounded accounting and discovery defects, without evidence of an urgent shipped outage.
  • merge-risk: 🚨 compatibility: The shared root-selection and persisted-cache changes affect existing Claude/Codex cost reports and require upgrade validation.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The four inspected historical screenshots demonstrate synthetic presentation, but not this head's process discovery, persisted-cache reload, and publication behavior in a real setup. The captured body explicitly retains a maintainer-owned packaged-runtime hold; that owner should supply redacted runtime and upgrade evidence. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The four inspected historical screenshots demonstrate synthetic presentation, but not this head's process discovery, persisted-cache reload, and publication behavior in a real setup. The captured body explicitly retains a maintainer-owned packaged-runtime hold; that owner should supply redacted runtime and upgrade evidence.

Evidence

What I checked:

  • Repository policy: Read the complete root AGENTS.md. No nested AGENTS.md files or maintainer-notes directory were found. Applied provider isolation, focused validation, and Keychain safeguards; no builds or tests were executed under the read-only review contract. (AGENTS.md:1, c8fb54efb551)
  • Pinned introduction and review continuity: GitHub's comparison of the previous reviewed head with the current head confirms retained-root scope lookup, settings provenance keys, optional CWD handling for absolute session selectors, and hidden-source accounting changes. The corresponding source and focused regressions were inspected. Local git comparisons encountered unavailable promisor objects and HTTP 403; GitHub read-only comparisons supplied the relevant patches. (c8fb54efb551)
  • Still distinct from main: The provider enumeration on pinned main does not register Pi. Existing Pi/OMP contributions to Claude and Codex reports do not provide the proposed independently selectable Pi surface. (Sources/CodexBarCore/Providers/Providers.swift:22, c9f2eca8da03)
  • Latest release check: The provider enumeration at the supplied v0.58.0 release commit also lacks Pi. No verified merged replacement was established. (Sources/CodexBarCore/Providers/Providers.swift, 88fa2f45fa1e)
  • Incomplete settings replacement: Retained roots are discarded only when a newly resolved root carries the same retention key. Removing sessionDir returns a default root without that key, allowing the old configured directory to remain in the scanned dataset. (Sources/CodexBarCore/PiSessionCostScanner.swift:504, c8fb54efb551)
  • OMP selector loss remains: Process discovery retains a missing-CWD context only for an absolute session-directory selector. The existing OMP resolver can resolve a named profile from an absolute HOME, so dropping that context loses the explicit selection and its required-root completeness semantics. This also matches the discussion at Add Pi token usage provider #3246 (comment). (Sources/CodexBarCore/LocalAgentSessionScanner.swift:234, c8fb54efb551)

Likely related people:

  • steipete: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • Yuxin-Qiao: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Repair settings removal, missing-CWD OMP profiles, and Pi subscription classification with focused regressions.
  • Provide current-candidate real-history, fresh-install, and upgrade evidence, and resolve the recorded packaged-runtime hold.
  • Resolve the reported conflicts and validate the resulting integration.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (41 earlier review cycles; latest 8 shown)
  • reviewed 2026-09-10T10:44:06.294Z sha cb57e8b :: needs real behavior proof before merge. :: [P1] Preserve inclusive standalone Claude and Codex totals | [P2] Invalidate cached parses for the stricter validation | [P2] Base CLI ownership on providers actually emitted | [P2] Restrict process discovery to Pi-consuming providers | [P2] Keep configured roots out of retained live provenance | [P2] Include Pi accounting mode in coordinated cost operations
  • reviewed 2026-09-10T12:17:05.762Z sha 0ffa963 :: needs real behavior proof before merge. :: [P1] Preserve inclusive standalone Claude and Codex totals | [P2] Invalidate cached parses for the stricter validation | [P2] Base CLI ownership on providers actually emitted | [P2] Restrict process discovery to Pi-consuming providers | [P2] Keep configured roots out of retained live provenance | [P2] Include Pi accounting mode in coordinated cost operations
  • reviewed 2026-09-10T13:24:05.012Z sha 0daeef7 :: needs real behavior proof before merge. :: [P1] Preserve inclusive standalone Claude and Codex totals | [P2] Invalidate cached parses for the stricter validation | [P2] Base CLI ownership on providers actually emitted | [P2] Restrict process discovery to Pi-consuming providers | [P2] Keep configured roots out of retained live provenance | [P2] Include Pi accounting mode in coordinated cost operations
  • reviewed 2026-09-10T18:20:56.787Z sha f772243 :: needs real behavior proof before merge. :: [P1] Select native totals only when Pi owns a visible source | [P2] Restrict app process discovery to Pi-consuming providers | [P2] Retain history discovered through project settings after exit | [P2] Label retained reports with their actual root scope
  • reviewed 2026-09-10T18:30:19.345Z sha f772243 :: needs real behavior proof before merge. :: [P1] Select native totals only when Pi owns a visible source | [P2] Restrict app process discovery to Pi-consuming providers | [P2] Retain history discovered through project settings after exit | [P2] Label retained reports with their actual root scope
  • reviewed 2026-09-10T19:22:09.472Z sha 75a4893 :: needs real behavior proof before merge. :: [P1] Include retained roots in the advertised publication scope | [P2] Replace settings roots when their selector changes | [P2] Preserve absolute session selectors when CWD lookup fails
  • reviewed 2026-09-10T20:09:22.291Z sha f2e8547 :: needs real behavior proof before merge. :: [P1] Include retained roots in the advertised publication scope | [P2] Replace settings roots when their selector changes | [P2] Preserve absolute session selectors when CWD lookup fails
  • reviewed 2026-09-10T20:22:59.748Z sha f2e8547 :: needs real behavior proof before merge. :: [P1] Include retained roots in the advertised publication scope | [P2] Replace settings roots when their selector changes | [P2] Preserve absolute session selectors when CWD lookup fails | [P2] Keep Pi accounting separate when its source is hidden

steipete added a commit to Yuxin-Qiao/CodexBar that referenced this pull request Aug 27, 2026
Integrate the Pi provider and preserve standalone Claude/Codex reports while
counting selected Pi history exactly once in combined spend surfaces.
Bind scans, caches and publications to validated roots and coverage, share
Pi settings resolution, and retain native Codex account isolation.

Add isolated regression and production-view proof, repair template icon and
local-source labels, and document the estimator's accounting limits.

Refs steipete#3246
Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>
@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. P1 Urgent regression or broken agent/channel workflow affecting real users now. labels Aug 27, 2026
@Yuxin-Qiao
Yuxin-Qiao force-pushed the feat/pi-provider-tokscale branch from 6f5e173 to 9723a64 Compare September 2, 2026 10:59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9723a6497c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="48" fill="#7C3AED"/><text x="50" y="62" text-anchor="middle" font-family="Helvetica, Arial, sans-serif" font-size="42" font-weight="700" fill="white">π</text></svg> No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the Pi glyph in the template icon

ProviderBrandIcon.image(for:) marks every provider SVG as a template image, but this asset composites opaque white text over an opaque purple circle. Template rendering uses the resulting alpha mask, which is only a solid circle, so the π disappears anywhere the provider brand icon is displayed. Encode the glyph and surrounding shape using transparency, preferably with paths rather than font-dependent SVG text.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Sep 2, 2026
Yuxin-Qiao and others added 5 commits September 3, 2026 02:48
Use a final-path atomic write and cover repeated cache saves with a portable roundtrip regression.

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>
@Yuxin-Qiao
Yuxin-Qiao force-pushed the feat/pi-provider-tokscale branch from 365a2a7 to 2df0447 Compare September 2, 2026 18:48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2df04477d3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/CodexBarCore/CostUsageFetcher.swift Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6653f8333d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +537 to +539
if provider == .claude, selectedProviders.contains(.pi) {
return false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude Pi rows from Codex when Pi is selected

When a multi-provider cost selection contains both Codex and Pi, this ownership check applies only to Claude. For the default ungrouped text or JSON paths, CostUsageFetcher.swift:756-764 therefore merges Codex-priced Pi/OMP rows into the unscoped Codex snapshot, while the Pi snapshot returns those rows again, duplicating tokens and spend in cost, dashboard, and serve output. Fresh evidence after the Claude-specific fix is that the final helper still returns includePiSessions for Codex unless it is session-grouped text.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d8cee6f. CLI cost, dashboard, and serve now suppress Pi/OMP rows in the Codex snapshot whenever Pi is also selected, for both text and JSON output; Pi is the sole owner of those rows. Added regression coverage for both formats.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8cee6f9af

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +683 to +685
let cwdURLs = (baseDirectories?.isEmpty == false ? baseDirectories! : [URL(
fileURLWithPath: FileManager.default.currentDirectoryPath,
isDirectory: true)])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve historical roots alongside live project roots

Fresh evidence after the live-CWD fix is that a nonempty baseDirectories list replaces, rather than augments, the fallback/default resolution. If a live project uses a project-level custom sessionDir, the Pi default store containing sessions from other projects is omitted; when that process exits, the custom root is omitted instead. Each transition changes the root fingerprint and a complete scan replaces the cache, so valid historical usage appears and disappears with the currently running processes. Keep the default and previously discovered historical roots alongside live project roots.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in db96555. Cost-root resolution now preserves the default and project roots, and appends valid roots from the previous cache fingerprint so historical usage remains available after a live process exits. Added a regression covering the first scan and the post-exit scan.

guard !result.contains(where: { $0.path == url.path }) else { return }
result.append(url)
}
let process = AgentProcessRecord(pid: 0, ppid: 0, startedAt: nil, command: "")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Carry live command-line root selectors into cost scans

When Pi or OMP is launched with --session-dir (or OMP with --profile) and no equivalent environment override, this synthetic process always has an empty command, so the command-line branches in piSessionRootResolution and ompSessionRootResolution can never select the live process's store. piWorkingDirectories forwards only CWDs, causing the historical token scan to use settings/default roots and omit sessions that the live scanner already discovers. Preserve the relevant live process selectors or pass the resolved roots directly.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in db96555. Live Pi and OMP process contexts now carry both the command line and working directory into cost scans, so --session-dir and --profile selectors are resolved through the same root logic as live session discovery. Added regression coverage for Pi, OMP, and the default Pi root.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48baa380b8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1015 to +1017
switch Self.profileDirectoryInspection(canonicalProfile) {
case .missing, .unavailable:
isComplete = false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore non-directory entries during OMP profile discovery

When ~/.omp/profiles or the XDG profiles directory contains an ordinary non-hidden file, profileDirectoryInspection returns .unavailable and this branch marks the entire root resolution incomplete. On an initial/root-changed scan, PiSessionCostScanner then restores the pre-scan cache and suppresses otherwise valid Pi/OMP usage. Regular files are not profile candidates and should be skipped; only failures to inspect actual profile directories should make discovery incomplete.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c79f0dc. OMP profile discovery now distinguishes a non-directory entry from an unreadable directory: ordinary files in the profiles parent, and non-directory session-layout entries, are ignored; actual unreadable directories still make discovery incomplete. Added a regression covering a regular file beside the default profile root.

Comment on lines +105 to +106
let piWorkingDirectories: [URL] = if provider == .pi || effectiveIncludePiSessions {
await LocalAgentSessionScanner().piWorkingDirectories(environment: environment)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict Pi process discovery to Pi-consuming providers

For every non-Claude provider, shouldIncludePiSessionsInTokenSnapshot returns true, so this condition runs a full process/CWD scan before refreshing Cursor, Bedrock, Antigravity, and other providers that never consume Pi roots. The discovery also occurs before the timeout task group starts, so its latency is not covered by tokenFetchTimeout (the Linux path alone permits separate five-second ps and lsof waits). Gate this work to Pi and the Claude/Codex paths that actually merge Pi history.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db965559e8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

let defaultRoot = Self.defaultCostSessionRoot(for: dialect, environment: environment)
output.append(CostSessionRoot(
url: canonical,
missingIsKnownEmpty: !hasExplicitSelection && defaultRoot.map { $0 == canonical } == true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep augmented default roots optional

When a live Pi/OMP process supplies --session-dir or --profile, hasExplicitSelection becomes true for the whole dialect, including the default root added separately through uniqueCWDs. If that default directory does not exist—as is common when the user stores all sessions at the explicit location—this marks the otherwise optional default as required, so listPiSessionFiles makes the scan incomplete and the root-change path restores the old cache instead of publishing usage from the valid explicit root. Track explicit/default provenance per resolved root rather than applying the dialect-wide selector to every root.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3124109. Root optionality is now tracked per resolved root: the standard Pi/OMP default root is marked missingIsKnownEmpty only when it is truly default and no explicit process/config selection targets that dialect; explicit roots remain required. Added regression coverage. make check passes, and the full suite passes with 1060/1060 selections across 89/89 groups.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c79f0dcf99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +723 to +727
let process = AgentProcessRecord(
pid: 0,
ppid: 0,
startedAt: nil,
command: context.command)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve argv boundaries when resolving live roots

When a live Pi/OMP process uses --session-dir with whitespace in its path, this passes the flattened command back through commandLineValue, which splits on whitespace at PiFamilySessionScanner.swift:1148. On macOS, DarwinProcessEnumerator.parseProcArgs2 already joins the original argv with spaces, so a path such as /Users/me/Pi Sessions is resolved as /Users/me/Pi; the actual sessions are omitted and the nonexistent truncated root can keep the scan incomplete. Carry the original argument array or preserve argument boundaries before re-parsing the command.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3124109. Darwin KERN_PROCARGS2 now retains the original argv; live PiSessionProcessContext carries those arguments, and flag resolution uses exact argv with the command string only as a portable fallback. Paths containing spaces therefore remain one selector value. Added a regression for that path boundary. make check passes, and the full suite passes with 1060/1060 selections across 89/89 groups.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3124109936

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +435 to +437
return self.appendingPreviousSessionRoots(
resolvedRoots,
fingerprint: previousSessionRootsFingerprint)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Drop obsolete roots after explicit selector changes

When PI_CODING_AGENT_SESSION_DIR, PI_CODING_AGENT_DIR, or an explicit OMP profile changes from A to B while the same cache is reused, this appends every path from A's fingerprint to B's resolved roots. A complete B scan then persists totals from both stores instead of switching scope; if A later disappears, its retained required flag also makes every B scan incomplete. Fresh evidence after the earlier incomplete-root fix is that this preservation occurs before the completeness branch and is not limited to roots discovered from exited live processes. Preserve only live-discovered historical roots, not superseded explicit configuration roots.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2f4e6bc and pushed to feat/pi-provider-tokscale. Root provenance now distinguishes configured/default roots from roots discovered through live Pi/OMP process contexts. Cache fingerprints only carry forward entries explicitly marked live, so switching a configured selector from A to B drops A while an exited live process root remains available. Added the A-to-B regression: the second scan reports only B (15 -> 30 tokens) and its fingerprint excludes A. make check and the full suite pass (1060/1060 selections, 89/89 groups).

Comment on lines +210 to +211
piWorkingDirectories: [URL] = [],
piSessionProcessContexts: [PiSessionProcessContext] = []) async throws -> CostUsageTokenSnapshot

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve live Pi roots in CLI cost paths

When codexbar cost --provider pi runs outside the Pi project and a running Pi/OMP process selected its store through project .pi/settings.json, --session-dir, or --profile, the CLI leaves these new context parameters empty, so resolution uses the CLI's cwd/default roots and omits the actual logs. CLIDashboardCommand.swift:119 and CLIServeCommand.swift:1480 make the same direct call. Fresh evidence after the live-CWD/root-selector fix is that only UsageStore invokes LocalAgentSessionScanner.piSessionProcessContexts; all newly exposed CLI Pi cost paths bypass it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2f4e6bc and pushed to feat/pi-provider-tokscale. CLI cost now collects LocalAgentSessionScanner.piSessionProcessContexts once when Pi history is selected, then passes those CWDs and exact argv through cost, dashboard, and serve loads. This makes project .pi/settings.json, --session-dir, and OMP --profile roots resolve the same way as the live scanner even when the command runs elsewhere. Focused CLI/dashboard tests and the full suite pass (1060/1060 selections, 89/89 groups).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f4e6bc1af

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// Provider-specific by design: visible Pi owns its Claude-priced rows in the spend dashboard;
/// Claude only falls back to those rows while Pi is not an active cost source.
func shouldIncludePiSessionsInTokenSnapshot(for provider: UsageProvider) -> Bool {
guard provider == .claude else { return true }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude Pi rows from the visible Codex snapshot

When both Codex and Pi are enabled and Codex uses its ambient scope, this guard returns true for Codex, so CostUsageFetcher.loadLocalTokenScanResult merges Codex-priced Pi rows into the Codex snapshot while the separate Pi snapshot aggregates the same rows. The provider cards therefore display the same tokens and spend under both providers. Fresh evidence beyond the CLI ownership fix is that the regular UsageStore policy still special-cases only Claude; apply the same Pi-ownership check and scope invalidation to Codex.

AGENTS.md reference: AGENTS.md:L47-L47

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cb57e8b and pushed to feat/pi-provider-tokscale. UsageStore now treats Codex and Claude consistently: when Pi is enabled and cost usage is effective, the regular Codex/Claude snapshots suppress Pi rows so the Pi snapshot remains the sole owner. The piRows=fallback/owned marker is included in both provider scope signatures, invalidating stale publications when Pi visibility changes. Added regression coverage for both providers; make check and the full suite pass (1060/1060 selections, 89/89 groups).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb57e8b4f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


/// Provider-specific by design: visible Pi owns its Claude- and Codex-priced rows in the spend dashboard;
/// Claude and Codex only fall back to those rows while Pi is not an active cost source.
func shouldIncludePiSessionsInTokenSnapshot(for provider: UsageProvider) -> Bool {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply Pi ownership during cache hydration

When ambient Codex cost history and Pi are both enabled at app startup, hydrateCachedTokenSnapshots still calls loadCachedCodexTokenSnapshotResult with its default includePiSessions: true, bypassing this new ownership policy. It installs a Codex snapshot containing Pi rows and may mark it current for the token-fetch TTL, while the separately refreshed Pi snapshot publishes those rows again. Fresh evidence beyond the regular-refresh fix is the unchanged hydration call at UsageStore+TokenCost.swift:305-309; pass this policy into that cached load as well.

AGENTS.md reference: AGENTS.md:L47-L47

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0ffa963 and pushed to feat/pi-provider-tokscale. Cached Codex token hydration now captures and passes the same Pi ownership policy as regular refreshes, so when Pi is an active cost source it loads native Codex rows with includePiSessions=false and cannot duplicate Pi rows. Added a synthetic startup hydration regression (42 native + 7 Pi tokens remains 42 in the Codex snapshot). make check and make test pass (1060/1060 selections, 89/89 groups, 0 first-pass failures, 0 retries, 0 timeouts).

Comment on lines 744 to 747
let parsedBytes: Int64
var isComplete = true
do {
parsedBytes = try CostUsageJsonl.scan(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat unfinished JSONL tails as incomplete

If a scan catches a session file while its final JSON object is only partially written, CostUsageJsonl.scan leaves that tail uncommitted and never invokes onLine, so isComplete remains true. The scanner then stores the file's current size/mtime and publishes established history; if the writer stalls or crashes, later scans take the unchanged-metadata cache hit and never retry the omitted tail, potentially confirming an empty or undercounted Pi snapshot. Compare the returned committed offset with the observed file size and mark the parse incomplete when bytes remain.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0ffa963 and pushed to feat/pi-provider-tokscale. Pi JSONL scans now compare the committed offset with the file size after reading; an unfinished EOF tail marks the scan incomplete, so the cache is not advanced or published as established until the writer completes the record. The regression covers the malformed/unfinished tail and retains the previous usage. make check and make test pass (1060/1060 selections, 89/89 groups, 0 first-pass failures, 0 retries, 0 timeouts).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ffa96308e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +34 to +38
tokenCost: ProviderTokenCostConfig(
supportsTokenCost: true,
noDataMessage: self.noDataMessage,
menuHintLines: [.estimate],
supportsTokenSnapshot: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include Pi stores in token-cost auto-detection

On a Pi-only installation where tokenCostUsageEnabled has never been set, this provider remains unusable in the app by default: SettingsStore.applyTokenCostDefaultIfNeeded enables cost tracking only when hasAnyTokenCostUsageSources finds Codex or Claude logs (SettingsStore+TokenCost.swift:18-108), so existing ~/.pi or ~/.omp sessions are ignored and UsageStore.refreshTokenUsage clears Pi's token state while cost tracking is off. Extend source detection to the Pi-family roots when adding this cost-only provider.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0daeef7. hasAnyTokenCostUsageSources now resolves the shared Pi-family roots, including ~/.pi, ~/.omp, configured roots, and discovered OMP profiles, before checking Claude sources. This makes a Pi/OMP-only install auto-enable token cost when history exists. Added SettingsStoreTokenCostSourceTests covering both default stores; make check and make test passed (1062/1062 selections).

Comment on lines 204 to 205
for url in result.files {
files.append(SessionFileCandidate(url: url, rootIndex: rootIndex))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Deduplicate session files from overlapping roots

When a live or retained custom session root is nested under the newly preserved default root, such as ~/.pi/agent/sessions/project-a, the recursive enumeration of both roots appends the same JSONL path twice here. rebuildDailyUsage then applies unkeyedContributions once per candidate, so supported records without entry IDs are counted twice in Pi token and spend totals; canonicalize and deduplicate file paths before scanning and rebuilding.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0daeef7. The scanner now canonicalizes each discovered JSONL path with standardizedFileURL plus symlink resolution and removes duplicates before parsing or rebuilding daily usage, so overlapping retained/live roots cannot double-count ID-less records. Added a nested-root regression that asserts 7 tokens and one cached file; make check and make test passed (1062/1062 selections).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f772243fc8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +790 to +792
let processRootIsRetained = Self.hasExplicitProcessRootSelection(
dialect: dialect,
processContexts: [context])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retain roots discovered through project settings

When a live Pi process relies on a project-level .pi/settings.json to redirect sessionDir and has no --session-dir flag, this marks the resolved root as non-retainable. After the process exits, its working directory is no longer supplied, and PiSessionCostScanner.appendingPreviousSessionRoots keeps only fingerprint entries marked live, so the custom root is dropped and the cache is replaced with default-root usage, making valid historical spend disappear. Fresh evidence after the earlier preservation fix is that the final processRootIsRetained check now preserves only command-line selectors rather than project-settings roots.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 75a48933f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +521 to +523
self.sessionRootsFingerprint(self.defaultSessionRoots(
options: options,
previousSessionRootsFingerprint: nil))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include retained roots in the advertised scope fingerprint

When a live --session-dir or project-settings root has been cached with the live marker and the process exits, the scanner calls defaultSessionRoots with the cached fingerprint and continues returning that retained root, but this helper passes nil and advertises a scope without it. refreshPiHistoryScope then clears the old publication, while tokenAccountingScopeIsCurrent rejects every new result because the scanner's scopeFingerprint still contains the retained root; valid Pi history therefore disappears and cannot be republished after the process exits. Compute the advertised fingerprint using the same retained-root scope as the scan, or compare scopes with equivalent retention semantics.

Useful? React with 👍 / 👎.

Comment on lines +1104 to +1107
return PiSessionRootResolution(
// Project settings are durable configuration. Keep this root in the cache
// scope after the process exits so its history remains attributable.
roots: [SessionRoot(url: url, layout: .direct, preserveAfterProcessExit: true)],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Stop retaining superseded settings roots

When a project or global settings.json changes sessionDir from A to B, this marks A as retainable, so appendingPreviousSessionRoots adds A from the prior cache fingerprint alongside newly resolved B. A complete scan then rebuilds totals from both stores—especially visible in direct CLI cost loads, which have no publication-scope rejection—and if A disappears its required-root status can instead keep the scan incomplete. Retain roots only to bridge a process exit, while replacing roots superseded by current settings.

Useful? React with 👍 / 👎.

Comment on lines +229 to +230
return processes.compactMap { process in
guard let cwd = cwdByPID[process.pid], !cwd.isEmpty else { return nil }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve absolute selectors when CWD lookup fails

When CWD discovery fails for a live Pi/OMP process, this guard drops the entire process context even if its argv contains an absolute --session-dir, which requires no working directory to resolve; the historical scan consequently falls back to ambient/default roots and omits the selected store. Fresh evidence beyond the earlier live-selector fix is that the final compaction still conditions preservation of argv on a successful CWD lookup; retain contexts with absolute selectors using a neutral fallback directory or make the working directory optional.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2e85476a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

let piBaseline = providerBaselines.first { $0.provider == .pi }
let piCurrent = self.capturedTokenPublication(store: store, provider: .pi)
let piOwnsVisibleSource = providers.contains(.pi)
&& !configuration.hiddenSourceIDs.contains(UsageProvider.pi.rawValue)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Pi ownership when its dashboard row is hidden

When both Pi and Claude are enabled and Pi has recorded usage, hiding the Pi source makes this predicate false, so dashboardTokenSnapshot switches Claude from its native projection back to the inclusive snapshot containing Pi rows. The model then filters out the Pi input, but those costs remain visible under Claude, meaning the source filter does not actually remove Pi spend and misattributes it to another provider. Pi ownership should remain active when the row is hidden; visibility should only control whether the separate Pi input contributes to the dashboard.

AGENTS.md reference: AGENTS.md:L47-L47

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d04206180

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +234 to +237
guard workingDirectory != nil ||
PiFamilySessionScanner.hasAbsoluteSessionDirectorySelector(
in: process,
environment: environment)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve OMP profiles when CWD lookup fails

When an OMP process uses --profile work and its CWD cannot be read, this guard drops the process context because only an absolute --session-dir is accepted. OMP profile resolution is CWD-independent when HOME is available, so the later cost scan instead auto-discovers every profile and can include usage from unrelated profiles. Retain --profile contexts without a CWD and resolve them using the existing OMP profile resolver.

Useful? React with 👍 / 👎.

Comment on lines +34 to +35
tokenCost: ProviderTokenCostConfig(
supportsTokenCost: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Classify Pi as a local spend source

When Pi is enabled in Overview, this token-cost source enters the spend dashboard as a normal native input, and SpendDashboardController.publishCurrentState assigns every such input the .subscription role; SpendDashboardPublication.subscriptionCount therefore includes Pi in the text “%d of %d subscriptions have spend.” A Claude-plus-Pi setup is consequently reported as two subscriptions even though Pi is only a local-history estimator. Add a local-source classification or exclude Pi from subscription coverage counts.

Useful? React with 👍 / 👎.

@Yuxin-Qiao
Yuxin-Qiao force-pushed the feat/pi-provider-tokscale branch from 3d04206 to c8fb54e Compare September 10, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants