@ken-jo/agent-connector 0.4.91 → 0.4.92

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 (192) hide show
  1. package/README.md +301 -560
  2. package/dist/{action-L44DXFHT.js → action-CVIEPX4U.js} +14 -14
  3. package/dist/{amazon-q-B52EY2SV.js → amazon-q-TIT7FIW3.js} +5 -5
  4. package/dist/{amp-UXABVUKC.js → amp-NF3OAAUG.js} +5 -5
  5. package/dist/{antigravity-RZHN53VB.js → antigravity-7LPK7QOY.js} +6 -6
  6. package/dist/{antigravity-cli-JO6GUTV7.js → antigravity-cli-MDEMPPAH.js} +47 -16
  7. package/dist/antigravity-cli-MDEMPPAH.js.map +1 -0
  8. package/dist/{chunk-QKLJU4JX.js → chunk-2Y2MZRLP.js} +56 -2
  9. package/dist/chunk-2Y2MZRLP.js.map +1 -0
  10. package/dist/{chunk-UBB7T54N.js → chunk-3C5AASHM.js} +3 -3
  11. package/dist/{chunk-BLTVZACS.js → chunk-447JWFZO.js} +9 -9
  12. package/dist/{chunk-HORHRHNG.js → chunk-4NHXLXSD.js} +2 -2
  13. package/dist/chunk-5Z36KVU2.js +590 -0
  14. package/dist/chunk-5Z36KVU2.js.map +1 -0
  15. package/dist/{chunk-AY3RGRTT.js → chunk-6TF7MHG5.js} +2 -2
  16. package/dist/{chunk-R6LML2YS.js → chunk-7UT6OB52.js} +2 -2
  17. package/dist/{chunk-G4CEELKO.js → chunk-AY3VFNOH.js} +5 -5
  18. package/dist/{chunk-4HVQ7IUM.js → chunk-DI5S6TXJ.js} +17 -4
  19. package/dist/chunk-DI5S6TXJ.js.map +1 -0
  20. package/dist/{chunk-LAIITCMW.js → chunk-FBCBHEGB.js} +5 -5
  21. package/dist/{chunk-4NSU3KWX.js → chunk-FJCUKXGX.js} +2 -2
  22. package/dist/{chunk-ZMLVR4J7.js → chunk-FO5CEXXN.js} +2 -2
  23. package/dist/{chunk-IXOQDZWC.js → chunk-GZGLCCEE.js} +5 -1
  24. package/dist/chunk-GZGLCCEE.js.map +1 -0
  25. package/dist/{chunk-LF76VPGQ.js → chunk-IBLYVAWH.js} +28 -6
  26. package/dist/chunk-IBLYVAWH.js.map +1 -0
  27. package/dist/{chunk-4FWETID5.js → chunk-IVAWP6HH.js} +2 -2
  28. package/dist/{chunk-NBUEL74R.js → chunk-JFXL4HYA.js} +3 -3
  29. package/dist/{chunk-KIRCPLM4.js → chunk-JO2IM2JL.js} +538 -226
  30. package/dist/chunk-JO2IM2JL.js.map +1 -0
  31. package/dist/{chunk-NWLRJNXM.js → chunk-JVO6NBTT.js} +3 -3
  32. package/dist/{chunk-25CPWJA7.js → chunk-KA55FISM.js} +43 -43
  33. package/dist/{chunk-QARPXSIV.js → chunk-L26PSQTY.js} +4 -4
  34. package/dist/{chunk-YYNXIUR2.js → chunk-M2H7JURF.js} +2 -2
  35. package/dist/{chunk-56R2ER7K.js → chunk-NBYKLUF6.js} +2 -2
  36. package/dist/{chunk-VVFDU4IX.js → chunk-WFEHWTLM.js} +12 -5
  37. package/dist/{chunk-VVFDU4IX.js.map → chunk-WFEHWTLM.js.map} +1 -1
  38. package/dist/{chunk-LN76OGNR.js → chunk-Z2MRSS2I.js} +2 -2
  39. package/dist/{claude-code-WS4NAGZT.js → claude-code-7RS4YVGZ.js} +9 -9
  40. package/dist/cli/sdk.js +7 -7
  41. package/dist/cli.js +1 -1
  42. package/dist/{cline-NNMVCECA.js → cline-BZQAUYPC.js} +5 -5
  43. package/dist/{codebuddy-RBEZGXBG.js → codebuddy-G42IKGKB.js} +5 -5
  44. package/dist/{codebuff-RJIDSEU3.js → codebuff-5RLTLZAU.js} +5 -5
  45. package/dist/{codex-ZZ434GYR.js → codex-XHAMJILX.js} +11 -5
  46. package/dist/{codex-ZZ434GYR.js.map → codex-XHAMJILX.js.map} +1 -1
  47. package/dist/{continue-MNM7YVJY.js → continue-JLIB7R7X.js} +6 -6
  48. package/dist/{copilot-cli-SMTX5F65.js → copilot-cli-XZSUYNQZ.js} +5 -5
  49. package/dist/{crush-NYDBHIJE.js → crush-ESERLVLT.js} +5 -5
  50. package/dist/{cursor-AOELDNZU.js → cursor-FUDOV5VK.js} +6 -6
  51. package/dist/{detect-3S46RUMK.js → detect-Z5BDTY6B.js} +4 -4
  52. package/dist/{devin-PRJY2TTD.js → devin-Y7PWKVHY.js} +5 -5
  53. package/dist/{doctor-3CUBPQKU.js → doctor-GAP27PP2.js} +25 -21
  54. package/dist/doctor-GAP27PP2.js.map +1 -0
  55. package/dist/{droid-PTCH2K7Y.js → droid-DTO5POTK.js} +5 -5
  56. package/dist/{gemini-cli-QGLN2UMS.js → gemini-cli-RBIG6U2F.js} +5 -5
  57. package/dist/{goose-DQ6GSZ5O.js → goose-VGNOP5J2.js} +6 -6
  58. package/dist/{grok-cli-5QD235UB.js → grok-cli-2RFBK6J3.js} +5 -5
  59. package/dist/{hermes-E47IG63A.js → hermes-NUKFWZI5.js} +6 -6
  60. package/dist/{hook-P6EKDINW.js → hook-XPR3AHDI.js} +14 -14
  61. package/dist/index.d.ts +2 -2
  62. package/dist/index.js +5 -5
  63. package/dist/install-O32TDIZP.js +382 -0
  64. package/dist/install-O32TDIZP.js.map +1 -0
  65. package/dist/{introspect-DYOIX8Ov.d.ts → introspect-BkId4LGP.d.ts} +1 -1
  66. package/dist/{jetbrains-copilot-T2EPKROP.js → jetbrains-copilot-FXZ5AOTS.js} +23 -7
  67. package/dist/jetbrains-copilot-FXZ5AOTS.js.map +1 -0
  68. package/dist/{junie-SQ4SDLGK.js → junie-TSXIZSCE.js} +5 -5
  69. package/dist/{kilo-OU2ZLZKB.js → kilo-JLH3KVZJ.js} +5 -5
  70. package/dist/{kilo-cli-NMWGYF4F.js → kilo-cli-5W36VJQZ.js} +5 -5
  71. package/dist/{kimi-Z7L2LEEI.js → kimi-R62W7HKZ.js} +5 -5
  72. package/dist/{kiro-4IN5IH46.js → kiro-AUJMGIBL.js} +5 -5
  73. package/dist/{leaderboard-LF5SP6X2.js → leaderboard-YWMOSJBC.js} +5 -5
  74. package/dist/{mimo-code-G2CBZ4M6.js → mimo-code-PGLFFVER.js} +5 -5
  75. package/dist/{mistral-vibe-TRQDHAWV.js → mistral-vibe-36CZVQNQ.js} +5 -5
  76. package/dist/{mux-JNM3F2NW.js → mux-HWL4N5KH.js} +5 -5
  77. package/dist/{nemoclaw-SHA4IUML.js → nemoclaw-QPHETUXM.js} +6 -6
  78. package/dist/{omp-OOVUNXME.js → omp-3TFMTJ5U.js} +5 -5
  79. package/dist/{open-interpreter-4PKL56AA.js → open-interpreter-UTBKE2EH.js} +5 -5
  80. package/dist/openclaw-RYFO5TLY.js +17 -0
  81. package/dist/{opencode-W2RK4M7G.js → opencode-JX7GBE5Q.js} +5 -5
  82. package/dist/{openhands-5LNH3BKB.js → openhands-AZW4PXJ3.js} +5 -5
  83. package/dist/{package-2EAIYSJ4.js → package-2KKUGZFS.js} +12 -12
  84. package/dist/{pi-BUADR5MJ.js → pi-MRI3EBWU.js} +5 -5
  85. package/dist/{qwen-code-TUJNHKNI.js → qwen-code-ISR6BEET.js} +6 -6
  86. package/dist/{roo-code-L5F7S6QH.js → roo-code-6TSCME4R.js} +5 -5
  87. package/dist/runtime/index.d.ts +1 -1
  88. package/dist/runtime/index.js +12 -12
  89. package/dist/sdk/index.d.ts +3 -3
  90. package/dist/sdk/index.js +6 -6
  91. package/dist/sdk/test.d.ts +2 -2
  92. package/dist/sdk/test.js +10 -10
  93. package/dist/{serve-K62FW3V7.js → serve-EPRN7F2X.js} +14 -14
  94. package/dist/{status-E5MCFZM6.js → status-B2PG6YKR.js} +10 -10
  95. package/dist/{statusline-LIPF2KVP.js → statusline-5ERFMYSM.js} +13 -13
  96. package/dist/{telemetry-4OC56NTM.js → telemetry-ZMCAWBWB.js} +10 -10
  97. package/dist/{trae-Z7CQ2A2Q.js → trae-7KDCYIMN.js} +5 -5
  98. package/dist/{types-C4qMgbJn.d.ts → types-D0RqWxT8.d.ts} +43 -0
  99. package/dist/{uninstall-2YYKN5DX.js → uninstall-M76BHLTH.js} +35 -25
  100. package/dist/uninstall-M76BHLTH.js.map +1 -0
  101. package/dist/{upgrade-55AFPJEF.js → upgrade-JLSCNAQA.js} +23 -17
  102. package/dist/upgrade-JLSCNAQA.js.map +1 -0
  103. package/dist/{usage-3PB3WZSL.js → usage-5I72HWCR.js} +2 -2
  104. package/dist/{usage-event-KD5FW6W4.js → usage-event-HIX4ZI45.js} +13 -13
  105. package/dist/{vscode-copilot-LU5NC4ZS.js → vscode-copilot-LILHAPJI.js} +20 -5
  106. package/dist/vscode-copilot-LILHAPJI.js.map +1 -0
  107. package/dist/{warp-4PPG5LOM.js → warp-KJUCWEA3.js} +5 -5
  108. package/dist/{windsurf-3T3RVXKM.js → windsurf-5TGGQR5I.js} +5 -5
  109. package/dist/{zed-ZF2OQ75O.js → zed-EL3JCZ25.js} +5 -5
  110. package/package.json +1 -1
  111. package/dist/antigravity-cli-JO6GUTV7.js.map +0 -1
  112. package/dist/chunk-4HVQ7IUM.js.map +0 -1
  113. package/dist/chunk-7HUUINPB.js +0 -201
  114. package/dist/chunk-7HUUINPB.js.map +0 -1
  115. package/dist/chunk-IXOQDZWC.js.map +0 -1
  116. package/dist/chunk-KIRCPLM4.js.map +0 -1
  117. package/dist/chunk-LF76VPGQ.js.map +0 -1
  118. package/dist/chunk-QKLJU4JX.js.map +0 -1
  119. package/dist/doctor-3CUBPQKU.js.map +0 -1
  120. package/dist/install-7DMK53SB.js +0 -96
  121. package/dist/install-7DMK53SB.js.map +0 -1
  122. package/dist/jetbrains-copilot-T2EPKROP.js.map +0 -1
  123. package/dist/openclaw-BD56E5MV.js +0 -17
  124. package/dist/uninstall-2YYKN5DX.js.map +0 -1
  125. package/dist/upgrade-55AFPJEF.js.map +0 -1
  126. package/dist/vscode-copilot-LU5NC4ZS.js.map +0 -1
  127. /package/dist/{action-L44DXFHT.js.map → action-CVIEPX4U.js.map} +0 -0
  128. /package/dist/{amazon-q-B52EY2SV.js.map → amazon-q-TIT7FIW3.js.map} +0 -0
  129. /package/dist/{amp-UXABVUKC.js.map → amp-NF3OAAUG.js.map} +0 -0
  130. /package/dist/{antigravity-RZHN53VB.js.map → antigravity-7LPK7QOY.js.map} +0 -0
  131. /package/dist/{chunk-UBB7T54N.js.map → chunk-3C5AASHM.js.map} +0 -0
  132. /package/dist/{chunk-BLTVZACS.js.map → chunk-447JWFZO.js.map} +0 -0
  133. /package/dist/{chunk-HORHRHNG.js.map → chunk-4NHXLXSD.js.map} +0 -0
  134. /package/dist/{chunk-AY3RGRTT.js.map → chunk-6TF7MHG5.js.map} +0 -0
  135. /package/dist/{chunk-R6LML2YS.js.map → chunk-7UT6OB52.js.map} +0 -0
  136. /package/dist/{chunk-G4CEELKO.js.map → chunk-AY3VFNOH.js.map} +0 -0
  137. /package/dist/{chunk-LAIITCMW.js.map → chunk-FBCBHEGB.js.map} +0 -0
  138. /package/dist/{chunk-4NSU3KWX.js.map → chunk-FJCUKXGX.js.map} +0 -0
  139. /package/dist/{chunk-ZMLVR4J7.js.map → chunk-FO5CEXXN.js.map} +0 -0
  140. /package/dist/{chunk-4FWETID5.js.map → chunk-IVAWP6HH.js.map} +0 -0
  141. /package/dist/{chunk-NBUEL74R.js.map → chunk-JFXL4HYA.js.map} +0 -0
  142. /package/dist/{chunk-NWLRJNXM.js.map → chunk-JVO6NBTT.js.map} +0 -0
  143. /package/dist/{chunk-25CPWJA7.js.map → chunk-KA55FISM.js.map} +0 -0
  144. /package/dist/{chunk-QARPXSIV.js.map → chunk-L26PSQTY.js.map} +0 -0
  145. /package/dist/{chunk-YYNXIUR2.js.map → chunk-M2H7JURF.js.map} +0 -0
  146. /package/dist/{chunk-56R2ER7K.js.map → chunk-NBYKLUF6.js.map} +0 -0
  147. /package/dist/{chunk-LN76OGNR.js.map → chunk-Z2MRSS2I.js.map} +0 -0
  148. /package/dist/{claude-code-WS4NAGZT.js.map → claude-code-7RS4YVGZ.js.map} +0 -0
  149. /package/dist/{cline-NNMVCECA.js.map → cline-BZQAUYPC.js.map} +0 -0
  150. /package/dist/{codebuddy-RBEZGXBG.js.map → codebuddy-G42IKGKB.js.map} +0 -0
  151. /package/dist/{codebuff-RJIDSEU3.js.map → codebuff-5RLTLZAU.js.map} +0 -0
  152. /package/dist/{continue-MNM7YVJY.js.map → continue-JLIB7R7X.js.map} +0 -0
  153. /package/dist/{copilot-cli-SMTX5F65.js.map → copilot-cli-XZSUYNQZ.js.map} +0 -0
  154. /package/dist/{crush-NYDBHIJE.js.map → crush-ESERLVLT.js.map} +0 -0
  155. /package/dist/{cursor-AOELDNZU.js.map → cursor-FUDOV5VK.js.map} +0 -0
  156. /package/dist/{detect-3S46RUMK.js.map → detect-Z5BDTY6B.js.map} +0 -0
  157. /package/dist/{devin-PRJY2TTD.js.map → devin-Y7PWKVHY.js.map} +0 -0
  158. /package/dist/{droid-PTCH2K7Y.js.map → droid-DTO5POTK.js.map} +0 -0
  159. /package/dist/{gemini-cli-QGLN2UMS.js.map → gemini-cli-RBIG6U2F.js.map} +0 -0
  160. /package/dist/{goose-DQ6GSZ5O.js.map → goose-VGNOP5J2.js.map} +0 -0
  161. /package/dist/{grok-cli-5QD235UB.js.map → grok-cli-2RFBK6J3.js.map} +0 -0
  162. /package/dist/{hermes-E47IG63A.js.map → hermes-NUKFWZI5.js.map} +0 -0
  163. /package/dist/{hook-P6EKDINW.js.map → hook-XPR3AHDI.js.map} +0 -0
  164. /package/dist/{junie-SQ4SDLGK.js.map → junie-TSXIZSCE.js.map} +0 -0
  165. /package/dist/{kilo-OU2ZLZKB.js.map → kilo-JLH3KVZJ.js.map} +0 -0
  166. /package/dist/{kilo-cli-NMWGYF4F.js.map → kilo-cli-5W36VJQZ.js.map} +0 -0
  167. /package/dist/{kimi-Z7L2LEEI.js.map → kimi-R62W7HKZ.js.map} +0 -0
  168. /package/dist/{kiro-4IN5IH46.js.map → kiro-AUJMGIBL.js.map} +0 -0
  169. /package/dist/{leaderboard-LF5SP6X2.js.map → leaderboard-YWMOSJBC.js.map} +0 -0
  170. /package/dist/{mimo-code-G2CBZ4M6.js.map → mimo-code-PGLFFVER.js.map} +0 -0
  171. /package/dist/{mistral-vibe-TRQDHAWV.js.map → mistral-vibe-36CZVQNQ.js.map} +0 -0
  172. /package/dist/{mux-JNM3F2NW.js.map → mux-HWL4N5KH.js.map} +0 -0
  173. /package/dist/{nemoclaw-SHA4IUML.js.map → nemoclaw-QPHETUXM.js.map} +0 -0
  174. /package/dist/{omp-OOVUNXME.js.map → omp-3TFMTJ5U.js.map} +0 -0
  175. /package/dist/{open-interpreter-4PKL56AA.js.map → open-interpreter-UTBKE2EH.js.map} +0 -0
  176. /package/dist/{openclaw-BD56E5MV.js.map → openclaw-RYFO5TLY.js.map} +0 -0
  177. /package/dist/{opencode-W2RK4M7G.js.map → opencode-JX7GBE5Q.js.map} +0 -0
  178. /package/dist/{openhands-5LNH3BKB.js.map → openhands-AZW4PXJ3.js.map} +0 -0
  179. /package/dist/{package-2EAIYSJ4.js.map → package-2KKUGZFS.js.map} +0 -0
  180. /package/dist/{pi-BUADR5MJ.js.map → pi-MRI3EBWU.js.map} +0 -0
  181. /package/dist/{qwen-code-TUJNHKNI.js.map → qwen-code-ISR6BEET.js.map} +0 -0
  182. /package/dist/{roo-code-L5F7S6QH.js.map → roo-code-6TSCME4R.js.map} +0 -0
  183. /package/dist/{serve-K62FW3V7.js.map → serve-EPRN7F2X.js.map} +0 -0
  184. /package/dist/{status-E5MCFZM6.js.map → status-B2PG6YKR.js.map} +0 -0
  185. /package/dist/{statusline-LIPF2KVP.js.map → statusline-5ERFMYSM.js.map} +0 -0
  186. /package/dist/{telemetry-4OC56NTM.js.map → telemetry-ZMCAWBWB.js.map} +0 -0
  187. /package/dist/{trae-Z7CQ2A2Q.js.map → trae-7KDCYIMN.js.map} +0 -0
  188. /package/dist/{usage-3PB3WZSL.js.map → usage-5I72HWCR.js.map} +0 -0
  189. /package/dist/{usage-event-KD5FW6W4.js.map → usage-event-HIX4ZI45.js.map} +0 -0
  190. /package/dist/{warp-4PPG5LOM.js.map → warp-KJUCWEA3.js.map} +0 -0
  191. /package/dist/{windsurf-3T3RVXKM.js.map → windsurf-5TGGQR5I.js.map} +0 -0
  192. /package/dist/{zed-ZF2OQ75O.js.map → zed-EL3JCZ25.js.map} +0 -0
