Repository navigation
feat(daemon): mark Claude Code cloud session telemetry - #330
Conversation
Claude Code tags every event and metric of a cloud session (claude.ai/code) with ccr.session.id, the VM's CLAUDE_CODE_REMOTE_SESSION_ID. In a cloud VM the daemon is started by the session's SessionStart hook, so it inherits CLAUDE_CODE_REMOTE=true and the session id: it now adds ccr.session.id to Claude Code records that don't carry one, so the server can mark the session as a cloud session. A value Claude Code sent wins, Codex records are left alone, and nothing changes on a local machine. daemon/main_test.go clears both variables so the suite behaves the same inside a cloud session as on CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qinc9uT7wXFFuo7yaKBHKq
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
⏱️
|
| Scenario | base | head | Δ | p | |
|---|---|---|---|---|---|
Startup/floor |
223 µs ±37% | 222 µs ±17% | ~ | 0.912 | A/A |
Startup/version |
2.42 ms ±26% | 2.49 ms ±12% | ~ | 0.739 | ✅ |
Track/daemon/pre |
2.49 ms ±27% | 2.71 ms ±46% | ~ | 0.190 | ✅ |
Track/daemon/post |
2.53 ms ±27% | 2.59 ms ±19% | ~ | 0.853 | ✅ |
Track/direct/pre |
2.72 ms ±19% | 2.56 ms ±70% | ~ | 1.000 | ✅ |
Track/direct/post |
4.60 ms ±34% | 5.02 ms ±16% | ~ | 0.529 | ✅ |
Track/direct/post-sync |
6.13 ms ±21% | 6.25 ms ±20% | ~ | 0.796 | ✅ |
Binary size: 19.2 MiB → 19.2 MiB (+0.0%).
CPU, tail latency and memory
Per exec, base → head (Δ when significant).
| Scenario | p95 wall | user CPU | sys CPU | peak RSS |
|---|---|---|---|---|
Startup/floor |
262 µs → 269 µs | 191 µs → 197 µs | 8 µs → 8 µs | 9.0 MiB → 9.0 MiB |
Startup/version |
3.63 ms → 3.96 ms | 1.67 ms → 1.65 ms | 847 µs → 928 µs | 15.6 MiB → 15.6 MiB |
Track/daemon/pre |
3.13 ms → 3.53 ms | 1.59 ms → 1.77 ms (+11.03%) | 843 µs → 967 µs | 16.5 MiB → 16.5 MiB |
Track/daemon/post |
3.66 ms → 2.89 ms | 1.76 ms → 1.73 ms | 873 µs → 924 µs | 16.4 MiB → 16.4 MiB |
Track/direct/pre |
4.09 ms → 3.64 ms | 1.82 ms → 1.67 ms | 985 µs → 905 µs | 16.4 MiB → 16.4 MiB |
Track/direct/post |
5.41 ms → 7.33 ms | 3.28 ms → 2.98 ms | 1.87 ms → 1.93 ms | 17.6 MiB → 17.6 MiB |
Track/direct/post-sync |
8.46 ms → 8.89 ms | 4.35 ms → 4.18 ms | 2.09 ms → 2.33 ms | 19.6 MiB → 19.6 MiB |
benchstat
goos: linux
goarch: amd64
pkg: github.com/malamtime/cli/perf
cpu: Intel(R) Xeon(R) Processor
│ base │ head │
│ sec/op │ sec/op vs base │
Startup/floor-2 223.3µ ± 37% 221.9µ ± 17% ~ (p=0.912 n=10)
Startup/version-2 2.418m ± 26% 2.490m ± 12% ~ (p=0.739 n=10)
Track/daemon/pre-2 2.492m ± 27% 2.711m ± 46% ~ (p=0.190 n=10)
Track/daemon/post-2 2.529m ± 27% 2.589m ± 19% ~ (p=0.853 n=10)
Track/direct/pre-2 2.724m ± 19% 2.562m ± 70% ~ (p=1.000 n=10)
Track/direct/post-2 4.603m ± 34% 5.016m ± 16% ~ (p=0.529 n=10)
Track/direct/post-sync-2 6.129m ± 21% 6.250m ± 20% ~ (p=0.796 n=10)
geomean 2.215m 2.271m +2.53%
│ base │ head │
│ p50-sec/op │ p50-sec/op vs base │
Startup/floor-2 213.2µ ± 37% 216.9µ ± 9% ~ (p=0.739 n=10)
Startup/version-2 2.180m ± 23% 2.319m ± 18% ~ (p=0.739 n=10)
Track/daemon/pre-2 2.349m ± 17% 2.590m ± 70% ~ (p=0.190 n=10)
Track/daemon/post-2 2.311m ± 31% 2.390m ± 19% ~ (p=0.912 n=10)
Track/direct/pre-2 2.395m ± 19% 2.422m ± 92% ~ (p=0.631 n=10)
Track/direct/post-2 4.510m ± 21% 4.529m ± 21% ~ (p=0.739 n=10)
Track/direct/post-sync-2 5.897m ± 25% 5.825m ± 15% ~ (p=0.529 n=10)
geomean 2.066m 2.130m +3.10%
│ base │ head │
│ p95-sec/op │ p95-sec/op vs base │
Startup/floor-2 262.3µ ± 65% 268.5µ ± 28% ~ (p=0.796 n=10)
Startup/version-2 3.630m ± 39% 3.960m ± 25% ~ (p=0.739 n=10)
Track/daemon/pre-2 3.126m ± 59% 3.529m ± 49% ~ (p=0.579 n=10)
Track/daemon/post-2 3.663m ± 40% 2.887m ± 60% ~ (p=0.684 n=10)
Track/direct/pre-2 4.091m ± 41% 3.637m ± 52% ~ (p=1.000 n=10)
Track/direct/post-2 5.408m ± 64% 7.330m ± 21% ~ (p=0.247 n=10)
Track/direct/post-sync-2 8.457m ± 22% 8.891m ± 32% ~ (p=0.853 n=10)
geomean 2.970m 3.070m +3.34%
│ base │ head │
│ peak-rss-B │ peak-rss-B vs base │
Startup/floor-2 8.994Mi ± 1% 9.002Mi ± 1% ~ (p=0.446 n=10)
Startup/version-2 15.61Mi ± 0% 15.61Mi ± 0% ~ (p=0.378 n=10)
Track/daemon/pre-2 16.52Mi ± 0% 16.52Mi ± 0% ~ (p=0.897 n=10)
Track/daemon/post-2 16.40Mi ± 0% 16.41Mi ± 0% ~ (p=0.239 n=10)
Track/direct/pre-2 16.39Mi ± 0% 16.39Mi ± 0% ~ (p=0.469 n=10)
Track/direct/post-2 17.63Mi ± 0% 17.63Mi ± 0% ~ (p=0.698 n=10)
Track/direct/post-sync-2 19.58Mi ± 0% 19.60Mi ± 0% ~ (p=0.516 n=10)
geomean 15.50Mi 15.51Mi +0.03%
│ base │ head │
│ sys-sec/op │ sys-sec/op vs base │
Startup/floor-2 7.695µ ± 76% 8.140µ ± 48% ~ (p=0.842 n=10+9)
Startup/version-2 847.2µ ± 70% 927.5µ ± 38% ~ (p=0.739 n=10)
Track/daemon/pre-2 843.3µ ± 94% 966.9µ ± 99% ~ (p=0.529 n=10)
Track/daemon/post-2 873.0µ ± 72% 923.6µ ± 48% ~ (p=0.739 n=10)
Track/direct/pre-2 985.3µ ± 43% 905.1µ ± 124% ~ (p=0.579 n=10)
Track/direct/post-2 1.874m ± 29% 1.930m ± 31% ~ (p=0.393 n=10)
Track/direct/post-sync-2 2.090m ± 38% 2.326m ± 27% ~ (p=0.631 n=10)
geomean 565.6µ 598.1µ +5.75%
│ base │ head │
│ user-sec/op │ user-sec/op vs base │
Startup/floor-2 191.3µ ± 37% 196.6µ ± 19% ~ (p=0.579 n=10)
Startup/version-2 1.671m ± 11% 1.650m ± 9% ~ (p=1.000 n=10)
Track/daemon/pre-2 1.593m ± 8% 1.769m ± 22% +11.03% (p=0.035 n=10)
Track/daemon/post-2 1.764m ± 13% 1.727m ± 8% ~ (p=0.631 n=10)
Track/direct/pre-2 1.822m ± 11% 1.665m ± 37% ~ (p=0.353 n=10)
Track/direct/post-2 3.277m ± 22% 2.979m ± 35% ~ (p=1.000 n=10)
Track/direct/post-sync-2 4.354m ± 16% 4.175m ± 15% ~ (p=0.165 n=10)
geomean 1.568m 1.540m -1.82%
│ head │
│ sys-ns/op │
Startup/floor-2 0.000 ± ∞ ¹
¹ need >= 6 samples for confidence interval at level 0.95
Δ compares medians; ~ means no significant difference (Mann-Whitney U, p ≥ 0.05). A scenario is flagged when it is more than 10% and more than 250µs slower with p < 0.05. Startup/floor runs true, not shelltime: it is an A/A check of runner noise. Runner: linux/amd64, Intel(R) Xeon(R) Processor. go1.27.1, 10 rounds × 100 execs per scenario and binary.
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 1 file with indirect coverage changes 🚀 New features to boost your workflow:
|
☁️ Claude Code cloud · Add explicit Claude Code cloud-session trackingAdded explicit Claude Code cloud-session metadata across the CLI, server, and web UI, including remote session IDs and test coverage, then ran repository reviews and addressed valid findings.
94.1M tokens: 43K input · 207.5K output · 92.7M cache read · 1.1M cache write 📝 AI summaryImplemented first-class cloud-session tracking based on the documented Claude Code cloud environment variables. The CLI model in Extended the server-side session and summary models in View this session on ShellTime → Updated 2026-10-23 10:29 UTC by ShellTime · totals for the whole session so far · the session page is visible to its owner |
|
@claude review Generated by Claude Code |
|
Claude finished @AnnatarHe's task in 23s —— View job Review of #330: mark Claude Code cloud session telemetryI read the full diff ( Verdict: looks good. The change is small and well tested. I have one inaccuracy to fix and a few optional notes. Findings
The --- · branch |
…butes Metrics added ccr.session.id after the data point's own attributes, so a data point already at the 64-attribute cap dropped it. It is now seeded before them, like on events; a ccr.session.id on the data point still wins. Also covers a blank CLAUDE_CODE_REMOTE_SESSION_ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qinc9uT7wXFFuo7yaKBHKq
|
Thanks for the review. Responses by finding number:
Generated by Claude Code |
What
Claude Code cloud sessions (claude.ai/code) are tracked through the setup in the cloud tracking guide, but nothing marks them as cloud sessions. This adds the CLI part of marking them.
ccr.session.id, which is the VM'sCLAUDE_CODE_REMOTE_SESSION_ID(cse_…). The daemon already forwards it inattributes.CLAUDE_CODE_REMOTE=trueandCLAUDE_CODE_REMOTE_SESSION_ID.NewAICodeOtelProcessornow reads them once withmodel.CloudSessionIDFromEnv. It addsccr.session.idto Claude Code events and metrics that don't carry one.ot1:ids hash the OTLP proto, so they don't change.CLAUDE_CODE_REMOTEis nevertruelocally.The server side (storing the id on the session summary, GraphQL
isCloud/cloudSessionUrl, the PR comment heading) is in a separate server PR.Fact check
There is no
CLAUDE_CODE_CLOUD. Cloud environments documentsCLAUDE_CODE_REMOTEandCLAUDE_CODE_REMOTE_SESSION_ID. Monitoring listsccr.session.idamong the standard attributes. I checked both inside a running cloud session (Claude Code 2.1.308) and in the environment of the daemon its hook started.Tests
TestCloudSessionIDFromEnv(model) andTestCloudSessionIDFallback(daemon): the id is filled in when missing, Claude Code's value wins, metrics get it too, Codex is untouched, and nothing is added locally.daemon/main_test.goclears both variables. Without it, existing tests that compare whole attribute maps fail when the suite runs inside a cloud session.go vet ./...is clean.go test ./daemon/ ./model/ ./stloader/passes../commands/(TestTrackTestSuite) fails in this cloud VM with or without this change, because a real daemon owns/tmp/shelltime.sockthere.Generated by Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.