AI Assistant

Analytics & Plugins

This page covers the supporting services that provide feature flags, analytics tracking, plugin lifecycle management, policy enforcement, tips, and tool use summaries.

Feature Flags (GrowthBook)

Location: src/services/analytics/growthbook.ts

Claude Code uses GrowthBook for feature flags and A/B experiments. The integration supports remote evaluation with local caching for non-blocking reads.

User Attributes

Feature targeting uses a set of user attributes:

idstring

Unique user identifier.

sessionIdstring

Current session identifier.

platform'win32' | 'darwin' | 'linux'

Operating system platform.

organizationUUIDstring

Organization identifier for org-scoped targeting.

subscriptionTypestring

Subscription tier (Free, Pro, Max, Team, Enterprise).

rateLimitTierstring

Rate limit tier for capacity-based targeting.

appVersionstring

CLI version for progressive rollouts.

Cached Feature Values

Two primary access patterns are used throughout the codebase:

// Boolean feature flag (cached, non-blocking)
getFeatureValue_CACHED_MAY_BE_STALE('feature_key', false)

// Dynamic config object (cached, non-blocking)
getDynamicConfig_CACHED_MAY_BE_STALE<ConfigType>('config_key', {})

The _CACHED_MAY_BE_STALE suffix is a deliberate naming convention that reminds callers the value may be stale. Feature values are refreshed in the background but reads always return immediately from cache.

Blocking Initialization

For features that must be resolved before proceeding (rare), a blocking variant exists:

getDynamicConfig_BLOCKS_ON_INIT('config_key', defaultValue)

Experiment Tracking

When a user is enrolled in an experiment, exposure data is stored and logged:

type StoredExperimentData = {
  experimentId: string
  variationId: number
  inExperiment?: boolean
  hashAttribute?: string
  hashValue?: string
}

Exposures are forwarded to the first-party event logging system for analysis.

Analytics Event Logging

Location: src/services/analytics/index.ts

The analytics service provides a zero-dependency event logging API. Events are queued until the analytics sink is attached during initialization.

Design Principles

  • No import dependencies: Prevents import cycles across the codebase
  • Queue-then-flush: Events logged before initialization are queued and replayed
  • PII safety: String values require explicit type casting (AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) to verify no sensitive data is logged
  • Proto fields: Keys prefixed with _PROTO_ are routed to PII-tagged columns and stripped before general-access backends

Usage

import { logEvent } from '../analytics/index.js'

logEvent('tengu_api_retry', {
  attempt: 3,
  delayMs: 2000,
  status: 429,
})

Sink Architecture

The analytics sink routes events to multiple backends:

  • Datadog: Real-time metrics and dashboards (datadog.ts)
  • First-party event logging: Structured event export to internal analytics (firstPartyEventLogger.ts)
  • Sink killswitch: Remote ability to disable analytics if needed (sinkKillswitch.ts)

Plugin Installation Manager

Location: src/services/plugins/PluginInstallationManager.ts

The PluginInstallationManager handles automatic installation and reconciliation of plugins and marketplaces from trusted sources without blocking startup.

Marketplace Reconciliation

The manager reconciles declared marketplaces against materialized (installed) ones:

  1. Diff: Compare declared marketplaces against installed versions
  2. Install missing: Clone new marketplaces that aren't installed yet
  3. Update changed: Update marketplaces whose source has changed
  4. Refresh plugins: After new installs, refresh active plugins to pick up new tools, agents, LSP servers, and hooks

Installation Status

Plugin installation status is tracked in AppState.plugins.installationStatus:

type MarketplaceStatus = {
  name: string
  status: 'pending' | 'installing' | 'installed' | 'failed'
  error?: string
}

Post-Install Refresh

After marketplace reconciliation completes:

  • New installs: Automatically refresh plugins (fixes "plugin-not-found" errors from the initial cache-only load)
  • Updates only: Set needsRefresh flag and show a notification to run /reload-plugins

The broader plugin system (in utils/plugins/) supports:

  • Install: Clone a marketplace or install a specific plugin
  • Enable: Activate a plugin so its tools, agents, hooks, MCP servers, and LSP servers are loaded
  • Disable: Deactivate a plugin without removing it
  • Remove: Uninstall a plugin and clean up its resources
  • Reload: Refresh plugin caches and re-initialize dependent services (MCP, LSP)

Policy Limits Service

Location: src/services/policyLimits/

The policy limits service fetches organization-level restrictions from the API and uses them to disable CLI features. It follows the same patterns as remote managed settings.

Key Properties

PropertyValue
Fetch timeout10 seconds
Polling interval1 hour
Max retries5
Cache file~/.claude/policy-limits.json
Failure modeFail-open (non-blocking)

Eligibility

Console users (API key)All

All console users with API keys are eligible for policy limits.

OAuth users (Claude.ai)Team/Enterprise only

Only Team and Enterprise/C4E subscribers receive policy restrictions.

Policy limits fail open: if the fetch fails, the CLI continues without restrictions. This prevents a backend outage from blocking all users.

Tips Service

Location: src/services/tips/

The tips service shows contextual usage tips to help users discover CLI features.

tipRegistry.tsTipRegistry

Defines available tips with conditions for when they should be shown (e.g., multiple concurrent sessions, specific model in use, IDE detected).

tipScheduler.tsTipScheduler

Determines when and how often tips are displayed, preventing tip fatigue.

tipHistory.tsTipHistory

Tracks which tips have been shown to avoid repetition.

Tool Use Summary

Location: src/services/toolUseSummary/toolUseSummaryGenerator.ts

The tool use summary generator creates human-readable one-line summaries of completed tool batches. Primarily used by the SDK to provide high-level progress updates to clients.

How It Works

  1. Receives a list of tools with their inputs and outputs
  2. Sends a prompt to the Haiku model with a system prompt focused on brevity
  3. Returns a git-commit-style summary (under 30 characters)

Example Summaries

Searched in auth/
Fixed NPE in UserService
Created signup endpoint
Read config.json
Ran failing tests

The system prompt instructs the model to use past tense, keep the most distinctive noun, and drop articles and connectors.

export async function generateToolUseSummary({
  tools,
  signal,
  isNonInteractiveSession,
  lastAssistantText,
}: GenerateToolUseSummaryParams): Promise<string | null>