package/README.md CHANGED
@@ -1,248 +1,176 @@
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).
72
-
73
- ## Verification
74
-
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/).
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>
133
47
 
134
48
  ## Quick start
135
49
 
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.
140
-
141
- ### Agent-CLI end user
142
-
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.
50
+ agent-connector is an **SDK you depend on**, not a global tool. Add it to the
51
+ package that holds your connector, declare the connector once, then `install`
52
+ it deploys to every detected agent CLI in that host's own native config. The
53
+ linear path is: **get a server declare it install**.
146
54
 
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:
55
+ **0. You need an MCP server file first.** The config below points at
56
+ `./my-mcp-server.mjs`, so that file must exist before you install. Don't have an
57
+ MCP server yet? Copy
58
+ [`examples/acme-db/acme-db-mcp-server.mjs`](examples/acme-db/acme-db-mcp-server.mjs)
59
+ (a self-contained ~35-line stub) as `./my-mcp-server.mjs`, or follow the
60
+ [official MCP SDK quickstart](https://modelcontextprotocol.io/quickstart/server).
150
61
 
151
62
  ```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
63
+ # 1. add agent-connector as a DEPENDENCY of your connector package
64
+ npm install @ken-jo/agent-connector
65
+ ```
154
66
 
155
- # which agent CLI burned the most tokens?
156
- npx @ken-jo/agent-connector usage leaderboard --by platform # or --by model
67
+ ```js
68
+ // 2. agent-connector.config.mjs declare your server + hooks once
69
+ import { fileURLToPath } from "node:url";
70
+ import { defineConnector } from "@ken-jo/agent-connector";
157
71
 
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
- ```
72
+ const serverPath = fileURLToPath(new URL("./my-mcp-server.mjs", import.meta.url));
161
73
 
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.
74
+ export default defineConnector({
75
+ id: "acme-db",
76
+ server: {
77
+ transport: "stdio",
78
+ command: "node",
79
+ args: [serverPath],
80
+ },
81
+ // hooks, telemetry, and more surfaces see "What you define once" below
82
+ });
83
+ ```
191
84
 
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.
85
+ > While developing, `server.command` can be `node` + a local file path (as
86
+ > above); once your server is a published package, switch to `npx` + the package
87
+ > name (`command: "npx", args: ["-y", "@acme/acme-db-mcp"]`) the form the
88
+ > [site quick-start](https://agent-connector.ai) teaches.
196
89
 
197
90
  ```bash
198
- # 1. add agent-connector as a DEPENDENCY of your connector package
199
- npm install @ken-jo/agent-connector
200
-
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
91
+ # 3. deploy across the agent CLIs detected on this machine
92
+ npx @ken-jo/agent-connector detect # which platforms are installed here?
93
+ npx @ken-jo/agent-connector install --dry-run # preview every change first
94
+ npx @ken-jo/agent-connector install # write native config in each host
216
95
  ```
217
96
 
218
97
  > `install` targets only the hosts actually **detected** on this machine (or an
219
98
  > explicit `--targets` / `connector.targets` list), intersected with the
220
- > 35-adapter registry — there is no "install to all 35 unconditionally" path.
99
+ > 42-adapter registry — there is no "install to all 42 unconditionally" path.
100
+ > A global `npm i -g` is **not** required: `npx @ken-jo/agent-connector …` runs
101
+ > straight from your project.
221
102
 
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.
103
+ ## Ship it: direct install or a marketplace plugin
226
104
 
227
- ### Embed it / ship a branded CLI
105
+ Same one definition, your choice of distribution.
228
106
 
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.
107
+ **Direct install** `agent-connector install` writes each host's native MCP +
108
+ hook + content-surface config in place, with no per-platform marketplace
109
+ submission or review. This is the Quick start path above.
110
+
111
+ **Marketplace plugin** `agent-connector package` turns the connector into a
112
+ real plugin/extension bundle (manifest + bundled commands, agents, skills,
113
+ hooks, MCP) from one definition. Hooks + MCP keep the telemetry serve-wrapper,
114
+ so a marketplace-installed connector still reports per-tool tokens for its stdio
115
+ server. `--format all` emits **10 host formats**:
235
116
 
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
- }
117
+ | Format | Hosts |
118
+ |---|---|
119
+ | `claude-plugin` | Claude Code · Codex · VS Code Copilot · OpenClaw · OMP |
120
+ | `codex-plugin` | Codex (`.codex-plugin/` manifest variant) |
121
+ | `copilot-plugin` | GitHub Copilot CLI |
122
+ | `factory-plugin` | Droid |
123
+ | `gemini-extension` | Gemini CLI |
124
+ | `qwen-extension` | Qwen Code |
125
+ | `agy-plugin` | Antigravity (CLI + IDE) |
126
+ | `cursor-plugin` | Cursor |
127
+ | `kimi-plugin` | Kimi CLI |
128
+ | `npm-plugin` | OpenCode · Kilo CLI · Pi |
129
+
130
+ Two official **MCP standard artifacts** are opt-in (they need a `publish` block,
131
+ so they're excluded from `--format all`) — `mcp-server-json` (an MCP Registry
132
+ `server.json`) and `mcpb` (a one-click MCPB bundle); see
133
+ [Publish to the MCP ecosystem](#publish-to-the-mcp-ecosystem).
134
+
135
+ ```bash
136
+ # emit every host format (mcp-server-json + mcpb are opt-in by name)
137
+ agent-connector package --format all --out ./dist-plugin
138
+ agent-connector package --format gemini-extension --out ./ext # or just one
139
+
140
+ # e.g. Claude Code: /plugin marketplace add ./dist-plugin/claude-plugin
141
+ # /plugin install <connector-id>@agent-connector
142
+ # e.g. Gemini CLI: gemini extensions install ./dist-plugin/gemini-extension/<id>
244
143
  ```
245
144
 
145
+ > **Embedded-path caveat.** Most host bundles bake in the absolute home-bin
146
+ > launcher path of the machine that ran `package`, so they're valid for a
147
+ > **local install on that same machine/home**. For shared distribution use
148
+ > `npm-plugin` or the MCP standard artifacts, or re-run `package` per machine.
149
+
150
+ **Let agent-connector drive the host's own install flow** with `install --method
151
+ marketplace`:
152
+
153
+ - **What it does** — stages the bundle, registers a local marketplace where the
154
+ host has one, then runs the host's plugin-install verb (or, for npm-plugin
155
+ hosts, writes a local `file://` entry); headless and idempotent. Other
156
+ marketplace-format hosts print the exact manual commands.
157
+ - **Host coverage** — live-verified for Claude Code, Codex, OpenCode, Kilo
158
+ (CLI + ext), and Antigravity (CLI + IDE) on Linux, Windows, and macOS; Droid
159
+ and Qwen Code have the driver shipped but pending a live host; Gemini CLI is
160
+ legacy (sunsetting toward Antigravity — driver kept for existing installs).
161
+ - **Safety + reversal** — a guard refuses installing the same connector by BOTH
162
+ methods, `uninstall --method auto` reverses whichever method is installed, and
163
+ `doctor` checks registration drift.
164
+
165
+ ### Ship a branded CLI
166
+
167
+ A connector developer can ship their **own** bin instead of having users type
168
+ `agent-connector`. `createConnectorCli({ name, connector })` (from the
169
+ `@ken-jo/agent-connector/cli` export) exposes **every** subcommand under your
170
+ brand, fully delegated and **auto-scoped** to your connector — so your users
171
+ never install agent-connector globally or type `--connector`. See
172
+ [`examples/branded-cli`](examples/branded-cli) for the full, runnable package.
173
+
246
174
  ```js
247
175
  #!/usr/bin/env node
248
176
  // bin.mjs — every agent-connector subcommand, branded as `acme-db`
@@ -258,142 +186,21 @@ process.exitCode = await createConnectorCli({
258
186
  }).run();
259
187
  ```
260
188
 
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).
189
+ After a consumer installs **your** package, the `acme-db` bin is on their PATH
190
+ and every command is scoped to your connector (`acme-db install` ≈
191
+ `agent-connector install --connector ./agent-connector.config.mjs`). Auto-scoping
192
+ is pure argument injection over the SAME single home binary; `serve` and `hook`
193
+ still route through the one `~/.agent-connector` home binary every host config
194
+ points back to. An explicit `--connector` / `--connector-id` always overrides
195
+ the injected default.
381
196
 
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
- ```
197
+ ## What you define once
390
198
 
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.
395
-
396
- ## Define once
199
+ A single `defineConnector({...})` declares your MCP **server** + lifecycle
200
+ **hooks**, and optionally the additional surfaces **commands**, **skills**,
201
+ **subagents**, **memory**, **statusline**, **actions**, plus host-native escape
202
+ hatches. agent-connector renders each surface into every detected host's native
203
+ format, or *skip-warns* (never silently drops) where a host can't support it.
397
204
 
398
205
  ```ts
