@ken-jo/agent-connector 0.4.91 → 0.4.93

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 (196) hide show
  1. package/README.md +326 -563
  2. package/dist/{action-L44DXFHT.js → action-DOWHWEDZ.js} +14 -14
  3. package/dist/{amazon-q-B52EY2SV.js → amazon-q-ETMAGY3D.js} +5 -5
  4. package/dist/{amp-UXABVUKC.js → amp-67BZONGF.js} +5 -5
  5. package/dist/{antigravity-RZHN53VB.js → antigravity-VXLDLTO7.js} +6 -6
  6. package/dist/{antigravity-cli-JO6GUTV7.js → antigravity-cli-OM6SC3PE.js} +47 -16
  7. package/dist/antigravity-cli-OM6SC3PE.js.map +1 -0
  8. package/dist/{chunk-R6LML2YS.js → chunk-2RIFORQS.js} +2 -2
  9. package/dist/{chunk-QKLJU4JX.js → chunk-2Y2MZRLP.js} +56 -2
  10. package/dist/chunk-2Y2MZRLP.js.map +1 -0
  11. package/dist/{chunk-HORHRHNG.js → chunk-4NHXLXSD.js} +2 -2
  12. package/dist/{chunk-AY3RGRTT.js → chunk-6TF7MHG5.js} +2 -2
  13. package/dist/{chunk-NBUEL74R.js → chunk-6WZODR3Z.js} +3 -3
  14. package/dist/{chunk-LF76VPGQ.js → chunk-B5W3RHTI.js} +72 -22
  15. package/dist/chunk-B5W3RHTI.js.map +1 -0
  16. package/dist/{chunk-BLTVZACS.js → chunk-EHP7WISI.js} +9 -9
  17. package/dist/{chunk-4NSU3KWX.js → chunk-FJCUKXGX.js} +2 -2
  18. package/dist/{chunk-IXOQDZWC.js → chunk-GZGLCCEE.js} +5 -1
  19. package/dist/chunk-GZGLCCEE.js.map +1 -0
  20. package/dist/{chunk-LAIITCMW.js → chunk-I5TO42QC.js} +5 -5
  21. package/dist/{chunk-4FWETID5.js → chunk-IVAWP6HH.js} +2 -2
  22. package/dist/{chunk-UBB7T54N.js → chunk-JKKU2WKG.js} +3 -3
  23. package/dist/{chunk-G4CEELKO.js → chunk-KJLFGQQM.js} +180 -10
  24. package/dist/chunk-KJLFGQQM.js.map +1 -0
  25. package/dist/{chunk-NWLRJNXM.js → chunk-KSPMSRVU.js} +27 -15
  26. package/dist/chunk-KSPMSRVU.js.map +1 -0
  27. package/dist/{chunk-VVFDU4IX.js → chunk-MGTDQLJJ.js} +12 -5
  28. package/dist/{chunk-VVFDU4IX.js.map → chunk-MGTDQLJJ.js.map} +1 -1
  29. package/dist/{chunk-56R2ER7K.js → chunk-NBYKLUF6.js} +2 -2
  30. package/dist/chunk-OEADFFKO.js +590 -0
  31. package/dist/chunk-OEADFFKO.js.map +1 -0
  32. package/dist/{chunk-QARPXSIV.js → chunk-P23RVIUY.js} +4 -4
  33. package/dist/{chunk-25CPWJA7.js → chunk-SILKSP2Y.js} +43 -43
  34. package/dist/{chunk-KIRCPLM4.js → chunk-TTKSYJRY.js} +538 -226
  35. package/dist/chunk-TTKSYJRY.js.map +1 -0
  36. package/dist/{chunk-YYNXIUR2.js → chunk-UMQ6NBQR.js} +3 -3
  37. package/dist/chunk-UMQ6NBQR.js.map +1 -0
  38. package/dist/{chunk-4HVQ7IUM.js → chunk-XC5SJ35F.js} +17 -4
  39. package/dist/chunk-XC5SJ35F.js.map +1 -0
  40. package/dist/{chunk-LN76OGNR.js → chunk-Z2MRSS2I.js} +2 -2
  41. package/dist/{chunk-ZMLVR4J7.js → chunk-ZMAJ2XFD.js} +2 -2
  42. package/dist/{claude-code-WS4NAGZT.js → claude-code-DUZNOAS2.js} +9 -9
  43. package/dist/cli/sdk.js +7 -7
  44. package/dist/cli.js +1 -1
  45. package/dist/{cline-NNMVCECA.js → cline-25KW25IN.js} +5 -5
  46. package/dist/{codebuddy-RBEZGXBG.js → codebuddy-ZNYQACMF.js} +5 -5
  47. package/dist/{codebuff-RJIDSEU3.js → codebuff-VR6JUDIY.js} +5 -5
  48. package/dist/{codex-ZZ434GYR.js → codex-CPNKTXG3.js} +11 -5
  49. package/dist/{codex-ZZ434GYR.js.map → codex-CPNKTXG3.js.map} +1 -1
  50. package/dist/{continue-MNM7YVJY.js → continue-WU2IB5KS.js} +6 -6
  51. package/dist/{copilot-cli-SMTX5F65.js → copilot-cli-PAP377OM.js} +5 -5
  52. package/dist/{crush-NYDBHIJE.js → crush-3AVQA4YU.js} +5 -5
  53. package/dist/{cursor-AOELDNZU.js → cursor-GSLUET3V.js} +6 -6
  54. package/dist/define-connector-LQFJL_at.d.ts +89 -0
  55. package/dist/{detect-3S46RUMK.js → detect-DYQNUMXL.js} +4 -4
  56. package/dist/{devin-PRJY2TTD.js → devin-QMEM3OFA.js} +5 -5
  57. package/dist/{doctor-3CUBPQKU.js → doctor-H6XXAR63.js} +25 -21
  58. package/dist/doctor-H6XXAR63.js.map +1 -0
  59. package/dist/{droid-PTCH2K7Y.js → droid-MOKV53J4.js} +5 -5
  60. package/dist/{gemini-cli-QGLN2UMS.js → gemini-cli-47ZHCOZR.js} +5 -5
  61. package/dist/{goose-DQ6GSZ5O.js → goose-4EI5MYTI.js} +6 -6
  62. package/dist/{grok-cli-5QD235UB.js → grok-cli-QYQPDSVB.js} +5 -5
  63. package/dist/{hermes-E47IG63A.js → hermes-F75OSK3Y.js} +6 -6
  64. package/dist/{hook-P6EKDINW.js → hook-GIQTUDMN.js} +14 -14
  65. package/dist/index.d.ts +15 -88
  66. package/dist/index.js +15 -7
  67. package/dist/install-T27662FW.js +382 -0
  68. package/dist/install-T27662FW.js.map +1 -0
  69. package/dist/{introspect-DYOIX8Ov.d.ts → introspect-D4fEGuhN.d.ts} +1 -1
  70. package/dist/{jetbrains-copilot-T2EPKROP.js → jetbrains-copilot-ZGIWI6YV.js} +23 -7
  71. package/dist/jetbrains-copilot-ZGIWI6YV.js.map +1 -0
  72. package/dist/{junie-SQ4SDLGK.js → junie-DIFN2P22.js} +5 -5
  73. package/dist/{kilo-OU2ZLZKB.js → kilo-EMZJBEBB.js} +5 -5
  74. package/dist/{kilo-cli-NMWGYF4F.js → kilo-cli-S3GXBPAE.js} +5 -5
  75. package/dist/{kimi-Z7L2LEEI.js → kimi-IQJOIY6B.js} +5 -5
  76. package/dist/{kiro-4IN5IH46.js → kiro-BYX4HEAJ.js} +5 -5
  77. package/dist/{leaderboard-LF5SP6X2.js → leaderboard-CIMQBOUS.js} +5 -5
  78. package/dist/{mimo-code-G2CBZ4M6.js → mimo-code-7R53QDHB.js} +5 -5
  79. package/dist/{mistral-vibe-TRQDHAWV.js → mistral-vibe-LHJ55FSB.js} +5 -5
  80. package/dist/{mux-JNM3F2NW.js → mux-NYCNGL43.js} +5 -5
  81. package/dist/{nemoclaw-SHA4IUML.js → nemoclaw-WSIPSE7U.js} +6 -6
  82. package/dist/{omp-OOVUNXME.js → omp-562NK5BJ.js} +5 -5
  83. package/dist/{open-interpreter-4PKL56AA.js → open-interpreter-I2CNOEXY.js} +5 -5
  84. package/dist/openclaw-7EYBQS4R.js +17 -0
  85. package/dist/{opencode-W2RK4M7G.js → opencode-YS4WX2E2.js} +5 -5
  86. package/dist/{openhands-5LNH3BKB.js → openhands-QMYIKNOS.js} +5 -5
  87. package/dist/{package-2EAIYSJ4.js → package-LIPZKHAQ.js} +12 -12
  88. package/dist/{pi-BUADR5MJ.js → pi-644FIN3A.js} +5 -5
  89. package/dist/{qwen-code-TUJNHKNI.js → qwen-code-STDMX7EM.js} +6 -6
  90. package/dist/{roo-code-L5F7S6QH.js → roo-code-DLPIHHQ6.js} +5 -5
  91. package/dist/runtime/index.d.ts +1 -1
  92. package/dist/runtime/index.js +12 -12
  93. package/dist/sdk/index.d.ts +4 -4
  94. package/dist/sdk/index.js +6 -6
  95. package/dist/sdk/test.d.ts +2 -2
  96. package/dist/sdk/test.js +10 -10
  97. package/dist/{serve-K62FW3V7.js → serve-ABTO2NA2.js} +14 -14
  98. package/dist/{status-E5MCFZM6.js → status-J7SOUH7O.js} +10 -10
  99. package/dist/{statusline-LIPF2KVP.js → statusline-QF4G724E.js} +13 -13
  100. package/dist/{telemetry-4OC56NTM.js → telemetry-EICCFEIF.js} +10 -10
  101. package/dist/{trae-Z7CQ2A2Q.js → trae-UOYD6JZZ.js} +5 -5
  102. package/dist/{types-C4qMgbJn.d.ts → types-BhcUEIJJ.d.ts} +82 -3
  103. package/dist/{uninstall-2YYKN5DX.js → uninstall-NJNNZZZY.js} +35 -25
  104. package/dist/uninstall-NJNNZZZY.js.map +1 -0
  105. package/dist/{upgrade-55AFPJEF.js → upgrade-TIBUOQNM.js} +23 -17
  106. package/dist/upgrade-TIBUOQNM.js.map +1 -0
  107. package/dist/{usage-3PB3WZSL.js → usage-VEVBWPLS.js} +2 -2
  108. package/dist/{usage-event-KD5FW6W4.js → usage-event-GRQE7XWT.js} +13 -13
  109. package/dist/{vscode-copilot-LU5NC4ZS.js → vscode-copilot-NIMH2DGU.js} +20 -5
  110. package/dist/vscode-copilot-NIMH2DGU.js.map +1 -0
  111. package/dist/{warp-4PPG5LOM.js → warp-QYJGKURM.js} +5 -5
  112. package/dist/{windsurf-3T3RVXKM.js → windsurf-75LLZ37C.js} +5 -5
  113. package/dist/{zed-ZF2OQ75O.js → zed-HKAZXEJW.js} +5 -5
  114. package/package.json +1 -1
  115. package/dist/antigravity-cli-JO6GUTV7.js.map +0 -1
  116. package/dist/chunk-4HVQ7IUM.js.map +0 -1
  117. package/dist/chunk-7HUUINPB.js +0 -201
  118. package/dist/chunk-7HUUINPB.js.map +0 -1
  119. package/dist/chunk-G4CEELKO.js.map +0 -1
  120. package/dist/chunk-IXOQDZWC.js.map +0 -1
  121. package/dist/chunk-KIRCPLM4.js.map +0 -1
  122. package/dist/chunk-LF76VPGQ.js.map +0 -1
  123. package/dist/chunk-NWLRJNXM.js.map +0 -1
  124. package/dist/chunk-QKLJU4JX.js.map +0 -1
  125. package/dist/chunk-YYNXIUR2.js.map +0 -1
  126. package/dist/doctor-3CUBPQKU.js.map +0 -1
  127. package/dist/install-7DMK53SB.js +0 -96
  128. package/dist/install-7DMK53SB.js.map +0 -1
  129. package/dist/jetbrains-copilot-T2EPKROP.js.map +0 -1
  130. package/dist/openclaw-BD56E5MV.js +0 -17
  131. package/dist/uninstall-2YYKN5DX.js.map +0 -1
  132. package/dist/upgrade-55AFPJEF.js.map +0 -1
  133. package/dist/vscode-copilot-LU5NC4ZS.js.map +0 -1
  134. /package/dist/{action-L44DXFHT.js.map → action-DOWHWEDZ.js.map} +0 -0
  135. /package/dist/{amazon-q-B52EY2SV.js.map → amazon-q-ETMAGY3D.js.map} +0 -0
  136. /package/dist/{amp-UXABVUKC.js.map → amp-67BZONGF.js.map} +0 -0
  137. /package/dist/{antigravity-RZHN53VB.js.map → antigravity-VXLDLTO7.js.map} +0 -0
  138. /package/dist/{chunk-R6LML2YS.js.map → chunk-2RIFORQS.js.map} +0 -0
  139. /package/dist/{chunk-HORHRHNG.js.map → chunk-4NHXLXSD.js.map} +0 -0
  140. /package/dist/{chunk-AY3RGRTT.js.map → chunk-6TF7MHG5.js.map} +0 -0
  141. /package/dist/{chunk-NBUEL74R.js.map → chunk-6WZODR3Z.js.map} +0 -0
  142. /package/dist/{chunk-BLTVZACS.js.map → chunk-EHP7WISI.js.map} +0 -0
  143. /package/dist/{chunk-4NSU3KWX.js.map → chunk-FJCUKXGX.js.map} +0 -0
  144. /package/dist/{chunk-LAIITCMW.js.map → chunk-I5TO42QC.js.map} +0 -0
  145. /package/dist/{chunk-4FWETID5.js.map → chunk-IVAWP6HH.js.map} +0 -0
  146. /package/dist/{chunk-UBB7T54N.js.map → chunk-JKKU2WKG.js.map} +0 -0
  147. /package/dist/{chunk-56R2ER7K.js.map → chunk-NBYKLUF6.js.map} +0 -0
  148. /package/dist/{chunk-QARPXSIV.js.map → chunk-P23RVIUY.js.map} +0 -0
  149. /package/dist/{chunk-25CPWJA7.js.map → chunk-SILKSP2Y.js.map} +0 -0
  150. /package/dist/{chunk-LN76OGNR.js.map → chunk-Z2MRSS2I.js.map} +0 -0
  151. /package/dist/{chunk-ZMLVR4J7.js.map → chunk-ZMAJ2XFD.js.map} +0 -0
  152. /package/dist/{claude-code-WS4NAGZT.js.map → claude-code-DUZNOAS2.js.map} +0 -0
  153. /package/dist/{cline-NNMVCECA.js.map → cline-25KW25IN.js.map} +0 -0
  154. /package/dist/{codebuddy-RBEZGXBG.js.map → codebuddy-ZNYQACMF.js.map} +0 -0
  155. /package/dist/{codebuff-RJIDSEU3.js.map → codebuff-VR6JUDIY.js.map} +0 -0
  156. /package/dist/{continue-MNM7YVJY.js.map → continue-WU2IB5KS.js.map} +0 -0
  157. /package/dist/{copilot-cli-SMTX5F65.js.map → copilot-cli-PAP377OM.js.map} +0 -0
  158. /package/dist/{crush-NYDBHIJE.js.map → crush-3AVQA4YU.js.map} +0 -0
  159. /package/dist/{cursor-AOELDNZU.js.map → cursor-GSLUET3V.js.map} +0 -0
  160. /package/dist/{detect-3S46RUMK.js.map → detect-DYQNUMXL.js.map} +0 -0
  161. /package/dist/{devin-PRJY2TTD.js.map → devin-QMEM3OFA.js.map} +0 -0
  162. /package/dist/{droid-PTCH2K7Y.js.map → droid-MOKV53J4.js.map} +0 -0
  163. /package/dist/{gemini-cli-QGLN2UMS.js.map → gemini-cli-47ZHCOZR.js.map} +0 -0
  164. /package/dist/{goose-DQ6GSZ5O.js.map → goose-4EI5MYTI.js.map} +0 -0
  165. /package/dist/{grok-cli-5QD235UB.js.map → grok-cli-QYQPDSVB.js.map} +0 -0
  166. /package/dist/{hermes-E47IG63A.js.map → hermes-F75OSK3Y.js.map} +0 -0
  167. /package/dist/{hook-P6EKDINW.js.map → hook-GIQTUDMN.js.map} +0 -0
  168. /package/dist/{junie-SQ4SDLGK.js.map → junie-DIFN2P22.js.map} +0 -0
  169. /package/dist/{kilo-OU2ZLZKB.js.map → kilo-EMZJBEBB.js.map} +0 -0
  170. /package/dist/{kilo-cli-NMWGYF4F.js.map → kilo-cli-S3GXBPAE.js.map} +0 -0
  171. /package/dist/{kimi-Z7L2LEEI.js.map → kimi-IQJOIY6B.js.map} +0 -0
  172. /package/dist/{kiro-4IN5IH46.js.map → kiro-BYX4HEAJ.js.map} +0 -0
  173. /package/dist/{leaderboard-LF5SP6X2.js.map → leaderboard-CIMQBOUS.js.map} +0 -0
  174. /package/dist/{mimo-code-G2CBZ4M6.js.map → mimo-code-7R53QDHB.js.map} +0 -0
  175. /package/dist/{mistral-vibe-TRQDHAWV.js.map → mistral-vibe-LHJ55FSB.js.map} +0 -0
  176. /package/dist/{mux-JNM3F2NW.js.map → mux-NYCNGL43.js.map} +0 -0
  177. /package/dist/{nemoclaw-SHA4IUML.js.map → nemoclaw-WSIPSE7U.js.map} +0 -0
  178. /package/dist/{omp-OOVUNXME.js.map → omp-562NK5BJ.js.map} +0 -0
  179. /package/dist/{open-interpreter-4PKL56AA.js.map → open-interpreter-I2CNOEXY.js.map} +0 -0
  180. /package/dist/{openclaw-BD56E5MV.js.map → openclaw-7EYBQS4R.js.map} +0 -0
  181. /package/dist/{opencode-W2RK4M7G.js.map → opencode-YS4WX2E2.js.map} +0 -0
  182. /package/dist/{openhands-5LNH3BKB.js.map → openhands-QMYIKNOS.js.map} +0 -0
  183. /package/dist/{package-2EAIYSJ4.js.map → package-LIPZKHAQ.js.map} +0 -0
  184. /package/dist/{pi-BUADR5MJ.js.map → pi-644FIN3A.js.map} +0 -0
  185. /package/dist/{qwen-code-TUJNHKNI.js.map → qwen-code-STDMX7EM.js.map} +0 -0
  186. /package/dist/{roo-code-L5F7S6QH.js.map → roo-code-DLPIHHQ6.js.map} +0 -0
  187. /package/dist/{serve-K62FW3V7.js.map → serve-ABTO2NA2.js.map} +0 -0
  188. /package/dist/{status-E5MCFZM6.js.map → status-J7SOUH7O.js.map} +0 -0
  189. /package/dist/{statusline-LIPF2KVP.js.map → statusline-QF4G724E.js.map} +0 -0
  190. /package/dist/{telemetry-4OC56NTM.js.map → telemetry-EICCFEIF.js.map} +0 -0
  191. /package/dist/{trae-Z7CQ2A2Q.js.map → trae-UOYD6JZZ.js.map} +0 -0
  192. /package/dist/{usage-3PB3WZSL.js.map → usage-VEVBWPLS.js.map} +0 -0
  193. /package/dist/{usage-event-KD5FW6W4.js.map → usage-event-GRQE7XWT.js.map} +0 -0
  194. /package/dist/{warp-4PPG5LOM.js.map → warp-QYJGKURM.js.map} +0 -0
  195. /package/dist/{windsurf-3T3RVXKM.js.map → windsurf-75LLZ37C.js.map} +0 -0
  196. /package/dist/{zed-ZF2OQ75O.js.map → zed-HKAZXEJW.js.map} +0 -0
