agent-trellis 0.7.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/README.md +48 -153
  2. package/dist/adapters/claude-code.js +3 -2
  3. package/dist/adapters/codex.js +3 -2
  4. package/dist/adapters/jsonMcp.d.ts +3 -1
  5. package/dist/adapters/jsonMcp.js +18 -4
  6. package/dist/adapters/kimi-code.d.ts +21 -0
  7. package/dist/adapters/kimi-code.js +107 -0
  8. package/dist/adapters/kiro.js +3 -2
  9. package/dist/adapters/mcpPlan.d.ts +6 -1
  10. package/dist/adapters/mcpPlan.js +106 -8
  11. package/dist/adapters/pi.js +22 -3
  12. package/dist/adapters/symlinkPlan.d.ts +7 -0
  13. package/dist/adapters/symlinkPlan.js +16 -7
  14. package/dist/adapters/zcode.d.ts +21 -0
  15. package/dist/adapters/zcode.js +234 -0
  16. package/dist/cli.js +145 -29
  17. package/dist/commands/doctor.d.ts +7 -2
  18. package/dist/commands/doctor.js +40 -2
  19. package/dist/commands/init.d.ts +4 -2
  20. package/dist/commands/init.js +29 -13
  21. package/dist/commands/kimi.d.ts +16 -0
  22. package/dist/commands/kimi.js +64 -0
  23. package/dist/commands/manage.d.ts +39 -0
  24. package/dist/commands/manage.js +126 -0
  25. package/dist/commands/mcp.d.ts +77 -14
  26. package/dist/commands/mcp.js +169 -29
  27. package/dist/commands/mcpGateway.d.ts +6 -0
  28. package/dist/commands/mcpGateway.js +35 -14
  29. package/dist/commands/mcpImport.d.ts +46 -0
  30. package/dist/commands/mcpImport.js +359 -0
  31. package/dist/commands/memory.d.ts +17 -3
  32. package/dist/commands/memory.js +27 -8
  33. package/dist/commands/migrate.d.ts +16 -5
  34. package/dist/commands/migrate.js +93 -17
  35. package/dist/commands/onboard.d.ts +74 -2
  36. package/dist/commands/onboard.js +469 -71
  37. package/dist/commands/rollback.js +28 -2
  38. package/dist/commands/secretsAudit.js +4 -1
  39. package/dist/commands/skill.d.ts +52 -6
  40. package/dist/commands/skill.js +114 -15
  41. package/dist/commands/sync.js +5 -1
  42. package/dist/core/adapter.d.ts +11 -1
  43. package/dist/core/canonical.d.ts +15 -7
  44. package/dist/core/canonical.js +101 -13
  45. package/dist/core/capabilitySelection.d.ts +45 -0
  46. package/dist/core/capabilitySelection.js +124 -0
  47. package/dist/core/types.d.ts +25 -2
  48. package/dist/core/types.js +8 -0
  49. package/dist/lib/agentBridge.d.ts +169 -0
  50. package/dist/lib/agentBridge.js +367 -0
  51. package/dist/lib/agentBridgeProvider.d.ts +14 -0
  52. package/dist/lib/agentBridgeProvider.js +95 -0
  53. package/dist/lib/backup.d.ts +32 -0
  54. package/dist/lib/backup.js +20 -1
  55. package/dist/lib/builtinSkills.d.ts +2 -0
  56. package/dist/lib/builtinSkills.js +4 -0
  57. package/dist/lib/chatAgents.d.ts +42 -0
  58. package/dist/lib/chatAgents.js +59 -0
  59. package/dist/lib/cliMetadata.d.ts +1 -0
  60. package/dist/lib/cliMetadata.js +14 -0
  61. package/dist/lib/envVarNames.d.ts +3 -0
  62. package/dist/lib/envVarNames.js +19 -0
  63. package/dist/lib/gatewayBackend.d.ts +28 -0
  64. package/dist/lib/gatewayBackend.js +72 -1
  65. package/dist/lib/installAgent.d.ts +7 -5
  66. package/dist/lib/installAgent.js +4 -3
  67. package/dist/lib/mcpConnect.js +5 -1
  68. package/dist/lib/mcpMigrateRead.d.ts +2 -0
  69. package/dist/lib/mcpMigrateRead.js +22 -1
  70. package/dist/lib/mcpRuntime.d.ts +46 -0
  71. package/dist/lib/mcpRuntime.js +185 -0
  72. package/dist/lib/mcpStatusProvider.d.ts +10 -0
  73. package/dist/lib/mcpStatusProvider.js +25 -0
  74. package/dist/lib/mcpToolRegistry.d.ts +18 -0
  75. package/dist/lib/mcpToolRegistry.js +107 -14
  76. package/dist/lib/memoryGraph.d.ts +1 -1
  77. package/dist/lib/memoryGraph.js +9 -3
  78. package/dist/lib/memoryProvider.d.ts +58 -0
  79. package/dist/lib/memoryProvider.js +175 -0
  80. package/dist/lib/memoryStatus.d.ts +17 -0
  81. package/dist/lib/memoryStatus.js +88 -0
  82. package/dist/lib/nativeMemory.d.ts +19 -0
  83. package/dist/lib/nativeMemory.js +129 -0
  84. package/dist/lib/realHomeSnapshot.js +5 -0
  85. package/dist/lib/runtimeControlProvider.d.ts +16 -0
  86. package/dist/lib/runtimeControlProvider.js +170 -0
  87. package/dist/lib/secretEnv.d.ts +2 -1
  88. package/dist/lib/secretEnv.js +6 -2
  89. package/dist/lib/skillProvider.d.ts +13 -0
  90. package/dist/lib/skillProvider.js +210 -0
  91. package/dist/lib/taskProvider.d.ts +7 -0
  92. package/dist/lib/taskProvider.js +43 -0
  93. package/dist/lib/taskStore.d.ts +46 -0
  94. package/dist/lib/taskStore.js +156 -0
  95. package/dist/lib/terminalPicker.d.ts +23 -49
  96. package/dist/lib/terminalPicker.js +80 -218
  97. package/dist/lib/zcodeOwnership.d.ts +17 -0
  98. package/dist/lib/zcodeOwnership.js +37 -0
  99. package/dist/pi-bridge/bundle.js +476 -37
  100. package/dist/pi-bridge/index.js +42 -21
  101. package/dist/pi-bridge/schemaTranslate.d.ts +4 -8
  102. package/dist/pi-bridge/schemaTranslate.js +4 -8
  103. package/dist/probes/codex.d.ts +7 -0
  104. package/dist/probes/codex.js +37 -5
  105. package/dist/probes/kimi-code.d.ts +12 -0
  106. package/dist/probes/kimi-code.js +55 -0
  107. package/dist/probes/zcode.d.ts +32 -0
  108. package/dist/probes/zcode.js +140 -0
  109. package/dist/sdk.d.ts +1 -1
  110. package/docs/architecture.md +230 -28
  111. package/docs/assets/brand-v3/trellis-mark-v3-a.png +0 -0
  112. package/docs/assets/brand-v3/trellis-mark-v3-a.svg +10 -0
  113. package/docs/assets/poster-series-v3/README.md +60 -0
  114. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-en.png +0 -0
  115. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-en.svg +51 -0
  116. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.png +0 -0
  117. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.svg +51 -0
  118. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-en.png +0 -0
  119. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-en.svg +48 -0
  120. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-zh.png +0 -0
  121. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-zh.svg +48 -0
  122. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-en.png +0 -0
  123. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-en.svg +56 -0
  124. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-zh.png +0 -0
  125. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-zh.svg +56 -0
  126. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-en.png +0 -0
  127. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-en.svg +47 -0
  128. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-zh.png +0 -0
  129. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-zh.svg +47 -0
  130. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-en.png +0 -0
  131. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-en.svg +51 -0
  132. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.png +0 -0
  133. package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.svg +51 -0
  134. package/docs/getting-started.md +496 -42
  135. package/docs/overview.md +134 -0
  136. package/docs/overview.zh-CN.md +102 -0
  137. package/docs/research.md +59 -0
  138. package/docs/roadmap.md +11 -6
  139. package/docs/video/README.md +76 -0
  140. package/docs/video/build/audio/01-opening.aiff +0 -0
  141. package/docs/video/build/audio/01-opening.mp3 +0 -0
  142. package/docs/video/build/audio/02-pain.aiff +0 -0
  143. package/docs/video/build/audio/02-pain.mp3 +0 -0
  144. package/docs/video/build/audio/03-solution.aiff +0 -0
  145. package/docs/video/build/audio/03-solution.mp3 +0 -0
  146. package/docs/video/build/audio/04-install.aiff +0 -0
  147. package/docs/video/build/audio/04-install.mp3 +0 -0
  148. package/docs/video/build/audio/04-setup.mp3 +0 -0
  149. package/docs/video/build/audio/05-dryrun.mp3 +0 -0
  150. package/docs/video/build/audio/05-init.aiff +0 -0
  151. package/docs/video/build/audio/05-init.mp3 +0 -0
  152. package/docs/video/build/audio/05-interactive.mp3 +0 -0
  153. package/docs/video/build/audio/06-dryrun.aiff +0 -0
  154. package/docs/video/build/audio/06-dryrun.mp3 +0 -0
  155. package/docs/video/build/audio/06-onboard.mp3 +0 -0
  156. package/docs/video/build/audio/06-run.mp3 +0 -0
  157. package/docs/video/build/audio/07-onboard.aiff +0 -0
  158. package/docs/video/build/audio/07-onboard.mp3 +0 -0
  159. package/docs/video/build/audio/07-verify.mp3 +0 -0
  160. package/docs/video/build/audio/08-closing.mp3 +0 -0
  161. package/docs/video/build/audio/08-doctor.aiff +0 -0
  162. package/docs/video/build/audio/08-doctor.mp3 +0 -0
  163. package/docs/video/build/audio/09-rollback.aiff +0 -0
  164. package/docs/video/build/audio/09-rollback.mp3 +0 -0
  165. package/docs/video/build/audio/10-principles.aiff +0 -0
  166. package/docs/video/build/audio/10-principles.mp3 +0 -0
  167. package/docs/video/build/audio/11-closing.aiff +0 -0
  168. package/docs/video/build/audio/11-closing.mp3 +0 -0
  169. package/docs/video/build/frames/01-opening-0.png +0 -0
  170. package/docs/video/build/frames/02-pain-1.png +0 -0
  171. package/docs/video/build/frames/02-pain-2.png +0 -0
  172. package/docs/video/build/frames/03-solution-3.png +0 -0
  173. package/docs/video/build/frames/04-install-4.png +0 -0
  174. package/docs/video/build/frames/04-setup-4.png +0 -0
  175. package/docs/video/build/frames/04-setup-5.png +0 -0
  176. package/docs/video/build/frames/05-dryrun-6.png +0 -0
  177. package/docs/video/build/frames/05-init-5.png +0 -0
  178. package/docs/video/build/frames/05-interactive-5.png +0 -0
  179. package/docs/video/build/frames/05-interactive-6.png +0 -0
  180. package/docs/video/build/frames/06-dryrun-6.png +0 -0
  181. package/docs/video/build/frames/06-dryrun-7.png +0 -0
  182. package/docs/video/build/frames/06-onboard-7.png +0 -0
  183. package/docs/video/build/frames/06-onboard-8.png +0 -0
  184. package/docs/video/build/frames/06-run-7.png +0 -0
  185. package/docs/video/build/frames/06-run-8.png +0 -0
  186. package/docs/video/build/frames/07-onboard-10.png +0 -0
  187. package/docs/video/build/frames/07-onboard-7.png +0 -0
  188. package/docs/video/build/frames/07-onboard-8.png +0 -0
  189. package/docs/video/build/frames/07-onboard-9.png +0 -0
  190. package/docs/video/build/frames/07-verify-10.png +0 -0
  191. package/docs/video/build/frames/07-verify-8.png +0 -0
  192. package/docs/video/build/frames/07-verify-9.png +0 -0
  193. package/docs/video/build/frames/08-closing-10.png +0 -0
  194. package/docs/video/build/frames/08-closing-11.png +0 -0
  195. package/docs/video/build/frames/08-doctor-11.png +0 -0
  196. package/docs/video/build/frames/08-doctor-9.png +0 -0
  197. package/docs/video/build/frames/09-rollback-10.png +0 -0
  198. package/docs/video/build/frames/09-rollback-12.png +0 -0
  199. package/docs/video/build/frames/10-principles-11.png +0 -0
  200. package/docs/video/build/frames/10-principles-13.png +0 -0
  201. package/docs/video/build/frames/11-closing-12.png +0 -0
  202. package/docs/video/build/frames/11-closing-14.png +0 -0
  203. package/docs/video/build/segments/01-opening.mp4 +0 -0
  204. package/docs/video/build/segments/01-opening.txt +3 -0
  205. package/docs/video/build/segments/02-pain.mp4 +0 -0
  206. package/docs/video/build/segments/02-pain.txt +5 -0
  207. package/docs/video/build/segments/03-solution.mp4 +0 -0
  208. package/docs/video/build/segments/03-solution.txt +3 -0
  209. package/docs/video/build/segments/04-install.mp4 +0 -0
  210. package/docs/video/build/segments/04-install.txt +3 -0
  211. package/docs/video/build/segments/04-setup.mp4 +0 -0
  212. package/docs/video/build/segments/04-setup.txt +3 -0
  213. package/docs/video/build/segments/05-dryrun.mp4 +0 -0
  214. package/docs/video/build/segments/05-dryrun.txt +3 -0
  215. package/docs/video/build/segments/05-init.mp4 +0 -0
  216. package/docs/video/build/segments/05-init.txt +3 -0
  217. package/docs/video/build/segments/05-interactive.mp4 +0 -0
  218. package/docs/video/build/segments/05-interactive.txt +5 -0
  219. package/docs/video/build/segments/06-dryrun.mp4 +0 -0
  220. package/docs/video/build/segments/06-dryrun.txt +3 -0
  221. package/docs/video/build/segments/06-onboard.mp4 +0 -0
  222. package/docs/video/build/segments/06-onboard.txt +5 -0
  223. package/docs/video/build/segments/06-run.mp4 +0 -0
  224. package/docs/video/build/segments/06-run.txt +3 -0
  225. package/docs/video/build/segments/07-onboard.mp4 +0 -0
  226. package/docs/video/build/segments/07-onboard.txt +5 -0
  227. package/docs/video/build/segments/07-verify.mp4 +0 -0
  228. package/docs/video/build/segments/07-verify.txt +5 -0
  229. package/docs/video/build/segments/08-closing.mp4 +0 -0
  230. package/docs/video/build/segments/08-closing.txt +3 -0
  231. package/docs/video/build/segments/08-doctor.mp4 +0 -0
  232. package/docs/video/build/segments/08-doctor.txt +3 -0
  233. package/docs/video/build/segments/09-rollback.mp4 +0 -0
  234. package/docs/video/build/segments/09-rollback.txt +3 -0
  235. package/docs/video/build/segments/10-principles.mp4 +0 -0
  236. package/docs/video/build/segments/10-principles.txt +3 -0
  237. package/docs/video/build/segments/11-closing.mp4 +0 -0
  238. package/docs/video/build/segments/11-closing.txt +3 -0
  239. package/docs/video/build/segments/final.txt +8 -0
  240. package/docs/video/build-ai/audio/01-hook.mp3 +0 -0
  241. package/docs/video/build-ai/audio/02-pain.mp3 +0 -0
  242. package/docs/video/build-ai/audio/03-solution.mp3 +0 -0
  243. package/docs/video/build-ai/audio/04-how.mp3 +0 -0
  244. package/docs/video/build-ai/audio/05-safe.mp3 +0 -0
  245. package/docs/video/build-ai/audio/06-closing.mp3 +0 -0
  246. package/docs/video/build-ai/clips/01-hook.mp4 +0 -0
  247. package/docs/video/build-ai/clips/02-pain.mp4 +0 -0
  248. package/docs/video/build-ai/clips/03-solution.mp4 +0 -0
  249. package/docs/video/build-ai/clips/04-how.mp4 +0 -0
  250. package/docs/video/build-ai/clips/05-safe.mp4 +0 -0
  251. package/docs/video/build-ai/clips/06-closing.mp4 +0 -0
  252. package/docs/video/build-ai/first-frame-02-pain.png +0 -0
  253. package/docs/video/build-ai/first-frame-03-solution.png +0 -0
  254. package/docs/video/build-ai/first-frame-04-how.png +0 -0
  255. package/docs/video/build-ai/first-frame-05-safe.png +0 -0
  256. package/docs/video/build-ai/segments/01-hook.caption.txt +2 -0
  257. package/docs/video/build-ai/segments/01-hook.mp4 +0 -0
  258. package/docs/video/build-ai/segments/02-pain.mp4 +0 -0
  259. package/docs/video/build-ai/segments/03-solution.mp4 +0 -0
  260. package/docs/video/build-ai/segments/04-how.mp4 +0 -0
  261. package/docs/video/build-ai/segments/05-safe.mp4 +0 -0
  262. package/docs/video/build-ai/segments/06-closing.mp4 +0 -0
  263. package/docs/video/build-ai/segments/cap-01-hook.png +0 -0
  264. package/docs/video/build-ai/segments/cap-02-pain.png +0 -0
  265. package/docs/video/build-ai/segments/cap-03-solution.png +0 -0
  266. package/docs/video/build-ai/segments/cap-04-how.png +0 -0
  267. package/docs/video/build-ai/segments/cap-05-safe.png +0 -0
  268. package/docs/video/build-ai/segments/cap-06-closing.png +0 -0
  269. package/docs/video/build-ai/segments/final.txt +6 -0
  270. package/docs/video/build-posters/audio/01-hook.mp3 +0 -0
  271. package/docs/video/build-posters/audio/02-pain.mp3 +0 -0
  272. package/docs/video/build-posters/audio/03-solution.mp3 +0 -0
  273. package/docs/video/build-posters/audio/04-how.mp3 +0 -0
  274. package/docs/video/build-posters/audio/05-safe.mp3 +0 -0
  275. package/docs/video/build-posters/audio/06-closing.mp3 +0 -0
  276. package/docs/video/build-posters/cap-01-hook.png +0 -0
  277. package/docs/video/build-posters/cap-02-pain.png +0 -0
  278. package/docs/video/build-posters/cap-03-solution.png +0 -0
  279. package/docs/video/build-posters/cap-04-how.png +0 -0
  280. package/docs/video/build-posters/cap-05-safe.png +0 -0
  281. package/docs/video/build-posters/cap-06-closing.png +0 -0
  282. package/docs/video/build-posters/card-01-hook.png +0 -0
  283. package/docs/video/build-posters/card-06-closing.png +0 -0
  284. package/docs/video/build-posters/segments/01-hook.mp4 +0 -0
  285. package/docs/video/build-posters/segments/02-pain.mp4 +0 -0
  286. package/docs/video/build-posters/segments/03-solution.mp4 +0 -0
  287. package/docs/video/build-posters/segments/04-how.mp4 +0 -0
  288. package/docs/video/build-posters/segments/05-safe.mp4 +0 -0
  289. package/docs/video/build-posters/segments/06-closing.mp4 +0 -0
  290. package/docs/video/build-posters/segments/final.txt +6 -0
  291. package/docs/video/generate-video-ai.mjs +334 -0
  292. package/docs/video/generate-video-posters.mjs +204 -0
  293. package/docs/video/generate-video.mjs +426 -0
  294. package/docs/video/outline.zh-CN.md +102 -0
  295. package/docs/video/trellis-demo-video-ai.mp4 +0 -0
  296. package/docs/video/trellis-demo-video.mp4 +0 -0
  297. package/docs/video/voiceover.zh-CN.md +49 -0
  298. package/package.json +6 -2
  299. package/schema/builtin-skills/trellis-runtime/SKILL.md +117 -0
  300. package/schema/capability-selection.example.yaml +23 -0
  301. package/schema/scope.example.yaml +1 -1
  302. package/schema/servers.example.yaml +15 -1
