Skip to content

feat(claude-code): report the branch each prompt works on - #44

Merged
brandontaslater merged 2 commits into
mainfrom
feat/claude-code-session-context
Oct 1, 2026
Merged

brandontaslater merged 2 commits into
mainfrom
feat/claude-code-session-context

Conversation

@brandontaslater

Copy link
Copy Markdown
Member

What

The telemetry export names a repository and never a branch, and it resolves that repository once at process launch and never again — so a session that moves between branches, or between repositories, reports the first one for its whole life. Per-pull-request cost was an estimate built on a guess.

New hooks post what the client was actually working on, keyed by prompt_id because that is what the cost events already carry.

Pairs with opentrace-api#352, which consumes this.

The hooks

Session start, working-directory change, prompt submit, and file-touching tool calls. Debounced per (session, agent, prompt, remote, branch), posted asynchronously, failing open and silent — telemetry must never block the user or break a session.

They send the git remote, branch, head commit and the session/prompt/agent ids. Never a user, an organisation, a file path, a prompt, or any code. The server attributes every observation to the member the key belongs to, so there is nothing to spoof by editing the script.

Settings

OTEL_METRICS_INCLUDE_REPOSITORY is off by default upstream and is the single setting per-repository cost rests on. OPENTRACE_API_URL goes in beside it because Claude Code strips OTEL_* from hook subprocesses — verified directly — so the hooks cannot read the exporter's endpoint however carefully they try. Left unset, the destination falls back to the public host, which silently points a self-hosted install at the wrong place.

The key deliberately does not go in that block

Everything in env is inherited by every hook, every Bash tool call and every MCP server a session starts — readable with a bare env, and apt to end up in a transcript. The key lands in ~/.claude/opentrace-telemetry.token at 0600 instead.

Its own file, not the MCP's. opentrace-plugin.token holds a graph-reading CLI key; this is a usage key that cannot read anything. Sharing one path made the outcome depend on which command wrote last — install left the usage key where the MCP looks and broke it outright, connect left the CLI key where the hooks look and posted a graph-reading credential on every prompt.

Upgrade behaviour:

  • a copy an earlier build left in env is stripped on write, not merely superseded, so upgrading remediates the exposure instead of preserving it
  • the file outranks the variable when both exist, so a stale value cannot shadow a rotated key and fail quietly
  • the MCP's token file is still the last fallback, which is what keeps machines on the older plugin reporting until the CLI writes the new file
  • disconnect --usage clears the key file, or turning monitoring off would leave the hooks authenticated and still reporting

Verification

115 unit tests pass, lint clean. Thirteen are new and pin the behaviour above: the two credentials staying in separate files, 0600 on creation, recreating a world-readable file from an older build, writing through a symlink rather than replacing it, stripping the legacy key while keeping unrelated vars, and both token-resolution orders. The symlink and resolution-order tests fail against the previous code, so they are guards rather than documentation.

Known gap, not addressed here

ensurePluginInstalled returns early when the plugin is already present and never compares versions, so existing installs will not receive these hooks. Bumping to 0.6.0 does not change that on its own. Worth deciding before this is relied on, since the API side has nothing to consume until the hooks reach people.

🤖 Generated with Claude Code

brandontaslater and others added 2 commits September 29, 2026 16:20
The telemetry export names a repository and never a branch, and it resolves that
repository once at process launch and never again — so a session that moves
between branches, or between repositories, reports the first one for its whole
life. Per-pull-request cost was therefore an estimate built on a guess.

New hooks post what the client was actually working on, keyed by `prompt_id`
because that is what the cost events carry. Session start, working-directory
change, prompt submit and file-touching tool calls, debounced per
`(session, agent, prompt, remote, branch)`, posted asynchronously, failing open
and silent — telemetry must never block the user or break a session.

`OTEL_METRICS_INCLUDE_REPOSITORY` goes into the settings block: it is off by
default upstream and is the single setting per-repository cost rests on.
`OPENTRACE_API_URL` goes in beside it because Claude Code strips `OTEL_*` from
hook subprocesses, so the hooks cannot read the exporter's endpoint however
carefully they try.

The ingest key does NOT go in that block. Everything in `env` is inherited by
every hook, every Bash tool call and every MCP server a session starts, readable
with a bare `env`. It lands in `~/.claude/opentrace-telemetry.token` at 0600
instead — its own file, not the MCP's, because that one holds a graph-reading CLI
key and sharing a path made the outcome depend on which command wrote last.

A copy an earlier build left in `env` is stripped on write rather than merely
superseded, and the file outranks the variable when both exist, so a stale value
cannot shadow a rotated key and fail quietly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`claude plugin validate --strict` treats warnings as errors, and the validator
now warns on an unquoted `${CLAUDE_PLUGIN_ROOT}`: a plugin installed under a path
containing a space expands into several words and the hook fails to run.

Six commands, four of them added by the session-context hooks and two that
predate them — so this was failing on `main` too, from the moment the warning
shipped. CI installs `@anthropic-ai/claude-code` unpinned and `main` last ran on
20 August, which is why it went unnoticed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@brandontaslater
brandontaslater merged commit 2883e11 into main Oct 1, 2026
5 checks passed
@brandontaslater
brandontaslater deleted the feat/claude-code-session-context branch October 1, 2026 09:04
@codehub-agent

codehub-agent Bot commented Oct 1, 2026

Copy link
Copy Markdown

💰 Agent economics

no agent sessions have reported to this workspace in the last 30 days, so there is no spend to attribute. Set up agent telemetry →

Full economics → · by CodeHub

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant