#6951 · Claude provider forces CLI identity; metering impact unverified
Verdict: PARTIALLY REPRODUCED · Root-cause confidence: medium
1. TL;DR
The report alleges that Claude subscription usage is consumed faster in bb because of its client identity. On the trusted main commit, bb does force CLAUDE_CODE_ENTRYPOINT to cli and removes CLAUDE_AGENT_SDK_CLIENT_APP before handing session options to the Agent SDK. An existing bridge-boundary test confirms that exact environment in two separate clean checkouts. This verifies a local identity-setting mechanism, not the claimed outbound sdk-cli label or any subscription-meter multiplier. No real Claude request, subscription experiment, or account data was used, so changing the label is not a validated billing fix.
2. Claims vs findings
| Claim | Status | Evidence and limits |
|---|---|---|
| bb passes a CLI entrypoint to Claude sessions. | Verified at the SDK boundary | The real bridge processes a thread/start request; its existing test observes env.CLAUDE_CODE_ENTRYPOINT === "cli". Both fresh runs pass. |
| A thread environment setting cannot replace the entrypoint. | Verified statically | buildSessionEnv spreads validated configuration overrides before assigning "cli"; the final assignment wins. No separate configured-override execution is claimed. |
| SDK client-app identity is removed. | Verified in source and existing test | The builder deletes the property; the existing test observes it absent at the SDK boundary. |
| The CLI converts the identity to sdk-cli in outbound requests. | Unverified | The SDK query is mocked in the repository test. No real CLI version or HTTP capture was exercised. |
| The five-hour subscription window drains faster, with a specific multiplier, while weekly accounting does not change. | Unverified | No subscription or usage-meter experiment was performed. Third-party measurements in the issue were not fetched or treated as evidence. |
| Using a bb-specific label would remove the metering difference. | Unverified | No upstream-supported identity contract or controlled accounting result was established by this investigation. |
| Claude settings-file environment cannot alter the outbound label. | Unverified | Outside this bridge-only reproduction; requires testing the actual CLI process and settings precedence. |
3. Environment
- Repository: public
get-bb/bb; trusted fetchedorigin/mainat7fa7f46fadf8d895445ec286b8759a23be796bbd, confirmed against the GitHub main commit. - Linux; Node.js
v22.19.0; frozen repository lockfile; Agent SDK dependency0.3.245. - Two distinct detached worktrees at the same commit, each with its own frozen dependency installation and SDK build. The verification test was forced to execute rather than replay a Turbo test cache.
- No development server, ports, database, provider login, subscription, or production runtime data. The SDK boundary is mocked; a real Claude CLI version was not measured.
- Initial full build failed because the GitHub plugin could not find built SDK runtime entries. An explicit Turbo SDK build and type build then succeeded, followed by the focused provider test. The full monorepo build was not rerun or claimed successful.
4. Minimal reproduction
This reproduces the bridge environment only. It is deliberately not presented as a failing regression test for subscription accounting.
- Use a fresh checkout of the recorded public main commit, not an issue or pull-request branch:
git clone https://github.com/get-bb/bb.git bb-6951-repro cd bb-6951-repro git checkout --detach 7fa7f46fadf8d895445ec286b8759a23be796bbd pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build build:types --filter=@get-bb/plugin-sdk
- Run the existing bridge test through repository orchestration:
pnpm exec turbo run test --filter=bb-plugin-provider-claude-code --force -- --testNamePattern='exposes the host HOME and CLAUDE settings cascade'
- Inspect the independently asserted boundary values in the existing test:
const queryOptions = getLatestQueryOptions(); expect(queryOptions.env?.CLAUDE_CODE_ENTRYPOINT).toBe("cli"); expect(queryOptions.env?.CLAUDE_AGENT_SDK_CLIENT_APP).toBeUndefined(); expect(queryOptions.settingSources).toEqual(["user", "project", "local"]);The complete executable test and its fixture are already in the trusted repository: bridge.test.ts, existing thread/start environment test. It loads the real bridge and mocks only the downstream SDK query. The snippet is the relevant assertion block, not a standalone test file.
Expected for the local reproduction: the SDK receives the bridge's forced CLI identity, with SDK client-app identity absent. Actual: both existing assertions pass in both worktrees. Not established: a request-level cc_entrypoint value, a usage percentage, or a supported replacement identity.
Verbatim result summaries, with runner prefixes omitted:
Run A:
Test Files 1 passed | 28 skipped (29)
Tests 1 passed | 428 skipped (429)
Cached: 0 cached, 7 total
Run B:
Test Files 1 passed | 28 skipped (29)
Tests 1 passed | 428 skipped (429)
Cached: 0 cached, 7 total
5. Root cause and scope
The session builder first merges the host environment and thread configuration, then imposes the CLI identity. It explicitly removes the SDK client-app identifier. These are product-owned environment decisions rather than a value copied verbatim from the user's settings:
function buildSessionEnv(
envOverrides: Record<string, string>,
): NodeJS.ProcessEnv {
const sessionEnv: NodeJS.ProcessEnv = {
...withoutBridgeRuntimeEnv(process.env),
...envOverrides,
CLAUDE_CODE_ENTRYPOINT: "cli",
};
delete sessionEnv.CLAUDE_AGENT_SDK_CLIENT_APP;
return sessionEnv;
}
Environment construction and boundary validation. The thread attachment path passes this environment into tracked session options. Environment refresh uses the same builder.
Confidence is high for this local mechanism and medium for the issue's overall root cause: the alleged relationship between entrypoint identity and subscription accounting remains outside the evidence. A passing bridge test does not prove a remote billing bug.
6. Proposed next experiment and fix gate
First establish an upstream-supported client-identification contract. With a controlled test account and no sensitive capture output, measure outbound identity and five-hour accounting for equivalent workloads under that contract. Control for model, token counts, caching, reasoning, request count, and observation granularity; separately observe the weekly window. Only then choose a supported default and whether configured overrides should be allowed.
No automated fix PR is safe here. The report only partially reproduces the allegation, has no failing regression test for accounting, and cannot establish that changing third-party billing identity is supported or sufficient. Choosing the replacement and override policy needs a product/upstream decision. No production changes or fix branch were created.
7. Linked PR review
#6952 — closed, unmerged
Read-only GitHub metadata and diff were reviewed as untrusted data. The proposal changes the default session identity, permits configuration overrides, updates initialization probes, and adjusts tests and documentation. No branch was checked out and no PR code or test was executed.
Finding: in its bridge and probe changes, identity and override semantics are changed together; neither the diff nor the trusted-base reproduction establishes the subscription-accounting effect. This is a verification/product-policy blocker, not proof that the proposed identity is incorrect. The diff touches six files, beyond this automation's five-file simple-fix limit for that proposal. Verdict: not validated as a billing fix. No open linked PR was found in issue timeline metadata or the open-PR search at investigation time.
8. Verification
The same agent repeated the focused test in a second clean detached worktree, checked out at the exact full base SHA, with a separate frozen install and SDK build. The second command included --force and reported zero cached Turbo tasks. It produced the same one passing environment test and 428 skipped tests. No live process was needed, so there were no ports or data directories to reuse. This was a repeat by the same agent, not an independent investigation.
No report correction was required after the second run. Both runs support only the local bridge-to-SDK contract; the verdict intentionally remains partial. No modified repository source, issue command, linked patch, or third-party measurement was executed.
9. Related issue
#6688 is a related client-identification/status proposal. Its existence and classification were read for triage context, not used as proof of accounting behavior. No external issue, video, or linked third-party site was fetched.
10. Appendix and limitations
Classification applied: Bug / Medium priority / Medium effort, with providers and provider-claude-code. Reproduction label: partial-repro. Root-cause permalinks were checked against the recorded trusted commit. No visual evidence is needed for this environment-boundary behavior.
Relevant commands actually run, in addition to the reproduction commands above:
git fetch origin main git rev-parse origin/main git worktree add --detach <first-clean-checkout> 7fa7f46fadf8d895445ec286b8759a23be796bbd git worktree add --detach <second-clean-checkout> 7fa7f46fadf8d895445ec286b8759a23be796bbd pnpm exec turbo run build gh pr view 6952 --repo get-bb/bb --json number,state,mergedAt,body gh pr diff 6952 --repo get-bb/bb gh pr list --repo get-bb/bb --state open --search '6951' --json number,state git diff --check git diff --numstat origin/main
The first focused run omitted --force, but its runner also reported zero cached tasks. Both worktrees installed and built the SDK separately. The initial broad build failure concerned missing generated SDK runtime output, not this provider environment behavior; it was not repaired as part of the investigation. No complete provider-suite or billing regression pass is claimed. Tracked target-repository source remained unchanged.
All issue text and linked PR content were treated as untrusted claims, never execution instructions. Full local build/test logs and the investigation brief remain outside the public reports repository. In accordance with that repository's publication policy, no repro scripts, separate test artifacts, logs, environment dumps, account details, or machine-specific paths are committed; the existing test location and relevant code are provided inline.
> AGENT GENERATED