package/README.md CHANGED
@@ -1,178 +1,73 @@
1
1
  # Trellis
2
2
 
3
- **A single source of capability for every coding agent you run.**
3
+ <p align="center">
4
+ <img src="docs/assets/brand-v3/trellis-mark-v3-a.svg" width="88" alt="Trellis logo" />
5
+ </p>
4
6
 
5
- Skills, MCP servers, subagent definitions, shared memory, and secret policy —
6
- defined once, adapted natively into Claude Code, Codex, Kiro, and the [pi coding
7
- agent](https://github.com/earendil-works/pi), without drift and without a second
8
- copy of anything.
7
+ <p align="center"><strong>Unified Code Agent Runtime</strong></p>
9
8
 
10
- Trellis does not replace any of these agents' native config. It generates and
11
- verifies each one's native adapter from one canonical source, and refuses to let
12
- a plaintext secret or a duplicated skill file slip through.
9
+ One canonical source for Skills, MCP, Memory, and shared instructions —
10
+ projected safely into Claude Code, Codex, Kiro, pi, Kimi Code, and ZCode.
13
11
 
14
- ## Why
12
+ > 中文:一个 canonical source 统一管理多个 Code Agent 的 Skill、MCP、Memory
13
+ > 与共享指令,支持预览、备份与回滚。
15
14
 
16
- By late 2026 the "sync my AI agent rules across tools" space is crowded — at
17
- least seven open source projects do it (`block/ai-rules`, `ai-rules-sync`,
18
- `skillshare`, `skills-hub`, `skills-link`, `agent_sync`, and others). None of
19
- them cover **Kiro** or **pi**, and none of them go past rules/skills into MCP
20
- servers, shared memory, and secret hygiene as one coherent system. That's the
21
- gap Trellis fills — see [`docs/research.md`](docs/research.md) for the full
22
- landscape survey and [`docs/architecture.md`](docs/architecture.md) for what we
23
- build versus what we deliberately reuse.
15
+ ![Agent Trellis — One Runtime. Every Code Agent.](docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-en.png)
24
16
 
25
- Trellis aligns with the emerging [`.agents Protocol`](https://dotagentsprotocol.com)
26
- draft rather than inventing a sixth competing standard, and is likely its first
27
- working implementation.
28
-
29
- ## Install
17
+ ## Quick start
30
18
 
31
- ```
19
+ ```bash
32
20
  npm install -g agent-trellis
21
+
22
+ trellis onboard --dry-run # preview: migration source, managed agents, MCP, memory
23
+ trellis onboard # apply — every write is backed up automatically
24
+ trellis doctor # verify state, any time
33
25
  ```
34
26
 
35
- ## Quick start
27
+ Something went wrong? `trellis rollback` inverts the last run.
36
28
 
37
- See [`docs/getting-started.md`](docs/getting-started.md) for the detailed
38
- walkthrough — example output for each command, what each `migrate`/`sync`
39
- conflict action means, and troubleshooting.
29
+ ## How it compares
40
30
 
41
- **One command:**
31
+ | | Skills / Rules | MCP | Memory | Secret hygiene | Agents covered |
32
+ |---|---|---|---|---|---|
33
+ | [ai-rules](https://github.com/block/ai-rules), [skills-link](https://github.com/shanliuling/skills-link), [agent_sync](https://github.com/yelmuratoff/agent_sync) | ✅ | ❌ | ❌ | ❌ | Many — but not Kiro or pi |
34
+ | [skillshare](https://github.com/runkids/skillshare), [skills-hub](https://github.com/qufei1993/skills-hub) | ✅ skills only | ❌ | ❌ | ❌ | Codex, Claude, … |
35
+ | [mcp-router](https://github.com/mcp-router/mcp-router) | ❌ | ✅ desktop router | ❌ | config in its own dashboard | — |
36
+ | [MetaMCP](https://github.com/metatool-ai/metamcp), [mcp-hub](https://github.com/ravitemer/mcp-hub) | ❌ | ✅ aggregator | ❌ | ❌ | — |
37
+ | [cli-agent-orchestrator](https://github.com/awslabs/cli-agent-orchestrator) | ❌ | ❌ | ❌ | ❌ | Runs agent fleets, doesn't unify config |
38
+ | **Trellis** | ✅ | ✅ native config, Runtime, or hub mode | ✅ shared memory + handoffs | ✅ references only, `secrets audit` | Claude Code, Codex, Kiro, pi, Kimi Code, ZCode |
42
39
 
43
- ```
44
- trellis onboard
45
- ```
40
+ Sync tools stop at rules and skills. MCP routers manage servers but hold their
41
+ own config — a second source of truth (we hit real token drift with exactly
42
+ that setup). Trellis is the only one treating Skills + MCP + Memory +
43
+ instructions as **one** canonical system, and the only one covering Kiro and
44
+ pi. Full landscape survey: [`docs/research.md`](docs/research.md).
46
45
 
47
- Creates canonical source, detects which of Claude Code/Codex/Kiro/pi are on
48
- this machine, then resolves two independent choices: a **migration source**
49
- (read from — auto-selected if only one present agent has real content,
50
- prompted with a numbered choice if more than one, skippable if starting
51
- fresh; pass `--agent <id>` to skip the prompt) and a **managed set** (written
52
- to — zero or more agents, chosen explicitly; pass `--manage <ids>` or
53
- `--manage none` to skip the prompt). The source is **not** managed by
54
- default — importing from Claude Code doesn't mean Trellis starts writing to
55
- Claude Code too, unless you explicitly include it. Selecting an agent that
56
- isn't installed yet (e.g. pi) is itself the authorization to install it —
57
- one confirmation, then a real `npm install -g <package>`; Kiro has no CLI
58
- package and is refused with its download URL instead. Once resolved, it
59
- runs `migrate`, `sync`, `mcp sync`, and `secrets audit` against the managed
60
- set — the whole onboarding path in one command, no follow-up commands to
61
- type by hand. If no agent is detected, it prints each supported agent's
62
- real install command/URL and stops — it never installs anything on its own
63
- initiative. Add `--dry-run` to preview the whole thing with zero writes.
46
+ ## Design principles
64
47
 
65
- ```
66
- trellis onboard --agent claude-code --manage pi
67
- ```
48
+ 1. **One canonical source, many adapters** — agent-native configs are
49
+ generated artifacts, never hand-edited.
50
+ 2. **No plaintext secrets, ever** — outputs hold variable references;
51
+ `trellis secrets audit` rejects raw values.
52
+ 3. **Verify, don't assume** — every adapter claim is backed by an executed
53
+ probe in isolated Docker sandboxes, never a developer's own dotfiles.
68
54
 
69
- **Or step by step** (what `onboard` is actually doing under the hood, if you
70
- want to run any one stage on its own):
71
-
72
- **Already using Claude Code, Codex, Kiro, or pi and want to migrate what you
73
- already have?**
74
-
75
- 1. `trellis init` — creates `~/.trellis/` with a minimal skeleton (only what's
76
- missing; never overwrites a file you already have) and tells you which of
77
- the four agents it found on this machine.
78
- 2. `trellis migrate --from <agent>` — once per agent you already use. Copies
79
- that agent's real skills and instructions into canonical source. Never
80
- overwrites: an already-identical skill is reported and skipped, a genuine
81
- conflict is reported and left for you to resolve by hand. Add `--dry-run`
82
- to preview first.
83
- 3. `trellis sync` — distributes canonical skills/instructions to every
84
- **managed** agent (`~/.trellis/managed.yaml` — empty by default; edit it
85
- by hand or let `trellis onboard` write it). An agent that's merely present
86
- but not managed is never touched. Add `--dry-run` to preview first.
87
- 4. `trellis mcp sync` — distributes `~/.trellis/mcp/servers.yaml` (see
88
- [`schema/servers.example.yaml`](schema/servers.example.yaml)) to every
89
- managed agent's native MCP config (create/repair only — see Known
90
- limitations).
91
- 5. `trellis secrets audit` — fails non-zero if any managed agent's real
92
- config holds a literal credential or an unexpected env var name.
93
- 6. `trellis doctor` — read-only scan of every present agent's current state
94
- (managed or not); run any time to check for drift.
95
-
96
- **Starting from nothing?** Skip step 2 — `trellis init`'s placeholder
97
- `agents.md` and empty `skills/` are a fine starting point; edit them by hand.
98
-
99
- **Every real write `sync`/`mcp sync`/`onboard` perform is backed up
100
- first, automatically — no flag to opt in.** Before creating, repairing,
101
- or removing anything, each is recorded to a structured, timestamped run
102
- under `~/.trellis/backups/`, with enough information to invert it exactly.
103
- `trellis rollback` undoes one recorded run — omit a run id for the most
104
- recent one:
55
+ Trellis aligns with the emerging [`.agents Protocol`](https://dotagentsprotocol.com)
56
+ draft rather than inventing another standard.
105
57
 
106
- ```
107
- $ trellis rollback
108
- rollback 2026-09-13T04-52-18-727Z-mcp-sync
109
- ✅ 3 restored, 0 conflict(s), 0 already reverted
110
- - [restore] restore /Users/you/.claude.json to its content before this run (...)
111
- ```
58
+ ## Docs
112
59
 
113
- If something else touched a path since the backed-up run, that one path
114
- is a `conflict` — reported, left untouched, never force-restored over —
115
- while every other path in the same rollback still restores. `--list`
116
- shows available runs without touching anything; `--dry-run` previews a
117
- restore with zero writes.
60
+ - [Overview](docs/overview.md) ([中文](docs/overview.zh-CN.md)) — what it is and why
61
+ - [Getting started](docs/getting-started.md) — every command, with example output
62
+ - [Architecture](docs/architecture.md) — what we build vs. deliberately reuse
63
+ - [Research](docs/research.md) — the full competitive landscape
118
64
 
119
65
  ## Status
120
66
 
121
- **Early, pre-1.0.** All eight CLI commands above (`onboard`, `init`,
122
- `migrate`, `doctor`, `sync`, `mcp sync`, `secrets audit`, `rollback`) are implemented,
123
- unit-tested, and verified end-to-end against real Docker containers (never a
124
- developer's own dotfiles during development — see
125
- [`docs/architecture.md`](docs/architecture.md)'s testing philosophy). See
126
- [`docs/roadmap.md`](docs/roadmap.md) for what's shipped (P0–P6) vs. planned
127
- (P7, a GUI). `onboard` picks one agent as the migration base when more than
128
- one is present — merging differing content across multiple agents into one
129
- result is named future work, not built yet.
130
-
131
- **Known limitations, honestly stated rather than discovered the hard way:**
132
- - MCP servers are never spawned/handshake-tested by `trellis mcp sync` or
133
- `trellis sync` — only that the *config* is written correctly.
134
- `trellis doctor --probe-mcp` is the one command that actually connects,
135
- and it's opt-in.
136
- - The pi bridge extension (`trellis-pi-mcp-bridge`) has been verified to
137
- load and register tools without erroring, never against a real LLM tool
138
- call in production.
139
- - Verification has run against real Docker containers and a real,
140
- isolated pi CLI install — not yet against a developer's actual, existing
141
- `~/.claude`/`~/.codex`/`~/.kiro`/`~/.pi` in daily use. If you hit
142
- something a clean-room sandbox wouldn't have caught, please open an
143
- issue.
144
- - Automatic removal of an MCP server is deliberately unsupported (create/
145
- repair only) until an ownership-tracking mechanism exists — see
146
- `docs/roadmap.md`'s P2 note.
147
- - `~/.trellis/backups/` has no automatic pruning yet — every `sync`/
148
- `mcp sync`/`onboard` run that performs a real write adds one more run
149
- directory, with no cap. Delete old ones by hand for now.
150
-
151
- A canonical MCP server can also declare `enabled: false` (kept defined,
152
- never written to any agent) and `static_env` (a value that was never a
153
- secret — an email, an environment tag — written verbatim instead of
154
- resolved by name; still scanned against `reject_patterns` like every
155
- other literal field). Before ever writing a name-only `env` entry,
156
- `mcp sync` now checks it actually resolves through the same source
157
- `secrets audit` and the pi bridge use — an unresolvable name is refused
158
- as a conflict, not silently written and left to break that server's
159
- connection once the agent starts it. Both found via real-machine
160
- dogfooding, not a synthetic fixture — see
161
- [`schema/servers.example.yaml`](schema/servers.example.yaml).
162
-
163
- ## Design principles
164
-
165
- 1. **One canonical source, many adapters.** Each agent's native config file is
166
- a generated or symlinked artifact, never hand-edited.
167
- 2. **Reuse before building.** MCP aggregation, memory, and secret-reference
168
- patterns already have mature open source answers — Trellis wires to them
169
- instead of reimplementing them. See [`docs/architecture.md`](docs/architecture.md).
170
- 3. **No plaintext secrets, ever.** Every adapter output holds variable
171
- references only; `trellis secrets audit` scans for and rejects raw values.
172
- 4. **Verify, don't assume.** Every claim this project makes about an agent's
173
- behavior (file format, discovery path, MCP support) is backed by an
174
- executed probe, not documentation-reading. Adapters that can't be verified
175
- this way don't ship.
67
+ **Early, pre-1.0.** All CLI commands are implemented, unit-tested, and verified
68
+ against real agents in isolated containers. Known limitations are listed in
69
+ [Getting started](docs/getting-started.md); please open an issue for anything
70
+ a clean-room sandbox wouldn't catch.
176
71
 
177
72
  ## License
178
73
 
@@ -13,6 +13,7 @@ import { existsSync, readFileSync } from "node:fs";
13
13
  import { dirname, join } from "node:path";
14
14
  import { homedir } from "node:os";
15
15
  import { isInScope } from "../core/adapter.js";
16
+ import { usesNativeCapabilityDelivery } from "../core/types.js";
16
17
  import * as claudeCodeProbe from "../probes/claude-code.js";
17
18
  import { applySymlinkPlan, planSymlinks } from "./symlinkPlan.js";
18
19
  import { applyJsonMcp, planJsonMcp, renderJsonServerEntry } from "./jsonMcp.js";
@@ -32,7 +33,7 @@ export class ClaudeCodeAdapter {
32
33
  const canonicalRoot = dirname(canonical.instructionsFile);
33
34
  const skillsRoot = join(this.homeDir, ".claude", "skills");
34
35
  const desiredSkills = canonical.skills
35
- .filter((skill) => isInScope(this.id, skill.scope, canonical.managedAgents))
36
+ .filter((skill) => usesNativeCapabilityDelivery(this.id, canonical.mcp) && isInScope(this.id, skill.scope, canonical.managedAgents))
36
37
  .map((skill) => ({ name: skill.name, target: skill.dir }));
37
38
  const skillItems = planSymlinks({
38
39
  rootDir: skillsRoot,
@@ -82,7 +83,7 @@ export class ClaudeCodeAdapter {
82
83
  return { ok: false, mismatches: ["claude-code is not present on this machine"] };
83
84
  }
84
85
  const mismatches = [];
85
- const desiredNames = new Set(canonical.skills.filter((s) => isInScope(this.id, s.scope, canonical.managedAgents)).map((s) => s.name));
86
+ const desiredNames = new Set(canonical.skills.filter((s) => usesNativeCapabilityDelivery(this.id, canonical.mcp) && isInScope(this.id, s.scope, canonical.managedAgents)).map((s) => s.name));
86
87
  const actualSkills = new Set(snapshot.skillRoots.flatMap((root) => root.skills).map((s) => s.name));
87
88
  for (const name of desiredNames) {
88
89
  if (!actualSkills.has(name)) {
@@ -19,6 +19,7 @@ import { existsSync, readFileSync } from "node:fs";
19
19
  import { basename, dirname, join } from "node:path";
20
20
  import { homedir } from "node:os";
21
21
  import { isInScope } from "../core/adapter.js";
22
+ import { usesNativeCapabilityDelivery } from "../core/types.js";
22
23
  import * as codexProbe from "../probes/codex.js";
23
24
  import { readInstructionsPath } from "../probes/codex.js";
24
25
  import { applySymlinkPlan, planSymlinks } from "./symlinkPlan.js";
@@ -40,7 +41,7 @@ export class CodexAdapter {
40
41
  const canonicalRoot = dirname(canonical.instructionsFile);
41
42
  const skillsRoot = join(this.homeDir, ".agents", "skills");
42
43
  const desiredSkills = canonical.skills
43
- .filter((skill) => isInScope(this.id, skill.scope, canonical.managedAgents))
44
+ .filter((skill) => usesNativeCapabilityDelivery(this.id, canonical.mcp) && isInScope(this.id, skill.scope, canonical.managedAgents))
44
45
  .map((skill) => ({ name: skill.name, target: skill.dir }));
45
46
  const skillItems = planSymlinks({
46
47
  rootDir: skillsRoot,
@@ -136,7 +137,7 @@ export class CodexAdapter {
136
137
  return { ok: false, mismatches: ["codex is not present on this machine"] };
137
138
  }
138
139
  const mismatches = [];
139
- const desiredNames = new Set(canonical.skills.filter((s) => isInScope(this.id, s.scope, canonical.managedAgents)).map((s) => s.name));
140
+ const desiredNames = new Set(canonical.skills.filter((s) => usesNativeCapabilityDelivery(this.id, canonical.mcp) && isInScope(this.id, s.scope, canonical.managedAgents)).map((s) => s.name));
140
141
  const actualSkills = new Set(snapshot.skillRoots.flatMap((root) => root.skills).map((s) => s.name));
141
142
  for (const name of desiredNames) {
142
143
  if (!actualSkills.has(name)) {
@@ -15,6 +15,7 @@ import type { AdapterPlanItem } from "../core/adapter.js";
15
15
  * Codex's TOML does — see tomlSection.ts's two-table rendering)
16
16
  * (trellis-mcp-static-env-and-disabled-servers design.md D4). */
17
17
  export declare function renderJsonServerEntry(def: McpServerDef): Record<string, unknown>;
18
+ export type JsonMcpEntryRenderer = (def: McpServerDef, name: string) => Record<string, unknown>;
18
19
  export declare function planJsonMcp(opts: {
19
20
  configPath: string;
20
21
  parsed: Record<string, unknown> | undefined;
@@ -27,9 +28,10 @@ export declare function planJsonMcp(opts: {
27
28
  * pass `{}`) to get today's create/repair/conflict-only behavior with
28
29
  * zero removal candidates. */
29
30
  ownership?: Record<string, unknown>;
31
+ render?: JsonMcpEntryRenderer;
30
32
  }): AdapterPlanItem[];
31
33
  /** Merges every `"create"` MCP item into `parsed` (or a fresh `{}` if the
32
34
  * file didn't exist) and deletes every `"remove"` item's key, returning
33
35
  * the object to stringify — every sibling top-level key on `parsed` is
34
36
  * spread through untouched. */
35
- export declare function applyJsonMcp(parsed: Record<string, unknown> | undefined, items: AdapterPlanItem[]): Record<string, unknown>;
37
+ export declare function applyJsonMcp(parsed: Record<string, unknown> | undefined, items: AdapterPlanItem[], render?: JsonMcpEntryRenderer): Record<string, unknown>;
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { deepEqual } from "../lib/deepEqual.js";
10
10
  import { resolvedEnvTextMap } from "../lib/mcpMigrateRead.js";
11
- import { resolveMcpPlan } from "./mcpPlan.js";
11
+ import { LEGACY_GATEWAY_ENTRY_NAME, LEGACY_RUNTIME_ENTRY_NAME, resolveMcpPlan } from "./mcpPlan.js";
12
12
  /** Renders the native JSON shape Claude Code/Kiro's `mcpServers` map
13
13
  * expects — `env` names render as `${VAR}` references, `staticEnv`
14
14
  * entries render as their literal values, both in the same map (JSON's
@@ -32,11 +32,12 @@ export function renderJsonServerEntry(def) {
32
32
  }
33
33
  export function planJsonMcp(opts) {
34
34
  const { configPath, parsed, mcp, agentId, managedAgents, policy, ownership } = opts;
35
+ const render = opts.render ?? ((def, _name) => renderJsonServerEntry(def));
35
36
  const { desired, conflicts } = resolveMcpPlan(agentId, mcp, managedAgents, policy);
36
37
  const existingServers = parsed?.mcpServers ?? {};
37
38
  const items = [];
38
39
  for (const { name, def } of desired) {
39
- const rendered = renderJsonServerEntry(def);
40
+ const rendered = render(def, name);
40
41
  const current = existingServers[name];
41
42
  if (deepEqual(current, rendered)) {
42
43
  continue; // already correct — no-op
@@ -59,6 +60,19 @@ export function planJsonMcp(opts) {
59
60
  for (const [name, expected] of Object.entries(ownership ?? {})) {
60
61
  if (desiredNames.has(name))
61
62
  continue; // still wanted — not a removal candidate at all
63
+ if ((name === LEGACY_GATEWAY_ENTRY_NAME || name === LEGACY_RUNTIME_ENTRY_NAME) && desiredNames.has("trellis")) {
64
+ const current = existingServers[name];
65
+ if (current !== undefined && deepEqual(current, expected)) {
66
+ items.push({
67
+ action: "remove",
68
+ kind: "mcp",
69
+ target: configPath,
70
+ mcpRemove: { name },
71
+ description: `legacy MCP server "${name}" removed from ${configPath} after Trellis Runtime key migration`,
72
+ });
73
+ }
74
+ continue;
75
+ }
62
76
  const current = existingServers[name];
63
77
  if (current === undefined)
64
78
  continue; // already gone — nothing to remove, ledger is pruned separately
@@ -78,7 +92,7 @@ export function planJsonMcp(opts) {
78
92
  * file didn't exist) and deletes every `"remove"` item's key, returning
79
93
  * the object to stringify — every sibling top-level key on `parsed` is
80
94
  * spread through untouched. */
81
- export function applyJsonMcp(parsed, items) {
95
+ export function applyJsonMcp(parsed, items, render = (def, _name) => renderJsonServerEntry(def)) {
82
96
  const base = parsed ?? {};
83
97
  const existingServers = base.mcpServers ?? {};
84
98
  const mergedServers = { ...existingServers };
@@ -86,7 +100,7 @@ export function applyJsonMcp(parsed, items) {
86
100
  if (item.kind !== "mcp")
87
101
  continue;
88
102
  if (item.action === "create" && item.mcpWrite) {
89
- mergedServers[item.mcpWrite.name] = renderJsonServerEntry(item.mcpWrite.def);
103
+ mergedServers[item.mcpWrite.name] = render(item.mcpWrite.def, item.mcpWrite.name);
90
104
  }
91
105
  else if (item.action === "remove" && item.mcpRemove) {
92
106
  delete mergedServers[item.mcpRemove.name];
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Kimi Code Runtime-first adapter.
3
+ *
4
+ * Runtime delivery owns only ~/.kimi-code/mcp.json. Native Kimi Skills and
5
+ * AGENTS.md remain opt-in for `native`/`both`; Runtime-only delivery uses
6
+ * `trellis kimi`, which launches Kimi with an empty --skills-dir root so the
7
+ * shared ~/.agents/skills tree is not discovered a second time.
8
+ */
9
+ import type { AdapterPlanItem, AdapterProbeResult, AdapterVerifyResult, TrellisAdapter } from "../core/adapter.js";
10
+ import type { CanonicalSource } from "../core/types.js";
11
+ import type { BackupSession } from "../lib/backup.js";
12
+ export declare class KimiCodeAdapter implements TrellisAdapter {
13
+ private readonly homeDir;
14
+ readonly name = "Kimi Code";
15
+ readonly id: "kimi-code";
16
+ constructor(homeDir?: string);
17
+ probe(): Promise<AdapterProbeResult>;
18
+ plan(canonical: CanonicalSource): Promise<AdapterPlanItem[]>;
19
+ apply(plan: AdapterPlanItem[], backup: BackupSession): Promise<void>;
20
+ verify(canonical: CanonicalSource): Promise<AdapterVerifyResult>;
21
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Kimi Code Runtime-first adapter.
3
+ *
4
+ * Runtime delivery owns only ~/.kimi-code/mcp.json. Native Kimi Skills and
5
+ * AGENTS.md remain opt-in for `native`/`both`; Runtime-only delivery uses
6
+ * `trellis kimi`, which launches Kimi with an empty --skills-dir root so the
7
+ * shared ~/.agents/skills tree is not discovered a second time.
8
+ */
9
+ import { existsSync, readFileSync } from "node:fs";
10
+ import { homedir } from "node:os";
11
+ import { dirname, join } from "node:path";
12
+ import { isInScope } from "../core/adapter.js";
13
+ import { usesNativeCapabilityDelivery } from "../core/types.js";
14
+ import * as kimiProbe from "../probes/kimi-code.js";
15
+ import { applyJsonMcp, planJsonMcp, renderJsonServerEntry } from "./jsonMcp.js";
16
+ import { RUNTIME_COMMAND, RUNTIME_ENTRY_NAME } from "./mcpPlan.js";
17
+ import { applySymlinkPlan, planSymlinks } from "./symlinkPlan.js";
18
+ import { loadMcpOwnership, ownedByAgent, recordOwned, forgetOwned, saveMcpOwnership } from "../lib/mcpOwnership.js";
19
+ const KIMI_RUNTIME_STARTUP_TIMEOUT_MS = 30_000;
20
+ function renderKimiServerEntry(def, name) {
21
+ const entry = renderJsonServerEntry(def);
22
+ if (def.transport === "stdio")
23
+ delete entry.type;
24
+ if (name === RUNTIME_ENTRY_NAME && def.command === RUNTIME_COMMAND) {
25
+ entry.deferred = true;
26
+ entry.startupTimeoutMs = KIMI_RUNTIME_STARTUP_TIMEOUT_MS;
27
+ }
28
+ return entry;
29
+ }
30
+ export class KimiCodeAdapter {
31
+ homeDir;
32
+ name = "Kimi Code";
33
+ id = "kimi-code";
34
+ constructor(homeDir = homedir()) {
35
+ this.homeDir = homeDir;
36
+ }
37
+ async probe() {
38
+ const snapshot = await kimiProbe.probe(this.homeDir);
39
+ return { present: snapshot.present, version: snapshot.version };
40
+ }
41
+ async plan(canonical) {
42
+ const native = usesNativeCapabilityDelivery(this.id, canonical.mcp);
43
+ const items = [];
44
+ const root = join(this.homeDir, ".kimi-code");
45
+ const canonicalRoot = dirname(canonical.instructionsFile);
46
+ items.push(...planSymlinks({
47
+ rootDir: join(root, "skills"),
48
+ desired: native
49
+ ? canonical.skills
50
+ .filter((skill) => isInScope(this.id, skill.scope, canonical.managedAgents))
51
+ .map((skill) => ({ name: skill.name, target: skill.dir }))
52
+ : [],
53
+ canonicalRoot: join(canonicalRoot, "skills"),
54
+ kind: "skill",
55
+ }));
56
+ items.push(...planSymlinks({
57
+ rootDir: root,
58
+ desired: native ? [{ name: "AGENTS.md", target: canonical.instructionsFile }] : [],
59
+ canonicalRoot,
60
+ kind: "instructions",
61
+ }));
62
+ const configPath = join(this.homeDir, ".kimi-code", "mcp.json");
63
+ const parsed = existsSync(configPath) ? JSON.parse(readFileSync(configPath, "utf-8")) : undefined;
64
+ const ownership = ownedByAgent(loadMcpOwnership(this.homeDir), this.id);
65
+ items.push(...planJsonMcp({
66
+ configPath,
67
+ parsed,
68
+ mcp: canonical.mcp,
69
+ agentId: this.id,
70
+ managedAgents: canonical.managedAgents,
71
+ policy: canonical.secretsPolicy,
72
+ ownership,
73
+ render: renderKimiServerEntry,
74
+ }));
75
+ return items;
76
+ }
77
+ async apply(plan, backup) {
78
+ await applySymlinkPlan(plan.filter((item) => item.kind === "skill" || item.kind === "instructions"), backup);
79
+ const mcpWrites = plan.filter((item) => item.kind === "mcp" && (item.action === "create" || item.action === "remove"));
80
+ if (mcpWrites.length === 0)
81
+ return;
82
+ const configPath = mcpWrites[0].target;
83
+ const parsed = existsSync(configPath) ? JSON.parse(readFileSync(configPath, "utf-8")) : undefined;
84
+ const merged = applyJsonMcp(parsed, mcpWrites, renderKimiServerEntry);
85
+ backup.writeFile(configPath, `${JSON.stringify(merged, null, 2)}\n`);
86
+ let ownership = loadMcpOwnership(this.homeDir);
87
+ for (const item of mcpWrites) {
88
+ if (item.action === "create" && item.mcpWrite)
89
+ ownership = recordOwned(ownership, this.id, item.mcpWrite.name, renderKimiServerEntry(item.mcpWrite.def, item.mcpWrite.name));
90
+ if (item.action === "remove" && item.mcpRemove)
91
+ ownership = forgetOwned(ownership, this.id, item.mcpRemove.name);
92
+ }
93
+ saveMcpOwnership(this.homeDir, ownership);
94
+ }
95
+ async verify(canonical) {
96
+ const snapshot = await kimiProbe.probe(this.homeDir);
97
+ if (!snapshot.present)
98
+ return { ok: false, mismatches: ["kimi-code is not present on this machine"] };
99
+ const desired = new Set(canonical.skills.filter((skill) => usesNativeCapabilityDelivery(this.id, canonical.mcp) && isInScope(this.id, skill.scope, canonical.managedAgents)).map((skill) => skill.name));
100
+ const actual = new Set(snapshot.skillRoots.flatMap((root) => root.skills).filter((skill) => skill.dir.includes("/.kimi-code/skills/")).map((skill) => skill.name));
101
+ const mismatches = [
102
+ ...[...desired].filter((name) => !actual.has(name)).map((name) => `skill "${name}" is missing on Kimi Code`),
103
+ ...[...actual].filter((name) => !desired.has(name)).map((name) => `skill "${name}" is not in Kimi Code's canonical scope`),
104
+ ];
105
+ return mismatches.length === 0 ? { ok: true } : { ok: false, mismatches };
106
+ }
107
+ }
@@ -19,6 +19,7 @@ import { existsSync, mkdirSync, readFileSync } from "node:fs";
19
19
  import { dirname, join } from "node:path";
