Skip to content

[STG-2445] feat(cli): classify execution environment in telemetry#2293

Open
shrey150 wants to merge 2 commits into
mainfrom
shrey/cli-env-telemetry
Open

[STG-2445] feat(cli): classify execution environment in telemetry#2293
shrey150 wants to merge 2 commits into
mainfrom
shrey/cli-env-telemetry

Conversation

@shrey150

@shrey150 shrey150 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

STG-2445

What & why

The CLI's anonymous telemetry can't be segmented by where it runs, so "real user" metrics are reconstructed each window via fragile behavioral fingerprinting (one-day + linux + node-version) that drifts. This adds self-reported execution-environment properties so events segment at the source (human vs CI vs container vs sandbox).

Changes

  • New packages/cli/src/lib/environment.tsclassifyEnvironment(){ is_container, is_tty, runtime_provider }, memoized (env is static per process), mirrors agent.ts.
    • is_ttystd-env hasTTY; is_container/.dockerenv / /run/.containerenv; runtime_providerstd-env provider, else an env-var allowlist for agent sandboxes (E2B_SANDBOX→e2b, MODAL_SANDBOX_ID/MODAL_TASK_ID→modal, DAYTONA_SANDBOX_ID→daytona, CODESPACES, GITPOD_WORKSPACE_ID, REPL_ID), else unknown.
  • telemetry.ts — spread classifyEnvironment(env) into baseProperties so the props ride every cli.* event. TelemetryProperties already allows the types — no schema change.
  • Dependency: std-env (only new dep; tier-1, runs from node_modules).
  • Tests (tests/cli-telemetry.test.ts) + changeset (browse: patch).

Purely additive — no change to what is collected: CI suppression is untouched and there is intentionally no is_ci (CI events are already suppressed; see notes). The rollup (environment_type) is derived downstream in PostHog, not shipped.

E2E Test Matrix

Command / flow Observed output Confidence / sufficiency
pnpm --filter browse test (vitest) 16/16 pass (14 existing + 2 new) proves the new props ride emitted events and the sandbox env-var classification works end-to-end via the local telemetry-capture server
pnpm --filter browse lint + tsc --noEmit clean type-safe; no lint regressions
built CLI, baseline shell {is_container:false, is_tty:false, runtime_provider:"unknown"} correct default (agent, no TTY, macOS, no provider)
E2B_SANDBOX=true → built classifyEnvironment() runtime_provider:"e2b" allowlist classification verified
CODESPACES=true → built classifyEnvironment() runtime_provider:"codespaces" allowlist classification verified
Probe run inside real Docker / E2B / Daytona / Modal is_tty=false in all; /.dockerenvis_container=true (Docker, Daytona); E2B/Modal microVMs have no /.dockerenv → resolved via env var; egress to PostHog reached from sandboxes the detection design validated in the real environments it targets (microVMs confirmed to need the env-var allowlist, not the container check)

Notes

  • CI telemetry is currently suppressed (isTelemetryDisabledisCiEnvironment), so is_ci would be ~always-false in the data; this PR deliberately omits it. "Tag-and-keep CI" (stop suppressing, add is_ci) is a separate, deliberate collection-scope decision.
  • DAYTONA_SANDBOX_ID is observed live but undocumented (best-effort).

🤖 Generated with Claude Code


Summary by cubic

Tag anonymous CLI telemetry with execution-environment properties so events can be segmented by where the CLI runs (container, sandbox, interactive). Addresses STG-2445 by removing fragile behavior-based fingerprinting; classification only runs when telemetry is enabled.

  • New Features

    • Add classifyEnvironment() in packages/cli/src/lib/environment.ts returning is_container, is_tty, and runtime_provider (memoized per process).
    • Attach these props to all CLI telemetry events via telemetry.ts base properties; gated by telemetryEnabled to avoid filesystem checks when opted out; no schema change.
    • Detection: TTY from std-env hasTTY; container via /.dockerenv or /run/.containerenv; provider from std-env provider or sandbox env vars (E2B_SANDBOX, MODAL_SANDBOX_ID/MODAL_TASK_ID, DAYTONA_SANDBOX_ID, CODESPACES, GITPOD_WORKSPACE_ID, REPL_ID).
  • Dependencies

    • Add std-env ^4.1.0.

Written for commit 82a8f0c. Summary will update on new commits.

Review in cubic

Add is_container, is_tty, and runtime_provider to anonymous CLI
telemetry so events segment by where the CLI runs (container /
sandbox / interactive) at the source, instead of fragile behavioral
fingerprinting. runtime_provider is derived from std-env plus an
env-var allowlist for agent sandboxes (e2b, modal, daytona,
codespaces, gitpod, replit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 82a8f0c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 6 files

Confidence score: 3/5

  • In packages/cli/src/lib/telemetry.ts, classifyEnvironment still runs when telemetry is opted out, which can collect new environment signals despite user intent and create privacy/compliance risk if merged as-is — gate classifyEnvironment behind telemetryEnabled before merging.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/lib/telemetry.ts">

<violation number="1" location="packages/cli/src/lib/telemetry.ts:175">
P2: Opted-out telemetry still classifies the execution environment. Gate classifyEnvironment behind telemetryEnabled so disabled telemetry does not collect new environment signals at all.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant CLI as CLI Command
    participant Telemetry as TelemetryService
    participant Classifier as EnvironmentClassifier
    participant StdEnv as std-env
    participant FS as FileSystem
    participant Env as ProcessEnv

    Note over CLI,Telemetry: CLI Anonymous Telemetry Flow (NEW: environment classification)

    CLI->>Telemetry: invoke command → create telemetry
    Telemetry->>Telemetry: build baseProperties

    Telemetry->>Classifier: classifyEnvironment(env) [NEW]
    Classifier->>Classifier: check memoized cache

    alt First call (cache miss)
        Classifier->>FS: detectContainer(): existsSync("/.dockerenv")
        FS-->>Classifier: false (typical host)
        Classifier->>FS: detectContainer(): existsSync("/run/.containerenv")
        FS-->>Classifier: false

        Classifier->>StdEnv: hasTTY
        StdEnv-->>Classifier: false (piped/CI)

        Classifier->>StdEnv: provider
        alt StdEnv provider exists (e.g., GITHUB_ACTIONS)
            StdEnv-->>Classifier: "github_actions"
        else No std-env provider
            Classifier->>Env: iterate sandbox vars [E2B_SANDBOX, MODAL_SANDBOX_ID, ...]
            alt Sandbox var found
                Env-->>Classifier: "e2b" (e.g., E2B_SANDBOX=true)
            else No match
                Env-->>Classifier: "unknown"
            end
        end

        Classifier->>Classifier: memoize result
    end

    Classifier-->>Telemetry: { is_container, is_tty, runtime_provider }

    Telemetry->>Telemetry: spread into baseProperties
    Note over Telemetry: All subsequent cli.* events carry these properties

    Telemetry-->>CLI: telemetry ready (events sent to PostHog)

    Note over CLI,Env: Unchanged: CI suppression remains, no is_ci property
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/cli/src/lib/telemetry.ts Outdated
Skip classifyEnvironment() filesystem checks when telemetry is opted
out, matching the existing gating of install-id and agent detection in
createCliTelemetry. No behavior change for enabled telemetry; opted-out
users already send zero events.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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