399
206
  import { fileURLToPath } from "node:url";
@@ -424,42 +231,6 @@ export default defineConnector({
424
231
  });
425
232
  ```
426
233
 
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
234
  `agent-connector install` turns that into, e.g.:
464
235
 
465
236
  | Host | What gets written |
@@ -471,150 +242,80 @@ export default defineConnector({
471
242
  …each pointing hooks at a **single stable home binary**, so one update propagates
472
243
  everywhere.
473
244
 
474
- ### Standing guidance (`memory`) aligned with the AGENTS.md standard
245
+ **Secret env-refs (`${env:VAR}`).** Write `"${env:VAR}"` (or `"${env:VAR:-default}"`) anywhere in `command` / `args` / `env` / `url` / `headers` to reference an environment variable.
475
246
 
476
- Ship the rules every agent should follow when your MCP is installed:
247
+ <details>
248
+ <summary>Native interpolation vs. literal-at-install resolution</summary>
477
249
 
478
- ```ts
479
- memory: [
480
- {
481
- content:
482
- "Use the acme-db MCP tools for schema questions; never hand-edit migrations.",
483
- },
484
- ],
485
- ```
250
+ > On hosts with **native** interpolation (Claude Code, Cursor, VS Code Copilot,
251
+ > amp, codebuff) the token is written through to the host config and resolved at
252
+ > runtime. Every other host has **no** native interpolation, so the value is
253
+ > resolved to a **literal at install time**; an unset variable with no default
254
+ > resolves to an **empty string**, and `install` emits a `warn` for it on a
255
+ > literal-resolving host.
486
256
 
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:
257
+ </details>
520
258
 
521
- ```ts
522
- import { defineConnector, defineStatusline } from "@ken-jo/agent-connector";
259
+ **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 } } } }`.
523
260
 
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
- ```
535
-
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:
261
+ <details>
262
+ <summary>Raw-payload semantics and the ~14 passthrough hosts</summary>
566
263
 