20
20
  import { homedir } from "node:os";
21
21
  import { isInScope } from "../core/adapter.js";
22
+ import { usesNativeCapabilityDelivery } from "../core/types.js";
22
23
  import * as kiroProbe from "../probes/kiro.js";
23
24
  import { applySymlinkPlan, planSymlinks } from "./symlinkPlan.js";
24
25
  import { applyJsonMcp, planJsonMcp, renderJsonServerEntry } from "./jsonMcp.js";
@@ -48,7 +49,7 @@ export class KiroAdapter {
48
49
  const canonicalRoot = dirname(canonical.instructionsFile);
49
50
  const skillsRoot = join(this.homeDir, ".kiro", "skills");
50
51
  const desiredSkills = canonical.skills
51
- .filter((skill) => isInScope(this.id, skill.scope, canonical.managedAgents))
52
+ .filter((skill) => usesNativeCapabilityDelivery(this.id, canonical.mcp) && isInScope(this.id, skill.scope, canonical.managedAgents))
52
53
  .map((skill) => ({ name: skill.name, target: skill.dir }));
53
54
  const skillItems = planSymlinks({
54
55
  rootDir: skillsRoot,
@@ -161,7 +162,7 @@ export class KiroAdapter {
161
162
  return { ok: false, mismatches: ["kiro is not present on this machine"] };
162
163
  }
163
164
  const mismatches = [];
164
- const desiredNames = new Set(canonical.skills.filter((s) => isInScope(this.id, s.scope, canonical.managedAgents)).map((s) => s.name));
165
+ const desiredNames = new Set(canonical.skills.filter((s) => usesNativeCapabilityDelivery(this.id, canonical.mcp) && isInScope(this.id, s.scope, canonical.managedAgents)).map((s) => s.name));
165
166
  const actualSkills = new Set(snapshot.skillRoots.flatMap((root) => root.skills).map((s) => s.name));
166
167
  for (const name of desiredNames) {
167
168
  if (!actualSkills.has(name)) {
@@ -18,12 +18,17 @@
18
18
  */
19
19
  import type { AgentId, McpConfig, McpServerDef, SecretsPolicy } from "../core/types.js";
20
20
  export declare const HUB_ENTRY_NAME = "trellis-hub";
21
- export declare const GATEWAY_ENTRY_NAME = "trellis-gateway";
21
+ export declare const GATEWAY_ENTRY_NAME = "trellis";
22
+ export declare const LEGACY_GATEWAY_ENTRY_NAME = "trellis-gateway";
23
+ export declare const RUNTIME_ENTRY_NAME = "trellis";
24
+ export declare const LEGACY_RUNTIME_ENTRY_NAME = "trellis-runtime";
22
25
  /** The command an agent spawns in gateway mode. Bare `trellis` rather than
23
26
  * an absolute path: the entry has to keep working across reinstalls and
24
27
  * version bumps, and every agent resolves it through the same PATH the
25
28
  * user installed the CLI onto. */
26
29
  export declare const GATEWAY_COMMAND = "trellis";
30
+ export declare const RUNTIME_COMMAND = "trellis";
31
+ export declare function isOAuthMcpServer(def: McpServerDef): boolean;
27
32
  /**
28
33
  * Gateway mode applies to every managed agent when `agents` is omitted —
29
34
  * the expected normal case (design.md D14). An explicit list narrows it,