@opensearch-project/agent-health 0.3.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -6
- package/cli/dist/index.js +10072 -4502
- package/deployment/cloudformation/agent-health-observability.yaml +762 -0
- package/dist/assets/index-CCQRDlO0.js +243 -0
- package/dist/assets/index-CNHQVbcj.css +1 -0
- package/dist/index.html +2 -2
- package/docs/ARCHITECTURE.md +450 -0
- package/docs/BACKEND_JOB_QUEUE.md +405 -0
- package/docs/CLAUDE_CODE_TELEMETRY.md +283 -0
- package/docs/CLI.md +431 -0
- package/docs/CODING_AGENT_ANALYTICS.md +298 -0
- package/docs/CONFIGURATION.md +388 -0
- package/docs/CONNECTORS.md +536 -0
- package/docs/INSTRUMENT_WITH_OTEL.md +390 -0
- package/docs/ML-COMMONS-SETUP.md +289 -0
- package/docs/NPX_PACKAGING.md +195 -0
- package/docs/PERFORMANCE-MONITORING.md +200 -0
- package/docs/PERFORMANCE.md +390 -0
- package/docs/PI_PROFILING.md +169 -0
- package/docs/PLAN-non-agui-agent-support.md +525 -0
- package/docs/SDK.md +577 -0
- package/docs/SKILLS.md +264 -0
- package/docs/blogs/2026-02-28-opensearch-agent-health.md +200 -0
- package/docs/blogs/getting-started-blog.md +608 -0
- package/docs/diagrams/Agent-health.excalidraw +5656 -0
- package/docs/diagrams/architecture.png +0 -0
- package/docs/plans/field-redesign.md +468 -0
- package/docs/rfcs/001-coding-agent-analytics.md +374 -0
- package/docs/rfcs/002-enterprise-leaderboard.md +267 -0
- package/docs/rfcs/003-remote-aggregation.md +146 -0
- package/docs/rfcs/004-test-sdk-v2.md +599 -0
- package/docs/skills/AGENT_HEALTH.md +598 -0
- package/docs/skills/AGENT_PROFILE.md +191 -0
- package/docs/skills/add-connector/SKILL.md +68 -0
- package/docs/skills/agent-health-profile/SKILL.md +40 -0
- package/docs/skills/config-auth/SKILL.md +194 -0
- package/docs/skills/config-auth/evals/evals.json +35 -0
- package/docs/skills/create-pr/SKILL.md +73 -0
- package/docs/skills/instrument-otel/SKILL.md +84 -0
- package/docs/skills/write-test/SKILL.md +124 -0
- package/docs/ui prd.md +376 -0
- package/examples/README.md +53 -0
- package/examples/config/agent-health.config.example.ts +155 -0
- package/examples/connectors/echo-connector.ts +131 -0
- package/examples/eval-files/demo.eval.js +128 -0
- package/examples/eval-files/sdk-hooks-demo.eval.js +99 -0
- package/examples/pi-profiling/README.md +77 -0
- package/examples/pi-profiling/agent-health-profile.ts +417 -0
- package/lib/dist/lib/agentUtils.d.ts +29 -0
- package/lib/dist/lib/agentUtils.d.ts.map +1 -0
- package/lib/dist/lib/agentUtils.js +43 -0
- package/lib/dist/lib/agentUtils.js.map +1 -0
- package/lib/dist/lib/benchmarkExport.d.ts +14 -0
- package/lib/dist/lib/benchmarkExport.d.ts.map +1 -0
- package/lib/dist/lib/benchmarkExport.js +41 -0
- package/lib/dist/lib/benchmarkExport.js.map +1 -0
- package/lib/dist/lib/benchmarkVersionUtils.d.ts +37 -0
- package/lib/dist/lib/benchmarkVersionUtils.d.ts.map +1 -0
- package/lib/dist/lib/benchmarkVersionUtils.js +68 -0
- package/lib/dist/lib/benchmarkVersionUtils.js.map +1 -0
- package/lib/dist/lib/config/defineConfig.d.ts +27 -0
- package/lib/dist/lib/config/defineConfig.d.ts.map +1 -0
- package/lib/dist/lib/config/defineConfig.js +28 -0
- package/lib/dist/lib/config/defineConfig.js.map +1 -0
- package/lib/dist/lib/config/index.d.ts +9 -0
- package/lib/dist/lib/config/index.d.ts.map +1 -0
- package/lib/dist/lib/config/index.js +8 -0
- package/lib/dist/lib/config/index.js.map +1 -0
- package/lib/dist/lib/config/loader.d.ts +39 -0
- package/lib/dist/lib/config/loader.d.ts.map +1 -0
- package/lib/dist/lib/config/loader.js +258 -0
- package/lib/dist/lib/config/loader.js.map +1 -0
- package/lib/dist/lib/config/statePaths.d.ts +61 -0
- package/lib/dist/lib/config/statePaths.d.ts.map +1 -0
- package/lib/dist/lib/config/statePaths.js +188 -0
- package/lib/dist/lib/config/statePaths.js.map +1 -0
- package/lib/dist/lib/config/types.d.ts +231 -0
- package/lib/dist/lib/config/types.d.ts.map +1 -0
- package/lib/dist/lib/config/types.js +6 -0
- package/lib/dist/lib/config/types.js.map +1 -0
- package/lib/dist/lib/config.d.ts +39 -0
- package/lib/dist/lib/config.d.ts.map +1 -0
- package/lib/dist/lib/config.js +118 -0
- package/lib/dist/lib/config.js.map +1 -0
- package/lib/dist/lib/constants.d.ts +70 -0
- package/lib/dist/lib/constants.d.ts.map +1 -0
- package/lib/dist/lib/constants.js +365 -0
- package/lib/dist/lib/constants.js.map +1 -0
- package/lib/dist/lib/contextUtilization.d.ts +23 -0
- package/lib/dist/lib/contextUtilization.d.ts.map +1 -0
- package/lib/dist/lib/contextUtilization.js +72 -0
- package/lib/dist/lib/contextUtilization.js.map +1 -0
- package/lib/dist/lib/dashboardMetrics.d.ts +87 -0
- package/lib/dist/lib/dashboardMetrics.d.ts.map +1 -0
- package/lib/dist/lib/dashboardMetrics.js +242 -0
- package/lib/dist/lib/dashboardMetrics.js.map +1 -0
- package/lib/dist/lib/dataSourceConfig.d.ts +108 -0
- package/lib/dist/lib/dataSourceConfig.d.ts.map +1 -0
- package/lib/dist/lib/dataSourceConfig.js +166 -0
- package/lib/dist/lib/dataSourceConfig.js.map +1 -0
- package/lib/dist/lib/debug.d.ts +26 -0
- package/lib/dist/lib/debug.d.ts.map +1 -0
- package/lib/dist/lib/debug.js +132 -0
- package/lib/dist/lib/debug.js.map +1 -0
- package/lib/dist/lib/diagnostics.d.ts +28 -0
- package/lib/dist/lib/diagnostics.d.ts.map +1 -0
- package/lib/dist/lib/diagnostics.js +65 -0
- package/lib/dist/lib/diagnostics.js.map +1 -0
- package/lib/dist/lib/envCompat.d.ts +27 -0
- package/lib/dist/lib/envCompat.d.ts.map +1 -0
- package/lib/dist/lib/envCompat.js +73 -0
- package/lib/dist/lib/envCompat.js.map +1 -0
- package/lib/dist/lib/findPackageRoot.d.ts +7 -0
- package/lib/dist/lib/findPackageRoot.d.ts.map +1 -0
- package/lib/dist/lib/findPackageRoot.js +57 -0
- package/lib/dist/lib/findPackageRoot.js.map +1 -0
- package/lib/dist/lib/hooks.d.ts +36 -0
- package/lib/dist/lib/hooks.d.ts.map +1 -0
- package/lib/dist/lib/hooks.js +112 -0
- package/lib/dist/lib/hooks.js.map +1 -0
- package/lib/dist/lib/index.d.ts +47 -0
- package/lib/dist/lib/index.d.ts.map +1 -0
- package/lib/dist/lib/index.js +62 -0
- package/lib/dist/lib/index.js.map +1 -0
- package/lib/dist/lib/labels.d.ts +90 -0
- package/lib/dist/lib/labels.d.ts.map +1 -0
- package/lib/dist/lib/labels.js +158 -0
- package/lib/dist/lib/labels.js.map +1 -0
- package/lib/dist/lib/markdown.d.ts +16 -0
- package/lib/dist/lib/markdown.d.ts.map +1 -0
- package/lib/dist/lib/markdown.js +42 -0
- package/lib/dist/lib/markdown.js.map +1 -0
- package/lib/dist/lib/matchers/expect.d.ts +3 -0
- package/lib/dist/lib/matchers/expect.d.ts.map +1 -0
- package/lib/dist/lib/matchers/expect.js +225 -0
- package/lib/dist/lib/matchers/expect.js.map +1 -0
- package/lib/dist/lib/matchers/index.d.ts +8 -0
- package/lib/dist/lib/matchers/index.d.ts.map +1 -0
- package/lib/dist/lib/matchers/index.js +9 -0
- package/lib/dist/lib/matchers/index.js.map +1 -0
- package/lib/dist/lib/matchers/judgeAccessor.d.ts +113 -0
- package/lib/dist/lib/matchers/judgeAccessor.d.ts.map +1 -0
- package/lib/dist/lib/matchers/judgeAccessor.js +183 -0
- package/lib/dist/lib/matchers/judgeAccessor.js.map +1 -0
- package/lib/dist/lib/matchers/session.d.ts +39 -0
- package/lib/dist/lib/matchers/session.d.ts.map +1 -0
- package/lib/dist/lib/matchers/session.js +116 -0
- package/lib/dist/lib/matchers/session.js.map +1 -0
- package/lib/dist/lib/matchers/traces.d.ts +55 -0
- package/lib/dist/lib/matchers/traces.d.ts.map +1 -0
- package/lib/dist/lib/matchers/traces.js +116 -0
- package/lib/dist/lib/matchers/traces.js.map +1 -0
- package/lib/dist/lib/matchers/types.d.ts +75 -0
- package/lib/dist/lib/matchers/types.d.ts.map +1 -0
- package/lib/dist/lib/matchers/types.js +6 -0
- package/lib/dist/lib/matchers/types.js.map +1 -0
- package/lib/dist/lib/packagePaths.d.ts +29 -0
- package/lib/dist/lib/packagePaths.d.ts.map +1 -0
- package/lib/dist/lib/packagePaths.js +63 -0
- package/lib/dist/lib/packagePaths.js.map +1 -0
- package/lib/dist/lib/performance.d.ts +51 -0
- package/lib/dist/lib/performance.d.ts.map +1 -0
- package/lib/dist/lib/performance.js +159 -0
- package/lib/dist/lib/performance.js.map +1 -0
- package/lib/dist/lib/portConfig.d.ts +29 -0
- package/lib/dist/lib/portConfig.d.ts.map +1 -0
- package/lib/dist/lib/portConfig.js +64 -0
- package/lib/dist/lib/portConfig.js.map +1 -0
- package/lib/dist/lib/preferences.d.ts +63 -0
- package/lib/dist/lib/preferences.d.ts.map +1 -0
- package/lib/dist/lib/preferences.js +117 -0
- package/lib/dist/lib/preferences.js.map +1 -0
- package/lib/dist/lib/resolveAgentModel.d.ts +22 -0
- package/lib/dist/lib/resolveAgentModel.d.ts.map +1 -0
- package/lib/dist/lib/resolveAgentModel.js +37 -0
- package/lib/dist/lib/resolveAgentModel.js.map +1 -0
- package/lib/dist/lib/runStats.d.ts +92 -0
- package/lib/dist/lib/runStats.d.ts.map +1 -0
- package/lib/dist/lib/runStats.js +160 -0
- package/lib/dist/lib/runStats.js.map +1 -0
- package/lib/dist/lib/telemetry/constants.d.ts +60 -0
- package/lib/dist/lib/telemetry/constants.d.ts.map +1 -0
- package/lib/dist/lib/telemetry/constants.js +87 -0
- package/lib/dist/lib/telemetry/constants.js.map +1 -0
- package/lib/dist/lib/telemetry/evalSpans.d.ts +61 -0
- package/lib/dist/lib/telemetry/evalSpans.d.ts.map +1 -0
- package/lib/dist/lib/telemetry/evalSpans.js +254 -0
- package/lib/dist/lib/telemetry/evalSpans.js.map +1 -0
- package/lib/dist/lib/telemetry/index.d.ts +11 -0
- package/lib/dist/lib/telemetry/index.d.ts.map +1 -0
- package/lib/dist/lib/telemetry/index.js +15 -0
- package/lib/dist/lib/telemetry/index.js.map +1 -0
- package/lib/dist/lib/telemetry/opensearchExporter.d.ts +43 -0
- package/lib/dist/lib/telemetry/opensearchExporter.d.ts.map +1 -0
- package/lib/dist/lib/telemetry/opensearchExporter.js +217 -0
- package/lib/dist/lib/telemetry/opensearchExporter.js.map +1 -0
- package/lib/dist/lib/telemetry/provider.d.ts +55 -0
- package/lib/dist/lib/telemetry/provider.d.ts.map +1 -0
- package/lib/dist/lib/telemetry/provider.js +140 -0
- package/lib/dist/lib/telemetry/provider.js.map +1 -0
- package/lib/dist/lib/testCaseLabels.d.ts +34 -0
- package/lib/dist/lib/testCaseLabels.d.ts.map +1 -0
- package/lib/dist/lib/testCaseLabels.js +88 -0
- package/lib/dist/lib/testCaseLabels.js.map +1 -0
- package/lib/dist/lib/testCaseValidation.d.ts +140 -0
- package/lib/dist/lib/testCaseValidation.d.ts.map +1 -0
- package/lib/dist/lib/testCaseValidation.js +162 -0
- package/lib/dist/lib/testCaseValidation.js.map +1 -0
- package/lib/dist/lib/testCases/agentFixture.d.ts +80 -0
- package/lib/dist/lib/testCases/agentFixture.d.ts.map +1 -0
- package/lib/dist/lib/testCases/agentFixture.js +43 -0
- package/lib/dist/lib/testCases/agentFixture.js.map +1 -0
- package/lib/dist/lib/testCases/authoringSurface.d.ts +10 -0
- package/lib/dist/lib/testCases/authoringSurface.d.ts.map +1 -0
- package/lib/dist/lib/testCases/authoringSurface.js +54 -0
- package/lib/dist/lib/testCases/authoringSurface.js.map +1 -0
- package/lib/dist/lib/testCases/codemod.d.ts +13 -0
- package/lib/dist/lib/testCases/codemod.d.ts.map +1 -0
- package/lib/dist/lib/testCases/codemod.js +169 -0
- package/lib/dist/lib/testCases/codemod.js.map +1 -0
- package/lib/dist/lib/testCases/define.d.ts +114 -0
- package/lib/dist/lib/testCases/define.d.ts.map +1 -0
- package/lib/dist/lib/testCases/define.js +253 -0
- package/lib/dist/lib/testCases/define.js.map +1 -0
- package/lib/dist/lib/testCases/evaluators.d.ts +80 -0
- package/lib/dist/lib/testCases/evaluators.d.ts.map +1 -0
- package/lib/dist/lib/testCases/evaluators.js +105 -0
- package/lib/dist/lib/testCases/evaluators.js.map +1 -0
- package/lib/dist/lib/testCases/index.d.ts +14 -0
- package/lib/dist/lib/testCases/index.d.ts.map +1 -0
- package/lib/dist/lib/testCases/index.js +12 -0
- package/lib/dist/lib/testCases/index.js.map +1 -0
- package/lib/dist/lib/testCases/judge.d.ts +165 -0
- package/lib/dist/lib/testCases/judge.d.ts.map +1 -0
- package/lib/dist/lib/testCases/judge.js +359 -0
- package/lib/dist/lib/testCases/judge.js.map +1 -0
- package/lib/dist/lib/testCases/loader.d.ts +26 -0
- package/lib/dist/lib/testCases/loader.d.ts.map +1 -0
- package/lib/dist/lib/testCases/loader.js +149 -0
- package/lib/dist/lib/testCases/loader.js.map +1 -0
- package/lib/dist/lib/testCases/types.d.ts +242 -0
- package/lib/dist/lib/testCases/types.d.ts.map +1 -0
- package/lib/dist/lib/testCases/types.js +6 -0
- package/lib/dist/lib/testCases/types.js.map +1 -0
- package/lib/dist/lib/theme.d.ts +6 -0
- package/lib/dist/lib/theme.d.ts.map +1 -0
- package/lib/dist/lib/theme.js +36 -0
- package/lib/dist/lib/theme.js.map +1 -0
- package/lib/dist/lib/uiTelemetry.d.ts +7 -0
- package/lib/dist/lib/uiTelemetry.d.ts.map +1 -0
- package/lib/dist/lib/uiTelemetry.js +25 -0
- package/lib/dist/lib/uiTelemetry.js.map +1 -0
- package/lib/dist/lib/utils.d.ts +96 -0
- package/lib/dist/lib/utils.d.ts.map +1 -0
- package/lib/dist/lib/utils.js +232 -0
- package/lib/dist/lib/utils.js.map +1 -0
- package/lib/dist/lib/workflow/consolidate.d.ts +12 -0
- package/lib/dist/lib/workflow/consolidate.d.ts.map +1 -0
- package/lib/dist/lib/workflow/consolidate.js +33 -0
- package/lib/dist/lib/workflow/consolidate.js.map +1 -0
- package/lib/dist/lib/workflow/index.d.ts +13 -0
- package/lib/dist/lib/workflow/index.d.ts.map +1 -0
- package/lib/dist/lib/workflow/index.js +12 -0
- package/lib/dist/lib/workflow/index.js.map +1 -0
- package/lib/dist/lib/workflow/ledger.d.ts +30 -0
- package/lib/dist/lib/workflow/ledger.d.ts.map +1 -0
- package/lib/dist/lib/workflow/ledger.js +41 -0
- package/lib/dist/lib/workflow/ledger.js.map +1 -0
- package/lib/dist/lib/workflow/pool.d.ts +13 -0
- package/lib/dist/lib/workflow/pool.d.ts.map +1 -0
- package/lib/dist/lib/workflow/pool.js +44 -0
- package/lib/dist/lib/workflow/pool.js.map +1 -0
- package/lib/dist/lib/workflow/source.d.ts +22 -0
- package/lib/dist/lib/workflow/source.d.ts.map +1 -0
- package/lib/dist/lib/workflow/source.js +29 -0
- package/lib/dist/lib/workflow/source.js.map +1 -0
- package/lib/dist/lib/workflow/stepB.d.ts +71 -0
- package/lib/dist/lib/workflow/stepB.d.ts.map +1 -0
- package/lib/dist/lib/workflow/stepB.js +99 -0
- package/lib/dist/lib/workflow/stepB.js.map +1 -0
- package/lib/dist/lib/workflow/types.d.ts +86 -0
- package/lib/dist/lib/workflow/types.d.ts.map +1 -0
- package/lib/dist/lib/workflow/types.js +6 -0
- package/lib/dist/lib/workflow/types.js.map +1 -0
- package/lib/dist/lib/workflow/workflow.d.ts +119 -0
- package/lib/dist/lib/workflow/workflow.d.ts.map +1 -0
- package/lib/dist/lib/workflow/workflow.js +195 -0
- package/lib/dist/lib/workflow/workflow.js.map +1 -0
- package/lib/dist/services/agent/aguiConverter.d.ts +50 -0
- package/lib/dist/services/agent/aguiConverter.d.ts.map +1 -0
- package/lib/dist/services/agent/aguiConverter.js +449 -0
- package/lib/dist/services/agent/aguiConverter.js.map +1 -0
- package/lib/dist/services/agent/index.d.ts +10 -0
- package/lib/dist/services/agent/index.d.ts.map +1 -0
- package/lib/dist/services/agent/index.js +12 -0
- package/lib/dist/services/agent/index.js.map +1 -0
- package/lib/dist/services/agent/payloadBuilder.d.ts +33 -0
- package/lib/dist/services/agent/payloadBuilder.d.ts.map +1 -0
- package/lib/dist/services/agent/payloadBuilder.js +75 -0
- package/lib/dist/services/agent/payloadBuilder.js.map +1 -0
- package/lib/dist/services/agent/sseStream.d.ts +43 -0
- package/lib/dist/services/agent/sseStream.d.ts.map +1 -0
- package/lib/dist/services/agent/sseStream.js +223 -0
- package/lib/dist/services/agent/sseStream.js.map +1 -0
- package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts +44 -0
- package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js +95 -0
- package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js.map +1 -0
- package/lib/dist/services/connectors/base/BaseConnector.d.ts +81 -0
- package/lib/dist/services/connectors/base/BaseConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/base/BaseConnector.js +170 -0
- package/lib/dist/services/connectors/base/BaseConnector.js.map +1 -0
- package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts +116 -0
- package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js +403 -0
- package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js.map +1 -0
- package/lib/dist/services/connectors/index.d.ts +13 -0
- package/lib/dist/services/connectors/index.d.ts.map +1 -0
- package/lib/dist/services/connectors/index.js +32 -0
- package/lib/dist/services/connectors/index.js.map +1 -0
- package/lib/dist/services/connectors/kiro/KiroConnector.d.ts +48 -0
- package/lib/dist/services/connectors/kiro/KiroConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/kiro/KiroConnector.js +158 -0
- package/lib/dist/services/connectors/kiro/KiroConnector.js.map +1 -0
- package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts +36 -0
- package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/langgraph/LangGraphConnector.js +175 -0
- package/lib/dist/services/connectors/langgraph/LangGraphConnector.js.map +1 -0
- package/lib/dist/services/connectors/mock/MockConnector.d.ts +37 -0
- package/lib/dist/services/connectors/mock/MockConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/mock/MockConnector.js +120 -0
- package/lib/dist/services/connectors/mock/MockConnector.js.map +1 -0
- package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts +42 -0
- package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js +133 -0
- package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js.map +1 -0
- package/lib/dist/services/connectors/pi/PiConnector.d.ts +87 -0
- package/lib/dist/services/connectors/pi/PiConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/pi/PiConnector.js +274 -0
- package/lib/dist/services/connectors/pi/PiConnector.js.map +1 -0
- package/lib/dist/services/connectors/registry.d.ts +57 -0
- package/lib/dist/services/connectors/registry.d.ts.map +1 -0
- package/lib/dist/services/connectors/registry.js +106 -0
- package/lib/dist/services/connectors/registry.js.map +1 -0
- package/lib/dist/services/connectors/rest/RESTConnector.d.ts +38 -0
- package/lib/dist/services/connectors/rest/RESTConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/rest/RESTConnector.js +117 -0
- package/lib/dist/services/connectors/rest/RESTConnector.js.map +1 -0
- package/lib/dist/services/connectors/server.d.ts +13 -0
- package/lib/dist/services/connectors/server.d.ts.map +1 -0
- package/lib/dist/services/connectors/server.js +34 -0
- package/lib/dist/services/connectors/server.js.map +1 -0
- package/lib/dist/services/connectors/strands/StrandsConnector.d.ts +48 -0
- package/lib/dist/services/connectors/strands/StrandsConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/strands/StrandsConnector.js +221 -0
- package/lib/dist/services/connectors/strands/StrandsConnector.js.map +1 -0
- package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts +88 -0
- package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts.map +1 -0
- package/lib/dist/services/connectors/subprocess/SubprocessConnector.js +418 -0
- package/lib/dist/services/connectors/subprocess/SubprocessConnector.js.map +1 -0
- package/lib/dist/services/connectors/types.d.ts +213 -0
- package/lib/dist/services/connectors/types.d.ts.map +1 -0
- package/lib/dist/services/connectors/types.js +6 -0
- package/lib/dist/services/connectors/types.js.map +1 -0
- package/lib/dist/services/evaluation/bedrockJudge.d.ts +64 -0
- package/lib/dist/services/evaluation/bedrockJudge.d.ts.map +1 -0
- package/lib/dist/services/evaluation/bedrockJudge.js +167 -0
- package/lib/dist/services/evaluation/bedrockJudge.js.map +1 -0
- package/lib/dist/services/evaluation/evaluatorError.d.ts +56 -0
- package/lib/dist/services/evaluation/evaluatorError.d.ts.map +1 -0
- package/lib/dist/services/evaluation/evaluatorError.js +56 -0
- package/lib/dist/services/evaluation/evaluatorError.js.map +1 -0
- package/lib/dist/services/evaluation/index.d.ts +106 -0
- package/lib/dist/services/evaluation/index.d.ts.map +1 -0
- package/lib/dist/services/evaluation/index.js +684 -0
- package/lib/dist/services/evaluation/index.js.map +1 -0
- package/lib/dist/services/evaluation/mockTrajectory.d.ts +3 -0
- package/lib/dist/services/evaluation/mockTrajectory.d.ts.map +1 -0
- package/lib/dist/services/evaluation/mockTrajectory.js +72 -0
- package/lib/dist/services/evaluation/mockTrajectory.js.map +1 -0
- package/lib/dist/services/opensearch/client.d.ts +26 -0
- package/lib/dist/services/opensearch/client.d.ts.map +1 -0
- package/lib/dist/services/opensearch/client.js +131 -0
- package/lib/dist/services/opensearch/client.js.map +1 -0
- package/lib/dist/services/opensearch/index.d.ts +16 -0
- package/lib/dist/services/opensearch/index.d.ts.map +1 -0
- package/lib/dist/services/opensearch/index.js +25 -0
- package/lib/dist/services/opensearch/index.js.map +1 -0
- package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts +123 -0
- package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts.map +1 -0
- package/lib/dist/services/storage/asyncBenchmarkStorage.js +429 -0
- package/lib/dist/services/storage/asyncBenchmarkStorage.js.map +1 -0
- package/lib/dist/services/storage/asyncRunStorage.d.ts +127 -0
- package/lib/dist/services/storage/asyncRunStorage.d.ts.map +1 -0
- package/lib/dist/services/storage/asyncRunStorage.js +448 -0
- package/lib/dist/services/storage/asyncRunStorage.js.map +1 -0
- package/lib/dist/services/storage/asyncTestCaseStorage.d.ts +156 -0
- package/lib/dist/services/storage/asyncTestCaseStorage.d.ts.map +1 -0
- package/lib/dist/services/storage/asyncTestCaseStorage.js +285 -0
- package/lib/dist/services/storage/asyncTestCaseStorage.js.map +1 -0
- package/lib/dist/services/storage/index.d.ts +17 -0
- package/lib/dist/services/storage/index.d.ts.map +1 -0
- package/lib/dist/services/storage/index.js +20 -0
- package/lib/dist/services/storage/index.js.map +1 -0
- package/lib/dist/services/storage/migration.d.ts +54 -0
- package/lib/dist/services/storage/migration.d.ts.map +1 -0
- package/lib/dist/services/storage/migration.js +296 -0
- package/lib/dist/services/storage/migration.js.map +1 -0
- package/lib/dist/services/storage/opensearchClient.d.ts +924 -0
- package/lib/dist/services/storage/opensearchClient.d.ts.map +1 -0
- package/lib/dist/services/storage/opensearchClient.js +435 -0
- package/lib/dist/services/storage/opensearchClient.js.map +1 -0
- package/lib/dist/services/traces/browserRecovery.d.ts +26 -0
- package/lib/dist/services/traces/browserRecovery.d.ts.map +1 -0
- package/lib/dist/services/traces/browserRecovery.js +81 -0
- package/lib/dist/services/traces/browserRecovery.js.map +1 -0
- package/lib/dist/services/traces/categoryStyles.d.ts +21 -0
- package/lib/dist/services/traces/categoryStyles.d.ts.map +1 -0
- package/lib/dist/services/traces/categoryStyles.js +56 -0
- package/lib/dist/services/traces/categoryStyles.js.map +1 -0
- package/lib/dist/services/traces/executionOrderTransform.d.ts +35 -0
- package/lib/dist/services/traces/executionOrderTransform.d.ts.map +1 -0
- package/lib/dist/services/traces/executionOrderTransform.js +313 -0
- package/lib/dist/services/traces/executionOrderTransform.js.map +1 -0
- package/lib/dist/services/traces/fetchSpansForRun.d.ts +86 -0
- package/lib/dist/services/traces/fetchSpansForRun.d.ts.map +1 -0
- package/lib/dist/services/traces/fetchSpansForRun.js +69 -0
- package/lib/dist/services/traces/fetchSpansForRun.js.map +1 -0
- package/lib/dist/services/traces/flowTransform.d.ts +24 -0
- package/lib/dist/services/traces/flowTransform.d.ts.map +1 -0
- package/lib/dist/services/traces/flowTransform.js +228 -0
- package/lib/dist/services/traces/flowTransform.js.map +1 -0
- package/lib/dist/services/traces/index.d.ts +121 -0
- package/lib/dist/services/traces/index.d.ts.map +1 -0
- package/lib/dist/services/traces/index.js +255 -0
- package/lib/dist/services/traces/index.js.map +1 -0
- package/lib/dist/services/traces/intentTransform.d.ts +20 -0
- package/lib/dist/services/traces/intentTransform.d.ts.map +1 -0
- package/lib/dist/services/traces/intentTransform.js +131 -0
- package/lib/dist/services/traces/intentTransform.js.map +1 -0
- package/lib/dist/services/traces/judgeAgentsHints.d.ts +63 -0
- package/lib/dist/services/traces/judgeAgentsHints.d.ts.map +1 -0
- package/lib/dist/services/traces/judgeAgentsHints.js +89 -0
- package/lib/dist/services/traces/judgeAgentsHints.js.map +1 -0
- package/lib/dist/services/traces/messageExtraction.d.ts +15 -0
- package/lib/dist/services/traces/messageExtraction.d.ts.map +1 -0
- package/lib/dist/services/traces/messageExtraction.js +251 -0
- package/lib/dist/services/traces/messageExtraction.js.map +1 -0
- package/lib/dist/services/traces/spanCategorization.d.ts +63 -0
- package/lib/dist/services/traces/spanCategorization.d.ts.map +1 -0
- package/lib/dist/services/traces/spanCategorization.js +276 -0
- package/lib/dist/services/traces/spanCategorization.js.map +1 -0
- package/lib/dist/services/traces/spanPreprocessing.d.ts +37 -0
- package/lib/dist/services/traces/spanPreprocessing.d.ts.map +1 -0
- package/lib/dist/services/traces/spanPreprocessing.js +102 -0
- package/lib/dist/services/traces/spanPreprocessing.js.map +1 -0
- package/lib/dist/services/traces/spansToTrajectory.d.ts +36 -0
- package/lib/dist/services/traces/spansToTrajectory.d.ts.map +1 -0
- package/lib/dist/services/traces/spansToTrajectory.js +387 -0
- package/lib/dist/services/traces/spansToTrajectory.js.map +1 -0
- package/lib/dist/services/traces/toolSimilarity.d.ts +35 -0
- package/lib/dist/services/traces/toolSimilarity.d.ts.map +1 -0
- package/lib/dist/services/traces/toolSimilarity.js +203 -0
- package/lib/dist/services/traces/toolSimilarity.js.map +1 -0
- package/lib/dist/services/traces/traceComparison.d.ts +31 -0
- package/lib/dist/services/traces/traceComparison.d.ts.map +1 -0
- package/lib/dist/services/traces/traceComparison.js +318 -0
- package/lib/dist/services/traces/traceComparison.js.map +1 -0
- package/lib/dist/services/traces/traceGrouping.d.ts +19 -0
- package/lib/dist/services/traces/traceGrouping.d.ts.map +1 -0
- package/lib/dist/services/traces/traceGrouping.js +107 -0
- package/lib/dist/services/traces/traceGrouping.js.map +1 -0
- package/lib/dist/services/traces/tracePoller.d.ts +84 -0
- package/lib/dist/services/traces/tracePoller.d.ts.map +1 -0
- package/lib/dist/services/traces/tracePoller.js +309 -0
- package/lib/dist/services/traces/tracePoller.js.map +1 -0
- package/lib/dist/services/traces/traceStats.d.ts +45 -0
- package/lib/dist/services/traces/traceStats.d.ts.map +1 -0
- package/lib/dist/services/traces/traceStats.js +114 -0
- package/lib/dist/services/traces/traceStats.js.map +1 -0
- package/lib/dist/services/traces/traceSummary.d.ts +47 -0
- package/lib/dist/services/traces/traceSummary.d.ts.map +1 -0
- package/lib/dist/services/traces/traceSummary.js +68 -0
- package/lib/dist/services/traces/traceSummary.js.map +1 -0
- package/lib/dist/services/traces/utils.d.ts +33 -0
- package/lib/dist/services/traces/utils.d.ts.map +1 -0
- package/lib/dist/services/traces/utils.js +114 -0
- package/lib/dist/services/traces/utils.js.map +1 -0
- package/lib/dist/types/agui.d.ts +13 -0
- package/lib/dist/types/agui.d.ts.map +1 -0
- package/lib/dist/types/agui.js +16 -0
- package/lib/dist/types/agui.js.map +1 -0
- package/lib/dist/types/index.d.ts +1175 -0
- package/lib/dist/types/index.d.ts.map +1 -0
- package/lib/dist/types/index.js +12 -0
- package/lib/dist/types/index.js.map +1 -0
- package/lib/dist/types/skills.d.ts +146 -0
- package/lib/dist/types/skills.d.ts.map +1 -0
- package/lib/dist/types/skills.js +6 -0
- package/lib/dist/types/skills.js.map +1 -0
- package/observio-sample-agent/pi-package/README.md +112 -0
- package/observio-sample-agent/pi-package/extensions/agent-health.ts +373 -0
- package/observio-sample-agent/pi-package/package.json +17 -0
- package/observio-sample-agent/pi-package/prompts/agent-health.md +37 -0
- package/observio-sample-agent/pi-package/skills/create-pr/SKILL.md +88 -0
- package/observio-sample-agent/pi-package/skills/fix-bug/SKILL.md +71 -0
- package/observio-sample-agent/pi-package/skills/implement-feature/SKILL.md +156 -0
- package/observio-sample-agent/pi-package/skills/instrument-otel/SKILL.md +208 -0
- package/observio-sample-agent/pi-package/skills/setup-collector/SKILL.md +146 -0
- package/observio-sample-agent/pi-package/skills/write-test/SKILL.md +115 -0
- package/package.json +64 -13
- package/server/dist/app.js +32651 -17637
- package/server/dist/index.js +29875 -14638
- package/tsconfig.lib.json +71 -0
- package/dist/assets/index-EvPLSTAS.js +0 -267
- package/dist/assets/index-RXasQKUs.css +0 -1
- package/lib/dist/config/index.js +0 -404
- package/lib/dist/index.js +0 -1665
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
* Copyright OpenSearch Contributors
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# RFC 001: Coding Agent Analytics
|
|
7
|
+
|
|
8
|
+
| Field | Value |
|
|
9
|
+
|--------------|--------------------------------------------|
|
|
10
|
+
| **Status** | Implemented |
|
|
11
|
+
| **Author** | Anirudha Jadhav |
|
|
12
|
+
| **Created** | 2026-04-06 |
|
|
13
|
+
| **PR** | anirudha/agent-health#1 |
|
|
14
|
+
| **See also** | [RFC 003](003-remote-aggregation.md) (remote aggregation), RFC 002 (enterprise leaderboard, future) |
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
|
|
18
|
+
Add a unified analytics dashboard to Agent Health that reads local session data from coding agents — **Claude Code**, **Kiro**, and **Codex CLI** — and provides cross-agent usage metrics, cost estimation, activity patterns, and tool analytics. This transforms Agent Health from a pure evaluation framework into a complete agentic observability platform.
|
|
19
|
+
|
|
20
|
+
## Motivation
|
|
21
|
+
|
|
22
|
+
### Problem
|
|
23
|
+
|
|
24
|
+
Developers using AI coding agents lack visibility into their usage patterns:
|
|
25
|
+
|
|
26
|
+
1. **No cross-agent view** — Each agent stores data in its own format in its own directory. There's no way to see combined usage across Claude Code, Kiro, and Codex CLI.
|
|
27
|
+
2. **No cost visibility** — Token usage is buried in JSONL files and SQLite databases. Developers can't easily answer "how much am I spending on AI coding?"
|
|
28
|
+
3. **No usage patterns** — Activity heatmaps, streaks, peak hours, and tool preferences require manual log parsing.
|
|
29
|
+
4. **No tool comparison** — Understanding which tools different agents use, how often, and for what purposes requires reading raw session data.
|
|
30
|
+
|
|
31
|
+
### Prior Art
|
|
32
|
+
|
|
33
|
+
- **[cc-lens](https://github.com/Arindam200/cc-lens)** (MIT) — Claude Code-specific analytics dashboard. Rich feature set but limited to a single agent and runs as a standalone Next.js app.
|
|
34
|
+
- **[openSVM/vibedev](https://github.com/openSVM/vibedev)** — Rust CLI/TUI for AI coding assistant usage across 15+ tools. Broad but shallow; no web dashboard.
|
|
35
|
+
|
|
36
|
+
### Why Agent Health
|
|
37
|
+
|
|
38
|
+
Agent Health already has:
|
|
39
|
+
- An Express server with API routes
|
|
40
|
+
- React frontend with recharts and shadcn/ui
|
|
41
|
+
- A connector system for different agent protocols
|
|
42
|
+
- Trace visualization for OTel spans
|
|
43
|
+
- Benchmark/evaluation infrastructure
|
|
44
|
+
|
|
45
|
+
Adding coding agent analytics is a natural extension — developers can now see both **how well agents perform** (existing benchmarks) and **how agents are actually used** (new analytics).
|
|
46
|
+
|
|
47
|
+
## Design
|
|
48
|
+
|
|
49
|
+
### Architecture Overview
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
53
|
+
│ Local Filesystem │
|
|
54
|
+
│ │
|
|
55
|
+
│ ~/.claude/ ~/.kiro/ ~/.codex/ │
|
|
56
|
+
│ └── projects/ └── sessions/cli/ └── sessions/ │
|
|
57
|
+
│ └── <slug>/ ├── <id>.jsonl └── YYYY/ │
|
|
58
|
+
│ └── <id>.jsonl └── <id>.json └── DD/│
|
|
59
|
+
│ └── rollout-*.jsonl
|
|
60
|
+
└──────────────┬────────────────────┬──────────────────┬──────────┘
|
|
61
|
+
│ │ │
|
|
62
|
+
▼ ▼ ▼
|
|
63
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
64
|
+
│ Coding Agent Readers │
|
|
65
|
+
│ │
|
|
66
|
+
│ ┌─────────────────┐ ┌─────────────┐ ┌────────────────────────┐ │
|
|
67
|
+
│ │ ClaudeCodeReader │ │ KiroReader │ │ CodexReader │ │
|
|
68
|
+
│ │ JSONL parser │ │ JSONL+JSON │ │ Rollout JSONL parser │ │
|
|
69
|
+
│ │ Full tokens │ │ Partial tkn │ │ No tokens (runtime) │ │
|
|
70
|
+
│ └────────┬─────────┘ └─────┬───────┘ └──────────┬─────────────┘ │
|
|
71
|
+
│ │ │ │ │
|
|
72
|
+
│ ▼ ▼ ▼ │
|
|
73
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
74
|
+
│ │ CodingAgentReader Interface │ │
|
|
75
|
+
│ │ isAvailable() → bool │ │
|
|
76
|
+
│ │ getSessions() → AgentSession[] │ │
|
|
77
|
+
│ │ getStats() → AgentStats │ │
|
|
78
|
+
│ └─────────────────────────┬───────────────────────────┘ │
|
|
79
|
+
│ │ │
|
|
80
|
+
│ ┌─────────────────────────▼───────────────────────────┐ │
|
|
81
|
+
│ │ CodingAgentRegistry │ │
|
|
82
|
+
│ │ getAvailableReaders() — auto-detect installed agents │ │
|
|
83
|
+
│ │ getAllSessions() — merge + sort across agents │ │
|
|
84
|
+
│ │ getCombinedStats() — aggregate metrics │ │
|
|
85
|
+
│ │ getCostAnalytics() — cross-agent cost breakdown │ │
|
|
86
|
+
│ │ getActivityData() — streaks, heatmap, patterns │ │
|
|
87
|
+
│ │ getToolsAnalytics() — tool usage rankings │ │
|
|
88
|
+
│ └─────────────────────────┬───────────────────────────┘ │
|
|
89
|
+
└─────────────────────────────┼────────────────────────────────────┘
|
|
90
|
+
│
|
|
91
|
+
▼
|
|
92
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
93
|
+
│ Express API Routes │
|
|
94
|
+
│ │
|
|
95
|
+
│ GET /api/coding-agents/available — detected agents │
|
|
96
|
+
│ GET /api/coding-agents/stats — combined metrics │
|
|
97
|
+
│ GET /api/coding-agents/sessions — all sessions (?agent=&limit=)│
|
|
98
|
+
│ GET /api/coding-agents/costs — cost analytics │
|
|
99
|
+
│ GET /api/coding-agents/activity — streaks, heatmap, patterns │
|
|
100
|
+
│ GET /api/coding-agents/tools — tool usage rankings │
|
|
101
|
+
└─────────────────────────────┬───────────────────────────────────┘
|
|
102
|
+
│
|
|
103
|
+
▼
|
|
104
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
105
|
+
│ React Frontend │
|
|
106
|
+
│ │
|
|
107
|
+
│ /coding-agents (tabbed dashboard) │
|
|
108
|
+
│ ├── Overview — stat cards, agent pie chart, daily activity │
|
|
109
|
+
│ ├── Sessions — filterable table with agent badges │
|
|
110
|
+
│ ├── Costs — model breakdown, project costs │
|
|
111
|
+
│ ├── Activity — streaks, hourly/DOW charts, heatmap │
|
|
112
|
+
│ └── Tools — category chart, top tools table │
|
|
113
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Reader Plugin Interface
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
interface CodingAgentReader {
|
|
120
|
+
readonly agentName: AgentKind; // 'claude-code' | 'kiro' | 'codex'
|
|
121
|
+
readonly displayName: string; // 'Claude Code' | 'Kiro' | 'Codex CLI'
|
|
122
|
+
isAvailable(): Promise<boolean>; // Check if data dir exists
|
|
123
|
+
getSessions(): Promise<AgentSession[]>;
|
|
124
|
+
getStats(): Promise<AgentStats>;
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
All readers normalize their output to a common `AgentSession` type:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
interface AgentSession {
|
|
132
|
+
agent: AgentKind;
|
|
133
|
+
session_id: string;
|
|
134
|
+
project_path: string;
|
|
135
|
+
start_time: string;
|
|
136
|
+
duration_minutes: number;
|
|
137
|
+
user_message_count: number;
|
|
138
|
+
assistant_message_count: number;
|
|
139
|
+
tool_counts: Record<string, number>;
|
|
140
|
+
input_tokens: number; // 0 if unavailable
|
|
141
|
+
output_tokens: number; // 0 if unavailable
|
|
142
|
+
cache_creation_input_tokens: number;
|
|
143
|
+
cache_read_input_tokens: number;
|
|
144
|
+
first_prompt: string;
|
|
145
|
+
estimated_cost: number; // 0 if tokens unavailable
|
|
146
|
+
uses_mcp: boolean;
|
|
147
|
+
model?: string;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Data Sources Per Agent
|
|
152
|
+
|
|
153
|
+
| Data Source | Claude Code | Kiro | Codex CLI |
|
|
154
|
+
|-------------|-------------|------|-----------|
|
|
155
|
+
| **Location** | `~/.claude/projects/<slug>/<id>.jsonl` | `~/.kiro/sessions/cli/<id>.jsonl` + `<id>.json` | `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl` |
|
|
156
|
+
| **Format** | JSONL (one object per event) | JSONL (transcript) + JSON (per-turn metadata) | JSONL (timestamped items) |
|
|
157
|
+
| **Session ID** | Filename (UUID) | Filename (UUID) | Embedded in rollout filename |
|
|
158
|
+
| **Timestamps** | `timestamp` field on each event | `timestamp` field | `timestamp` field |
|
|
159
|
+
| **User messages** | `type: "user"` events | `role: "user"` lines | `item.type: "message", item.role: "user"` |
|
|
160
|
+
| **Assistant messages** | `type: "assistant"` events | `role: "assistant"` lines | `item.type: "message", item.role: "assistant"` |
|
|
161
|
+
| **Token usage** | `message.usage.{input_tokens, output_tokens, cache_*}` | Companion `.json` file has `turns[].{input_token_count, output_token_count}` | Runtime-only (`ThreadTokenUsageUpdatedNotification`) — **not persisted** |
|
|
162
|
+
| **Tool invocations** | `content[].type === "tool_use"` with `name` field | `content[].toolName` + optional `serverName` for MCP | `item.type === "EventMsg"` or `"function_call"` |
|
|
163
|
+
| **Cost estimation** | Full (input + output + cache write + cache read) | Partial (input + output, no cache breakdown) | **Unavailable** (no token counts in rollout files) |
|
|
164
|
+
| **Project path** | `cwd` field in early JSONL lines | `cwd` field | `item.working_directory` in SessionMeta |
|
|
165
|
+
| **MCP tools** | Prefix `mcp__<server>__<tool>` | `serverName` + `toolName` fields | Not applicable |
|
|
166
|
+
| **Model info** | `message.model` on assistant turns | Not in JSONL (available in SQLite) | `item.model` in SessionMeta |
|
|
167
|
+
| **Stats cache** | `~/.claude/stats-cache.json` (pre-aggregated) | None | None |
|
|
168
|
+
|
|
169
|
+
### Pricing Engine
|
|
170
|
+
|
|
171
|
+
Multi-vendor pricing with fuzzy model matching:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const PRICING: Record<string, ModelPricing> = {
|
|
175
|
+
// Claude models
|
|
176
|
+
'claude-opus-4-6': { input: $15/1M, output: $75/1M, cacheWrite: $18.75/1M, cacheRead: $1.50/1M },
|
|
177
|
+
'claude-sonnet-4-6': { input: $3/1M, output: $15/1M, cacheWrite: $3.75/1M, cacheRead: $0.30/1M },
|
|
178
|
+
'claude-haiku-4-5': { input: $0.80/1M, output: $4/1M, cacheWrite: $1/1M, cacheRead: $0.08/1M },
|
|
179
|
+
// Bedrock (Kiro)
|
|
180
|
+
'us.anthropic.claude-sonnet-4-6': { input: $3/1M, output: $15/1M, ... },
|
|
181
|
+
// OpenAI (Codex)
|
|
182
|
+
'o3': { input: $2/1M, output: $8/1M, cacheWrite: $0, cacheRead: $0 },
|
|
183
|
+
'o4-mini': { input: $1.10/1M, output: $4.40/1M, ... },
|
|
184
|
+
'gpt-4.1': { input: $2/1M, output: $8/1M, ... },
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Fallback: if model not found, fuzzy-match on prefix, then default to `claude-sonnet-4-6`.
|
|
189
|
+
|
|
190
|
+
### Tool Categorization
|
|
191
|
+
|
|
192
|
+
Unified categories across all agents:
|
|
193
|
+
|
|
194
|
+
| Category | Claude Code Tools | Kiro Tools | Codex Tools |
|
|
195
|
+
|----------|------------------|------------|-------------|
|
|
196
|
+
| File I/O | Read, Write, Edit, Glob, Grep, NotebookEdit | readFile, writeFile, editFile, listFiles, searchFiles | read_file, write_file, list_directory |
|
|
197
|
+
| Shell | Bash | executeCommand | shell |
|
|
198
|
+
| Agent | Task*, Agent | — | — |
|
|
199
|
+
| Web | WebSearch, WebFetch | — | — |
|
|
200
|
+
| Planning | EnterPlanMode, ExitPlanMode, AskUserQuestion | — | — |
|
|
201
|
+
| Todo | TodoWrite | — | — |
|
|
202
|
+
| Skills | Skill, ToolSearch | — | — |
|
|
203
|
+
| MCP | `mcp__*` prefix | `mcp_<server>__<tool>` | — |
|
|
204
|
+
| Other | Everything else | Everything else | Everything else |
|
|
205
|
+
|
|
206
|
+
### Auto-Detection
|
|
207
|
+
|
|
208
|
+
The registry checks for directory existence at startup:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
~/.claude/projects/ → Claude Code detected
|
|
212
|
+
~/.kiro/sessions/cli/ → Kiro detected
|
|
213
|
+
~/.codex/sessions/ → Codex CLI detected
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
No configuration required for defaults. Optional override in `agent-health.config.ts`:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
export default {
|
|
220
|
+
codingAgents: {
|
|
221
|
+
claudeCode: { enabled: true, dataDir: "~/.claude" },
|
|
222
|
+
kiro: { enabled: true, dataDir: "~/.kiro" },
|
|
223
|
+
codex: { enabled: true, dataDir: "~/.codex" },
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Implementation Plan
|
|
229
|
+
|
|
230
|
+
### Phase 1: Core Infrastructure + Claude Code (Implemented)
|
|
231
|
+
|
|
232
|
+
**Status: Complete** — PR anirudha/agent-health#1
|
|
233
|
+
|
|
234
|
+
- [x] `CodingAgentReader` interface and common types
|
|
235
|
+
- [x] `CodingAgentRegistry` with auto-detection
|
|
236
|
+
- [x] Claude Code reader (ported from cc-lens)
|
|
237
|
+
- [x] Kiro reader (JSONL + JSON metadata)
|
|
238
|
+
- [x] Codex CLI reader (rollout JSONL)
|
|
239
|
+
- [x] Pricing engine (Claude, Bedrock, OpenAI models)
|
|
240
|
+
- [x] Tool categorization across all agents
|
|
241
|
+
- [x] 6 Express API routes
|
|
242
|
+
- [x] React tabbed dashboard (Overview, Sessions, Costs, Activity, Tools)
|
|
243
|
+
- [x] Sidebar navigation entry
|
|
244
|
+
|
|
245
|
+
### Phase 2: Enhanced Readers & Session Replay
|
|
246
|
+
|
|
247
|
+
- [ ] **Claude Code stats-cache integration** — Merge `~/.claude/stats-cache.json` pre-aggregated data with JSONL-derived data for faster initial load
|
|
248
|
+
- [ ] **Session replay** — Turn-by-turn conversation view with token-per-turn visualization (port cc-lens `replay-parser.ts`)
|
|
249
|
+
- [ ] **Kiro SQLite integration** — Read `devdata.sqlite` for more accurate token counts and historical data going back further than CLI sessions
|
|
250
|
+
- [ ] **Codex SQLite state DB** — Read thread metadata (model, working directory, timestamps) for richer session info
|
|
251
|
+
- [ ] **Facets integration** — Read Claude Code's `~/.claude/usage-data/facets/` for goal categorization, satisfaction analysis, and session type classification
|
|
252
|
+
|
|
253
|
+
### Phase 3: Cross-Agent Comparison & Insights
|
|
254
|
+
|
|
255
|
+
- [ ] **Side-by-side comparison page** — Compare agent performance on the same project (token efficiency, tool preferences, session length)
|
|
256
|
+
- [ ] **Cost trends over time** — Stacked area chart showing daily/weekly cost by agent and model
|
|
257
|
+
- [ ] **Project-level analytics** — Drill into a specific project to see all agent sessions, costs, and tool usage for that repo
|
|
258
|
+
- [ ] **Export/import** — Export analytics data as JSON/CSV for sharing or archival
|
|
259
|
+
|
|
260
|
+
### Phase 4: Advanced Analytics
|
|
261
|
+
|
|
262
|
+
- [ ] **Prompt pattern analysis** — Categorize first prompts (bug fix, feature, refactor, question) and correlate with session characteristics
|
|
263
|
+
- [ ] **Cache efficiency dashboard** — Detailed Claude Code cache hit rates, savings over time, and optimization suggestions
|
|
264
|
+
- [ ] **MCP server analytics** — Which MCP servers are used, how often, by which agents, and error rates
|
|
265
|
+
- [ ] **Memory & plans viewer** — Port cc-lens Memory and Plans tabs for Claude Code data
|
|
266
|
+
- [ ] **Historical trends** — Week-over-week and month-over-month comparisons
|
|
267
|
+
|
|
268
|
+
### Phase 5: Extensibility
|
|
269
|
+
|
|
270
|
+
- [ ] **Reader SDK** — Document how to create custom readers for new agents (Cursor, Windsurf, Aider, Continue, etc.)
|
|
271
|
+
- [ ] **CLI integration** — `npx @opensearch-project/agent-health coding-agents stats` for headless analytics
|
|
272
|
+
- [ ] **Webhook/export** — Push analytics data to external systems (Prometheus, Grafana, OpenSearch)
|
|
273
|
+
- [ ] **Config file override** — Allow custom data directories for non-standard agent installations
|
|
274
|
+
|
|
275
|
+
## Data Flow
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
┌────────────────────┐
|
|
279
|
+
│ Browser (React) │
|
|
280
|
+
│ │
|
|
281
|
+
│ GET /api/coding- │
|
|
282
|
+
│ agents/stats │
|
|
283
|
+
└─────────┬───────────┘
|
|
284
|
+
│ HTTP
|
|
285
|
+
▼
|
|
286
|
+
┌────────────────────┐
|
|
287
|
+
│ Express Server │
|
|
288
|
+
│ (port 4001) │
|
|
289
|
+
│ │
|
|
290
|
+
│ codingAgentsRoutes │
|
|
291
|
+
└─────────┬───────────┘
|
|
292
|
+
│
|
|
293
|
+
▼
|
|
294
|
+
┌────────────────────┐
|
|
295
|
+
│ Registry │
|
|
296
|
+
│ │
|
|
297
|
+
│ 1. Check which │
|
|
298
|
+
│ agents exist │
|
|
299
|
+
│ 2. Call readers │
|
|
300
|
+
│ 3. Merge results │
|
|
301
|
+
└───┬─────┬─────┬────┘
|
|
302
|
+
│ │ │
|
|
303
|
+
┌──────────────┘ │ └──────────────┐
|
|
304
|
+
▼ ▼ ▼
|
|
305
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
306
|
+
│ ClaudeCode │ │ Kiro │ │ Codex │
|
|
307
|
+
│ Reader │ │ Reader │ │ Reader │
|
|
308
|
+
│ │ │ │ │ │
|
|
309
|
+
│ fs.readFile │ │ fs.readFile │ │ fs.readFile │
|
|
310
|
+
│ JSON.parse │ │ JSON.parse │ │ JSON.parse │
|
|
311
|
+
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
|
312
|
+
│ │ │
|
|
313
|
+
▼ ▼ ▼
|
|
314
|
+
~/.claude/ ~/.kiro/ ~/.codex/
|
|
315
|
+
projects/ sessions/cli/ sessions/
|
|
316
|
+
<slug>/*.jsonl *.jsonl + *.json YYYY/MM/DD/*.jsonl
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Security Considerations
|
|
320
|
+
|
|
321
|
+
1. **Read-only access** — Readers only read from agent data directories. No writes, no deletions.
|
|
322
|
+
2. **Local data only** — All data stays on the local machine. No network calls to agent APIs.
|
|
323
|
+
3. **No credential exposure** — Session JSONL files may contain prompts and code snippets. The API routes serve this data only to `localhost`.
|
|
324
|
+
4. **First prompt truncation** — Session first prompts are truncated to 500 characters to limit exposure of potentially sensitive content.
|
|
325
|
+
5. **Path traversal** — Agent data directories are hardcoded to `~/.claude/`, `~/.kiro/`, `~/.codex/` — not user-controllable in Phase 1 (config override planned for Phase 5).
|
|
326
|
+
|
|
327
|
+
## Performance Considerations
|
|
328
|
+
|
|
329
|
+
1. **Lazy tab loading** — Frontend only fetches data for the active tab. Overview and stats load on mount; sessions, costs, activity, and tools load on tab switch.
|
|
330
|
+
2. **File I/O bound** — Readers parse JSONL files synchronously line-by-line. For users with thousands of sessions, this could take seconds. Phase 2 should add caching or incremental parsing.
|
|
331
|
+
3. **No caching** — API responses are not cached in Phase 1. Each request re-reads the filesystem. This is acceptable for local usage but should be addressed with in-memory caching + file watcher invalidation.
|
|
332
|
+
4. **Session limit** — The sessions endpoint defaults to 100 sessions (configurable via `?limit=`) to avoid loading thousands of sessions into the browser.
|
|
333
|
+
|
|
334
|
+
## Alternatives Considered
|
|
335
|
+
|
|
336
|
+
### Embed cc-lens as iframe
|
|
337
|
+
|
|
338
|
+
**Rejected.** Would require users to run two servers (agent-health on 4001, cc-lens on 3000). Poor integration, no cross-agent view, and breaks the single-server principle.
|
|
339
|
+
|
|
340
|
+
### Import cc-lens as a dependency
|
|
341
|
+
|
|
342
|
+
**Rejected.** cc-lens is a Next.js app, not a library. Its code is tightly coupled to Next.js API routes and React Server Components. Porting the core logic (reader, parser, pricing) is cleaner.
|
|
343
|
+
|
|
344
|
+
### Read agent data from browser via File System Access API
|
|
345
|
+
|
|
346
|
+
**Rejected.** The File System Access API requires user permission per directory and doesn't work in all browsers. Server-side filesystem reading is more reliable and consistent with agent-health's server-mediated architecture.
|
|
347
|
+
|
|
348
|
+
### Use agent APIs instead of local files
|
|
349
|
+
|
|
350
|
+
**Rejected.** Claude Code, Kiro, and Codex CLI don't expose usage analytics APIs. Local file reading is the only way to access historical session data.
|
|
351
|
+
|
|
352
|
+
## Open Questions
|
|
353
|
+
|
|
354
|
+
1. **Caching strategy** — Should we implement LRU in-memory caching with file modification time checks, or is filesystem read performance acceptable for typical usage (~100-1000 sessions)?
|
|
355
|
+
2. **Incremental updates** — Should readers track which files have been processed and only parse new sessions, or re-scan everything on each request?
|
|
356
|
+
3. **Agent comparison scoring** — How should we compare agents that have different data availability? Codex has no token counts, so cost comparisons are inherently unfair.
|
|
357
|
+
4. **Privacy controls** — Should we add options to redact first prompts or limit which projects appear in analytics?
|
|
358
|
+
5. **Agent detection frequency** — Should the registry re-check for newly installed agents on each request, or only at server startup?
|
|
359
|
+
|
|
360
|
+
## Scope Boundary
|
|
361
|
+
|
|
362
|
+
This RFC covers **local, single-machine analytics only**. Related capabilities are covered by separate RFCs:
|
|
363
|
+
|
|
364
|
+
- **[RFC 003: Remote Aggregation](003-remote-aggregation.md)** — Multi-machine monitoring via headless remote servers, API key authentication, and session merging
|
|
365
|
+
- **RFC 002: Enterprise Leaderboard** (future) — OpenSearch-backed team analytics, rankings, badges, and recommendations
|
|
366
|
+
|
|
367
|
+
Each RFC is independently shippable. Merge order: RFC 001 → RFC 003 → RFC 002.
|
|
368
|
+
|
|
369
|
+
## References
|
|
370
|
+
|
|
371
|
+
- [cc-lens](https://github.com/Arindam200/cc-lens) — Claude Code analytics dashboard (MIT license, data format reference)
|
|
372
|
+
- [OpenAI Codex CLI](https://github.com/openai/codex) — Codex CLI source (rollout file format)
|
|
373
|
+
- [Agent Health Architecture](../ARCHITECTURE.md) — Server-mediated access principle
|
|
374
|
+
- [Agent Health Connectors](../CONNECTORS.md) — Existing connector system for agent protocols
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
* Copyright OpenSearch Contributors
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# RFC 002: Enterprise AI Usage Leaderboard
|
|
7
|
+
|
|
8
|
+
| Field | Value |
|
|
9
|
+
|--------------|--------------------------------------------|
|
|
10
|
+
| **Status** | Draft |
|
|
11
|
+
| **Author** | Anirudha Jadhav |
|
|
12
|
+
| **Created** | 2026-04-07 |
|
|
13
|
+
| **Depends** | RFC 001 (Coding Agent Analytics) |
|
|
14
|
+
|
|
15
|
+
## Summary
|
|
16
|
+
|
|
17
|
+
Add an enterprise-grade AI usage analytics and leaderboard system to Agent Health. Local coding agent session data (from RFC 001) is synced to an OpenSearch `ai_usage_events` index on demand. Team dashboards, leaderboards, badges, and learning recommendations are computed live via OpenSearch PPL — no materialized views or rollup indexes required.
|
|
18
|
+
|
|
19
|
+
## Motivation
|
|
20
|
+
|
|
21
|
+
### Problem
|
|
22
|
+
|
|
23
|
+
1. **No team visibility** — Individual developers can see their own AI usage (RFC 001), but team leads and engineering managers have no way to understand AI adoption patterns across their organization.
|
|
24
|
+
2. **No cost attribution** — Enterprises paying for AI coding tools (Claude Max, Copilot Enterprise, Cursor Teams) cannot attribute costs to teams or projects.
|
|
25
|
+
3. **No adoption benchmarking** — There is no way to compare how different teams or individuals are leveraging AI tools, making it impossible to identify best practices or training needs.
|
|
26
|
+
4. **No learning from peers** — Developers cannot learn from teammates who are more effective with AI tools (e.g., which tool patterns lead to higher completion rates).
|
|
27
|
+
|
|
28
|
+
### Market Context
|
|
29
|
+
|
|
30
|
+
- **GitHub Copilot** is the only AI coding tool with mature enterprise analytics (team-level metrics API, SPACE framework). Their original Metrics API was deprecated April 2, 2026, in favor of newer endpoints — the space is actively evolving.
|
|
31
|
+
- **10+ fragmented tools** exist for Claude Code cost tracking alone (ccbase, Claud-ometer, ObservAgent, goccc, etc.), all single-agent, all tiny. No tool provides cross-agent team analytics.
|
|
32
|
+
- **Claude Code issue #33978** consolidates 10+ open issues requesting usage analytics — token usage visibility is the #1 most-requested feature category.
|
|
33
|
+
- **Enterprise LLM platforms** (Helicone $799/mo, Braintrust $249/mo, LangSmith enterprise) focus on production LLM apps, not coding agent usage.
|
|
34
|
+
|
|
35
|
+
### Privacy-First Design
|
|
36
|
+
|
|
37
|
+
Developer productivity tracking is controversial. GitHub removed public streak counters in 2016 due to backlash. The SPACE framework recommends team-level aggregation, never individual scoring. Our design:
|
|
38
|
+
|
|
39
|
+
- **Opt-in only** — Data only leaves the local machine when explicitly synced
|
|
40
|
+
- **Anonymizable** — Team admins see aggregates; individual data requires user consent
|
|
41
|
+
- **No content logging** — Prompts and responses never synced, only metrics
|
|
42
|
+
- **Team-level defaults** — Leaderboards show team rankings by default, individual opt-in
|
|
43
|
+
- **Configurable granularity** — Users control what is shared
|
|
44
|
+
|
|
45
|
+
## Design
|
|
46
|
+
|
|
47
|
+
### Architecture Overview
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
51
|
+
│ Local Machine (existing RFC 001) │
|
|
52
|
+
│ CodingAgentRegistry → AgentSession[] (in-memory, from filesystem) │
|
|
53
|
+
└──────────────────────────────┬──────────────────────────────────────┘
|
|
54
|
+
│ POST /api/coding-agents/leaderboard/sync
|
|
55
|
+
│ (on-demand, user-initiated)
|
|
56
|
+
▼
|
|
57
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
58
|
+
│ OpenSearch (ai_usage_events index) │
|
|
59
|
+
│ │
|
|
60
|
+
│ Per-session documents with: user_id, team_id, agent, model, │
|
|
61
|
+
│ project (hashed), tokens, cost, tool counts, duration, completion │
|
|
62
|
+
│ │
|
|
63
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
|
|
64
|
+
│ │ PPL Query │ │ PPL Query │ │ PPL Query │ │
|
|
65
|
+
│ │ Team Stats │ │ Leaderboard │ │ Recommendations │ │
|
|
66
|
+
│ └──────┬──────┘ └──────┬───────┘ └──────────┬───────────────┘ │
|
|
67
|
+
└─────────┼────────────────┼──────────────────────┼───────────────────┘
|
|
68
|
+
│ │ │
|
|
69
|
+
▼ ▼ ▼
|
|
70
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
71
|
+
│ API Layer (Express routes) │
|
|
72
|
+
│ │
|
|
73
|
+
│ GET /api/coding-agents/leaderboard/team-stats │
|
|
74
|
+
│ GET /api/coding-agents/leaderboard/rankings │
|
|
75
|
+
│ GET /api/coding-agents/leaderboard/badges │
|
|
76
|
+
│ GET /api/coding-agents/leaderboard/recommendations │
|
|
77
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Data Model
|
|
81
|
+
|
|
82
|
+
Single index, no materialized views. All aggregations computed live via PPL/DSL at query time.
|
|
83
|
+
|
|
84
|
+
**Index: `ai_usage_events`**
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface UsageEvent {
|
|
88
|
+
// Identity (anonymizable)
|
|
89
|
+
user_id: string; // configurable: real name, hash, or "anonymous"
|
|
90
|
+
team_id: string; // team/org identifier
|
|
91
|
+
|
|
92
|
+
// Session metadata
|
|
93
|
+
session_id: string; // unique, prevents duplicate sync
|
|
94
|
+
agent: AgentKind; // claude-code | kiro | codex
|
|
95
|
+
model: string; // claude-opus-4-6, etc.
|
|
96
|
+
project_hash: string; // SHA-256 of project path (privacy)
|
|
97
|
+
project_display: string; // last path segment only
|
|
98
|
+
start_time: string; // ISO 8601
|
|
99
|
+
|
|
100
|
+
// Metrics
|
|
101
|
+
duration_minutes: number;
|
|
102
|
+
user_message_count: number;
|
|
103
|
+
assistant_message_count: number;
|
|
104
|
+
input_tokens: number;
|
|
105
|
+
output_tokens: number;
|
|
106
|
+
cache_creation_tokens: number;
|
|
107
|
+
cache_read_tokens: number;
|
|
108
|
+
estimated_cost: number;
|
|
109
|
+
|
|
110
|
+
// Tool usage
|
|
111
|
+
total_tool_calls: number;
|
|
112
|
+
total_tool_errors: number;
|
|
113
|
+
tool_success_rate: number;
|
|
114
|
+
top_tools: string[]; // top 5 tool names used
|
|
115
|
+
tool_categories: string[]; // unique categories used
|
|
116
|
+
uses_mcp: boolean;
|
|
117
|
+
|
|
118
|
+
// Outcome
|
|
119
|
+
session_completed: boolean;
|
|
120
|
+
|
|
121
|
+
// Sync metadata
|
|
122
|
+
synced_at: string; // when this event was pushed to OpenSearch
|
|
123
|
+
source_server: string; // "local" or remote server name
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Implementation Phases
|
|
128
|
+
|
|
129
|
+
#### Phase 1: OpenSearch Ingestion Pipeline
|
|
130
|
+
|
|
131
|
+
Transform `AgentSession[]` → `UsageEvent[]` and index into OpenSearch.
|
|
132
|
+
|
|
133
|
+
- New service: `server/services/codingAgents/leaderboard/ingestion.ts`
|
|
134
|
+
- New route: `POST /api/coding-agents/leaderboard/sync` — triggers sync
|
|
135
|
+
- New route: `GET /api/coding-agents/leaderboard/sync-status` — last sync time, event count
|
|
136
|
+
- Config: `leaderboard.userId`, `leaderboard.teamId`, `leaderboard.enabled` in `agent-health.config.json`
|
|
137
|
+
- Deduplication: Uses `session_id` as document ID to prevent double-sync
|
|
138
|
+
- Privacy: Project paths hashed, no prompt content synced
|
|
139
|
+
|
|
140
|
+
#### Phase 2: Team Dashboard
|
|
141
|
+
|
|
142
|
+
Live PPL queries against `ai_usage_events` for team-level analytics.
|
|
143
|
+
|
|
144
|
+
- New service: `server/services/codingAgents/leaderboard/teamAnalytics.ts`
|
|
145
|
+
- Endpoints:
|
|
146
|
+
- `GET /api/coding-agents/leaderboard/team-stats` — aggregate stats by team
|
|
147
|
+
- `GET /api/coding-agents/leaderboard/user-stats` — per-user stats (opt-in)
|
|
148
|
+
- `GET /api/coding-agents/leaderboard/project-stats` — per-project stats
|
|
149
|
+
- `GET /api/coding-agents/leaderboard/trends` — daily/weekly trends
|
|
150
|
+
|
|
151
|
+
PPL examples:
|
|
152
|
+
```sql
|
|
153
|
+
-- Team stats
|
|
154
|
+
source=ai_usage_events | where team_id='engineering'
|
|
155
|
+
| stats count() as sessions, sum(estimated_cost) as total_cost,
|
|
156
|
+
avg(tool_success_rate) as avg_success_rate,
|
|
157
|
+
sum(session_completed) as completed
|
|
158
|
+
by user_id
|
|
159
|
+
| sort - total_cost
|
|
160
|
+
|
|
161
|
+
-- Daily trends
|
|
162
|
+
source=ai_usage_events | where team_id='engineering'
|
|
163
|
+
| eval day=date_format(start_time, 'yyyy-MM-dd')
|
|
164
|
+
| stats count() as sessions, sum(estimated_cost) as cost by day
|
|
165
|
+
| sort day
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Phase 3: Leaderboard + Badges
|
|
169
|
+
|
|
170
|
+
Rankings and achievement badges computed live via PPL.
|
|
171
|
+
|
|
172
|
+
- New service: `server/services/codingAgents/leaderboard/rankings.ts`
|
|
173
|
+
- New service: `server/services/codingAgents/leaderboard/badges.ts`
|
|
174
|
+
- Endpoints:
|
|
175
|
+
- `GET /api/coding-agents/leaderboard/rankings` — ranked users by configurable metric
|
|
176
|
+
- `GET /api/coding-agents/leaderboard/badges` — earned badges for a user
|
|
177
|
+
- `GET /api/coding-agents/leaderboard/badges/definitions` — all badge definitions
|
|
178
|
+
|
|
179
|
+
**Badge Definitions:**
|
|
180
|
+
|
|
181
|
+
| Badge | Criteria | Category |
|
|
182
|
+
|-------|----------|----------|
|
|
183
|
+
| Cost Optimizer | Bottom 25th percentile cost/completion | efficiency |
|
|
184
|
+
| Power User | 100+ sessions | volume |
|
|
185
|
+
| Multi-Agent | Used 3+ different agents | diversity |
|
|
186
|
+
| Streak Master | 7+ day streak | consistency |
|
|
187
|
+
| Tool Expert | 95%+ tool success rate | quality |
|
|
188
|
+
| Night Owl | 50%+ sessions between 10pm-4am | pattern |
|
|
189
|
+
| Early Bird | 50%+ sessions between 5am-9am | pattern |
|
|
190
|
+
| MCP Pioneer | Used MCP tools in 10+ sessions | adoption |
|
|
191
|
+
| Completionist | 90%+ session completion rate (20+ sessions) | quality |
|
|
192
|
+
| Cache Champion | 80%+ cache hit rate | efficiency |
|
|
193
|
+
|
|
194
|
+
**Ranking metrics** (configurable via query param):
|
|
195
|
+
- `sessions` — total session count
|
|
196
|
+
- `cost` — total estimated cost
|
|
197
|
+
- `completion_rate` — session completion rate
|
|
198
|
+
- `efficiency` — cost per completed session (lower is better)
|
|
199
|
+
- `tool_success` — tool success rate
|
|
200
|
+
- `active_days` — days with at least one session
|
|
201
|
+
|
|
202
|
+
#### Phase 4: Learning Recommendations
|
|
203
|
+
|
|
204
|
+
Analyze patterns from top performers and generate actionable recommendations.
|
|
205
|
+
|
|
206
|
+
- New service: `server/services/codingAgents/leaderboard/recommendations.ts`
|
|
207
|
+
- Endpoint:
|
|
208
|
+
- `GET /api/coding-agents/leaderboard/recommendations` — personalized recommendations
|
|
209
|
+
- `GET /api/coding-agents/leaderboard/team-insights` — team-level insights
|
|
210
|
+
|
|
211
|
+
**Recommendation types:**
|
|
212
|
+
|
|
213
|
+
1. **Tool Patterns** — "Top performers use Edit 40% more than you. Try editing files directly instead of writing new ones."
|
|
214
|
+
2. **Model Selection** — "Your Opus usage is 3x team average. Consider Sonnet for simple tasks — teammates using Sonnet for file reads save 60%."
|
|
215
|
+
3. **Session Hygiene** — "Your sessions average 45 min. Teammates with <20 min sessions have 15% higher completion rates."
|
|
216
|
+
4. **Cache Optimization** — "Your cache hit rate is 40% vs team average 70%. Longer sessions with stable context improve caching."
|
|
217
|
+
5. **Agent Diversity** — "You only use Claude Code. Teammates using Kiro for IDE tasks report faster completion."
|
|
218
|
+
|
|
219
|
+
### API Reference
|
|
220
|
+
|
|
221
|
+
All leaderboard endpoints require OpenSearch storage to be configured.
|
|
222
|
+
|
|
223
|
+
| Endpoint | Method | Description |
|
|
224
|
+
|----------|--------|-------------|
|
|
225
|
+
| `/api/coding-agents/leaderboard/sync` | POST | Sync local sessions to OpenSearch |
|
|
226
|
+
| `/api/coding-agents/leaderboard/sync-status` | GET | Last sync time, total events |
|
|
227
|
+
| `/api/coding-agents/leaderboard/team-stats` | GET | Team aggregate stats |
|
|
228
|
+
| `/api/coding-agents/leaderboard/user-stats` | GET | Per-user stats (opt-in) |
|
|
229
|
+
| `/api/coding-agents/leaderboard/project-stats` | GET | Per-project stats |
|
|
230
|
+
| `/api/coding-agents/leaderboard/trends` | GET | Daily/weekly cost and usage trends |
|
|
231
|
+
| `/api/coding-agents/leaderboard/rankings` | GET | Ranked users by metric |
|
|
232
|
+
| `/api/coding-agents/leaderboard/badges` | GET | Badges earned by a user |
|
|
233
|
+
| `/api/coding-agents/leaderboard/badges/definitions` | GET | All badge definitions |
|
|
234
|
+
| `/api/coding-agents/leaderboard/recommendations` | GET | Personalized recommendations |
|
|
235
|
+
| `/api/coding-agents/leaderboard/team-insights` | GET | Team-level insights |
|
|
236
|
+
|
|
237
|
+
Query parameters: `team_id`, `user_id`, `from`, `to` (date range), `metric` (for rankings), `period` (daily/weekly/monthly for trends).
|
|
238
|
+
|
|
239
|
+
### Security Considerations
|
|
240
|
+
|
|
241
|
+
- **Authentication**: Leaderboard endpoints use the same storage client middleware as existing storage routes — OpenSearch auth (basic, SigV4) handles access control
|
|
242
|
+
- **Data minimization**: Only metrics synced, never prompt content or conversation text
|
|
243
|
+
- **Project privacy**: Full project paths hashed; only last path segment exposed as display name
|
|
244
|
+
- **User identity**: Configurable — real name, email hash, or fully anonymous
|
|
245
|
+
- **Index access**: OpenSearch RBAC can restrict `ai_usage_events` access per team
|
|
246
|
+
|
|
247
|
+
### Performance
|
|
248
|
+
|
|
249
|
+
- **Ingestion**: Bulk indexing with `refresh: false` — one bulk call per sync
|
|
250
|
+
- **Queries**: PPL queries with date range filters hit OpenSearch's inverted index efficiently
|
|
251
|
+
- **No rollups**: OpenSearch handles aggregation of raw events at query time — tested performant up to millions of documents
|
|
252
|
+
- **Caching**: Route-level caching (30s TTL) for frequently-accessed team stats
|
|
253
|
+
|
|
254
|
+
## Alternatives Considered
|
|
255
|
+
|
|
256
|
+
1. **Materialized views / daily rollup index** — Rejected. OpenSearch PPL computes aggregations live without stale data issues or sync complexity. Simpler architecture, one index.
|
|
257
|
+
2. **Local-only leaderboard** — Would limit to single-machine data. OpenSearch enables multi-machine aggregation for distributed teams.
|
|
258
|
+
3. **External analytics service** — Helicone/Braintrust could work but adds vendor dependency, cost ($79-799/mo), and requires API proxy setup. Our approach is free and self-hosted.
|
|
259
|
+
4. **ClickHouse backend** — Better raw query performance for analytics workloads, but adds a new dependency. OpenSearch is already in the stack.
|
|
260
|
+
|
|
261
|
+
## References
|
|
262
|
+
|
|
263
|
+
- [RFC 001: Coding Agent Analytics](001-coding-agent-analytics.md)
|
|
264
|
+
- [GitHub Copilot Metrics API](https://docs.github.com/en/rest/copilot/copilot-metrics)
|
|
265
|
+
- [SPACE Framework](https://queue.acm.org/detail.cfm?id=3454124) — Satisfaction, Performance, Activity, Communication, Efficiency
|
|
266
|
+
- [anthropics/claude-code#33978](https://github.com/anthropics/claude-code/issues/33978) — Consolidated usage analytics feature request
|
|
267
|
+
- [Pragmatic Engineer on Developer Productivity](https://newsletter.pragmaticengineer.com/p/measuring-developer-productivity)
|