package/README.md CHANGED
@@ -1,248 +1,201 @@
1
+ <p align="center">
2
+ <img src="site/public/mascot.png" alt="agent-connector mascot — a pixel-art lobster worker in a tool belt" width="160" />
3
+ </p>
4
+
1
5
  # agent-connector
2
6
 
3
- > **If you BUILD an MCP integration:** write your server + hooks once with
4
- > `defineConnector()`, deploy it to every detected AI-agent platform, and measure
5
- > your own server's per-tool tokens.
6
- > **If you just USE agent CLIs:** run `agent-connector usage` to read their logs
7
- > and see per-CLI / per-model token totals — no connector, config, or install.
7
+ ### Deploy one MCP to every agent CLI.
8
+
9
+ Write your server + hooks once with `defineConnector()`, then `install` it into
10
+ the native config or `package` it as a real plugin across **42 agent CLIs**
11
+ (Claude Code, Codex, Cursor, Copilot, Gemini, OpenCode, Warp, Zed…).
8
12
 
9
13
  [![npm](https://img.shields.io/npm/v/@ken-jo/agent-connector?color=cb3837&logo=npm)](https://www.npmjs.com/package/@ken-jo/agent-connector)
10
14
  [![license](https://img.shields.io/npm/l/@ken-jo/agent-connector?color=22c55e)](LICENSE)
11
15
  ![platforms](https://img.shields.io/badge/platforms-42-2563eb)
12
16
  ![surfaces](https://img.shields.io/badge/surfaces-MCP%20%7C%20hooks%20%7C%20commands%20%7C%20tools%20%7C%20memory%20%7C%20status%20line-2563eb)
13
17
  ![hook paradigms](https://img.shields.io/badge/hook%20paradigms-3-2563eb)
14
- ![install verified](https://img.shields.io/badge/install%20verified-35%2F35-22c55e)
18
+ ![install verified](https://img.shields.io/badge/install%20verified-42%2F42-22c55e)
15
19
  ![headless runtime](https://img.shields.io/badge/headless%20runtime-20%20CLIs%20activated-22c55e)
16
- ![marketplace](https://img.shields.io/badge/package-9%20marketplace%20formats-2563eb)
20
+ ![marketplace](https://img.shields.io/badge/package-10%20marketplace%20formats-2563eb)
17
21
  ![tests](https://img.shields.io/badge/tests-passing-22c55e)
18
22
 
19
- ## Who this is for
20
-
21
- agent-connector serves **two distinct audiences** — pick your track:
22
-
23
- - **I build an MCP integration** (MCP developer) you write your server + hooks
24
- once and deploy them everywhere, then measure **your own server's** per-tool
25
- tokens. Start at [**Quick start MCP developer**](#mcp-developer).
26
- - **I just use agent CLIs and want to see token usage** (agent-CLI user) you
27
- already run Claude Code / Codex / Cursor and haven't authored a connector; you
28
- just want per-CLI / per-model token totals. Run
29
- [**`agent-connector usage`**](#agent-cli-end-user) — no connector, config, or
30
- install required.
31
-
32
- > The dividing line: the connector-free `usage` path reports **whole-conversation
33
- > totals** per agent CLI / model / project / session / day. It does **not** itemize
34
- > cost by individual MCP server or tool — agent CLIs don't log per-tool token
35
- > attribution. Per-MCP and per-tool numbers come only from the serve-proxy
36
- > telemetry that an MCP developer's own connector produces (the developer track).
37
-
38
- Every agent host — Claude Code, Codex, Cursor, OpenCode, Copilot, Gemini, Warp,
39
- — re-invents the same two integration surfaces (**MCP registration** and
40
- **lifecycle hooks**) with incompatible config files, root keys, formats (JSON /
41
- JSONC / TOML / YAML / exported functions), transports, scopes, and event names.
42
- Supporting them today means hand-authoring and maintaining *N* dialects and *N*
43
- install flows, then chasing each platform's quirks.
44
-
45
- agent-connector is the middleware that does it for you:
46
-
47
- 1. **One API, every platform.** Declare your server + hooks once with
48
- `defineConnector({...})`; the CLI detects every installed host and renders the
49
- right native config in each — install, uninstall, upgrade, doctor.
50
- 2. **Token telemetry, by default.** No host reports per-tool usage back to an MCP
51
- server. agent-connector measures your server's *own* bytes (args in, results
52
- out, tool schemas) and tokenizes them locally — so you get a
53
- platform-independent answer to *"which of **your server's own tools** (the MCP
54
- your connector declares and wraps) cost the most context?"*, with **aggregate
55
- counts only, stored locally, zero egress by default.** Per-tool telemetry is
56
- automatic for **stdio** servers only; remote (`http`/`sse`/`ws`) servers are
57
- registered but **not wrapped** (the proxy cannot intercept remote transports),
58
- so they yield no per-tool telemetry.
59
-
60
- > Status: **35 platforms, all 3 hook paradigms** (exceeds the
61
- > [tokscale](https://github.com/junhoyeo/tokscale) token-leaderboard coverage).
62
- >
63
- > | Paradigm | Platforms |
64
- > |---|---|
65
- > | `json-stdio` (full hook dispatch) | CodeBuddy · Claude Code · Codex CLI · Cursor · VS Code Copilot · JetBrains Copilot · GitHub Copilot CLI · Gemini CLI · Qwen CLI · Kiro · Kimi CLI · Crush · Goose · Hermes · Droid (Factory) · OpenHands · Antigravity · Antigravity CLI · Continue · Amazon Q · Grok CLI · Devin CLI |
66
- > | `mcp-only` (MCP registration only) | Warp · Roo Code · Cline · Trae · Zed · Codebuff · Mux · Pi · Windsurf · Open Interpreter · Junie · Mistral Vibe |
67
- > | `ts-plugin` (generated bridge module) | OpenCode · MiMoCode · Kilo CLI · Kilo · OMP · NemoClaw · OpenClaw · Amp |
68
- >
69
- > …plus the telemetry core. Adding a platform = **one registry entry + one
70
- > adapter**. (Google Antigravity is now fully supported, including the `agy` CLI,
71
- > as Gemini CLI sunsets.) See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
23
+ **Two audiences:** connector developers start at [Quick start](#quick-start);
24
+ if you already run an agent CLI and just want token totals, jump straight to
25
+ [`usage`](#token-telemetry--usage).
26
+
27
+ - [Quick start](#quick-start) depend on the SDK, declare a connector, install it
28
+ - [Ship it](#ship-it-direct-install-or-a-marketplace-plugin) direct install or a marketplace plugin
29
+ - [What you define once](#what-you-define-once) — server, hooks, and the other surfaces
30
+ - [How it works](#how-it-works) single home binary, per-project data, hook paradigms
31
+ - [CLI](#cli) every command at a glance
32
+ - [Token telemetry & usage](#token-telemetry--usage) per-tool telemetry vs. connector-free `usage`
33
+ - [Publish to the MCP ecosystem](#publish-to-the-mcp-ecosystem) — emit the official MCP standard artifacts
34
+ - [Verification](#verification) — how the 42-platform contract is proven
35
+
36
+ <p align="center">
37
+ <a href="examples/showcase-demo/">
38
+ <img src="examples/showcase-demo/demo.gif" width="820"
39
+ alt="agent-connector showcase: define a connector once, ship it as your own branded CLI, install it via each host's native marketplace, and drive every CLI with one command." />
40
+ </a>
41
+ </p>
42
+
43
+ <p align="center"><sub>
44
+ Define once ship it as your own branded CLI → users install via their host's native marketplace → one command drives every CLI.
45
+ <a href="examples/showcase-demo/">Regenerate this demo.</a>
46
+ </sub></p>
72
47
 
73
- ## Verification
48
+ ## Quick start
74
49
 
75
- The full single-API contract is **install-verified across the platform set**. A
76
- sample connector declaring **all four launch surfaces** MCP server **+**
77
- lifecycle hooks **+** slash commands **+** tools (skills + subagents) was
78
- installed into an isolated environment for every adapter and inspected on disk
79
- (the full 35-platform sweep below now locked by a committed registry-driven
80
- install-roundtrip harness that, for every adapter, drives the real install →
81
- uninstall into an isolated HOME and asserts on-disk placement + zero residue):
82
-
83
- - **35 / 35 platforms zero missing, zero failed surfaces.** Each surface is
84
- written where the host supports it and gracefully *skip-warned* (never silently
85
- dropped) where it does not, across all three hook paradigms — JSON/TOML/YAML
86
- hook entries (`json-stdio`), synthesized + registered plugin modules
87
- (`ts-plugin`), and MCP-only graceful degradation.
88
- - **Live hook dispatch + telemetry, proven end-to-end.** Hooks fire with the
89
- correct allow / deny / context decisions through the universal entrypoint, and
90
- the telemetry serve-proxy records per-MCP token usage in vivo — both the
91
- 🔌 MCP/plugin and 🖥️ host/user leaderboards verified against real CLI logs.
92
- - **Runtime-activated, headlessly — 10 real host CLIs.** **Claude Code · Codex ·
93
- OpenCode · Kilo CLI · OpenClaw · qwen-code · Hermes · Gemini CLI · GitHub
94
- Copilot CLI · Antigravity CLI (agy)** each genuinely loaded the config, spawned
95
- our telemetry serve-wrapper, completed the MCP handshake, and were captured *in
96
- vivo* by our own telemetry store. Most via their own `mcp list`/`reconnect` handshake with
97
- no API key, login, or model turn; Codex, Gemini CLI & Copilot CLI on real
98
- logged-in sessions (Codex/Gemini recorded actual tool-call rows). Each row now
99
- carries the correct `hostPlatform` (the install target is baked into the
100
- wrapper as `--host`). Kimi also spawned the server (its probe tears the pipe
101
- down before the row flushes).
102
- - **Committed live host-CLI driver — 20 real CLIs.** A reusable
103
- `scripts/verify-host.mjs` installs each host's actual binary into an isolated
104
- HOME and verifies install → placement → clean-uninstall: **12 confirm offline
105
- config-acceptance** (Codex · Gemini CLI · Copilot CLI · Antigravity CLI · Amp ·
106
- qwen-code · Droid · Cursor · Kimi + OpenCode · Kilo CLI · MiMoCode) and **3 of
107
- those fire a live hook** (OpenCode · Kilo CLI · MiMoCode → handler ran to our
108
- event log); the other 8 (Claude Code · Codebuff · Crush · Continue · OpenClaw ·
109
- Goose · Amazon Q · OMP) reach install-placement + clean-uninstall. So amp,
110
- goose, codebuff & omp — previously config-write-only — are now exercised
111
- against their real CLIs. The remaining 15 hosts (IDE extensions / GUI editors,
112
- no headless CLI) stay covered by the install-roundtrip harness above.
113
- - **Clean uninstall + `--purge`.** Every installed surface reverses; `--purge`
114
- deregisters the connector record and tears down the home binary when no
115
- connectors remain (35 / 35).
116
- - **Full `npm test` suite passing** · `tsc` clean · build green.
117
-
118
- The 0.2.0 additions — the `memory` surface, the `nativeHooks` passthrough, and
119
- `configPatch` — went through the same bar: dogfooded against real connector
120
- migrations (context-mode, oh-my-claudecode) and verified in isolated-home
121
- installs before landing (see [`CHANGELOG.md`](CHANGELOG.md)).
122
-
123
- **Dogfood result:** the context-mode connector migration — porting a real
124
- multi-host plugin to `defineConnector` — collapsed **~20,322 lines of
125
- hand-maintained per-host code down to ~76 lines** (a 99.63% reduction). The
126
- other hand-maintained surfaces — MCP registration, hook entries, memory files —
127
- dissolved into the same single config declaration.
128
-
129
- Coverage was confirmed by **installing the real, not-yet-present agent CLIs into
130
- isolated homes and observing their actual config** — which caught defects a
131
- static code/web audit missed. See the reports under
132
- [`docs/research/`](docs/research/).
50
+ agent-connector is an **SDK connector developers depend on**. Add it to the
51
+ package that holds your connector, declare the connector once, then ship a
52
+ branded MCP package/bin such as `npx @acme/acme-db-mcp install` it deploys to
53
+ every detected agent CLI in that host's own native config. Installing
54
+ `@ken-jo/agent-connector` globally is only an optional path for connector-free
55
+ token usage reports. The linear path is:
56
+ **get a server declare it install through your branded package**.
57
+
58
+ **0. You need an MCP server file first.** The config below points at
59
+ `./my-mcp-server.mjs`, so that file must exist before you install. Don't have an
60
+ MCP server yet? Copy
61
+ [`examples/acme-db/acme-db-mcp-server.mjs`](examples/acme-db/acme-db-mcp-server.mjs)
62
+ (a self-contained ~35-line stub) as `./my-mcp-server.mjs`, or follow the
63
+ [official MCP SDK quickstart](https://modelcontextprotocol.io/quickstart/server).
133
64
 
134
- ## Quick start
65
+ ```bash
66
+ # 1. add agent-connector as a DEPENDENCY of your connector package
67
+ npm install @ken-jo/agent-connector
68
+ ```
69
+
70
+ ```jsonc
71
+ // 2. package.json — this is the user-facing package identity
72
+ {
73
+ "name": "@acme/acme-db-mcp",
74
+ "mcpName": "io.github.acme/acme-db",
75
+ "bin": { "acme-db": "./bin.mjs" },
76
+ "dependencies": { "@ken-jo/agent-connector": "^0.4.92" }
77
+ }
78
+ ```
135
79
 
136
- The Quick start forks by audience. Just want to see your agent CLIs' token
137
- usage? **Agent-CLI end user** comes first it needs no connector at all, and
138
- those few lines are the entire track. Build an integration? Skip ahead to
139
- **MCP developer** everything from there to the end of the README is yours.
80
+ ```js
81
+ // 3. agent-connector.config.mjsdeclare your server + hooks once
82
+ import { fileURLToPath } from "node:url";
83
+ import { defineConnector } from "@ken-jo/agent-connector";
140
84
 
141
- ### Agent-CLI end user
85
+ const serverPath = fileURLToPath(new URL("./my-mcp-server.mjs", import.meta.url));
142
86
 
143
- > **Audience B** — you already run agent CLIs (Claude Code / Codex / Cursor / …)
144
- > and have **not** authored a connector. You just want to know how many tokens
145
- > your agent CLIs are burning.
87
+ export default defineConnector({
88
+ // package.json / npm metadata is the source of truth. The host alias/runtime
89
+ // id and connector version are derived from name/mcpName/bin/version unless
90
+ // you need a multi-instance alias.
91
+ server: {
92
+ transport: "stdio",
93
+ command: "node",
94
+ args: [serverPath],
95
+ },
96
+ // hooks, telemetry, and more surfaces — see "What you define once" below
97
+ });
98
+ ```
146
99
 
147
- **No connector, no config file, no install.** Run it straight from `npx`; it
148
- reads your local agent-CLI session logs **read-only** and never writes any host
149
- config:
100
+ > While developing, `server.command` can be `node` + a local file path (as
101
+ > above); once your server is a published package, switch to `npx` + the package
102
+ > name (`command: "npx", args: ["-y", "@acme/acme-db-mcp"]`) — the form the
103
+ > [site quick-start](https://agent-connector.ai) teaches.
150
104
 
151
105
  ```bash
152
- # how many tokens are my agent CLIs burning, grouped by CLI/model/project/session/day?
153
- npx @ken-jo/agent-connector usage report --by platform # or model|project|session|day
106
+ # 4. deploy under your branded MCP package/bin
107
+ npx @acme/acme-db-mcp detect # which platforms are installed here?
108
+ npx @acme/acme-db-mcp install --dry-run # preview every change first
109
+ npx @acme/acme-db-mcp install # write native config in each host
110
+ ```
111
+
112
+ > `install` targets only the hosts actually **detected** on this machine (or an
113
+ > explicit `--targets` / `connector.targets` list), intersected with the
114
+ > 42-adapter registry — there is no "install to all 42 unconditionally" path.
115
+ > `@ken-jo/agent-connector` is the framework dependency underneath; use it
116
+ > directly for development fallback or connector-free token telemetry, not as
117
+ > the foreground install brand for your users.
154
118
 
155
- # which agent CLI burned the most tokens?
156
- npx @ken-jo/agent-connector usage leaderboard --by platform # or --by model
119
+ ## Ship it: direct install or a marketplace plugin
157
120
 
158
- # export the raw aggregate rows (counts only — never your prompts or results)
159
- npx @ken-jo/agent-connector usage export --format csv --out usage.csv
160
- ```
121
+ Same one definition, your choice of distribution.
161
122
 
162
- > **What `usage` does and doesn't show.** It reports **whole-conversation
163
- > totals** per agent CLI / model / project / session / day. It does **not** break
164
- > down cost by individual MCP server or by tool — agent CLIs don't log per-tool
165
- > token attribution, so the connector-free path can only see session totals.
166
- > To get **per-MCP / per-tool** numbers for an MCP, that MCP must be deployed and
167
- > wrapped via a connector (the MCP-developer track and its `telemetry` command).
168
-
169
- > **Coverage caveats.** Local readers (claude-code, codex, gemini-cli, …) report
170
- > host-logged exact counts; a few readers are host-estimated (labeled in the
171
- > `CONFIDENCE` column). Five "synced" platforms — **cursor, antigravity,
172
- > antigravity-cli, trae, warp** — are reported as skipped (`requires sync — no
173
- > local cache found`) unless a local cache already exists, since agent-connector
174
- > does not populate that cache.
175
-
176
- > **That's the entire agent-CLI track.** Everything below this point is the
177
- > MCP-developer track. ([back to top](#agent-connector))
178
-
179
- ### MCP developer
180
-
181
- > **Audience A** — you write an MCP server + hooks once and deploy them across
182
- > every detected host, measuring **your own server's** per-tool tokens.
183
-
184
- **Step 0 — write your MCP server.** agent-connector deploys and wraps an MCP
185
- server you already have (or are about to write). If you haven't built one yet,
186
- the [official MCP SDK quickstart](https://modelcontextprotocol.io/quickstart/server)
187
- is the fastest on-ramp — pick your language, follow the tutorial, and come back
188
- with a working stdio server binary or script. The
189
- [`examples/acme-db/acme-db-mcp-server.mjs`](examples/acme-db/acme-db-mcp-server.mjs)
190
- in this repo is a self-contained ~35-line stub you can copy as a template.
123
+ **Direct install** — your branded command (`acme-db install`,
124
+ `npx @acme/acme-db-mcp install`) writes each host's native MCP + hook +
125
+ content-surface config in place, with no per-platform marketplace submission or
126
+ review. This is the Quick start path above.
191
127
 
192
- agent-connector is an **SDK you depend on**, not a global tool. Add it to the
193
- package that holds your connector, declare the connector once, then **either**
194
- ship a branded CLI your users drive directly **or** run it with `npx`. No
195
- separate global install is required.
128
+ **Marketplace plugin** — `agent-connector package` turns the connector into a
129
+ real plugin/extension bundle (manifest + bundled commands, agents, skills,
130
+ hooks, MCP) from one definition. Hooks + MCP keep the telemetry serve-wrapper,
131
+ so a marketplace-installed connector still reports per-tool tokens for its stdio
132
+ server. `--format all` emits **10 host formats**:
133
+
134
+ | Format | Hosts |
135
+ |---|---|
136
+ | `claude-plugin` | Claude Code · Codex · VS Code Copilot · OpenClaw · OMP |
137
+ | `codex-plugin` | Codex (`.codex-plugin/` manifest variant) |
138
+ | `copilot-plugin` | GitHub Copilot CLI |
139
+ | `factory-plugin` | Droid |
140
+ | `gemini-extension` | Gemini CLI |
141
+ | `qwen-extension` | Qwen Code |
142
+ | `agy-plugin` | Antigravity (CLI + IDE) |
143
+ | `cursor-plugin` | Cursor |
144
+ | `kimi-plugin` | Kimi CLI |
145
+ | `npm-plugin` | OpenCode · Kilo CLI · Pi |
146
+
147
+ Two official **MCP standard artifacts** are opt-in (they need a `publish` block,
148
+ so they're excluded from `--format all`) — `mcp-server-json` (an MCP Registry
149
+ `server.json`) and `mcpb` (a one-click MCPB bundle); see
150
+ [Publish to the MCP ecosystem](#publish-to-the-mcp-ecosystem).
196
151
 
197
152
  ```bash
198
- # 1. add agent-connector as a DEPENDENCY of your connector package
199
- npm install @ken-jo/agent-connector
153
+ # emit every host format (mcp-server-json + mcpb are opt-in by name)
154
+ agent-connector package --format all --out ./dist-plugin
155
+ agent-connector package --format gemini-extension --out ./ext # or just one
200
156
 
201
- # 2. write agent-connector.config.mjs (defineConnector see "Define once" below)
202
-
203
- # 3a. ship a branded CLI so YOUR users drive it (auto-scoped — no --connector):
204
- acme-db detect # which platforms are installed here?
205
- acme-db install --dry-run # preview every change across the detected hosts
206
- acme-db install # deploy across the hosts detected on this machine
207
- acme-db doctor # health-check every detected platform — add --probe for a live MCP handshake (initialize → ping → tools/list)
208
- acme-db upgrade # day 2: re-render configs + heal the home-binary pointer (aliases: sync, update)
209
- acme-db leaderboard # acme-db's token footprint vs the boards
210
- acme-db package # OR distribute: marketplace plugin (9 formats) — or --format mcp-server-json | mcpb for the MCP Registry / an MCPB bundle (see "Publish to the MCP ecosystem")
211
- acme-db uninstall # full inverse — removes everything install wrote; --purge clears framework state; --dry-run works here too
212
-
213
- # 3b. …or just run it from the project with npx — still no global install:
214
- npx @ken-jo/agent-connector detect
215
- npx @ken-jo/agent-connector install
157
+ # e.g. Claude Code: /plugin marketplace add ./dist-plugin/claude-plugin
158
+ # /plugin install <connector-id>@agent-connector
159
+ # e.g. Gemini CLI: gemini extensions install ./dist-plugin/gemini-extension/<id>
216
160
  ```
217
161
 
218
- > `install` targets only the hosts actually **detected** on this machine (or an
219
- > explicit `--targets` / `connector.targets` list), intersected with the
220
- > 35-adapter registry there is no "install to all 35 unconditionally" path.
221
-
222
- > **Optional convenience.** A global `npm i -g @ken-jo/agent-connector` is **not**
223
- > required for the flow above — `npx @ken-jo/agent-connector …` runs it straight from
224
- > your project. Install it globally only if you want to poke at the CLI by hand
225
- > outside any connector package.
162
+ > **Embedded-path caveat.** Most host bundles bake in the absolute home-bin
163
+ > launcher path of the machine that ran `package`, so they're valid for a
164
+ > **local install on that same machine/home**. For shared distribution use
165
+ > `npm-plugin` or the MCP standard artifacts, or re-run `package` per machine.
226
166
 
227
- ### Embed it / ship a branded CLI
167
+ **Let your branded MCP package drive the host's own install flow** with
168
+ `install --method marketplace`:
228
169
 
229
- A connector developer adds agent-connector as a dependency and ships their
230
- **own** bin. `createConnectorCli({ name, connector })` (from the
231
- `agent-connector/cli` export) exposes **every** agent-connector subcommand under
232
- your brand, fully delegated and **auto-scoped** to your connector — so your
233
- users never install agent-connector globally or type `--connector`. See
234
- [`examples/branded-cli`](examples/branded-cli) for the full, runnable package.
170
+ ```bash
171
+ acme-db install --method marketplace
235
172
 
236
- ```jsonc
237
- // package.json — agent-connector is a dependency (not -g); your package owns the bin
238
- {
239
- "name": "acme-db-tools",
240
- "type": "module",
241
- "bin": { "acme-db": "./bin.mjs" },
242
- "dependencies": { "@ken-jo/agent-connector": "^0.4.0" }
243
- }
173
+ # framework fallback for local framework development/debugging only
174
+ npx @ken-jo/agent-connector install --method marketplace --connector ./agent-connector.config.mjs
244
175
  ```
245
176
 
177
+ - **What it does** — stages the bundle, registers a local marketplace where the
178
+ host has one, then runs the host's plugin-install verb (or, for npm-plugin
179
+ hosts, writes a local `file://` entry); headless and idempotent. Other
180
+ marketplace-format hosts print the exact manual commands.
181
+ - **Host coverage** — live-verified for Claude Code, Codex, OpenCode, Kilo
182
+ (CLI + ext), and Antigravity (CLI + IDE) on Linux, Windows, and macOS; Droid
183
+ and Qwen Code have the driver shipped but pending a live host; Gemini CLI is
184
+ legacy (sunsetting toward Antigravity — driver kept for existing installs).
185
+ - **Safety + reversal** — a guard refuses installing the same connector by BOTH
186
+ methods, `uninstall --method auto` reverses whichever method is installed, and
187
+ `doctor` checks registration drift.
188
+
189
+ ### Ship a branded CLI
190
+
191
+ A connector developer can ship their **own** bin instead of having users type
192
+ `agent-connector`. `createConnectorCli({ name, connector })` (from the
193
+ `@ken-jo/agent-connector/cli` export) exposes **every** subcommand under your
194
+ brand, fully delegated and **auto-scoped** to your connector — so your users
195
+ do not need a framework global install or `--connector` for branded MCP
196
+ install/doctor/uninstall. See
197
+ [`examples/branded-cli`](examples/branded-cli) for the full, runnable package.
198
+
246
199
  ```js
247
200
  #!/usr/bin/env node
248
201
  // bin.mjs — every agent-connector subcommand, branded as `acme-db`
@@ -258,142 +211,21 @@ process.exitCode = await createConnectorCli({
258
211
  }).run();
259
212
  ```
260
213
 
261
- After a consumer installs **your** package (`npm install acme-db-tools`), the
262
- `acme-db` bin is on their PATH and every command is scoped to your connector:
263
-
264
- ```bash
265
- acme-db install # deploy acme-db across the detected hosts (no --connector)
266
- acme-db upgrade # bring everything current (alias: sync, update)
267
- acme-db doctor # health-check every detected platform for acme-db
268
- acme-db leaderboard # the 🔌 MCP/plugin section, scoped to acme-db
269
- acme-db telemetry report --by tool # per-tool tokens for acme-db's own wrapped server
270
- acme-db --help # every agent-connector subcommand, branded
271
- ```
272
-
273
- **Auto-scoping is pure argument injection over the SAME single home binary.** A
274
- branded subcommand is the matching agent-connector command with your connector
275
- pre-injected — `acme-db leaderboard` ≈ `agent-connector leaderboard --connector
276
- acme-db`, `acme-db install` ≈ `agent-connector install --connector
277
- ./agent-connector.config.mjs`. `serve` and `hook` still route through the one
278
- `~/.agent-connector` home binary every host config points back to, so branded
279
- tools share that infrastructure. An explicit `--connector` / `--connector-id`
280
- always overrides the injected default.
281
-
282
- ### Author + test offline — the Connector SDK (`/sdk`, `/sdk/test`)
283
-
284
- ```ts
285
- import { defineConnector, defineHook, hostsSupporting } from "@ken-jo/agent-connector/sdk";
286
- import { simulate, explain } from "@ken-jo/agent-connector/sdk/test";
287
- ```
288
-
289
- `@ken-jo/agent-connector/sdk` is the consolidated **authoring** surface — it
290
- re-exports `defineConnector`, the full `define*` family, the introspection
291
- helpers, and public types from one import site (the root export is unchanged;
292
- `/sdk` is additive).
293
-
294
- **`define*` typed helpers** — each is a typed identity function (`(def) => def`)
295
- that gives you per-surface type inference and a single import site:
296
- `defineCommand`, `defineSkill`, `defineSubagent`, `defineMemory`,
297
- `defineConfigPatch`, `defineNativeHook`. `defineHook` is event-parameterized
298
- so the handler payload narrows to the concrete event type:
299
-
300
- ```ts
301
- const guard = defineHook("PreToolUse", {
302
- handler(evt) {
303
- // evt.toolName is typed as PreToolUseEvent — not the union
304
- return evt.toolName === "acme_write"
305
- ? { decision: "ask", reason: "Confirm write" }
306
- : { decision: "allow" };
307
- },
308
- });
309
- ```
310
-
311
- **Introspection** (async — adapters load lazily):
312
-
313
- - `hostsSupporting(surface)` → `Promise<PlatformId[]>` — which registered hosts
314
- honor a surface (`"hooks"` | `"statusline"` | `"memory"` | …).
315
- - `capabilitiesOf(host)` → `Promise<PlatformCapabilities | undefined>`.
316
- - `surfaceSupport(host, surface)` → `Promise<boolean>` — convenience single-pair check.
317
-
318
- **Offline harness** (`@ken-jo/agent-connector/sdk/test`) answers *"does my
319
- handler / HUD actually work on host X?"* before you touch a real host:
320
-
321
- - `explain(connector)` → `Promise<ExplainRow[]>` — the per-host × per-declared-surface
322
- matrix. Each row is `{ host, surface, support: "native"|"skip-warn"|"disabled", reason }`.
323
- Only surfaces the connector actually declares are included. The `hooks` row is judged
324
- against **your connector's specific declared events** — a Stop-only connector reports
325
- `skip-warn` (not `native`) on a host that cannot fire Stop, naming the dead events.
326
- - `explainHooks(connector, hosts)` → `Promise<HookEventVerdict[]>` — the per-`(host, event)`
327
- honor matrix (`honored | degraded | dropped` + reason), powered by `simulate()`. This is
328
- what `agent-connector doctor --explain` prints — the trustworthy per-event diagnostic,
329
- no hand-enumeration of `(host, event)` pairs.
330
- - `simulate(connector, { surface, host, event?, input })` → `Promise<{ honored, hostReply?, reason }>`
331
- — runs the **real** adapter parse→handler→format chain offline and judges the
332
- actual `(event, decision)` contract. It encodes each host's real honor / drop /
333
- degrade quirks — not substring guessing:
334
-
335
- ```ts
336
- // Does codex honor a context injection on UserPromptSubmit?
337
- const result = await simulate(connector, {
338
- surface: "hooks",
339
- host: "codex",
340
- event: "UserPromptSubmit",
341
- input: { hookEventName: "UserPromptSubmit", prompt: "explain this" },
342
- });
343
- // → { honored: false, reason: "drops context on UserPromptSubmit (no stdout path)" }
344
- ```
345
-
346
- > Other verdicts the harness encodes: a `deny` on `Stop`/`SubagentStop` is
347
- > continuation/persistence → `honored:true` (reason explains); `deny` on
348
- > `SubagentStart`/`PostToolUseFailure` degrades to a context note →
349
- > `honored:false`; a PermissionRequest `ask` is honored by the host's native
350
- > dialog → `honored:true`. Matcher-scoped handlers that don't match the input
351
- > are not run. The harness mirrors the runtime exactly — tolerant stdin,
352
- > matcher filtering, real verdict.
353
-
354
- ### Two ways to ship: direct install **or** a marketplace package
355
-
356
- Same one definition, your choice of distribution:
357
-
358
- - **Direct install** (above) — `install` writes each host's native MCP + plugin/
359
- extension config in place; no per-platform marketplace submission or review.
360
- - **Marketplace install** — `install --method marketplace` drives the host's own
361
- plugin flow end-to-end for **10 hosts**: Claude Code, Codex, OpenCode, Kilo
362
- (CLI + ext), Antigravity (CLI + IDE) — live-verified on Linux, Windows, and
363
- macOS — plus Droid and Qwen Code (driver shipped, pending a live host) and
364
- Gemini CLI (legacy — sunsetting toward Antigravity; driver kept for existing
365
- installs). It stages the bundle, registers a local marketplace where the host
366
- has one, then runs the host's plugin-install verb (or, for npm-plugin hosts,
367
- writes a local `file://` entry); headless and idempotent. `uninstall --method
368
- auto` reverses whichever method is installed, a guard refuses installing the
369
- same connector by BOTH methods, and `doctor` checks registration drift. Other
370
- marketplace-format hosts print the exact manual commands.
371
- - **Marketplace package** — `agent-connector package` turns the connector into a
372
- marketplace/extension bundle (manifest + bundled commands, agents, skills,
373
- hooks, MCP) for **9 host formats** (plus 2 official MCP standard artifacts —
374
- see *Publish to the MCP ecosystem*) across the ecosystem, from one definition:
375
- `claude-plugin` (Claude Code · Codex · VS Code Copilot · OpenClaw · OMP) ·
376
- `codex-plugin` · `factory-plugin` (Droid) · `gemini-extension` (Gemini CLI) ·
377
- `qwen-extension` · `agy-plugin` (Antigravity CLI/IDE) · `cursor-plugin` ·
378
- `kimi-plugin` · `npm-plugin` (OpenCode / Kilo CLI / Pi). Hooks + MCP keep the
379
- telemetry serve-wrapper, so a marketplace-installed connector still reports
380
- per-tool tokens (for its stdio server).
381
-
382
- ```bash
383
- # emit all 9 host formats (mcp-server-json + mcpb are opt-in by name — they need publish{})
384
- agent-connector package --format all --out ./dist-plugin
385
- agent-connector package --format gemini-extension --out ./ext # or one
386
- # e.g. Claude Code: /plugin marketplace add ./dist-plugin/claude-plugin
387
- # /plugin install <connector-id>@agent-connector
388
- # e.g. Gemini CLI: gemini extensions install ./dist-plugin/gemini-extension/<id>
389
- ```
214
+ After a consumer installs **your** package, the `acme-db` bin is on their PATH
215
+ and every command is scoped to your connector (`acme-db install` ≈
216
+ `agent-connector install --connector ./agent-connector.config.mjs`). Auto-scoping
217
+ is pure argument injection over the SAME single home binary; `serve` and `hook`
218
+ still route through the one `~/.agent-connector` home binary every host config
219
+ points back to. An explicit `--connector` / `--connector-id` always overrides
220
+ the injected default.
390
221
 
391
- > **Embedded-path caveat.** 8 of the 9 host bundles bake in the absolute
392
- > home-bin launcher path of the machine that ran `package`, so they're valid
393
- > for a **local install on that same machine/home**. For shared distribution use
394
- > `npm-plugin` or the 2 MCP standard artifacts, or re-run `package` per machine.
222
+ ## What you define once
395
223
 
396
- ## Define once
224
+ A single `defineConnector({...})` declares your MCP **server** + lifecycle
225
+ **hooks**, and optionally the additional surfaces — **commands**, **skills**,
226
+ **subagents**, **memory**, **statusline**, **actions**, plus host-native escape
227
+ hatches. agent-connector renders each surface into every detected host's native
228
+ format, or *skip-warns* (never silently drops) where a host can't support it.
397
229
 
398
230
  ```ts
399
231
  import { fileURLToPath } from "node:url";
@@ -403,7 +235,6 @@ import { defineConnector } from "@ken-jo/agent-connector";
403
235
  const serverPath = fileURLToPath(new URL("./my-mcp-server.mjs", import.meta.url));
404
236
 
405
237
  export default defineConnector({
406
- id: "acme-db",
407
238
  server: {
408
239
  transport: "stdio",
409
240
  command: "node", // or "npx", "python", etc. — whatever starts your server
@@ -424,43 +255,7 @@ export default defineConnector({
424
255
  });
425
256
  ```
426
257
 
427
- > **Secret env-refs (`${env:VAR}`).** Write `"${env:VAR}"` in `command`, `args`,
428
- > `env`, `url`, or `headers` to reference an environment variable, or
429
- > `"${env:VAR:-default}"` to supply a fallback. On hosts with **native**
430
- > interpolation (Claude Code, Cursor, VS Code Copilot, amp, codebuff) the token
431
- > is written through to the host config and resolved at runtime — the secret is
432
- > never baked into a file. Every other host has **no** native interpolation, so
433
- > the value is resolved to a **literal at install time**. An unset variable with
434
- > no default resolves to an **empty string**; on a literal-resolving host that
435
- > would silently bake `""` where a secret was meant, so `install` now emits a
436
- > `warn` for it (e.g. *"ACME_DB_DSN is unset — baking an empty value into codex
437
- > config"*) — `export` the variable before installing, or give the ref a
438
- > `:-default`.
439
-
440
- > **Native hooks escape hatch.** The normalized `hooks` API covers the 13
441
- > cross-platform events. For host-only events — Claude Code alone ships 30
442
- > (`TaskCompleted`, `TeammateIdle`, `WorktreeCreate`, …) — declare
443
- > `platforms: { "claude-code": { nativeHooks: { TaskCompleted: { handler } } } }`:
444
- > the handler receives the host's **raw** payload and whatever it returns is the
445
- > **verbatim** JSON reply (exit 0 only — exit-2 blocking isn't modeled). Claude
446
- > Code is not the only nativeHooks host: `amp`, `claude-code`, `continue`,
447
- > `copilot-cli`, `cursor`, `gemini-cli`, `hermes`, `jetbrains-copilot`, `kimi`,
448
- > `nemoclaw`, `omp`, `openclaw`, `opencode`, and `qwen-code` currently support
449
- > host-native passthrough. Other hosts skip-warn, never silently.
450
-
451
- > **Host-config key patches.** For host-exclusive *settings keys* no other
452
- > surface reaches (e.g. an experimental `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`
453
- > flag), declare `platforms: { "claude-code": { configPatch: [{ key, value, reason }] } }`.
454
- > Semantics are fixed: **set-if-absent + skip-warn on any conflict** — never
455
- > overwrite, never deep-merge. Ownership is refcounted in a persisted ledger, so
456
- > uninstall removes a key only when the last owning connector releases it and the
457
- > value is untouched; security-relevant keys (`permissions*`, `apiKey*`,
458
- > `env.ANTHROPIC_*`, token/secret env vars, …) are hard-refused, as are keys
459
- > agent-connector models as first-class surfaces (`hooks*`, `mcpServers*`,
460
- > `statusLine` → use the `statusline` surface instead). Claude Code only for now;
461
- > other hosts skip-warn with the exact manual edit.
462
-
463
- `agent-connector install` turns that into, e.g.:
258
+ `npx @acme/acme-db-mcp install` turns that into, e.g.:
464
259
 
465
260
  | Host | What gets written |
466
261
  |---|---|
@@ -471,150 +266,80 @@ export default defineConnector({
471
266
  …each pointing hooks at a **single stable home binary**, so one update propagates
472
267
  everywhere.
473
268
 
474
- ### Standing guidance (`memory`) aligned with the AGENTS.md standard
475
-
476
- Ship the rules every agent should follow when your MCP is installed:
477
-
478
- ```ts
479
- memory: [
480
- {
481
- content:
482
- "Use the acme-db MCP tools for schema questions; never hand-edit migrations.",
483
- },
484
- ],
485
- ```
486
-
487
- **Write the guidance once — it lands in the standard
488
- [AGENTS.md](https://agents.md) on 29 of the 35 hosts** (the open, Linux
489
- Foundation-stewarded "README for agents" format): project scope targets
490
- `<projectDir>/AGENTS.md` — and where a host resolves its rules file
491
- exclusively, the target is *probed* so the block lands in the file the host
492
- actually reads (zed's first-match rules list, warp's `WARP.md` priority,
493
- hermes' `.hermes.md`, opencode's `CLAUDE.md` fallback, codex's
494
- `AGENTS.override.md`). User scope goes to the host's documented global memory
495
- file (AGENTS.md where one exists, else the host's own file — `~/.qwen/QWEN.md`,
496
- goose `.goosehints`, kilo/roo/kiro rules dirs).
497
- The two hosts that don't read AGENTS.md are wired per their own official docs:
498
-
499
- - **Claude Code** → the block goes in `CLAUDE.md` (the official memory docs are
500
- explicit: *"Claude Code reads CLAUDE.md, not AGENTS.md"*). Opt-in
501
- `platforms: { "claude-code": { memory: { mode: "agents-import" } } }` instead
502
- writes the canonical AGENTS.md block plus Anthropic's documented `@AGENTS.md`
503
- import line as a managed bridge in CLAUDE.md — opt-in because the import makes
504
- Claude read the *entire* AGENTS.md.
505
- - **Gemini CLI** → `GEMINI.md`, unless the user's `context.fileName` setting
506
- already opts Gemini into AGENTS.md (probed and respected — never edited).
507
-
508
- Writes are **surgical managed blocks** — marker-fenced
509
- (`<!-- agent-connector:begin <id>/memory hash=… -->`), hash-stamped, multiple
510
- connectors coexist in one file, and bytes outside your own markers are never
511
- touched. If a user edits inside the block, the hash mismatch is detected and the
512
- edit is *left intact* (sync warns; `install --force` overwrites after a backup).
513
- Uninstall excises exactly your blocks and `doctor` verifies them (present /
514
- hash-intact / user-edited / file missing). Hosts with no writable memory file at
515
- a scope skip-warn, never silently.
516
-
517
- ### Status line (`statusline`) — live HUD per connector
518
-
519
- Ship a render function that the host calls on every status refresh:
520
-
521
- ```ts
522
- import { defineConnector, defineStatusline } from "@ken-jo/agent-connector";
269
+ **Secret env-refs (`${env:VAR}`).** Write `"${env:VAR}"` (or `"${env:VAR:-default}"`) anywhere in `command` / `args` / `env` / `url` / `headers` to reference an environment variable.
523
270
 
524
- export default defineConnector({
525
- id: "acme-db",
526
- // ...
527
- statusline: defineStatusline({
528
- render(ctx) {
529
- const model = ctx.model?.displayName ?? ctx.model?.id ?? "unknown";
530
- return `acme-db · ${model} · $${(ctx.cost?.totalUsd ?? 0).toFixed(4)}`;
531
- },
532
- }),
533
- });
534
- ```
271
+ <details>
272
+ <summary>Native interpolation vs. literal-at-install resolution</summary>
535
273
 
536
- `StatuslineContext` provides (where the host supplies them) `host`,
537
- `connectorId`, `sessionId`, `cwd`, `model` (`id` / `displayName`),
538
- `cost` (`totalUsd`), `context` (`usedTokens` / `maxTokens` / `percent`),
539
- `transcriptPath`, and `raw` (the host's verbatim payload). Fields the host
540
- does not provide are `undefined`.
541
-
542
- > **`ctx.context` is reserved** — `context.usedTokens` / `maxTokens` / `percent`
543
- > are declared in `StatuslineContext` for a future AC-usage integration but are
544
- > **not populated by any v1 code path**. Rendering `ctx.context?.percent ?? 0`
545
- > always produces `0%`. Use `ctx.cost?.totalUsd` and `ctx.model?.displayName`
546
- > (both populated by claude-code) instead.
547
-
548
- **v1: claude-code and qwen-code.** Install registers Claude Code's
549
- `settings.json.statusLine` or Qwen Code's nested `settings.json.ui.statusLine`
550
- via the same ownership ledger — **set-if-absent, never clobbers a status line
551
- agent-connector doesn't own** (skip-warns and prints the manual edit instead),
552
- refcounted, reversible. Every other host adapter skip-warns at install time,
553
- never silently. The runtime is **fail-safe**: any error — a
554
- throwing `render`, unknown connector, malformed stdin — exits 0 with empty
555
- stdout so a HUD never wedges the host. `doctor` includes a dedicated
556
- `statusline wired` check.
557
-
558
- > `defineStatusline` is a typed identity helper and is optional — you can
559
- > pass the `{ render }` object directly to `statusline:`. Both
560
- > `StatuslineDef` and `StatuslineContext` are exported from
561
- > `@ken-jo/agent-connector`.
562
-
563
- ### Actions (`defineAction`) — user-triggered dispatch
564
-
565
- Declare named, user-invocable operations on your connector:
274
+ > On hosts with **native** interpolation (Claude Code, Cursor, VS Code Copilot,
275
+ > amp, codebuff) the token is written through to the host config and resolved at
276
+ > runtime. Every other host has **no** native interpolation, so the value is
277
+ > resolved to a **literal at install time**; an unset variable with no default
278
+ > resolves to an **empty string**, and `install` emits a `warn` for it on a
279
+ > literal-resolving host.
566
280
 
567
- ```ts
568
- import { defineConnector, defineAction } from "@ken-jo/agent-connector";
281
+ </details>
569
282
 
570
- export default defineConnector({
571
- id: "acme-db",
572
- // ...
573
- actions: [
574
- defineAction({
575
- id: "flush-cache",
576
- description: "Flush the acme-db query cache",
577
- async run(ctx) {
578
- // ctx is HostCtx — same context object as hooks
579
- await flushCache();
580
- return { message: "Cache flushed." };
581
- },
582
- }),
583
- ],
584
- });
585
- ```
283
+ **Native hooks escape hatch.** The normalized `hooks` API covers the 13 cross-platform events; for host-only events (Claude Code alone ships 30) declare `platforms: { "claude-code": { nativeHooks: { TaskCompleted: { handler } } } }`.
586
284
 
587
- The **universal verb** runs any declared action from the shell (or from a
588
- script / IDE task):
285
+ <details>
286
+ <summary>Raw-payload semantics and the ~14 passthrough hosts</summary>
589
287
 
590
- ```bash
591
- agent-connector action <platform> flush-cache --connector acme-db
592
- ```
288
+ > The handler receives the host's **raw** payload and whatever it returns is the
289
+ > **verbatim** JSON reply (exit 0 only — exit-2 blocking isn't modeled). Hosts
290
+ > supporting host-native passthrough: `amp`, `claude-code`, `continue`,
291
+ > `copilot-cli`, `cursor`, `gemini-cli`, `hermes`, `jetbrains-copilot`, `kimi`,
292
+ > `nemoclaw`, `omp`, `openclaw`, `opencode`, `qwen-code`. Others skip-warn.
593
293
 
594
- `run(ctx)` executes and its optional `{ message }` return is printed to
595
- stdout. **Error semantics are user-triggered**: an unknown action id or a
596
- throw exits 1 and writes to stderr (unlike hooks and statusline, which are
597
- fail-safe/silent on error).
294
+ </details>
598
295
 
599
- `defineAction` is a typed identity helper and is exported from both
600
- `@ken-jo/agent-connector` and `@ken-jo/agent-connector/sdk`.
601
- `ActionDef = { id, description?, run, hosts? }` and `ActionResult = { message? }`.
296
+ **Host-config key patches.** For host-exclusive *settings keys* no other surface reaches, declare `platforms: { "claude-code": { configPatch: [{ key, value, reason }] } }` (Claude Code only for now; other hosts skip-warn with the exact manual edit).
602
297
 
603
- **v1: universal dispatch plus selected host affordances.** The `action` verb is
604
- fully functional everywhere a connector can be loaded. `install` emits host-side
605
- affordances on `droid`, `hermes`, `nemoclaw`, `omp`, `openclaw`, and `warp`; every
606
- other host skip-warns rather than silently dropping declared actions. `explain()`
607
- reports those emitter hosts as native and the rest as skip-warn. `simulate()`
608
- does not cover actions (actions take no host payload and have no host-honor
609
- verdict — intentional).
298
+ <details>
299
+ <summary>Set-if-absent + refcount + denylist semantics</summary>
610
300
 
611
- ## How it works (operating model)
301
+ > Semantics are fixed: **set-if-absent + skip-warn on any conflict** — never
302
+ > overwrite, never deep-merge. Ownership is refcounted in a persisted ledger;
303
+ > security-relevant keys and keys agent-connector models as first-class surfaces
304
+ > are hard-refused.
305
+
306
+ </details>
307
+
308
+ ### Memory, statusline, actions, and the SDK
309
+
310
+ - **`memory`** (aligned with the [AGENTS.md](https://agents.md) standard) — ship
311
+ standing guidance that lands in `AGENTS.md` on 33 of the 42 hosts; the two that
312
+ don't read it (Claude Code → `CLAUDE.md`, Gemini CLI → `GEMINI.md`) are wired
313
+ per their own official docs. Writes are surgical marker-fenced, hash-stamped
314
+ managed blocks — multiple connectors coexist, bytes outside your markers are
315
+ never touched, and uninstall excises exactly your blocks.
316
+ - **`statusline`** (`defineStatusline`) — a live HUD render function the host
317
+ calls on every status refresh. v1 registers Claude Code's `settings.json.statusLine`
318
+ or Qwen Code's `settings.json.ui.statusLine` (set-if-absent, refcounted,
319
+ reversible); other hosts skip-warn. The runtime is **fail-safe**: any error
320
+ exits 0 with empty stdout so a HUD never wedges the host.
321
+ - **`actions`** (`defineAction`) — named, user-invocable operations dispatched by
322
+ the universal verb `agent-connector action <platform> <id> --connector <id>`.
323
+ `install` emits host-side affordances on `droid`, `hermes`, `nemoclaw`, `omp`,
324
+ `openclaw`, and `warp`; other hosts skip-warn. Error semantics are
325
+ user-triggered (unknown id or throw exits 1).
326
+ - **The Connector SDK** (`@ken-jo/agent-connector/sdk`, `/sdk/test`) — the
327
+ consolidated authoring surface re-exports `defineConnector`, the full `define*`
328
+ family (`defineHook`, `defineCommand`, `defineSkill`, `defineSubagent`,
329
+ `defineMemory`, `defineStatusline`, `defineAction`, `defineConfigPatch`,
330
+ `defineNativeHook`), introspection helpers (`hostsSupporting`,
331
+ `capabilitiesOf`, `surfaceSupport`), and an **offline harness**
332
+ (`simulate`, `explain`, `explainHooks`) that runs the real adapter
333
+ parse→handler→format chain to answer *"does my handler actually work on host
334
+ X?"* before you touch a real host. See
335
+ [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
336
+
337
+ ## How it works
612
338
 
613
339
  - **Home-dir, single binary.** The runtime installs once under
614
- `~/.agent-connector` (override `AGENT_CONNECTOR_DATA_DIR`). Every platform
615
- config we write is a thin pointer back to that one binary update it in one
616
- place. Updates are **explicit/managed** (`agent-connector upgrade`), never silent
617
- auto-update, so one bad release can't break every project at once.
340
+ `~/.agent-connector` (override `AGENT_CONNECTOR_DATA_DIR`). Every host config we
341
+ write is a thin pointer back to that one binary. Updates are
342
+ **explicit/managed** (`agent-connector upgrade`), never silent auto-update.
618
343
  - **Per-project data, kept.** Telemetry/state is keyed by a stable project
619
344
  identity (git remote or normalized path), partitioned per project, stored under
620
345
  the home data-root — surviving `git clean`, shared across hosts opening the same
@@ -623,45 +348,83 @@ verdict — intentional).
623
348
  only framework-owned state lives under the data-root.
624
349
  - **Windows-first correctness.** No symlinks, no POSIX-only assumptions.
625
350
 
351
+ **Three hook paradigms**, all install-verified across the 42-platform set
352
+ (see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)):
353
+
354
+ | Paradigm | Platforms |
355
+ |---|---|
356
+ | `json-stdio` (full hook dispatch) | CodeBuddy · Claude Code · Codex CLI · Cursor · VS Code Copilot · JetBrains Copilot · GitHub Copilot CLI · Gemini CLI · Qwen CLI · Kiro · Kimi CLI · Crush · Goose · Hermes · Droid (Factory) · OpenHands · Antigravity · Antigravity CLI · Continue · Amazon Q · Grok CLI · Devin CLI |
357
+ | `mcp-only` (MCP registration only) | Warp · Roo Code · Cline · Trae · Zed · Codebuff · Mux · Pi · Windsurf · Open Interpreter · Junie · Mistral Vibe |
358
+ | `ts-plugin` (generated bridge module) | OpenCode · MiMoCode · Kilo CLI · Kilo · OMP · NemoClaw · OpenClaw · Amp |
359
+
360
+ Adding a platform = **one registry entry + one adapter**.
361
+
626
362
  ## CLI
627
363
 
628
364
  | Command | Purpose |
629
365
  |---|---|
630
366
  | `detect` | List installed platforms, scopes, capabilities, hook paradigm. |
631
- | `install [--scope user\|project] [--targets …] [--dry-run] [--force]` | Render + write MCP + hooks + content surfaces (commands / skills / subagents / memory) across targets. `--force` overwrites user-edited memory blocks (after a backup). |
632
- | `uninstall [--targets …]` | Full inverse — removes everything we wrote. |
633
- | `upgrade [--channel stable\|latest]` | One verb (alias: `update`, `sync`) — re-render host config + heal stale pointers + refresh the home-binary pointer, printing managed-update guidance (never a silent self-update). |
634
- | `doctor [--probe] [--explain]` | Per-platform health checks with fixes; `--probe` runs a live MCP handshake (initialize → ping → tools/list) against the real server; `--explain` prints the per-`(host, event)` hook honor matrix (`honored` / `degraded` / `dropped` + reason) for the connector's declared events. **Exit code:** `--explain` fails (exit 1) ONLY when an explicitly-targeted host (`--targets` / `targets:[...]`) `degraded`s a declared event — it fires the event but silently won't honor the reply. A `dropped` cell (an mcp-only host that architecturally can't fire hooks) and fleet-wide gaps under `targets:"auto"` are expected and stay informational (exit 0) — the same scope-aware non-failure as plain `doctor`. |
367
+ | `install [--scope ] [--targets …] [--method …] [--dry-run] [--force]` | Render + write MCP + hooks + content surfaces across targets. |
368
+ | `uninstall [--targets …] [--purge] [--method …]` | Full inverse — removes everything we wrote; `--purge` also clears framework state. |
369
+ | `upgrade [--channel ]` | Re-render host config + heal stale pointers + refresh the home binary (alias: `update`, `sync`); never a silent self-update. |
370
+ | `doctor [--probe] [--explain]` | Per-platform health checks with fixes; `--probe` runs a live MCP handshake, `--explain` prints the per-`(host, event)` hook honor matrix. |
635
371
  | `status` | Light install-state: which connectors are present on which hosts (always exits 0). |
636
- | `package [--format <fmt>\|all]` | Emit a host bundle, or an OFFICIAL standard artifact: `mcp-server-json` (registry) · `mcpb` (one-click bundle). |
637
- | `telemetry report [--by tool\|session\|project] [--since 7d] [--connector <id>]` | **MCP-developer track.** Per-tool token footprint of **your connector's own wrapped server** (scope with `--connector`). Stdio servers only. |
638
- | `telemetry export [--format csv\|json] [--connector <id>]` | Raw aggregate records for your wrapped server. |
639
- | `usage report\|export\|leaderboard [--by platform\|model\|project\|session\|day]` | **Agent-CLI-user track (no connector needed).** Host-native token usage parsed read-only from each agent CLI's own logs — **whole-conversation totals per platform / model / project / session / day. Does NOT break down by individual MCP or tool** (agent CLIs don't log per-tool attribution). Never summed with `telemetry`. |
640
- | `leaderboard [--since 7d] [--connector <id>] [--scope <slice>]` | Three origin-labeled boards with **different prerequisites** (counts are never summed across them): 🔌 MCP/plugin needs a connector + serve traffic; 🛰️ host-native turns need the opt-in usage hook (Gemini CLI / Antigravity only); 🖥️ host/user works with **no setup**. `--connector` filters the 🔌 board to one connector. |
372
+ | `package [--format <fmt>\|all]` | Emit a host plugin bundle, or an OFFICIAL standard artifact: `mcp-server-json` (registry) · `mcpb` (one-click bundle). |
373
+ | `action <platform> <id> [--connector <id>]` | Run a declared action from the shell. |
374
+ | `telemetry report [--by ] [--since …] [--connector <id>]` | Per-tool token footprint of **your connector's own wrapped server**. Stdio servers only. |
375
+ | `telemetry export [--format ] [--connector <id>]` | Raw aggregate records for your wrapped server. |
376
+ | `usage report\|export\|leaderboard [--by ]` | **No connector needed.** Host-native whole-conversation token totals parsed read-only from each agent CLI's own logs. Does NOT break down by individual MCP or tool. |
377
+ | `leaderboard [--since …] [--connector <id>] [--scope …]` | Three origin-labeled boards with **different prerequisites** (🔌 MCP/plugin · 🛰️ host-native turns · 🖥️ host/user); counts are never summed across them. |
641
378
 
642
379
  > `hook` and `serve` also exist — internal entrypoints the written host configs
643
380
  > point at; you never run them by hand. Full flag-level reference: the
644
381
  > [docs site `/docs/dev/cli`](https://agent-connector.ai/docs/dev/cli) · `llms-full.txt` §3 (canonical, drift-guarded by tests).
645
382
 
646
- > A **branded CLI** auto-injects `--connector` for you: `<your-tool>
647
- > leaderboard` ≈ `agent-connector leaderboard --connector <id>`, and
648
- > `<your-tool> telemetry report` `agent-connector telemetry report --connector
649
- > <id>` — so a connector developer sees **their** connector's token usage by
650
- > default.
383
+ ## Token telemetry & usage
384
+
385
+ Two independent, never-summed views of token cost:
386
+
387
+ - **Per-tool telemetry for *your own* server** (the MCP-developer path). No host
388
+ reports per-tool usage back to an MCP server, so agent-connector measures your
389
+ server's *own* bytes (args in, results out, tool schemas) and tokenizes them
390
+ locally — **aggregate counts only, stored locally, zero egress by default.**
391
+ Per-tool telemetry is automatic for **stdio** servers; remote (`http`/`sse`/`ws`)
392
+ servers are registered but not wrapped (the proxy can't intercept remote
393
+ transports). Read it with `agent-connector telemetry report --by tool`.
394
+ - **Connector-free usage** (`agent-connector usage`). Already run Claude Code /
395
+ Codex / Cursor and just want totals? `usage` reads your local agent-CLI session
396
+ logs **read-only** and never writes any host config — no connector, no install:
397
+
398
+ ```bash
399
+ npx @ken-jo/agent-connector usage report --by platform # CLI/model/project/session/day
400
+ npx @ken-jo/agent-connector usage leaderboard --by platform # or --by model
401
+ npx @ken-jo/agent-connector usage export --format csv --out usage.csv
402
+ ```
403
+
404
+ It reports **whole-conversation totals** per agent CLI / model / project /
405
+ session / day. It does **not** itemize cost by individual MCP server or tool —
406
+ agent CLIs don't log per-tool attribution.
407
+
408
+ **Privacy & tokenizer.** Default tokenizer is `gpt-tokenizer` (pure-JS, no native
409
+ build) — `o200k_base` for OpenAI/Codex-family, a documented approximation for
410
+ Anthropic; falls back to a `chars/4` heuristic if it can't load. Every record
411
+ carries a confidence tag. Raw tool arguments and results are never stored or
412
+ transmitted. Off switch: `AGENT_CONNECTOR_TELEMETRY=0`, or
413
+ `telemetry: { enabled: false }`.
651
414
 
652
415
  ## Publish to the MCP ecosystem
653
416
 
654
- Where the MCP standard already covers your server's functionality, agent-connector
655
- **emits the standard exactly** so your already-standard work is portable — you
656
- write the server, we carry the distribution:
657
-
658
- - **`package --format mcp-server-json`** → an official **MCP Registry** `server.json`
659
- (schema `2025-12-11`). It describes your **real upstream server** (what a registry
660
- installer runs), not our telemetry wrapper. Publish it with the official
661
- `mcp-publisher` CLI.
662
- - **`package --format mcpb`** → an official **MCPB** (`.mcpb`, formerly DXT) bundle
663
- `manifest.json` (`manifest_version 0.3`) for one-click local install in Claude
664
- Desktop and any MCPB host, with secrets routed through the host keychain
417
+ Where the MCP standard already covers your server's functionality,
418
+ agent-connector **emits the standard exactly** so your already-standard work is
419
+ portable:
420
+
421
+ - **`package --format mcp-server-json`** → an official **MCP Registry**
422
+ `server.json` (schema `2025-12-11`). It describes your **real upstream server**
423
+ (what a registry installer runs), not our telemetry wrapper. Publish it with
424
+ the official `mcp-publisher` CLI.
425
+ - **`package --format mcpb`** → an official **MCPB** (`.mcpb`, formerly DXT)
426
+ bundle `manifest.json` (`manifest_version 0.3`) for one-click local install in
427
+ Claude Desktop and any MCPB host, with secrets routed through the host keychain
665
428
  (`user_config`).
666
429
 
667
430
  Both read a `publish` block on your connector (the namespace you own + your
@@ -669,8 +432,6 @@ published package + author):
669
432
 
670
433
  ```ts
671
434
  defineConnector({
672
- id: "acme-db",
673
- version: "1.2.0",
674
435
  server: { transport: "stdio", command: "npx", args: ["-y", "@acme/acme-db-mcp"] },
675
436
  publish: {
676
437
  registryNamespace: "io.github.acme", // a namespace YOU proved ownership of
@@ -682,32 +443,34 @@ defineConnector({
682
443
 
683
444
  > **Config we write is the standard.** `install` writes each host's native MCP
684
445
  > config in the de-facto canonical `mcpServers` shape — `{ command, args, env }`
685
- > for stdio, `{ url, headers }` for remote across every target in one call. The
686
- > spec transport slug for streamable HTTP is `streamable-http` (registry
687
- > `server.json`); host configs canonically use `http`. WebSocket (`ws`) is **not**
688
- > an MCP spec transport and the standard artifacts reject it.
446
+ > for stdio, `{ url, headers }` for remote. The spec transport slug for
447
+ > streamable HTTP is `streamable-http` (registry `server.json`); host configs
448
+ > canonically use `http`. WebSocket (`ws`) is **not** an MCP spec transport and
449
+ > the standard artifacts reject it.
689
450
 
690
451
  > **Forward-compatible by transport.** The `serve` proxy is **byte-transparent**:
691
452
  > it forwards every JSON-RPC message verbatim and only tees a copy to count
692
- > `tools/call` round-trips (+ the one-time `tools/list` overhead). So newer MCP
693
- > features ride through untouched and uncounted — **MCP Apps** (the official
694
- > `io.modelcontextprotocol/ui` extension: `ui://` resource templates, `_meta.ui`
695
- > tool linkage, the bidirectional `ui/*` + `sampling` traffic) and **any
453
+ > `tools/call` round-trips. So newer MCP features ride through untouched
454
+ > **MCP Apps** (the official `io.modelcontextprotocol/ui` extension) and **any
696
455
  > reverse-DNS extension** negotiated at `initialize`. A connector whose server
697
456
  > already speaks these deploys across every host and keeps its telemetry today,
698
- > no agent-connector change required. (Authoring such a UI is the dev's own MCP
699
- > server's job; we deploy + wrap it. `doctor --probe` offers the latest released
700
- > protocol revision and accepts whatever a server negotiates.)
701
-
702
- ## Telemetry & privacy
703
-
704
- - Default tokenizer: `gpt-tokenizer` (pure-JS, no native build) `o200k_base`
705
- for OpenAI/Codex-family, used as a documented approximation for Anthropic
706
- (labeled `tokenizer-approx`). Falls back to a `chars/4` heuristic (labeled
707
- `heuristic`) if the tokenizer can't load. Every record carries a confidence tag.
708
- - **Aggregate counts only** raw tool arguments and results are never stored or
709
- transmitted. Local-first; zero network egress by default.
710
- - Off switch: `AGENT_CONNECTOR_TELEMETRY=0`, or `telemetry: { enabled: false }`.
457
+ > no agent-connector change required.
458
+
459
+ ## Verification
460
+
461
+ The full single-API contract is **install-verified across all 42 platforms** by
462
+ a committed registry-driven install-roundtrip harness that, for every adapter,
463
+ drives the real install uninstall into an isolated HOME and asserts on-disk
464
+ placement + zero residue. A separate committed `scripts/verify-host.mjs` driver
465
+ installs **20 real host CLIs** and verifies install → placement →
466
+ clean-uninstall, and live hook dispatch + telemetry are proven end-to-end on
467
+ several of them. The remaining hosts (IDE extensions / GUI editors with no
468
+ headless CLI) stay covered by the install-roundtrip harness.
469
+
470
+ **Dogfood result:** porting the real multi-host context-mode plugin to
471
+ `defineConnector` collapsed **~20,322 lines of hand-maintained per-host code down
472
+ to ~76 lines** (a 99.63% reduction). See the reports under
473
+ [`docs/research/`](docs/research/) and [`CHANGELOG.md`](CHANGELOG.md).
711
474
 
712
475
  ## Development
713
476