567
- ```ts
568
- import { defineConnector, defineAction } from "@ken-jo/agent-connector";
569
-
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
- ```
586
-
587
- The **universal verb** runs any declared action from the shell (or from a
588
- script / IDE task):
589
-
590
- ```bash
591
- agent-connector action <platform> flush-cache --connector acme-db
592
- ```
264
+ > The handler receives the host's **raw** payload and whatever it returns is the
265
+ > **verbatim** JSON reply (exit 0 only — exit-2 blocking isn't modeled). Hosts
266
+ > supporting host-native passthrough: `amp`, `claude-code`, `continue`,
267
+ > `copilot-cli`, `cursor`, `gemini-cli`, `hermes`, `jetbrains-copilot`, `kimi`,
268
+ > `nemoclaw`, `omp`, `openclaw`, `opencode`, `qwen-code`. Others skip-warn.
593
269
 
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).
270
+ </details>
598
271
 
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? }`.
272
+ **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
273
 
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).
274
+ <details>
275
+ <summary>Set-if-absent + refcount + denylist semantics</summary>
610
276
 
611
- ## How it works (operating model)
277
+ > Semantics are fixed: **set-if-absent + skip-warn on any conflict** — never
278
+ > overwrite, never deep-merge. Ownership is refcounted in a persisted ledger;
279
+ > security-relevant keys and keys agent-connector models as first-class surfaces
280
+ > are hard-refused.
281
+
282
+ </details>
283
+
284
+ ### Memory, statusline, actions, and the SDK
285
+
286
+ - **`memory`** (aligned with the [AGENTS.md](https://agents.md) standard) — ship
287
+ standing guidance that lands in `AGENTS.md` on 33 of the 42 hosts; the two that
288
+ don't read it (Claude Code → `CLAUDE.md`, Gemini CLI → `GEMINI.md`) are wired
289
+ per their own official docs. Writes are surgical marker-fenced, hash-stamped
290
+ managed blocks — multiple connectors coexist, bytes outside your markers are
291
+ never touched, and uninstall excises exactly your blocks.
292
+ - **`statusline`** (`defineStatusline`) — a live HUD render function the host
293
+ calls on every status refresh. v1 registers Claude Code's `settings.json.statusLine`
294
+ or Qwen Code's `settings.json.ui.statusLine` (set-if-absent, refcounted,
295
+ reversible); other hosts skip-warn. The runtime is **fail-safe**: any error
296
+ exits 0 with empty stdout so a HUD never wedges the host.
297
+ - **`actions`** (`defineAction`) — named, user-invocable operations dispatched by
298
+ the universal verb `agent-connector action <platform> <id> --connector <id>`.
299
+ `install` emits host-side affordances on `droid`, `hermes`, `nemoclaw`, `omp`,
300
+ `openclaw`, and `warp`; other hosts skip-warn. Error semantics are
301
+ user-triggered (unknown id or throw exits 1).
302
+ - **The Connector SDK** (`@ken-jo/agent-connector/sdk`, `/sdk/test`) — the
303
+ consolidated authoring surface re-exports `defineConnector`, the full `define*`
304
+ family (`defineHook`, `defineCommand`, `defineSkill`, `defineSubagent`,
305
+ `defineMemory`, `defineStatusline`, `defineAction`, `defineConfigPatch`,
306
+ `defineNativeHook`), introspection helpers (`hostsSupporting`,
307
+ `capabilitiesOf`, `surfaceSupport`), and an **offline harness**
308
+ (`simulate`, `explain`, `explainHooks`) that runs the real adapter
309
+ parse→handler→format chain to answer *"does my handler actually work on host
310
+ X?"* before you touch a real host. See
311
+ [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
312
+
313
+ ## How it works
612
314
 
613
315
  - **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.
316
+ `~/.agent-connector` (override `AGENT_CONNECTOR_DATA_DIR`). Every host config we
317
+ write is a thin pointer back to that one binary. Updates are
318
+ **explicit/managed** (`agent-connector upgrade`), never silent auto-update.
618
319
  - **Per-project data, kept.** Telemetry/state is keyed by a stable project
619
320
  identity (git remote or normalized path), partitioned per project, stored under
620
321
  the home data-root — surviving `git clean`, shared across hosts opening the same
@@ -623,45 +324,83 @@ verdict — intentional).
623
324
  only framework-owned state lives under the data-root.
624
325
  - **Windows-first correctness.** No symlinks, no POSIX-only assumptions.
625
326
 
327
+ **Three hook paradigms**, all install-verified across the 42-platform set
328
+ (see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)):
329
+
330
+ | Paradigm | Platforms |
331
+ |---|---|
332
+ | `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 |
333
+ | `mcp-only` (MCP registration only) | Warp · Roo Code · Cline · Trae · Zed · Codebuff · Mux · Pi · Windsurf · Open Interpreter · Junie · Mistral Vibe |
334
+ | `ts-plugin` (generated bridge module) | OpenCode · MiMoCode · Kilo CLI · Kilo · OMP · NemoClaw · OpenClaw · Amp |
335
+
336
+ Adding a platform = **one registry entry + one adapter**.
337
+
626
338
  ## CLI
