@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.
Files changed (518) hide show
  1. package/README.md +77 -6
  2. package/cli/dist/index.js +10072 -4502
  3. package/deployment/cloudformation/agent-health-observability.yaml +762 -0
  4. package/dist/assets/index-CCQRDlO0.js +243 -0
  5. package/dist/assets/index-CNHQVbcj.css +1 -0
  6. package/dist/index.html +2 -2
  7. package/docs/ARCHITECTURE.md +450 -0
  8. package/docs/BACKEND_JOB_QUEUE.md +405 -0
  9. package/docs/CLAUDE_CODE_TELEMETRY.md +283 -0
  10. package/docs/CLI.md +431 -0
  11. package/docs/CODING_AGENT_ANALYTICS.md +298 -0
  12. package/docs/CONFIGURATION.md +388 -0
  13. package/docs/CONNECTORS.md +536 -0
  14. package/docs/INSTRUMENT_WITH_OTEL.md +390 -0
  15. package/docs/ML-COMMONS-SETUP.md +289 -0
  16. package/docs/NPX_PACKAGING.md +195 -0
  17. package/docs/PERFORMANCE-MONITORING.md +200 -0
  18. package/docs/PERFORMANCE.md +390 -0
  19. package/docs/PI_PROFILING.md +169 -0
  20. package/docs/PLAN-non-agui-agent-support.md +525 -0
  21. package/docs/SDK.md +577 -0
  22. package/docs/SKILLS.md +264 -0
  23. package/docs/blogs/2026-02-28-opensearch-agent-health.md +200 -0
  24. package/docs/blogs/getting-started-blog.md +608 -0
  25. package/docs/diagrams/Agent-health.excalidraw +5656 -0
  26. package/docs/diagrams/architecture.png +0 -0
  27. package/docs/plans/field-redesign.md +468 -0
  28. package/docs/rfcs/001-coding-agent-analytics.md +374 -0
  29. package/docs/rfcs/002-enterprise-leaderboard.md +267 -0
  30. package/docs/rfcs/003-remote-aggregation.md +146 -0
  31. package/docs/rfcs/004-test-sdk-v2.md +599 -0
  32. package/docs/skills/AGENT_HEALTH.md +598 -0
  33. package/docs/skills/AGENT_PROFILE.md +191 -0
  34. package/docs/skills/add-connector/SKILL.md +68 -0
  35. package/docs/skills/agent-health-profile/SKILL.md +40 -0
  36. package/docs/skills/config-auth/SKILL.md +194 -0
  37. package/docs/skills/config-auth/evals/evals.json +35 -0
  38. package/docs/skills/create-pr/SKILL.md +73 -0
  39. package/docs/skills/instrument-otel/SKILL.md +84 -0
  40. package/docs/skills/write-test/SKILL.md +124 -0
  41. package/docs/ui prd.md +376 -0
  42. package/examples/README.md +53 -0
  43. package/examples/config/agent-health.config.example.ts +155 -0
  44. package/examples/connectors/echo-connector.ts +131 -0
  45. package/examples/eval-files/demo.eval.js +128 -0
  46. package/examples/eval-files/sdk-hooks-demo.eval.js +99 -0
  47. package/examples/pi-profiling/README.md +77 -0
  48. package/examples/pi-profiling/agent-health-profile.ts +417 -0
  49. package/lib/dist/lib/agentUtils.d.ts +29 -0
  50. package/lib/dist/lib/agentUtils.d.ts.map +1 -0
  51. package/lib/dist/lib/agentUtils.js +43 -0
  52. package/lib/dist/lib/agentUtils.js.map +1 -0
  53. package/lib/dist/lib/benchmarkExport.d.ts +14 -0
  54. package/lib/dist/lib/benchmarkExport.d.ts.map +1 -0
  55. package/lib/dist/lib/benchmarkExport.js +41 -0
  56. package/lib/dist/lib/benchmarkExport.js.map +1 -0
  57. package/lib/dist/lib/benchmarkVersionUtils.d.ts +37 -0
  58. package/lib/dist/lib/benchmarkVersionUtils.d.ts.map +1 -0
  59. package/lib/dist/lib/benchmarkVersionUtils.js +68 -0
  60. package/lib/dist/lib/benchmarkVersionUtils.js.map +1 -0
  61. package/lib/dist/lib/config/defineConfig.d.ts +27 -0
  62. package/lib/dist/lib/config/defineConfig.d.ts.map +1 -0
  63. package/lib/dist/lib/config/defineConfig.js +28 -0
  64. package/lib/dist/lib/config/defineConfig.js.map +1 -0
  65. package/lib/dist/lib/config/index.d.ts +9 -0
  66. package/lib/dist/lib/config/index.d.ts.map +1 -0
  67. package/lib/dist/lib/config/index.js +8 -0
  68. package/lib/dist/lib/config/index.js.map +1 -0
  69. package/lib/dist/lib/config/loader.d.ts +39 -0
  70. package/lib/dist/lib/config/loader.d.ts.map +1 -0
  71. package/lib/dist/lib/config/loader.js +258 -0
  72. package/lib/dist/lib/config/loader.js.map +1 -0
  73. package/lib/dist/lib/config/statePaths.d.ts +61 -0
  74. package/lib/dist/lib/config/statePaths.d.ts.map +1 -0
  75. package/lib/dist/lib/config/statePaths.js +188 -0
  76. package/lib/dist/lib/config/statePaths.js.map +1 -0
  77. package/lib/dist/lib/config/types.d.ts +231 -0
  78. package/lib/dist/lib/config/types.d.ts.map +1 -0
  79. package/lib/dist/lib/config/types.js +6 -0
  80. package/lib/dist/lib/config/types.js.map +1 -0
  81. package/lib/dist/lib/config.d.ts +39 -0
  82. package/lib/dist/lib/config.d.ts.map +1 -0
  83. package/lib/dist/lib/config.js +118 -0
  84. package/lib/dist/lib/config.js.map +1 -0
  85. package/lib/dist/lib/constants.d.ts +70 -0
  86. package/lib/dist/lib/constants.d.ts.map +1 -0
  87. package/lib/dist/lib/constants.js +365 -0
  88. package/lib/dist/lib/constants.js.map +1 -0
  89. package/lib/dist/lib/contextUtilization.d.ts +23 -0
  90. package/lib/dist/lib/contextUtilization.d.ts.map +1 -0
  91. package/lib/dist/lib/contextUtilization.js +72 -0
  92. package/lib/dist/lib/contextUtilization.js.map +1 -0
  93. package/lib/dist/lib/dashboardMetrics.d.ts +87 -0
  94. package/lib/dist/lib/dashboardMetrics.d.ts.map +1 -0
  95. package/lib/dist/lib/dashboardMetrics.js +242 -0
  96. package/lib/dist/lib/dashboardMetrics.js.map +1 -0
  97. package/lib/dist/lib/dataSourceConfig.d.ts +108 -0
  98. package/lib/dist/lib/dataSourceConfig.d.ts.map +1 -0
  99. package/lib/dist/lib/dataSourceConfig.js +166 -0
  100. package/lib/dist/lib/dataSourceConfig.js.map +1 -0
  101. package/lib/dist/lib/debug.d.ts +26 -0
  102. package/lib/dist/lib/debug.d.ts.map +1 -0
  103. package/lib/dist/lib/debug.js +132 -0
  104. package/lib/dist/lib/debug.js.map +1 -0
  105. package/lib/dist/lib/diagnostics.d.ts +28 -0
  106. package/lib/dist/lib/diagnostics.d.ts.map +1 -0
  107. package/lib/dist/lib/diagnostics.js +65 -0
  108. package/lib/dist/lib/diagnostics.js.map +1 -0
  109. package/lib/dist/lib/envCompat.d.ts +27 -0
  110. package/lib/dist/lib/envCompat.d.ts.map +1 -0
  111. package/lib/dist/lib/envCompat.js +73 -0
  112. package/lib/dist/lib/envCompat.js.map +1 -0
  113. package/lib/dist/lib/findPackageRoot.d.ts +7 -0
  114. package/lib/dist/lib/findPackageRoot.d.ts.map +1 -0
  115. package/lib/dist/lib/findPackageRoot.js +57 -0
  116. package/lib/dist/lib/findPackageRoot.js.map +1 -0
  117. package/lib/dist/lib/hooks.d.ts +36 -0
  118. package/lib/dist/lib/hooks.d.ts.map +1 -0
  119. package/lib/dist/lib/hooks.js +112 -0
  120. package/lib/dist/lib/hooks.js.map +1 -0
  121. package/lib/dist/lib/index.d.ts +47 -0
  122. package/lib/dist/lib/index.d.ts.map +1 -0
  123. package/lib/dist/lib/index.js +62 -0
  124. package/lib/dist/lib/index.js.map +1 -0
  125. package/lib/dist/lib/labels.d.ts +90 -0
  126. package/lib/dist/lib/labels.d.ts.map +1 -0
  127. package/lib/dist/lib/labels.js +158 -0
  128. package/lib/dist/lib/labels.js.map +1 -0
  129. package/lib/dist/lib/markdown.d.ts +16 -0
  130. package/lib/dist/lib/markdown.d.ts.map +1 -0
  131. package/lib/dist/lib/markdown.js +42 -0
  132. package/lib/dist/lib/markdown.js.map +1 -0
  133. package/lib/dist/lib/matchers/expect.d.ts +3 -0
  134. package/lib/dist/lib/matchers/expect.d.ts.map +1 -0
  135. package/lib/dist/lib/matchers/expect.js +225 -0
  136. package/lib/dist/lib/matchers/expect.js.map +1 -0
  137. package/lib/dist/lib/matchers/index.d.ts +8 -0
  138. package/lib/dist/lib/matchers/index.d.ts.map +1 -0
  139. package/lib/dist/lib/matchers/index.js +9 -0
  140. package/lib/dist/lib/matchers/index.js.map +1 -0
  141. package/lib/dist/lib/matchers/judgeAccessor.d.ts +113 -0
  142. package/lib/dist/lib/matchers/judgeAccessor.d.ts.map +1 -0
  143. package/lib/dist/lib/matchers/judgeAccessor.js +183 -0
  144. package/lib/dist/lib/matchers/judgeAccessor.js.map +1 -0
  145. package/lib/dist/lib/matchers/session.d.ts +39 -0
  146. package/lib/dist/lib/matchers/session.d.ts.map +1 -0
  147. package/lib/dist/lib/matchers/session.js +116 -0
  148. package/lib/dist/lib/matchers/session.js.map +1 -0
  149. package/lib/dist/lib/matchers/traces.d.ts +55 -0
  150. package/lib/dist/lib/matchers/traces.d.ts.map +1 -0
  151. package/lib/dist/lib/matchers/traces.js +116 -0
  152. package/lib/dist/lib/matchers/traces.js.map +1 -0
  153. package/lib/dist/lib/matchers/types.d.ts +75 -0
  154. package/lib/dist/lib/matchers/types.d.ts.map +1 -0
  155. package/lib/dist/lib/matchers/types.js +6 -0
  156. package/lib/dist/lib/matchers/types.js.map +1 -0
  157. package/lib/dist/lib/packagePaths.d.ts +29 -0
  158. package/lib/dist/lib/packagePaths.d.ts.map +1 -0
  159. package/lib/dist/lib/packagePaths.js +63 -0
  160. package/lib/dist/lib/packagePaths.js.map +1 -0
  161. package/lib/dist/lib/performance.d.ts +51 -0
  162. package/lib/dist/lib/performance.d.ts.map +1 -0
  163. package/lib/dist/lib/performance.js +159 -0
  164. package/lib/dist/lib/performance.js.map +1 -0
  165. package/lib/dist/lib/portConfig.d.ts +29 -0
  166. package/lib/dist/lib/portConfig.d.ts.map +1 -0
  167. package/lib/dist/lib/portConfig.js +64 -0
  168. package/lib/dist/lib/portConfig.js.map +1 -0
  169. package/lib/dist/lib/preferences.d.ts +63 -0
  170. package/lib/dist/lib/preferences.d.ts.map +1 -0
  171. package/lib/dist/lib/preferences.js +117 -0
  172. package/lib/dist/lib/preferences.js.map +1 -0
  173. package/lib/dist/lib/resolveAgentModel.d.ts +22 -0
  174. package/lib/dist/lib/resolveAgentModel.d.ts.map +1 -0
  175. package/lib/dist/lib/resolveAgentModel.js +37 -0
  176. package/lib/dist/lib/resolveAgentModel.js.map +1 -0
  177. package/lib/dist/lib/runStats.d.ts +92 -0
  178. package/lib/dist/lib/runStats.d.ts.map +1 -0
  179. package/lib/dist/lib/runStats.js +160 -0
  180. package/lib/dist/lib/runStats.js.map +1 -0
  181. package/lib/dist/lib/telemetry/constants.d.ts +60 -0
  182. package/lib/dist/lib/telemetry/constants.d.ts.map +1 -0
  183. package/lib/dist/lib/telemetry/constants.js +87 -0
  184. package/lib/dist/lib/telemetry/constants.js.map +1 -0
  185. package/lib/dist/lib/telemetry/evalSpans.d.ts +61 -0
  186. package/lib/dist/lib/telemetry/evalSpans.d.ts.map +1 -0
  187. package/lib/dist/lib/telemetry/evalSpans.js +254 -0
  188. package/lib/dist/lib/telemetry/evalSpans.js.map +1 -0
  189. package/lib/dist/lib/telemetry/index.d.ts +11 -0
  190. package/lib/dist/lib/telemetry/index.d.ts.map +1 -0
  191. package/lib/dist/lib/telemetry/index.js +15 -0
  192. package/lib/dist/lib/telemetry/index.js.map +1 -0
  193. package/lib/dist/lib/telemetry/opensearchExporter.d.ts +43 -0
  194. package/lib/dist/lib/telemetry/opensearchExporter.d.ts.map +1 -0
  195. package/lib/dist/lib/telemetry/opensearchExporter.js +217 -0
  196. package/lib/dist/lib/telemetry/opensearchExporter.js.map +1 -0
  197. package/lib/dist/lib/telemetry/provider.d.ts +55 -0
  198. package/lib/dist/lib/telemetry/provider.d.ts.map +1 -0
  199. package/lib/dist/lib/telemetry/provider.js +140 -0
  200. package/lib/dist/lib/telemetry/provider.js.map +1 -0
  201. package/lib/dist/lib/testCaseLabels.d.ts +34 -0
  202. package/lib/dist/lib/testCaseLabels.d.ts.map +1 -0
  203. package/lib/dist/lib/testCaseLabels.js +88 -0
  204. package/lib/dist/lib/testCaseLabels.js.map +1 -0
  205. package/lib/dist/lib/testCaseValidation.d.ts +140 -0
  206. package/lib/dist/lib/testCaseValidation.d.ts.map +1 -0
  207. package/lib/dist/lib/testCaseValidation.js +162 -0
  208. package/lib/dist/lib/testCaseValidation.js.map +1 -0
  209. package/lib/dist/lib/testCases/agentFixture.d.ts +80 -0
  210. package/lib/dist/lib/testCases/agentFixture.d.ts.map +1 -0
  211. package/lib/dist/lib/testCases/agentFixture.js +43 -0
  212. package/lib/dist/lib/testCases/agentFixture.js.map +1 -0
  213. package/lib/dist/lib/testCases/authoringSurface.d.ts +10 -0
  214. package/lib/dist/lib/testCases/authoringSurface.d.ts.map +1 -0
  215. package/lib/dist/lib/testCases/authoringSurface.js +54 -0
  216. package/lib/dist/lib/testCases/authoringSurface.js.map +1 -0
  217. package/lib/dist/lib/testCases/codemod.d.ts +13 -0
  218. package/lib/dist/lib/testCases/codemod.d.ts.map +1 -0
  219. package/lib/dist/lib/testCases/codemod.js +169 -0
  220. package/lib/dist/lib/testCases/codemod.js.map +1 -0
  221. package/lib/dist/lib/testCases/define.d.ts +114 -0
  222. package/lib/dist/lib/testCases/define.d.ts.map +1 -0
  223. package/lib/dist/lib/testCases/define.js +253 -0
  224. package/lib/dist/lib/testCases/define.js.map +1 -0
  225. package/lib/dist/lib/testCases/evaluators.d.ts +80 -0
  226. package/lib/dist/lib/testCases/evaluators.d.ts.map +1 -0
  227. package/lib/dist/lib/testCases/evaluators.js +105 -0
  228. package/lib/dist/lib/testCases/evaluators.js.map +1 -0
  229. package/lib/dist/lib/testCases/index.d.ts +14 -0
  230. package/lib/dist/lib/testCases/index.d.ts.map +1 -0
  231. package/lib/dist/lib/testCases/index.js +12 -0
  232. package/lib/dist/lib/testCases/index.js.map +1 -0
  233. package/lib/dist/lib/testCases/judge.d.ts +165 -0
  234. package/lib/dist/lib/testCases/judge.d.ts.map +1 -0
  235. package/lib/dist/lib/testCases/judge.js +359 -0
  236. package/lib/dist/lib/testCases/judge.js.map +1 -0
  237. package/lib/dist/lib/testCases/loader.d.ts +26 -0
  238. package/lib/dist/lib/testCases/loader.d.ts.map +1 -0
  239. package/lib/dist/lib/testCases/loader.js +149 -0
  240. package/lib/dist/lib/testCases/loader.js.map +1 -0
  241. package/lib/dist/lib/testCases/types.d.ts +242 -0
  242. package/lib/dist/lib/testCases/types.d.ts.map +1 -0
  243. package/lib/dist/lib/testCases/types.js +6 -0
  244. package/lib/dist/lib/testCases/types.js.map +1 -0
  245. package/lib/dist/lib/theme.d.ts +6 -0
  246. package/lib/dist/lib/theme.d.ts.map +1 -0
  247. package/lib/dist/lib/theme.js +36 -0
  248. package/lib/dist/lib/theme.js.map +1 -0
  249. package/lib/dist/lib/uiTelemetry.d.ts +7 -0
  250. package/lib/dist/lib/uiTelemetry.d.ts.map +1 -0
  251. package/lib/dist/lib/uiTelemetry.js +25 -0
  252. package/lib/dist/lib/uiTelemetry.js.map +1 -0
  253. package/lib/dist/lib/utils.d.ts +96 -0
  254. package/lib/dist/lib/utils.d.ts.map +1 -0
  255. package/lib/dist/lib/utils.js +232 -0
  256. package/lib/dist/lib/utils.js.map +1 -0
  257. package/lib/dist/lib/workflow/consolidate.d.ts +12 -0
  258. package/lib/dist/lib/workflow/consolidate.d.ts.map +1 -0
  259. package/lib/dist/lib/workflow/consolidate.js +33 -0
  260. package/lib/dist/lib/workflow/consolidate.js.map +1 -0
  261. package/lib/dist/lib/workflow/index.d.ts +13 -0
  262. package/lib/dist/lib/workflow/index.d.ts.map +1 -0
  263. package/lib/dist/lib/workflow/index.js +12 -0
  264. package/lib/dist/lib/workflow/index.js.map +1 -0
  265. package/lib/dist/lib/workflow/ledger.d.ts +30 -0
  266. package/lib/dist/lib/workflow/ledger.d.ts.map +1 -0
  267. package/lib/dist/lib/workflow/ledger.js +41 -0
  268. package/lib/dist/lib/workflow/ledger.js.map +1 -0
  269. package/lib/dist/lib/workflow/pool.d.ts +13 -0
  270. package/lib/dist/lib/workflow/pool.d.ts.map +1 -0
  271. package/lib/dist/lib/workflow/pool.js +44 -0
  272. package/lib/dist/lib/workflow/pool.js.map +1 -0
  273. package/lib/dist/lib/workflow/source.d.ts +22 -0
  274. package/lib/dist/lib/workflow/source.d.ts.map +1 -0
  275. package/lib/dist/lib/workflow/source.js +29 -0
  276. package/lib/dist/lib/workflow/source.js.map +1 -0
  277. package/lib/dist/lib/workflow/stepB.d.ts +71 -0
  278. package/lib/dist/lib/workflow/stepB.d.ts.map +1 -0
  279. package/lib/dist/lib/workflow/stepB.js +99 -0
  280. package/lib/dist/lib/workflow/stepB.js.map +1 -0
  281. package/lib/dist/lib/workflow/types.d.ts +86 -0
  282. package/lib/dist/lib/workflow/types.d.ts.map +1 -0
  283. package/lib/dist/lib/workflow/types.js +6 -0
  284. package/lib/dist/lib/workflow/types.js.map +1 -0
  285. package/lib/dist/lib/workflow/workflow.d.ts +119 -0
  286. package/lib/dist/lib/workflow/workflow.d.ts.map +1 -0
  287. package/lib/dist/lib/workflow/workflow.js +195 -0
  288. package/lib/dist/lib/workflow/workflow.js.map +1 -0
  289. package/lib/dist/services/agent/aguiConverter.d.ts +50 -0
  290. package/lib/dist/services/agent/aguiConverter.d.ts.map +1 -0
  291. package/lib/dist/services/agent/aguiConverter.js +449 -0
  292. package/lib/dist/services/agent/aguiConverter.js.map +1 -0
  293. package/lib/dist/services/agent/index.d.ts +10 -0
  294. package/lib/dist/services/agent/index.d.ts.map +1 -0
  295. package/lib/dist/services/agent/index.js +12 -0
  296. package/lib/dist/services/agent/index.js.map +1 -0
  297. package/lib/dist/services/agent/payloadBuilder.d.ts +33 -0
  298. package/lib/dist/services/agent/payloadBuilder.d.ts.map +1 -0
  299. package/lib/dist/services/agent/payloadBuilder.js +75 -0
  300. package/lib/dist/services/agent/payloadBuilder.js.map +1 -0
  301. package/lib/dist/services/agent/sseStream.d.ts +43 -0
  302. package/lib/dist/services/agent/sseStream.d.ts.map +1 -0
  303. package/lib/dist/services/agent/sseStream.js +223 -0
  304. package/lib/dist/services/agent/sseStream.js.map +1 -0
  305. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts +44 -0
  306. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts.map +1 -0
  307. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js +95 -0
  308. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js.map +1 -0
  309. package/lib/dist/services/connectors/base/BaseConnector.d.ts +81 -0
  310. package/lib/dist/services/connectors/base/BaseConnector.d.ts.map +1 -0
  311. package/lib/dist/services/connectors/base/BaseConnector.js +170 -0
  312. package/lib/dist/services/connectors/base/BaseConnector.js.map +1 -0
  313. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts +116 -0
  314. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts.map +1 -0
  315. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js +403 -0
  316. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js.map +1 -0
  317. package/lib/dist/services/connectors/index.d.ts +13 -0
  318. package/lib/dist/services/connectors/index.d.ts.map +1 -0
  319. package/lib/dist/services/connectors/index.js +32 -0
  320. package/lib/dist/services/connectors/index.js.map +1 -0
  321. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts +48 -0
  322. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts.map +1 -0
  323. package/lib/dist/services/connectors/kiro/KiroConnector.js +158 -0
  324. package/lib/dist/services/connectors/kiro/KiroConnector.js.map +1 -0
  325. package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts +36 -0
  326. package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts.map +1 -0
  327. package/lib/dist/services/connectors/langgraph/LangGraphConnector.js +175 -0
  328. package/lib/dist/services/connectors/langgraph/LangGraphConnector.js.map +1 -0
  329. package/lib/dist/services/connectors/mock/MockConnector.d.ts +37 -0
  330. package/lib/dist/services/connectors/mock/MockConnector.d.ts.map +1 -0
  331. package/lib/dist/services/connectors/mock/MockConnector.js +120 -0
  332. package/lib/dist/services/connectors/mock/MockConnector.js.map +1 -0
  333. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts +42 -0
  334. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts.map +1 -0
  335. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js +133 -0
  336. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js.map +1 -0
  337. package/lib/dist/services/connectors/pi/PiConnector.d.ts +87 -0
  338. package/lib/dist/services/connectors/pi/PiConnector.d.ts.map +1 -0
  339. package/lib/dist/services/connectors/pi/PiConnector.js +274 -0
  340. package/lib/dist/services/connectors/pi/PiConnector.js.map +1 -0
  341. package/lib/dist/services/connectors/registry.d.ts +57 -0
  342. package/lib/dist/services/connectors/registry.d.ts.map +1 -0
  343. package/lib/dist/services/connectors/registry.js +106 -0
  344. package/lib/dist/services/connectors/registry.js.map +1 -0
  345. package/lib/dist/services/connectors/rest/RESTConnector.d.ts +38 -0
  346. package/lib/dist/services/connectors/rest/RESTConnector.d.ts.map +1 -0
  347. package/lib/dist/services/connectors/rest/RESTConnector.js +117 -0
  348. package/lib/dist/services/connectors/rest/RESTConnector.js.map +1 -0
  349. package/lib/dist/services/connectors/server.d.ts +13 -0
  350. package/lib/dist/services/connectors/server.d.ts.map +1 -0
  351. package/lib/dist/services/connectors/server.js +34 -0
  352. package/lib/dist/services/connectors/server.js.map +1 -0
  353. package/lib/dist/services/connectors/strands/StrandsConnector.d.ts +48 -0
  354. package/lib/dist/services/connectors/strands/StrandsConnector.d.ts.map +1 -0
  355. package/lib/dist/services/connectors/strands/StrandsConnector.js +221 -0
  356. package/lib/dist/services/connectors/strands/StrandsConnector.js.map +1 -0
  357. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts +88 -0
  358. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts.map +1 -0
  359. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js +418 -0
  360. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js.map +1 -0
  361. package/lib/dist/services/connectors/types.d.ts +213 -0
  362. package/lib/dist/services/connectors/types.d.ts.map +1 -0
  363. package/lib/dist/services/connectors/types.js +6 -0
  364. package/lib/dist/services/connectors/types.js.map +1 -0
  365. package/lib/dist/services/evaluation/bedrockJudge.d.ts +64 -0
  366. package/lib/dist/services/evaluation/bedrockJudge.d.ts.map +1 -0
  367. package/lib/dist/services/evaluation/bedrockJudge.js +167 -0
  368. package/lib/dist/services/evaluation/bedrockJudge.js.map +1 -0
  369. package/lib/dist/services/evaluation/evaluatorError.d.ts +56 -0
  370. package/lib/dist/services/evaluation/evaluatorError.d.ts.map +1 -0
  371. package/lib/dist/services/evaluation/evaluatorError.js +56 -0
  372. package/lib/dist/services/evaluation/evaluatorError.js.map +1 -0
  373. package/lib/dist/services/evaluation/index.d.ts +106 -0
  374. package/lib/dist/services/evaluation/index.d.ts.map +1 -0
  375. package/lib/dist/services/evaluation/index.js +684 -0
  376. package/lib/dist/services/evaluation/index.js.map +1 -0
  377. package/lib/dist/services/evaluation/mockTrajectory.d.ts +3 -0
  378. package/lib/dist/services/evaluation/mockTrajectory.d.ts.map +1 -0
  379. package/lib/dist/services/evaluation/mockTrajectory.js +72 -0
  380. package/lib/dist/services/evaluation/mockTrajectory.js.map +1 -0
  381. package/lib/dist/services/opensearch/client.d.ts +26 -0
  382. package/lib/dist/services/opensearch/client.d.ts.map +1 -0
  383. package/lib/dist/services/opensearch/client.js +131 -0
  384. package/lib/dist/services/opensearch/client.js.map +1 -0
  385. package/lib/dist/services/opensearch/index.d.ts +16 -0
  386. package/lib/dist/services/opensearch/index.d.ts.map +1 -0
  387. package/lib/dist/services/opensearch/index.js +25 -0
  388. package/lib/dist/services/opensearch/index.js.map +1 -0
  389. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts +123 -0
  390. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts.map +1 -0
  391. package/lib/dist/services/storage/asyncBenchmarkStorage.js +429 -0
  392. package/lib/dist/services/storage/asyncBenchmarkStorage.js.map +1 -0
  393. package/lib/dist/services/storage/asyncRunStorage.d.ts +127 -0
  394. package/lib/dist/services/storage/asyncRunStorage.d.ts.map +1 -0
  395. package/lib/dist/services/storage/asyncRunStorage.js +448 -0
  396. package/lib/dist/services/storage/asyncRunStorage.js.map +1 -0
  397. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts +156 -0
  398. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts.map +1 -0
  399. package/lib/dist/services/storage/asyncTestCaseStorage.js +285 -0
  400. package/lib/dist/services/storage/asyncTestCaseStorage.js.map +1 -0
  401. package/lib/dist/services/storage/index.d.ts +17 -0
  402. package/lib/dist/services/storage/index.d.ts.map +1 -0
  403. package/lib/dist/services/storage/index.js +20 -0
  404. package/lib/dist/services/storage/index.js.map +1 -0
  405. package/lib/dist/services/storage/migration.d.ts +54 -0
  406. package/lib/dist/services/storage/migration.d.ts.map +1 -0
  407. package/lib/dist/services/storage/migration.js +296 -0
  408. package/lib/dist/services/storage/migration.js.map +1 -0
  409. package/lib/dist/services/storage/opensearchClient.d.ts +924 -0
  410. package/lib/dist/services/storage/opensearchClient.d.ts.map +1 -0
  411. package/lib/dist/services/storage/opensearchClient.js +435 -0
  412. package/lib/dist/services/storage/opensearchClient.js.map +1 -0
  413. package/lib/dist/services/traces/browserRecovery.d.ts +26 -0
  414. package/lib/dist/services/traces/browserRecovery.d.ts.map +1 -0
  415. package/lib/dist/services/traces/browserRecovery.js +81 -0
  416. package/lib/dist/services/traces/browserRecovery.js.map +1 -0
  417. package/lib/dist/services/traces/categoryStyles.d.ts +21 -0
  418. package/lib/dist/services/traces/categoryStyles.d.ts.map +1 -0
  419. package/lib/dist/services/traces/categoryStyles.js +56 -0
  420. package/lib/dist/services/traces/categoryStyles.js.map +1 -0
  421. package/lib/dist/services/traces/executionOrderTransform.d.ts +35 -0
  422. package/lib/dist/services/traces/executionOrderTransform.d.ts.map +1 -0
  423. package/lib/dist/services/traces/executionOrderTransform.js +313 -0
  424. package/lib/dist/services/traces/executionOrderTransform.js.map +1 -0
  425. package/lib/dist/services/traces/fetchSpansForRun.d.ts +86 -0
  426. package/lib/dist/services/traces/fetchSpansForRun.d.ts.map +1 -0
  427. package/lib/dist/services/traces/fetchSpansForRun.js +69 -0
  428. package/lib/dist/services/traces/fetchSpansForRun.js.map +1 -0
  429. package/lib/dist/services/traces/flowTransform.d.ts +24 -0
  430. package/lib/dist/services/traces/flowTransform.d.ts.map +1 -0
  431. package/lib/dist/services/traces/flowTransform.js +228 -0
  432. package/lib/dist/services/traces/flowTransform.js.map +1 -0
  433. package/lib/dist/services/traces/index.d.ts +121 -0
  434. package/lib/dist/services/traces/index.d.ts.map +1 -0
  435. package/lib/dist/services/traces/index.js +255 -0
  436. package/lib/dist/services/traces/index.js.map +1 -0
  437. package/lib/dist/services/traces/intentTransform.d.ts +20 -0
  438. package/lib/dist/services/traces/intentTransform.d.ts.map +1 -0
  439. package/lib/dist/services/traces/intentTransform.js +131 -0
  440. package/lib/dist/services/traces/intentTransform.js.map +1 -0
  441. package/lib/dist/services/traces/judgeAgentsHints.d.ts +63 -0
  442. package/lib/dist/services/traces/judgeAgentsHints.d.ts.map +1 -0
  443. package/lib/dist/services/traces/judgeAgentsHints.js +89 -0
  444. package/lib/dist/services/traces/judgeAgentsHints.js.map +1 -0
  445. package/lib/dist/services/traces/messageExtraction.d.ts +15 -0
  446. package/lib/dist/services/traces/messageExtraction.d.ts.map +1 -0
  447. package/lib/dist/services/traces/messageExtraction.js +251 -0
  448. package/lib/dist/services/traces/messageExtraction.js.map +1 -0
  449. package/lib/dist/services/traces/spanCategorization.d.ts +63 -0
  450. package/lib/dist/services/traces/spanCategorization.d.ts.map +1 -0
  451. package/lib/dist/services/traces/spanCategorization.js +276 -0
  452. package/lib/dist/services/traces/spanCategorization.js.map +1 -0
  453. package/lib/dist/services/traces/spanPreprocessing.d.ts +37 -0
  454. package/lib/dist/services/traces/spanPreprocessing.d.ts.map +1 -0
  455. package/lib/dist/services/traces/spanPreprocessing.js +102 -0
  456. package/lib/dist/services/traces/spanPreprocessing.js.map +1 -0
  457. package/lib/dist/services/traces/spansToTrajectory.d.ts +36 -0
  458. package/lib/dist/services/traces/spansToTrajectory.d.ts.map +1 -0
  459. package/lib/dist/services/traces/spansToTrajectory.js +387 -0
  460. package/lib/dist/services/traces/spansToTrajectory.js.map +1 -0
  461. package/lib/dist/services/traces/toolSimilarity.d.ts +35 -0
  462. package/lib/dist/services/traces/toolSimilarity.d.ts.map +1 -0
  463. package/lib/dist/services/traces/toolSimilarity.js +203 -0
  464. package/lib/dist/services/traces/toolSimilarity.js.map +1 -0
  465. package/lib/dist/services/traces/traceComparison.d.ts +31 -0
  466. package/lib/dist/services/traces/traceComparison.d.ts.map +1 -0
  467. package/lib/dist/services/traces/traceComparison.js +318 -0
  468. package/lib/dist/services/traces/traceComparison.js.map +1 -0
  469. package/lib/dist/services/traces/traceGrouping.d.ts +19 -0
  470. package/lib/dist/services/traces/traceGrouping.d.ts.map +1 -0
  471. package/lib/dist/services/traces/traceGrouping.js +107 -0
  472. package/lib/dist/services/traces/traceGrouping.js.map +1 -0
  473. package/lib/dist/services/traces/tracePoller.d.ts +84 -0
  474. package/lib/dist/services/traces/tracePoller.d.ts.map +1 -0
  475. package/lib/dist/services/traces/tracePoller.js +309 -0
  476. package/lib/dist/services/traces/tracePoller.js.map +1 -0
  477. package/lib/dist/services/traces/traceStats.d.ts +45 -0
  478. package/lib/dist/services/traces/traceStats.d.ts.map +1 -0
  479. package/lib/dist/services/traces/traceStats.js +114 -0
  480. package/lib/dist/services/traces/traceStats.js.map +1 -0
  481. package/lib/dist/services/traces/traceSummary.d.ts +47 -0
  482. package/lib/dist/services/traces/traceSummary.d.ts.map +1 -0
  483. package/lib/dist/services/traces/traceSummary.js +68 -0
  484. package/lib/dist/services/traces/traceSummary.js.map +1 -0
  485. package/lib/dist/services/traces/utils.d.ts +33 -0
  486. package/lib/dist/services/traces/utils.d.ts.map +1 -0
  487. package/lib/dist/services/traces/utils.js +114 -0
  488. package/lib/dist/services/traces/utils.js.map +1 -0
  489. package/lib/dist/types/agui.d.ts +13 -0
  490. package/lib/dist/types/agui.d.ts.map +1 -0
  491. package/lib/dist/types/agui.js +16 -0
  492. package/lib/dist/types/agui.js.map +1 -0
  493. package/lib/dist/types/index.d.ts +1175 -0
  494. package/lib/dist/types/index.d.ts.map +1 -0
  495. package/lib/dist/types/index.js +12 -0
  496. package/lib/dist/types/index.js.map +1 -0
  497. package/lib/dist/types/skills.d.ts +146 -0
  498. package/lib/dist/types/skills.d.ts.map +1 -0
  499. package/lib/dist/types/skills.js +6 -0
  500. package/lib/dist/types/skills.js.map +1 -0
  501. package/observio-sample-agent/pi-package/README.md +112 -0
  502. package/observio-sample-agent/pi-package/extensions/agent-health.ts +373 -0
  503. package/observio-sample-agent/pi-package/package.json +17 -0
  504. package/observio-sample-agent/pi-package/prompts/agent-health.md +37 -0
  505. package/observio-sample-agent/pi-package/skills/create-pr/SKILL.md +88 -0
  506. package/observio-sample-agent/pi-package/skills/fix-bug/SKILL.md +71 -0
  507. package/observio-sample-agent/pi-package/skills/implement-feature/SKILL.md +156 -0
  508. package/observio-sample-agent/pi-package/skills/instrument-otel/SKILL.md +208 -0
  509. package/observio-sample-agent/pi-package/skills/setup-collector/SKILL.md +146 -0
  510. package/observio-sample-agent/pi-package/skills/write-test/SKILL.md +115 -0
  511. package/package.json +64 -13
  512. package/server/dist/app.js +32651 -17637
  513. package/server/dist/index.js +29875 -14638
  514. package/tsconfig.lib.json +71 -0
  515. package/dist/assets/index-EvPLSTAS.js +0 -267
  516. package/dist/assets/index-RXasQKUs.css +0 -1
  517. package/lib/dist/config/index.js +0 -404
  518. 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)