MCP Commands Reference
NR AI Coding Observability: Preflight — MCP Commands Reference
Every MCP tool exposed by the preflight, what it returns, how it computes each finding, and which trackers it queries.
Tools are conditionally registered — each tool only appears when its required tracker dependencies are provided to registerTools().
Session Tools
nr_observe_health
Check server health and connection status.
Parameters: None
Returns:
{ "status": "ok", "version": "1.0.0", "developer": "alice", "session_id": "uuid-string", "connected_at": "2026-06-03T10:00:00.000Z", "uptime_seconds": 3600, "hooks_installed": true, "setup_required": false, "event_send_status": "ok", "consecutive_event_send_failures": 0}Data source: Server startup metadata
How it works: Returns the current server version, the resolved developer name, how long the server has been running (uptime_seconds), the current session ID, and the ISO timestamp of when the MCP connection was established. Use this to confirm the MCP server is responsive and to verify the expected developer identity is being used. When a hook-detection function is available (e.g. in a Claude Code environment), also reports hooks_installed and setup_required so the caller can detect an incomplete setup — for example, right after a Smithery-driven install that only wired up the MCP server — and prompt to call nr_observe_install_hooks. Both fields are omitted when hook detection isn’t wired up for the current server mode. When event-send health tracking is available, also reports event_send_status ('ok' or 'failing') and consecutive_event_send_failures — the number of consecutive failed attempts to send telemetry events to New Relic — so the caller can detect a broken ingest path. Both fields are omitted when event-send health tracking isn’t wired up for the current server mode.
Requires: Always available
Source: src/tools/session-stats.ts
nr_observe_install_hooks
Install PreToolUse and PostToolUse monitoring hooks into ~/.claude/settings.json, headlessly (no TTY required).
Parameters: None
Returns:
{ "status": "installed", "message": "Monitoring hooks installed at /Users/alice/.claude/settings.json. Restart Claude Code to activate tool monitoring.", "settings_path": "/Users/alice/.claude/settings.json"}Data source: Reads and writes ~/.claude/settings.json directly
How it works: Call this when nr_observe_health reports setup_required: true — most commonly after installing Preflight via the Smithery MCP registry, which wires up the MCP server but has no mechanism to write Claude Code hooks. Returns status: "already_installed" if hooks are already present (no changes made), or status: "error" with a message if the settings file couldn’t be written. Only touches hook configuration in ~/.claude/settings.json — never modifies ~/.mcp.json. A Claude Code restart is required after installation for monitoring to activate.
Requires: A headless installer wired into ToolRegistrationOptions.headlessInstaller (available in the standard MCP server startup path)
Source: src/tools/session-stats.ts
nr_observe_get_config
Show the current server configuration with sensitive fields masked.
Parameters: None
Returns:
{ "mode": "cloud", "developer": "alice", "accountId": "12345", "licenseKeyMasked": "aabbccdd...NRAL", "nrApiKeyMasked": "NRAK-****", "region": "US", "storagePath": "/Users/alice/.newrelic-preflight", "dashboardUrl": "https://one.newrelic.com/dashboards/...", "configFilePath": "/Users/alice/.newrelic-preflight/config.json"}Data source: Server config at startup
How it works: Returns a sanitized snapshot of the active configuration. licenseKeyMasked shows the first 8 characters and last 4 characters only. nrApiKeyMasked shows the prefix only. Use this to diagnose misconfiguration (wrong region, unset developer name, unexpected mode) without exposing credentials.
Requires: Always available
Source: src/tools/session-stats.ts
nr_observe_get_session_stats
Current session metrics snapshot.
Parameters: None
Returns:
{ "identity": { "developer": "alice", "teamId": "backend-team", "projectId": "my-app" }, "session_trace_id": "uuid-string-or-null", "session_id": "string", "session_name": "my-project", "session_duration_ms": 0, "tool_calls": 0, "tool_calls_by_type": { "Read": 5, "Edit": 3 }, "success_rate": 0.95, "failed_calls": 1, "unique_files_read": 12, "unique_files_modified": 4, "bash_commands_run": 7, "search_queries": 3, "avg_tool_duration_ms": 45}Data source: SessionTracker
How each field is determined:
identity.developer— resolved developer name from config (normalised bynormalizeDeveloperName()). Defaults to"unknown"when not configured. Use this to confirm at runtime which identity is being attached to NR events.identity.teamId/identity.projectId— team and project identifiers from config.nullwhen not configured.projectIdis auto-derived from the git remote URL when unset.session_trace_id— UUID generated at server startup viarandomUUID(); threaded through every NR event, metric, and log entry emitted in this session. UseWHERE session_id = '<value>'in NRQL to query all telemetry for a single session.nullif the server was started without trace ID support.session_name— display name derived from the working directory path at session start (e.g. the repo folder name).nullif not available.tool_calls— running count incremented on eachrecordToolCall()tool_calls_by_type— per-tool-name counter mapsuccess_rate—successCount / totalCountfailed_calls— count of records wheresuccess === falseunique_files_read— size of Set collecting file paths from Read/Grep/Glob toolsunique_files_modified— size of Set collecting file paths from Write/Edit toolsbash_commands_run— count of Bash tool callssearch_queries— count of Grep/Glob tool callsavg_tool_duration_ms—sum(allDurations) / count(allDurations)across all tools
Requires: SessionTracker
Source: src/tools/session-stats.ts
nr_observe_get_session_timeline
Ordered list of recent tool calls.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
last_n |
number | 20 | Number of most recent tool calls to return |
Returns:
{ "timeline": [ { "timestamp": "2026-04-21T10:30:00.000Z", "tool": "Read", "duration_ms": 30, "success": true } ]}Data source: SessionTracker
How it works: Returns the last N entries from SessionTracker.getMetrics().toolCallTimeline, converting timestamps to ISO format. The timeline is a FIFO array of all tool calls recorded in the session.
Requires: SessionTracker
Source: src/tools/session-stats.ts
Cost Tools
nr_observe_report_tokens
Self-report token usage for cost tracking. Called by Claude Code to report its own token consumption.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
input_tokens |
number | Yes | Input/prompt token count |
output_tokens |
number | Yes | Output/completion token count |
model |
string | Yes | Model identifier (e.g., claude-sonnet-4-20250514) |
thinking_tokens |
number | No | Extended thinking token count |
cache_read_tokens |
number | No | Prompt cache read token count |
cache_creation_tokens |
number | No | Prompt cache creation token count |
Returns:
{ "recorded": true, "cost_this_report_usd": 0.0042, "session_total_cost_usd": 0.15, "model": "claude-sonnet-4-20250514"}Data source: CostTracker
How it works:
- Constructs a
TokenUsageobject from the reported counts - Calls
CostTracker.recordTokenUsage(usage, model)which looks up per-token prices from the pricing table (src/shared/pricing-data.ts) - Cost breakdown:
inputCost = inputTokens * inputPricePerToken, similarly for output, thinking, cache read, and cache creation tokens - Accumulates into session total and per-model totals
- Returns both the cost for this specific report and the running session total
Requires: CostTracker
Source: src/tools/cost-tools.ts
nr_observe_get_cost_breakdown
Session cost breakdown by task, model, and efficiency.
Parameters: None
Returns:
{ "total_usd": 0.52, "by_model": { "claude-sonnet-4-20250514": 0.4, "claude-haiku-4-5-20251001": 0.12 }, "by_task": [{ "task_id": "task-001", "cost_usd": 0.25, "tokens_used": 15000 }], "cost_per_line_of_code": 0.003, "cost_per_file_modified": 0.065, "cost_per_million_tokens": 7.43, "tokens": { "input": 50000, "output": 20000, "thinking": 10000 }, "rate_multiplier_applied": 1}Data source: CostTracker, TaskDetector (optional)
How each field is determined:
total_usd— sum of all token cost reports in the sessionby_model— per-model accumulator updated on eachreportTokenscallby_task— mapsTaskDetector.getCompletedTasks()to theirestimatedCostUsdandtokensUsedcost_per_line_of_code—totalCost / totalLinesChanged(null if no lines changed)cost_per_file_modified—totalCost / uniqueFilesWritten(null if no files modified)cost_per_million_tokens— blended session rate:(totalCost / totalTokens) * 1_000_000, summed across input, output, thinking, cache-read, and cache-creation tokens (null if no tokens reported). Not shipped as its own NR metric — it’s a pure ratio ofai.cost.session_total_usdand theai.cost.tokens_*counts already emitted, so it’s more flexibly computed in NRQL at query time (sum(cost)/sum(tokens)*1e6, facetable by any dimension) than as a pre-baked gauge.tokens— running totals by token type from all reportsrate_multiplier_applied—1unlesscostRateMultiplier/dataResidencyPremiumare configured (see ADVANCED.md), in which case every dollar figure above already reflects that correction. Preflight’s cost figures are always its own estimate from token counts × a pricing table, never a real invoice — this field only tells you whether that estimate has been adjusted toward an org’s actual contracted rate.
Requires: CostTracker; TaskDetector for per-task breakdown
Source: src/tools/cost-tools.ts
Workflow Tools
nr_observe_get_workflow_trace
Complete tool call trace for a task with anti-pattern and efficiency analysis.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
task_id |
string | most recent | ID of the task to trace |
Returns:
{ "task_id": "task-001", "duration_ms": 45000, "estimated_cost_usd": 0.25, "tool_calls": [ { "seq": 1, "tool": "Read", "target": "/src/index.ts", "duration_ms": 30, "success": true }, { "seq": 2, "tool": "Bash", "target": "npm test", "duration_ms": 5000, "success": true, "exit_code": 0 } ], "anti_patterns": [ { "type": "thrashing", "file": "/src/index.ts", "iterations": 4, "suggestion": "..." } ], "efficiency_score": 0.82}Data source: TaskDetector, AntiPatternDetector (optional), EfficiencyScorer (optional)
How it works:
- Finds the task by ID from
TaskDetector.getCompletedTasks(), or uses the most recent completed task - Maps each tool call in the task to a sequenced trace entry with
filePathorcommandas the target - If
AntiPatternDetectoris available, analyzes the task’s tool call sequence for anti-patterns - If
EfficiencyScoreris available, computes the task’s efficiency score
Requires: TaskDetector
Source: src/tools/workflow-tools.ts
nr_observe_get_anti_patterns
Detected anti-patterns for the most recent task.
Parameters: None
Returns:
[ { "type": "thrashing", "file": "/src/index.ts", "iterations": 4, "suggestion": "Consider a different approach" }, { "type": "re_reading", "file": "/src/config.ts", "read_count": 5, "suggestion": "Cache file contents" }]Data source: TaskDetector, AntiPatternDetector
Detection algorithms (5 pattern types):
| Pattern | How Detected | Default Threshold |
|---|---|---|
| Thrashing | Tracks Edit/Write → Bash(test:FAIL) cycles on the same file. Counts consecutive failures. Resets on test pass. |
3 consecutive failures |
| Re-reading | Counts Read calls per file path. Flags files read more than the threshold. |
3 reads of same file |
| Stuck loop | Detects repeated Bash commands with identical arguments. |
3 identical commands |
| Blind editing | Counts consecutive Edit/Write calls without an intervening Read or test run. |
3 edits without verification |
| Over-delegation | Counts Agent tool spawns in a single task. |
3 agent spawns |
Each detected pattern includes a suggestion field with a human-readable recommendation.
Requires: TaskDetector, AntiPatternDetector
Source: src/tools/workflow-tools.ts, src/metrics/anti-patterns.ts
nr_observe_get_efficiency_score
Composite efficiency score for the most recent task and session average.
Parameters: None
Returns:
{ "latest": { "score": 0.82, "components": { "speed": 0.7, "correctness": 1.0, "autonomy": 0.9, "firstAttemptQuality": 0.6 }, "task_id": "task-001", "timestamp": 1713700000000 }, "session_average": { "score": 0.78, "components": { "speed": 0.65, "correctness": 0.95, "autonomy": 0.85, "firstAttemptQuality": 0.7 }, "tasks_scored": 5 }}Data source: EfficiencyScorer, TaskDetector (optional), AntiPatternDetector (optional)
Scoring algorithm (4 equally-weighted components, each 0–1):
| Component | Formula | Baseline |
|---|---|---|
| Speed | linesChanged / (durationMs / 1000) normalized against baseline |
1 line/second = 1.0 |
| Correctness | testsPassed / testsRun |
0.5 if no tests were run |
| Autonomy | 1 - (askedUserQuestions / toolCallCount) |
1.0 if no questions asked |
| First-attempt quality | 1 - (thrashIterations / 3), floored at 0 |
1.0 if no thrashing detected |
Final score = weighted average of all four components, clamped to [0, 1].
On-demand scoring: When called, the handler scores any unscored completed tasks and always rescores the active task (since it grows over time). Session average is the mean score across all scored tasks.
Requires: EfficiencyScorer
Source: src/tools/workflow-tools.ts, src/metrics/efficiency-score.ts
nr_observe_report_feedback
Record user quality feedback for a task.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
quality |
string | Yes | "good", "bad", or "neutral" |
notes |
string | No | Free-text notes about the task quality |
task_id |
string | No | Task ID to attach feedback to (default: most recent) |
Returns:
{ "recorded": true, "quality": "good", "task_id": "task-001", "timestamp": 1713700000000}Data source: FeedbackCollector
How it works: Records the feedback with a timestamp. The FeedbackCollector stores all feedback records in memory and can emit ai.feedback.count metrics (keyed by quality) via the MetricAggregator. Used to correlate efficiency metrics with perceived quality.
Requires: FeedbackCollector
Source: src/tools/workflow-tools.ts
nr_observe_mark_task_boundary
Explicitly mark the end of the current task. This is the universal task-boundary signal — call it on any platform, but it’s the only boundary signal on platforms other than Claude Code, which also infers boundaries from its own AskUserQuestion/TaskUpdate tool calls.
Parameters: None
Returns:
{ "recorded": true, "closed_task_id": "task-001"}closed_task_id is null if no task was active.
Data source: TaskDetector
How it works: Calls TaskDetector.markBoundary(), which closes the active task (if any) the same way the AskUserQuestion/TaskUpdate boundary signals do — computing the cost/token delta since task start, appending the completed task to history, and clearing the active task. Improves the accuracy of anti-pattern, efficiency-score, and cost-per-outcome metrics, which all segment activity by task.
Requires: TaskDetector
Source: src/tools/workflow-tools.ts, src/metrics/task-detector.ts
Cross-Session Tools
These tools query persisted session data from disk (~/.newrelic-preflight/sessions/). They are only registered when SessionStore and related analyzers are available.
nr_observe_get_session_history
Paginated list of past sessions with summary metrics.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
since |
string | — | ISO date to filter from (e.g., "2026-04-01") |
developer |
string | — | Filter by developer name |
limit |
number | 20 | Maximum sessions to return |
Returns:
{ "sessions": [ { "session_id": "sess-abc", "developer": "alice", "start_time": "2026-04-21T10:00:00.000Z", "duration_ms": 300000, "tool_calls": 45, "efficiency_score": 0.82, "estimated_cost_usd": 0.35, "task_count": 3, "outcome": "completed", "model": "claude-sonnet-4-20250514" } ], "count": 1}Data source: SessionStore
How it works: Loads all session summary JSON files from ~/.newrelic-preflight/sessions/, applies optional date and developer filters, returns the last N sessions ordered by start time.
Requires: SessionStore
Source: src/tools/cross-session-tools.ts
nr_observe_get_weekly_summary
Weekly aggregate report with per-developer breakdown.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
week |
string | current week | ISO week (e.g., "2026-W16") or "latest" |
Returns: JSON object with weekly aggregates including per-developer metrics, total cost, average efficiency, test pass rates, tool call counts, and anti-pattern tallies by type.
Data source: WeeklySummaryGenerator
How it works:
- Resolves the target week (current ISO week if not specified or
"latest") - Loads or generates the weekly summary by aggregating all sessions in that week
- Groups metrics by developer
- Computes: average efficiency, total cost, test pass rates, tool call counts, anti-pattern counts
Requires: WeeklySummaryGenerator
Source: src/tools/cross-session-tools.ts
nr_observe_get_trends
Metric trends over time, aggregated by ISO week.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
metric |
string | "efficiency" |
"efficiency", "cost", "task_success", or "tool_calls" |
developer |
string | — | Filter by developer name |
weeks |
number | 8 | Number of weeks to include |
Returns:
{ "metric": "efficiency", "weeks": 8, "data_points": [ { "week": "2026-W14", "value": 0.72 }, { "week": "2026-W15", "value": 0.78 } ]}Data source: TrendAnalyzer
How each metric is aggregated per week:
| Metric | Aggregation |
|---|---|
efficiency |
Mean of efficiencyScore across sessions in the week |
cost |
Sum of estimatedCostUsd across sessions in the week |
task_success |
Mean of taskSuccessRate across sessions in the week |
tool_calls |
Mean of toolCallCount across sessions in the week |
Requires: TrendAnalyzer
Source: src/tools/cross-session-tools.ts
nr_observe_get_collaboration_profile
Developer collaboration style profile with team comparison.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
developer |
string | "unknown" |
Developer name |
Returns:
{ "developer": "alice", "classification": "Power User", "dimensions": { "specificity": 0.8, "autonomy": 0.9, "correctionRate": 0.1, "taskComplexity": 0.6 }, "session_count": 25, "team_comparison": { "specificity": 0.15, "autonomy": 0.1 }}Data source: CollaborationProfiler
Dimension calculations:
| Dimension | How Computed |
|---|---|
| Specificity | Estimated from tool call patterns and file modification specificity |
| Autonomy | 1 - (userCorrections / taskCount) — how often the developer redirects the AI |
| Correction rate | corrections / sessionCount — frequency of course corrections |
| Task complexity | (toolCallsPerTask * filesModifiedPerTask) / baseline |
Classification rules:
| Classification | Rule |
|---|---|
| Power User | specificity > 0.7 AND autonomy > 0.7 |
| Delegator | specificity < 0.3 AND autonomy > 0.7 |
| Learning | specificity < 0.3 AND correctionRate > 0.5 |
| Collaborative | All others |
Team comparison shows the delta between this developer’s dimensions and the team average.
Requires: CollaborationProfiler
Source: src/tools/cross-session-tools.ts, src/metrics/collaboration-profile.ts
nr_observe_get_claudemd_impact
Before/after impact analysis of the most recent CLAUDE.md change.
Parameters: None
Returns:
{ "change": { "file": "CLAUDE.md", "type": "modified", "timestamp": "2026-04-21T10:00:00.000Z" }, "before": { "avgEfficiencyScore": 0.72, "avgCostUsd": 0.45, "sessionCount": 10 }, "after": { "avgEfficiencyScore": 0.85, "avgCostUsd": 0.38, "sessionCount": 8 }, "deltas": { "efficiencyScore": { "value": 0.13, "percentChange": 18.1 } }, "context_tokens": 1250, "verdict": "Positive impact"}Data source: ClaudeMdTracker
How it works:
- Detects CLAUDE.md changes by monitoring Write/Edit tool calls targeting
CLAUDE.mdor.claude/files - Partitions sessions into before/after windows around the change timestamp
- Computes aggregate metrics for each window (average efficiency, cost, correction rate, tool calls per task, task success rate)
- Calculates deltas with percent change
- Estimates context token cost:
charCount * 0.25(tokens-per-char heuristic) - Generates verdict: compares the top changed metrics — “Positive impact” if 2+ improved, “Negative impact” if 2+ degraded, “Mixed impact” otherwise
Requires: ClaudeMdTracker
Source: src/tools/cross-session-tools.ts, src/metrics/claudemd-tracker.ts
nr_observe_get_cost_per_outcome
Cost attribution by outcome type with waste ratio and ROI estimate.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
since |
string | — | ISO date to filter tasks from |
Returns:
{ "outcome_distribution": { "bug_fix": { "count": 3, "totalCost": 0.45, "avgCost": 0.15 }, "feature": { "count": 2, "totalCost": 0.8, "avgCost": 0.4 }, "failed_attempt": { "count": 1, "totalCost": 0.2, "avgCost": 0.2 } }, "waste_ratio": 0.12, "total_cost": 1.65, "total_tasks": 8, "roi_estimate": { "totalAiCost": 1.65, "estimatedHoursSaved": 12.5, "estimatedValueUsd": 937.5, "roi": 56718 }}Data source: CostPerOutcomeAnalyzer, TaskDetector
Outcome classification (priority order — first match wins):
| Outcome | Detection Rule |
|---|---|
failed_attempt |
Tests failed and never recovered within the task |
bug_fix |
Sequence: test FAIL → Edit → test PASS |
feature |
New files created (Write tool calls) |
configuration |
Only config files modified (.json, .yaml, .yml, .toml, etc.) |
documentation |
Only .md files modified |
investigation |
Mostly Read/Grep/Glob calls with few or no modifications |
refactor |
Default — existing files modified, tests pass |
ROI estimation:
- Hours saved per outcome type: bug_fix=2h, feature=4h, refactor=1.5h, investigation=0.5h, configuration=0.5h, documentation=1h, failed_attempt=0h
estimatedValueUsd = hoursSaved * hourlyRate(default: $75/hr)roi = (estimatedValueUsd - totalAiCost) / totalAiCost * 100wasteRatio = failedAttemptCost / totalCost
Requires: CostPerOutcomeAnalyzer, TaskDetector
Source: src/tools/cross-session-tools.ts, src/metrics/cost-per-outcome.ts
nr_observe_get_recommendations
Personalized optimization recommendations from multiple analyzers.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
developer |
string | "unknown" |
Developer name |
topN |
number | — | Maximum recommendations to return |
Returns:
{ "recommendations": [ { "id": "abc123", "category": "cost", "priority": "high", "title": "Reduce failed attempts", "detail": "12% of your spend is on tasks that ultimately failed.", "evidence": "3 failed tasks totaling $0.20", "estimatedSavings": "$0.15/week" } ], "count": 5}Data source: RecommendationEngine (aggregates from multiple sub-analyzers)
Recommendation categories and sources:
| Category | Source Analyzer | Example |
|---|---|---|
| Cost optimization | CostPerOutcomeAnalyzer |
“Reduce failed attempts” |
| Efficiency | TrendAnalyzer |
“Speed is declining week-over-week” |
| Prompt engineering | PromptFeedbackEngine |
“Multi-step tasks improve efficiency” |
| CLAUDE.md | ClaudeMdTracker |
“Update CLAUDE.md with task patterns” |
| Model selection | TrendAnalyzer |
“Consider switching to a faster model” |
Recommendations are deduplicated by ID (hash of title + category), sorted by priority (high > medium > low), and optionally limited to topN.
Requires: RecommendationEngine
Source: src/tools/cross-session-tools.ts, src/metrics/recommendation-engine.ts
nr_observe_get_personal_insights
Narrative coaching report comparing this week’s personal AI coding metrics against the developer’s historical baseline. Generates highlights, regressions, streaks, and a top recommendation as plain English strings — no LLM call is made; narrative is built from template expressions over computed deltas.
Parameters: None
Returns (when ≥ 2 weeks of history exist):
{ "status": "ok", "developer": "alice", "generatedAt": 1747526400000, "weeksAnalyzed": 4, "highlights": ["Your efficiency score this week (78) is 8 points above your historical average."], "regressions": ["Cost per session this week ($0.62) is 35% above your average ($0.46)."], "streaks": ["Efficiency score has improved for 3 consecutive weeks. Keep it up."], "topRecommendation": "Review your longest sessions this week and identify which tasks could be broken into smaller, more focused sessions.", "thisWeek": { "weekId": "2026-W20", "totalCostUsd": 6.2, "avgCostPerSession": 0.62, "avgEfficiencyScore": 78, "antiPatternCount": 4, "antiPatternRate": 0.02, "sessionsCount": 10, "avgToolCallsPerSession": 20, "topAntiPattern": "stuck_loop" }, "lastWeek": { "weekId": "2026-W19", "...": "same shape as thisWeek" }, "baseline": { "weekId": "baseline", "...": "mean across all loaded weeks" }}Returns (when fewer than 2 weeks exist):
{ "status": "insufficient_data", "developer": "alice", "weeksAvailable": 1, "weeksRequired": 2, "message": "Need at least 2 weeks of session history to generate personal insights. Currently have 1. Keep using the AI coding assistant and check back next week."}Data source: WeeklySummaryGenerator.loadRecentWeeks(8) — pulls up to 8 weeks of WeeklySummary from disk, filters to the configured developer, and ignores weeks with zero sessions for that developer.
How each section is determined:
| Section | Trigger |
|---|---|
highlights |
Efficiency ≥ 5 points above baseline; cost-per-session ≥ 15% below baseline; anti-pattern rate ≥ 20% below last week |
regressions |
Efficiency ≥ 5 points below baseline; cost-per-session ≥ 25% above baseline; anti-pattern rate ≥ 25% above baseline (with the dominant pattern named) |
streaks |
≥ 2 consecutive weeks of efficiency improvement, or ≥ 2 consecutive weeks of cost-per-session reduction (only when 3+ weeks of data exist) |
topRecommendation |
First non-empty match against: anti-pattern spike → cost spike → efficiency drop → first regression. If no regressions: positive reinforcement when efficiency ≥ 70, otherwise a generic “maintain patterns” message |
baseline is the mean of each metric across all loaded weeks (up to 8). topAntiPattern in the baseline is the pattern that appears most frequently as the per-week top anti-pattern.
Requires: WeeklySummaryGenerator and a configured developer identity (registered conditionally — the tool is omitted when either is missing).
Source: src/tools/cross-session-tools.ts, src/metrics/personal-coach.ts
nr_observe_get_platform_comparison
Side-by-side comparison of AI coding platforms on a given metric.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
metric |
string | "efficiency" |
"efficiency", "cost", "task_success", "tool_calls", or "error_rate" |
weeks |
number | 4 | Number of weeks to include |
Returns:
{ "metric": "efficiency", "weeks": 4, "platforms": { "claude-code": { "session_count": 20, "average": 0.78 }, "cursor": { "session_count": 5, "average": 0.65 } }}Data source: SessionStore
How each metric is computed per platform:
| Metric | Aggregation |
|---|---|
efficiency |
Mean of efficiencyScore across platform’s sessions |
cost |
Mean of estimatedCostUsd |
task_success |
Mean of taskSuccessRate |
tool_calls |
Mean of toolCallCount |
error_rate |
Mean of (1 - taskSuccessRate) |
Sessions are grouped by platform (defaults to "claude-code" if not set). Only sessions within the lookback window are included.
Requires: SessionStore
Source: src/tools/cross-session-tools.ts
Cost and Budget Tools
nr_observe_get_budget_status
Current spend against configured session/daily/weekly budget caps.
Parameters: None
Returns:
{ "session": { "budgetUsd": 5.0, "spentUsd": 2.15, "remainingUsd": 2.85, "pctUsed": 43, "exceeded": false }, "daily": { "budgetUsd": 10.0, "spentUsd": 4.32, "remainingUsd": 5.68, "pctUsed": 43, "exceeded": false }, "weekly": { "budgetUsd": 50.0, "spentUsd": 18.9, "remainingUsd": 31.1, "pctUsed": 38, "exceeded": false }}Data source: BudgetTracker
How it works:
- Tracks cumulative spend per period (session, day, week)
- Compares against thresholds from config:
sessionBudgetUsd,dailyBudgetUsd,weeklyBudgetUsd - Returns
nullfor any budget not configured - Returns
exceeded: truewhen spend >= budget
Requires: BudgetTracker
Config fields:
NEW_RELIC_AI_SESSION_BUDGET_USD— session spend limit in USDNEW_RELIC_AI_DAILY_BUDGET_USD— daily spend limit in USDNEW_RELIC_AI_WEEKLY_BUDGET_USD— weekly spend limit in USD
Source: src/tools/cost-tools.ts
nr_observe_get_prompt_cache_health
Cache hit rate, savings, and a concrete recommendation for improving cache efficiency. A high hit rate means more context is served cheaply from cache rather than priced as fresh input.
Parameters: None
Returns:
{ "status": "can_improve", "cache_hit_rate_pct": 42, "total_cache_read_tokens": 145000, "total_cache_creation_tokens": 12000, "total_savings_usd": 1.83, "recommendation": "Cache hit rate is 42%. To improve: place stable content (CLAUDE.md rules, recurring file reads) before variable content (user messages, dynamic tool results) in your prompts.", "data_quality": "self_reported"}Data source: CostTracker
How each field is determined:
status—no_cache_activitywhen no cache tokens have been reported yet; otherwiseexcellent(hit rate ≥ 60%),can_improve(≥ 30%), orneeds_attention(< 30%)cache_hit_rate_pct—round(cacheReadTokens / (inputTokens + cacheReadTokens + cacheCreationTokens) * 100);nullwhen no cache tokens have been seentotal_cache_read_tokens/total_cache_creation_tokens— running totals accumulated from every token reporttotal_savings_usd— sum ofsavingsFromCacheUsd(cache-read discount vs. full input price) across all reportsrecommendation— status-specific guidance string that includes the actual hit-rate percentagedata_quality—self_reportedwhen at least onereportTokenscall has been made this session, otherwiseestimated
Requires: CostTracker
Source: src/tools/cost-tools.ts
nr_observe_get_cost_forecast
Projects future spend based on current session burn rate. When this session was resumed after being stale, the response also includes a resumeContext field (resumeCount, totalEstimatedCacheWriteUsd, lastResume) — Claude Code’s own SessionStart report of how long it had been and its estimated cost to re-warm the prompt cache, sourced from SessionResumeTracker. Riding alongside the forecast as extra JSON; it never changes the forecast fields themselves.
Parameters: None
Returns:
{ "current_session": { "startTime": "2026-04-21T10:00:00.000Z", "elapsedMs": 3600000, "currentCostUsd": 0.45, "burnRateUsd_per_hour": 0.45 }, "projections": { "end_of_session": { "estimatedCostUsd": 0.9, "confidence": "medium", "basis": "Assumes 2-hour session" }, "end_of_day": { "estimatedCostUsd": 2.7, "confidence": "low", "basis": "Assumes 6 more hours of coding today" }, "end_of_week": { "estimatedCostUsd": 15.75, "confidence": "low", "basis": "Assumes 5 more days at current rate" } }}Data source: CostTracker, BudgetTracker, session start time
How it works:
- Computes
burnRateUsd_per_hour = currentCostUsd / elapsedHours - End-of-session projection: assumes typical 2-hour session, medium confidence
- End-of-day projection: assumes remaining hours until midnight at current burn rate, low confidence
- End-of-week projection: extrapolates 5 more days at current rate, low confidence
- Confidence decreases with longer horizons due to variability in work patterns
Requires: BudgetTracker, CostTracker
Source: src/tools/cost-tools.ts
Analytics Tools
nr_observe_get_context_efficiency
Context window efficiency: unique vs. repeated file reads.
Parameters: None
Returns:
{ "uniqueFilesRead": 12, "totalReadOperations": 28, "repeatedReadCount": 16, "repeatedReadRatio": 0.57, "topRepeatedFiles": [ { "file": "src/app.ts", "readCount": 5 }, { "file": "src/utils.ts", "readCount": 3 } ], "estimatedWasteRatio": 0.57}Data source: ContextWindowTracker
How it works:
- Tracks every Read tool call and the file path accessed
- Counts how many times each file was read
repeatedReadCount= sum of(readCount - 1)for files read > 1 timerepeatedReadRatio=repeatedReadCount / totalReadOperations- High ratio suggests the model is losing context and re-reading instead of retaining
Requires: ContextWindowTracker
Source: src/tools/analytics-tools.ts, src/metrics/context-window-tracker.ts
nr_observe_get_latency_percentiles
Tool call latency: p50, p95, p99 per tool type.
Parameters: None
Returns:
{ "global": { "p50": 45, "p95": 280, "p99": 1200 }, "by_tool": { "Read": { "p50": 25, "p95": 120, "p99": 450, "sample_count": 15 }, "Edit": { "p50": 60, "p95": 320, "p99": 2100, "sample_count": 8 }, "Bash": { "p50": 150, "p95": 800, "p99": 5000, "sample_count": 3 } }}Data source: LatencyTracker
How it works:
- Collects
durationMsfrom every tool call - Computes percentiles globally and per tool type
- Percentiles indicate typical (p50), slow (p95), and very slow (p99) performance
- Helps identify bottleneck tools
Requires: LatencyTracker
Source: src/tools/analytics-tools.ts, src/metrics/latency-tracker.ts
nr_observe_get_task_completion_rate
Task lifecycle tracking: completed vs. in-progress vs. abandoned.
Parameters: None
Returns:
{ "detected_tasks": 8, "completed": 6, "in_progress": 1, "abandoned": 1, "completion_rate": 0.75, "avg_duration_ms": 480000, "avg_tool_calls_per_task": 12}Data source: TaskCompletionTracker
How it works:
- Uses
TaskDetectoroutput to identify task boundaries - Tracks state transitions: new → in-progress → completed (or abandoned if work stops)
completion_rate=completed / (completed + abandoned)- Helps identify whether tasks are finishing successfully
Requires: TaskCompletionTracker, TaskDetector
Source: src/tools/analytics-tools.ts, src/metrics/task-completion-tracker.ts
nr_observe_get_model_usage
Which AI model was used per request, cost-efficiency per model, and any model switches during the session.
Parameters: None
Returns:
{ "byModel": { "claude-sonnet-4-6": { "requestCount": 25, "totalInputTokens": 120000, "totalOutputTokens": 45000, "totalCacheReadTokens": 15000, "totalCacheCreationTokens": 5000, "totalThinkingTokens": 0, "totalCostUsd": 0.42, "costPerMillionTokens": 2.27, "avgOutputTokensPerRequest": 1800 }, "claude-opus-4-7": { "requestCount": 3, "totalInputTokens": 20000, "totalOutputTokens": 8000, "totalCacheReadTokens": 2000, "totalCacheCreationTokens": 1000, "totalThinkingTokens": 0, "totalCostUsd": 0.18, "costPerMillionTokens": 5.81, "avgOutputTokensPerRequest": 2666.67 } }, "mostUsedModel": "claude-sonnet-4-6", "totalModelsUsed": 2, "switchCount": 2, "automaticSwitchCount": 1, "recentSwitches": [ { "timestamp": 1767225600000, "fromModel": "claude-sonnet-4-6", "toModel": "claude-opus-4-7", "source": "command", "requestedModel": "opus" }, { "timestamp": 1767225660000, "fromModel": "claude-opus-4-7", "toModel": "claude-sonnet-4-6", "source": "auto", "requestedModel": null } ]}Field notes:
costPerMillionTokens— per-model rate:(totalCostUsd / (totalInputTokens + totalOutputTokens + totalThinkingTokens + totalCacheReadTokens + totalCacheCreationTokens)) * 1_000_000(null if no tokens). Counts every billed token, so it is comparable with list prices and withnr_observe_get_cost_breakdown’s session-blendedcost_per_million_tokens.mostUsedModel— the model with the highestrequestCountswitchCount/automaticSwitchCount— totalPostModelSwitchevents seen this session, and the subset wheresource === 'auto'(a persistent automatic change, e.g. a sustained fallback — not a one-turn fallback-chain substitution, which Claude Code doesn’t fire this hook for)recentSwitches— the most recent switches (newest last, bounded to 100);requestedModelisnullfor an automatic switch or session-resume restore
Data source: ModelUsageTracker
How it works:
- Tracks
modelfield from each request (e.g., “claude-sonnet-4-6”) - Aggregates request count, input/output/thinking/cache tokens, and cost per model
- Picks
mostUsedModel(highest request count) - Records each Claude Code
PostModelSwitchhook event as a discrete switch (deliberate/modelchange, persistent automatic fallback, or resume) viarecordModelSwitch()
Requires: ModelUsageTracker
Source: src/tools/analytics-tools.ts, src/metrics/model-usage-tracker.ts
nr_observe_get_model_recommendation
Data-driven model recommendation ranked by historical efficiency score, cost, and task success rate across past sessions, both overall and broken down by task outcome type.
Parameters:
developer(optional) — Developer name to scope the ranking to; aggregate across all developers if omitted.since(optional) — ISO date string; only consider sessions on or after this date.
Returns:
{ "ranked": [ { "model": "claude-sonnet-4-20250514", "sessionCount": 25, "avgCostUsd": 0.04, "avgEfficiencyScore": 0.82, "avgTaskSuccessRate": 0.95 }, { "model": "claude-opus-4-20250805", "sessionCount": 12, "avgCostUsd": 0.08, "avgEfficiencyScore": 0.78, "avgTaskSuccessRate": 0.92 } ], "recommendedModel": "claude-sonnet-4-20250514", "confidence": "high", "byOutcome": [ { "outcome": "bug_fix", "ranked": [ { "model": "claude-sonnet-4-20250514", "sessionCount": 15, "avgCostUsd": 0.03, "avgEfficiencyScore": 0.85, "avgTaskSuccessRate": 0.97 } ], "recommendedModel": "claude-sonnet-4-20250514", "confidence": "high" } ], "generatedAt": 1746345600000}Field notes:
ranked— All models ranked by efficiency score (descending), with ties broken by lower cost. Models with no scored sessions (avgEfficiencyScore: null) sort last.recommendedModel— Top-ranked model, ornullif insufficient data.confidence—insufficient_dataunless there’s a runner-up model with at least 3 sessions of its own AND the gap between the top and runner-up average efficiency scores is at least 0.05; otherwise gated by the top model’s own session count:high(≥20 sessions),medium(≥8),low(≥3).byOutcome— Rankings broken down by task outcome type (bug_fix, feature, refactor, investigation, configuration, documentation, failed_attempt).avgTaskSuccessRate—testPassCount / testRunCountfor sessions of that outcome, 0 if no tests run.
Data source: TrendAnalyzer.rankModelsByOutcome()
How it works:
- Loads all sessions (optionally filtered by
developerand/orsince). - Groups by model and outcome type (using
classifySessionOutcome). - Computes per-model averages (cost, efficiency, task success).
- Ranks by efficiency descending, cost ascending on ties, null-efficiency last.
- Assigns confidence tier based on the top-ranked model’s session count.
Requires: TrendAnalyzer
Source: src/metrics/trend-analyzer.ts, src/tools/cross-session-tools.ts
nr_observe_get_context_tracking
Per-turn context window tracking: token growth, category breakdown (system/tools/user/assistant), fill percentage, and per-tool output contribution.
Parameters: None
Returns:
{ "turnCount": 6, "growth": { "startTokens": 4200, "currentTokens": 18500, "deltaTokens": 14300 }, "currentBreakdown": { "system": 3800, "tools": 11200, "user": 900, "assistant": 2600 }, "fillPercent": 9.25, "contextWindow": 200000, "toolContributions": [ { "tool": "Read", "totalBytes": 48200, "estimatedTokens": 12050, "percentOfToolOutput": 61.4 } ]}Data source: ContextTrackerRegistry
How it works:
- Tracks token growth per turn (
recordTurn) and per-tool output bytes (recordToolCall) - Splits current context usage into system/tools/user/assistant categories via a byte/token-based estimate, not hardcoded proportions
fillPercentiscurrentInputTokens / contextWindow, wherecontextWindowis resolved per-model- With no
sessionIdargument, falls back to the most recently active tracker (single-active-session stdio server)
Requires: ContextTrackerRegistry
Source: src/tools/analytics-tools.ts, src/metrics/context-tracker.ts
nr_observe_get_cost_per_tool
Cost attribution per tool type — approximate, based on turn-level token correlation.
Parameters: None
Returns:
{ "turns": [ { "turnId": "turn-001", "startTime": 1713700000000, "endTime": 1713700005000, "toolCalls": ["Read", "Edit"], "inputTokens": 2000, "outputTokens": 500, "cacheReadTokens": 800, "model": "claude-sonnet-4-6", "estimatedCostUsd": 0.003, "costPerToolCall": 0.0015 } ], "costByToolType": { "Read": { "totalCost": 0.012, "callCount": 15, "avgCost": 0.0008 }, "Edit": { "totalCost": 0.025, "callCount": 8, "avgCost": 0.003 }, "Skill": { "totalCost": 0.042, "callCount": 4, "avgCost": 0.0105 } }, "costBySkill": { "code-review": { "callCount": 2, "attributedCallCount": 2, "totalCost": 0.025, "avgCost": 0.0125, "inputTokens": 3500, "outputTokens": 280, "cacheReadTokens": 15000, "totalDurationMs": 4200 }, "pstack:how": { "callCount": 2, "attributedCallCount": 2, "totalCost": 0.017, "avgCost": 0.0085, "inputTokens": 2100, "outputTokens": 120, "cacheReadTokens": 8000, "totalDurationMs": 2800 } }, "totalAttributedCost": 0.042, "attributionRate": 0.85}Data source: TurnCostAttributor
How it works: Attributes token costs reported via nr_observe_report_tokens to the tool calls that occurred within the same conversation turn. Each turn’s cost is split evenly across its tool calls, then aggregated by tool type. attributionRate is the fraction of total session cost that could be attributed (turns with no token report are excluded). Results are approximate — cost is correlated at the turn level, not the individual call level.
costBySkill has one row per invoked skill name (code-review, pstack:how). callCount and totalDurationMs are measured on every call. totalCost, inputTokens, outputTokens, and cacheReadTokens are the same even split across the turn’s tool calls that costByToolType uses, and they cover only the attributedCallCount calls whose turn received a token report. costByToolType.Skill equals the sum of the skill rows. Skill calls that arrive without a skill name (some non-Claude-Code adapters) count under costByToolType.Skill and get no row here. Calls and duration per skill over any window are also available in New Relic, since skillName rides on every AiToolCall:
FROM AiToolCall SELECT count(*), sum(duration_ms)/3.6e6 AS hours WHERE tool = 'Skill' FACET skillName SINCE 1 week agoCost and tokens per skill over any window come from AiTurnCost:
FROM AiTurnCost SELECT sum(cost_usd) WHERE tool = 'Skill' FACET skillName SINCE 1 week agoRequires: TurnCostAttributor
Source: src/tools/session-stats.ts, src/metrics/turn-cost-attributor.ts
nr_observe_get_turn_analysis
Conversation turn analysis: groups tool calls by AI response, shows parallelism and turn patterns.
Parameters: None
Returns:
{ "totalTurns": 12, "avgToolsPerTurn": 2.4, "maxToolsPerTurn": 5, "avgTurnDurationMs": 1850, "avgParallelism": 1.8, "recentTurns": [ { "turnId": "turn-012", "turnNumber": 12, "startTime": 1713700060000, "endTime": 1713700061850, "durationMs": 1850, "toolCalls": [ { "toolName": "Read", "toolUseId": "toolu_001", "success": true, "durationMs": 30, "timestamp": 1713700060100 } ], "toolCount": 3, "parallelism": 2, "uniqueTools": ["Read", "Bash"] } ], "turnsByToolCount": { "1": 4, "2": 3, "3": 3, "5": 2 }}Data source: TurnTracker
How it works: Groups tool calls into conversation turns — a turn is all tool calls issued between two consecutive AI responses. parallelism is the maximum number of tool calls running concurrently within the turn (detected from overlapping timestamps). avgParallelism > 1 indicates the AI is making parallel tool calls efficiently. turnsByToolCount shows the distribution of tools-per-turn across the session.
Requires: TurnTracker
Source: src/tools/session-stats.ts, src/metrics/turn-tracker.ts
nr_observe_get_git_efficiency
Git workflow efficiency metrics: merge conflicts, aborted operations, force pushes, stale branch detection, and actionable suggestions.
Parameters: None
Returns:
{ "totalGitCommands": 24, "mergeConflicts": 1, "rebaseConflicts": 0, "abortedOperations": 0, "forcePushes": 0, "resetHards": 1, "discardedChanges": 0, "pullCount": 5, "pushCount": 3, "commitCount": 8, "branchOperations": 4, "conflictResolutionRate": 1.0, "avgConflictResolutionMs": 45000, "staleBranchPulls": 0, "gitCommandTimeline": [], "conflictHistory": [], "suggestions": [ { "type": "merge_conflict_rate", "message": "Consider rebasing more frequently to reduce merge conflicts.", "severity": "medium" } ]}Data source: GitEfficiencyTracker
How it works: Classifies Bash tool calls that invoke git commands by inspecting the command string and output. Detects merge/rebase conflicts from command output patterns, flags force pushes and hard resets as risky operations, and identifies stale branch pulls (pulls that bring in a large number of incoming commits). conflictResolutionRate is the fraction of detected conflicts that were resolved rather than aborted. suggestions surfaces actionable recommendations when patterns exceed configured thresholds.
Requires: GitEfficiencyTracker
Source: src/tools/session-stats.ts, src/metrics/git-efficiency-tracker.ts
Extended Analytics Tools
These tools expose deeper session-level analysis. They are always registered when the trackers are available (no cross-session store dependency).
nr_observe_get_retry_alerts
Thrashing and retry detection alerts within a sliding window.
Parameters: None
Returns:
{ "alerts": [ { "type": "repeated_failure", "input": "npm test", "occurrences": 4, "windowSize": 5 } ], "totalTokensWasted": 2400, "totalAlertsEmitted": 1}Data source: RetryDetector
How it works: Tracks repeated tool calls with identical or highly similar inputs (similarity ≥ 0.8, via Levenshtein distance or exact input-hash match) within a rolling window (default: 5 calls). Fires an alert when the same input appears 3+ times consecutively. totalTokensWasted estimates tokens consumed on redundant calls (inputSize / 4).
Requires: RetryDetector
Source: src/tools/extended-analytics-tools.ts, src/metrics/retry-detector.ts
nr_observe_get_context_composition
Per-turn token breakdown by category with context fill percentage and dominance alerts.
Parameters: None
Returns:
{ "currentFillPercent": 62.5, "currentBreakdown": { "systemPrompt": 8000, "conversationHistory": 45000, "toolResults": 12000, "injectedFiles": 10000 }, "turnCount": 12, "thresholdAlerts": [{ "fillPercent": 62.5, "threshold": 50, "turnIndex": 11 }], "dominanceAlerts": [], "history": []}Data source: ContextCompositionTracker
How it works: Receives per-turn token reports categorized as systemPrompt, conversationHistory, toolResults, or injectedFiles. Tracks fill percentage against the model’s context window size. Fires threshold alerts when fill crosses 50%/75%/90% (configurable). Fires dominance alerts when a single category exceeds a configured fraction of total tokens.
Requires: ContextCompositionTracker
Source: src/tools/extended-analytics-tools.ts, src/metrics/context-composition-tracker.ts
nr_observe_get_latency_decomposition
Time split between LLM API calls, tool execution, and overhead — with p50/p95 percentiles for each component.
Status: not currently functional. Neither Claude Code hook events nor proxy mode observe the model-API-level timing this tool needs. It is not registered in tools/list; calling it directly by name returns an explanatory error.
Parameters: None
Data source: LatencyDecompositionTracker (implemented, correctly, but never fed — see src/index.ts for why)
nr_observe_get_decision_tree
Decision branch analysis with reasoning extraction and failure chain post-mortem.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
post_mortem |
boolean | false |
If true, return only failure-zone branches |
Returns (full):
{ "totalBranches": 24, "successRate": 0.79, "failurePoints": [ { "index": 3, "reasoning": "Expected test to pass...", "action": "Bash", "outcome": "failure" } ], "longestFailureStreak": 3, "firstFailureIndex": 3}Returns (post_mortem: true):
{ "postMortem": [{ "index": 3, "reasoning": "...", "action": "Bash", "outcome": "failure" }]}Data source: DecisionTracker
How it works: Records a branch for each tool call with extracted reasoning (from assistant message preceding the call, up to 500 chars), the action taken, and the outcome (success/failure). Computes successRate, identifies the longest consecutive failure streak, and can filter to only failure branches for post-mortem debugging.
Requires: DecisionTracker
Source: src/tools/extended-analytics-tools.ts, src/metrics/decision-tracker.ts
nr_observe_get_instruction_drift
CLAUDE.md and system prompt change correlations with session outcomes.
Parameters: None
Returns:
{ "currentPromptHash": "a1b2c3d4", "uniquePromptVariants": 3, "variantStats": [ { "hash": "a1b2c3d4", "sessionCount": 5, "avgSuccessRate": 0.82, "avgTokensPerSession": 45000 } ], "recentCorrelations": [ { "fromHash": "old123", "toHash": "a1b2c3d4", "deltaSuccessRate": 0.08, "deltaTokens": -3000 } ], "currentVariantSessionCount": 5}Data source: InstructionDriftTracker
How it works: Hashes the system prompt / CLAUDE.md content at each session start. Groups sessions by prompt hash and computes per-variant averages (success rate, token usage, thrashing). When the prompt changes, emits a correlation record showing how outcomes shifted. Requires ≥3 sessions per variant before comparisons are surfaced.
Requires: InstructionDriftTracker
Source: src/tools/extended-analytics-tools.ts, src/metrics/instruction-drift-tracker.ts
nr_observe_get_tool_selection_score
Tool selection quality score with penalty breakdown for redundant reads, repeated failures, and unused large outputs.
Parameters: None
Returns:
{ "score": 0.87, "totalCalls": 42, "penalizedCalls": 5, "penalties": [ { "tool": "Read", "file": "src/app.ts", "reason": "redundant_read", "penaltyWeight": 0.1 } ], "worstOffenders": [], "redundantReadCount": 3, "repeatedFailureCount": 2, "unusedOutputCount": 0}Data source: ToolSelectionScorer
How it works: Scores the full session tool call sequence. Penalizes: redundant reads (same file read again without intervening modification), repeated failures (same Bash command failed twice), and unused large outputs (tool returned a large response that was never referenced). Score 0–1 where 1 is perfect selection. worstOffenders lists the highest-penalty calls. See Improving Your Tool Selection Score for prompt-writing tips to reduce penalties.
Requires: ToolSelectionScorer
Source: src/tools/extended-analytics-tools.ts, src/metrics/tool-selection-scorer.ts
nr_observe_get_quality_proxy
Quality signal tracking: diff apply rate, test pass rate, self-correction count, and degradation detection.
Parameters: None
Returns:
{ "totalSignals": 18, "diffApplyRate": 0.92, "testPassRate": 0.75, "backtrackCount": 2, "selfCorrectionCount": 3, "qualityByTurnBucket": [], "degradationDetected": false, "events": []}Data source: QualityProxyTracker
How it works: Aggregates quality signals from tool call outcomes: Edit/Write success rate (diff apply), test pass/fail outcomes from Bash calls, backtrack detection (reverting to a previous file state), and self-corrections (re-editing a file shortly after a prior edit). Detects degradation when the trailing-window quality drops below a configured threshold.
Requires: QualityProxyTracker
Source: src/tools/extended-analytics-tools.ts, src/metrics/quality-proxy-tracker.ts
nr_observe_get_api_failures
API failure tracking: per-model reliability scorecards, tokens lost, throttle alerts, and mean time to recovery. Limitation: model-API-level failure data is not observable in Preflight’s current architecture (neither Claude Code hook events nor proxy mode see raw model-API traffic) — this tool currently always returns empty/zero metrics, with dataAvailable: false and a note field explaining why.
Parameters: None
Returns:
{ "totalFailures": 3, "byErrorType": { "rate_limit": 2, "server_error": 1 }, "byModel": { "claude-sonnet-4-6": { "totalRequests": 40, "failureCount": 2, "reliabilityScore": 0.95, "tokensLost": 8000, "estimatedCostLostUsd": 0.024, "meanTimeToRecoveryMs": 4200 } }, "bySessionPhase": { "early": 1, "mid": 2, "late": 0 }, "totalTokensLost": 8000, "totalEstimatedCostLostUsd": 0.024, "meanTimeToRecoveryMs": 4200, "throttleAlerts": [], "recentFailures": []}Data source: ApiFailureTracker
How it works: Records every failed AI API call with its error type, model, token count, and timestamp. Computes per-model reliability scorecards (failureCount / totalRequests). Fires throttle alerts when rate-limit errors exceed a threshold (default: 3 within 10 minutes). Estimates tokens and cost lost on failed requests. MTTR is the average time from failure to next success per model.
Requires: ApiFailureTracker
Source: src/tools/extended-analytics-tools.ts, src/metrics/api-failure-tracker.ts
Cross-Session and Team Tools
nr_observe_get_team_summary
Aggregated AI coding cost and efficiency metrics for all developers in the configured team, queried via New Relic NRQL.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
since |
string | "7 days ago" |
Time window (e.g. "7 days ago", "1 day ago") |
Returns:
{ "teamId": "backend-team", "since": "7 days ago", "developers": [ { "developer": "alice", "costUsd": 4.2, "efficiencyScore": 0.78, "antiPatterns": 3 }, { "developer": "bob", "costUsd": 2.15, "efficiencyScore": 0.65, "antiPatterns": 7 } ], "totals": { "costUsd": 6.35, "developerCount": 2 }}Data source: New Relic NerdGraph (NRQL queries against Metric and AiAntiPattern event types)
How it works:
- Runs three parallel NRQL queries against NR via NerdGraph: cost sum, avg efficiency score, and anti-pattern count — all faceted by
developerand filtered byteam_id - Merges results by developer name
- Returns error message (not stack trace) when
teamIdornrApiKeyis not configured
Requires: teamId and nrApiKey (NEW_RELIC_API_KEY) both configured
Config fields:
NEW_RELIC_AI_TEAM_ID— a label you choose (e.g."platform-eng") to group your team’s NR events. Not your NR account ID — pick any alphanumeric slug that identifies your team.NEW_RELIC_API_KEY— User API key (NRAK-…) for NerdGraph queries
Source: src/tools/cross-session-tools.ts
Digest and Subscription Tools
nr_observe_subscribe_digest
Register a Slack webhook URL to receive weekly AI coding cost and efficiency summaries.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
webhookUrl |
string | Yes | Slack incoming webhook URL (must start with https://hooks.slack.com/) |
Returns:
{ "ok": true, "message": "Webhook registered. Delivery is manual — call nr_observe_send_digest to send this week's digest."}Data source: Config file (~/.newrelic-preflight/config.json)
How it works:
- Validates the webhook URL starts with
https://hooks.slack.com/ - Reads the existing config file (or starts with an empty object)
- Writes
digestWebhookUrlto the config file with0o600permissions
Config fields:
NEW_RELIC_AI_DIGEST_WEBHOOK_URL— Slack incoming webhook endpointNEW_RELIC_AI_DIGEST_SCHEDULE— cron expression for digest delivery (default:"0 9 * * 1")
Note: Digest delivery is manual-only today. digestSchedule/NEW_RELIC_AI_DIGEST_SCHEDULE is stored for future use but nothing currently reads it to trigger a send — call nr_observe_send_digest on-demand (e.g. from an external cron job or CI schedule) to actually deliver a digest.
Requires: configFilePath
Source: src/tools/cross-session-tools.ts
nr_observe_unsubscribe_digest
Remove the registered Slack webhook for weekly digests.
Parameters: None
Returns:
{ "ok": true, "message": "Webhook removed."}Data source: Config file (~/.newrelic-preflight/config.json)
How it works:
- Reads the existing config file
- Deletes
digestWebhookUrlfrom the config and writes it back
Requires: configFilePath
Source: src/tools/cross-session-tools.ts
nr_observe_send_digest
Generate the current weekly AI coding summary and POST it to the configured Slack webhook immediately.
Parameters: None
Returns:
{ "ok": true, "week": "2026-W20", "message": "Digest sent successfully."}Data source: WeeklySummaryGenerator + config file webhook URL
How it works:
- Reads
digestWebhookUrlfrom the config file at call time - Generates the current week’s summary via
WeeklySummaryGenerator - Formats a Slack Block Kit payload via
formatSlackDigest() - POSTs the payload to the webhook URL
Requires: configFilePath + WeeklySummaryGenerator
Source: src/tools/cross-session-tools.ts