627
339
 
628
340
  | Command | Purpose |
629
341
  |---|---|
630
342
  | `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`. |
343
+ | `install [--scope ] [--targets …] [--method …] [--dry-run] [--force]` | Render + write MCP + hooks + content surfaces across targets. |
344
+ | `uninstall [--targets …] [--purge] [--method …]` | Full inverse — removes everything we wrote; `--purge` also clears framework state. |
345
+ | `upgrade [--channel ]` | Re-render host config + heal stale pointers + refresh the home binary (alias: `update`, `sync`); never a silent self-update. |
346
+ | `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
347
  | `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. |
348
+ | `package [--format <fmt>\|all]` | Emit a host plugin bundle, or an OFFICIAL standard artifact: `mcp-server-json` (registry) · `mcpb` (one-click bundle). |
349
+ | `action <platform> <id> [--connector <id>]` | Run a declared action from the shell. |
350
+ | `telemetry report [--by ] [--since …] [--connector <id>]` | Per-tool token footprint of **your connector's own wrapped server**. Stdio servers only. |
351
+ | `telemetry export [--format ] [--connector <id>]` | Raw aggregate records for your wrapped server. |
352
+ | `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. |
353
+ | `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
354
 
642
355
  > `hook` and `serve` also exist — internal entrypoints the written host configs
643
356
  > point at; you never run them by hand. Full flag-level reference: the
644
357
  > [docs site `/docs/dev/cli`](https://agent-connector.ai/docs/dev/cli) · `llms-full.txt` §3 (canonical, drift-guarded by tests).
645
358
 
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.
359
+ ## Token telemetry & usage
360
+
361
+ Two independent, never-summed views of token cost:
362
+
363
+ - **Per-tool telemetry for *your own* server** (the MCP-developer path). No host
364
+ reports per-tool usage back to an MCP server, so agent-connector measures your
365
+ server's *own* bytes (args in, results out, tool schemas) and tokenizes them
366
+ locally — **aggregate counts only, stored locally, zero egress by default.**
367
+ Per-tool telemetry is automatic for **stdio** servers; remote (`http`/`sse`/`ws`)
368
+ servers are registered but not wrapped (the proxy can't intercept remote
369
+ transports). Read it with `agent-connector telemetry report --by tool`.
370
+ - **Connector-free usage** (`agent-connector usage`). Already run Claude Code /
371
+ Codex / Cursor and just want totals? `usage` reads your local agent-CLI session
372
+ logs **read-only** and never writes any host config — no connector, no install:
373
+
374
+ ```bash
375
+ npx @ken-jo/agent-connector usage report --by platform # CLI/model/project/session/day
376
+ npx @ken-jo/agent-connector usage leaderboard --by platform # or --by model
377
+ npx @ken-jo/agent-connector usage export --format csv --out usage.csv
378
+ ```
379
+
380
+ It reports **whole-conversation totals** per agent CLI / model / project /
381
+ session / day. It does **not** itemize cost by individual MCP server or tool —
382
+ agent CLIs don't log per-tool attribution.
383
+
384
+ **Privacy & tokenizer.** Default tokenizer is `gpt-tokenizer` (pure-JS, no native
385
+ build) — `o200k_base` for OpenAI/Codex-family, a documented approximation for
386
+ Anthropic; falls back to a `chars/4` heuristic if it can't load. Every record
387
+ carries a confidence tag. Raw tool arguments and results are never stored or
388
+ transmitted. Off switch: `AGENT_CONNECTOR_TELEMETRY=0`, or
389
+ `telemetry: { enabled: false }`.
651
390
 
652
391
  ## Publish to the MCP ecosystem
653
392
 
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
393
+ Where the MCP standard already covers your server's functionality,
394
+ agent-connector **emits the standard exactly** so your already-standard work is
395
+ portable:
396
+
397
+ - **`package --format mcp-server-json`** → an official **MCP Registry**
398
+ `server.json` (schema `2025-12-11`). It describes your **real upstream server**
399
+ (what a registry installer runs), not our telemetry wrapper. Publish it with
400
+ the official `mcp-publisher` CLI.
401
+ - **`package --format mcpb`** → an official **MCPB** (`.mcpb`, formerly DXT)
402
+ bundle `manifest.json` (`manifest_version 0.3`) for one-click local install in
403
+ Claude Desktop and any MCPB host, with secrets routed through the host keychain
665
404
  (`user_config`).
666
405
 
667
406
  Both read a `publish` block on your connector (the namespace you own + your
@@ -682,32 +421,34 @@ defineConnector({
682
421
 
683
422
  > **Config we write is the standard.** `install` writes each host's native MCP
684
423
  > 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.
424
+ > for stdio, `{ url, headers }` for remote. The spec transport slug for
425
+ > streamable HTTP is `streamable-http` (registry `server.json`); host configs
426
+ > canonically use `http`. WebSocket (`ws`) is **not** an MCP spec transport and
427
+ > the standard artifacts reject it.
689
428
 
690
429
  > **Forward-compatible by transport.** The `serve` proxy is **byte-transparent**:
691
430
  > 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
431
+ > `tools/call` round-trips. So newer MCP features ride through untouched
432
+ > **MCP Apps** (the official `io.modelcontextprotocol/ui` extension) and **any
696
433
  > reverse-DNS extension** negotiated at `initialize`. A connector whose server
697
434
  > 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 }`.
435
+ > no agent-connector change required.
436
+
437
+ ## Verification
438
+
439
+ The full single-API contract is **install-verified across all 42 platforms** by
440
+ a committed registry-driven install-roundtrip harness that, for every adapter,
441
+ drives the real install uninstall into an isolated HOME and asserts on-disk
442
+ placement + zero residue. A separate committed `scripts/verify-host.mjs` driver
443
+ installs **20 real host CLIs** and verifies install → placement →
444
+ clean-uninstall, and live hook dispatch + telemetry are proven end-to-end on
445
+ several of them. The remaining hosts (IDE extensions / GUI editors with no
446
+ headless CLI) stay covered by the install-roundtrip harness.
447
+
448
+ **Dogfood result:** porting the real multi-host context-mode plugin to
449
+ `defineConnector` collapsed **~20,322 lines of hand-maintained per-host code down
450
+ to ~76 lines** (a 99.63% reduction). See the reports under
451
+ [`docs/research/`](docs/research/) and [`CHANGELOG.md`](CHANGELOG.md).
711
452
 
712
453
  ## Development
713
454