@wardby/cli 0.7.0 → 0.9.0

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 (367) hide show
  1. package/.env.example +5 -5
  2. package/README.md +6 -1
  3. package/deploy/local/docker-compose.quickstart-coding.yml +11 -0
  4. package/dist/claude-coding-worker/driver.d.ts +12 -0
  5. package/dist/claude-coding-worker/driver.js +29 -7
  6. package/dist/claude-coding-worker/main.js +5 -1
  7. package/dist/claude-coding-worker/sdk.js +17 -1
  8. package/dist/claude-plugin/command.d.ts +64 -0
  9. package/dist/claude-plugin/command.js +379 -0
  10. package/dist/cli-help.d.ts +1 -1
  11. package/dist/cli-help.js +2 -1
  12. package/dist/cli.js +71 -3
  13. package/dist/coding/code-host.d.ts +16 -0
  14. package/dist/coding/code-host.js +60 -0
  15. package/dist/coding/mcp-token.d.ts +12 -0
  16. package/dist/coding/mcp-token.js +26 -0
  17. package/dist/coding/protocol.js +2 -0
  18. package/dist/coding/redact.js +6 -1
  19. package/dist/coding/transcript/recorder.d.ts +5 -4
  20. package/dist/coding/transcript/recorder.js +3 -9
  21. package/dist/coding-worker/debug-trace.d.ts +3 -1
  22. package/dist/coding-worker/debug-trace.js +4 -2
  23. package/dist/coding-worker/driver.js +8 -1
  24. package/dist/coding-worker/main.js +5 -1
  25. package/dist/coding-worker/mcp-config.d.ts +27 -0
  26. package/dist/coding-worker/mcp-config.js +32 -0
  27. package/dist/coding-worker/sdk.d.ts +36 -0
  28. package/dist/coding-worker/sdk.js +28 -1
  29. package/dist/coding-worker/types.d.ts +4 -0
  30. package/dist/config/mcp-call-limit.d.ts +8 -0
  31. package/dist/config/mcp-call-limit.js +18 -0
  32. package/dist/config/mcp-servers.d.ts +8 -0
  33. package/dist/config/mcp-servers.js +12 -0
  34. package/dist/config/test-simulators.d.ts +10 -0
  35. package/dist/config/test-simulators.js +28 -0
  36. package/dist/config/tool-timeout.d.ts +1 -0
  37. package/dist/config/tool-timeout.js +18 -0
  38. package/dist/core/coding-mcp.d.ts +36 -0
  39. package/dist/core/coding-mcp.js +253 -0
  40. package/dist/core/coding-repository.d.ts +46 -0
  41. package/dist/core/coding-repository.js +92 -0
  42. package/dist/core/delegation-slots.d.ts +27 -0
  43. package/dist/core/delegation-slots.js +44 -0
  44. package/dist/core/dispatch.d.ts +6 -2
  45. package/dist/core/dispatch.js +39 -11
  46. package/dist/core/engine-native.d.ts +2 -0
  47. package/dist/core/engine-native.js +13 -0
  48. package/dist/core/error-code.js +2 -0
  49. package/dist/core/grants.d.ts +28 -3
  50. package/dist/core/grants.js +46 -4
  51. package/dist/core/host-events.js +7 -3
  52. package/dist/core/host-status.js +2 -2
  53. package/dist/core/issue-status.js +4 -3
  54. package/dist/core/listen-address.d.ts +10 -0
  55. package/dist/core/listen-address.js +14 -0
  56. package/dist/core/mark-ready.d.ts +1 -1
  57. package/dist/core/mark-ready.js +1 -1
  58. package/dist/core/mcp-client/client.d.ts +47 -0
  59. package/dist/core/mcp-client/client.js +141 -0
  60. package/dist/core/mcp-client/jsonrpc.d.ts +15 -0
  61. package/dist/core/mcp-client/jsonrpc.js +54 -0
  62. package/dist/core/mcp-client/results.d.ts +13 -0
  63. package/dist/core/mcp-client/results.js +42 -0
  64. package/dist/core/mcp-servers.d.ts +90 -0
  65. package/dist/core/mcp-servers.js +230 -0
  66. package/dist/core/mcp-tools.d.ts +108 -0
  67. package/dist/core/mcp-tools.js +287 -0
  68. package/dist/core/merge-order-check.js +38 -19
  69. package/dist/core/notification-dispatcher.js +2 -1
  70. package/dist/core/power-idle.d.ts +8 -2
  71. package/dist/core/power-idle.js +17 -3
  72. package/dist/core/power.d.ts +5 -0
  73. package/dist/core/power.js +5 -0
  74. package/dist/core/related-pull-requests.js +26 -10
  75. package/dist/core/retention-days.d.ts +5 -0
  76. package/dist/core/retention-days.js +14 -0
  77. package/dist/core/review-fix.js +2 -2
  78. package/dist/core/review-host-tools.js +3 -1
  79. package/dist/core/run-steps/config.d.ts +25 -0
  80. package/dist/core/run-steps/config.js +40 -0
  81. package/dist/core/run-steps/control-chars.d.ts +16 -0
  82. package/dist/core/run-steps/control-chars.js +26 -0
  83. package/dist/core/run-steps/detail.d.ts +32 -0
  84. package/dist/core/run-steps/detail.js +240 -0
  85. package/dist/core/run-steps/extract.d.ts +52 -0
  86. package/dist/core/run-steps/extract.js +467 -0
  87. package/dist/core/run-steps/ingress.d.ts +51 -0
  88. package/dist/core/run-steps/ingress.js +160 -0
  89. package/dist/core/run-steps/last-step.d.ts +15 -0
  90. package/dist/core/run-steps/last-step.js +35 -0
  91. package/dist/core/run-steps/native.d.ts +48 -0
  92. package/dist/core/run-steps/native.js +164 -0
  93. package/dist/core/run-steps/seen.d.ts +16 -0
  94. package/dist/core/run-steps/seen.js +35 -0
  95. package/dist/core/run-steps/summarize.d.ts +57 -0
  96. package/dist/core/run-steps/summarize.js +304 -0
  97. package/dist/core/run-steps/sweep.d.ts +21 -0
  98. package/dist/core/run-steps/sweep.js +41 -0
  99. package/dist/core/run-steps/types.d.ts +89 -0
  100. package/dist/core/run-steps/types.js +39 -0
  101. package/dist/core/run-steps/wire.d.ts +35 -0
  102. package/dist/core/run-steps/wire.js +47 -0
  103. package/dist/core/run-steps/writer.d.ts +49 -0
  104. package/dist/core/run-steps/writer.js +279 -0
  105. package/dist/core/runner.d.ts +70 -16
  106. package/dist/core/runner.js +296 -74
  107. package/dist/core/secret-broker-config.d.ts +2 -0
  108. package/dist/core/secret-broker-config.js +1 -1
  109. package/dist/core/secret-guard.d.ts +5 -2
  110. package/dist/core/secret-guard.js +22 -7
  111. package/dist/core/secrets.d.ts +11 -1
  112. package/dist/core/secrets.js +27 -1
  113. package/dist/core/serializable-retry.d.ts +18 -0
  114. package/dist/core/serializable-retry.js +43 -0
  115. package/dist/core/tool-admin.d.ts +5 -1
  116. package/dist/core/tool-admin.js +7 -2
  117. package/dist/core/tool-names.d.ts +13 -0
  118. package/dist/core/tool-names.js +20 -0
  119. package/dist/core/webhooks.d.ts +4 -0
  120. package/dist/core/webhooks.js +68 -49
  121. package/dist/core/workflow-run-events.js +2 -1
  122. package/dist/generated/prisma/browser.d.ts +39 -0
  123. package/dist/generated/prisma/client.d.ts +39 -0
  124. package/dist/generated/prisma/commonInputTypes.d.ts +80 -50
  125. package/dist/generated/prisma/enums.d.ts +6 -0
  126. package/dist/generated/prisma/enums.js +5 -0
  127. package/dist/generated/prisma/internal/class.d.ts +77 -0
  128. package/dist/generated/prisma/internal/class.js +4 -4
  129. package/dist/generated/prisma/internal/prismaNamespace.d.ts +632 -1
  130. package/dist/generated/prisma/internal/prismaNamespace.js +94 -3
  131. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +98 -0
  132. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +94 -3
  133. package/dist/generated/prisma/models/Agent.d.ts +372 -1
  134. package/dist/generated/prisma/models/AgentMcpServer.d.ts +1412 -0
  135. package/dist/generated/prisma/models/AgentMcpServer.js +1 -0
  136. package/dist/generated/prisma/models/AgentRepository.d.ts +40 -1
  137. package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
  138. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +0 -7
  139. package/dist/generated/prisma/models/CodingProxySession.d.ts +159 -2
  140. package/dist/generated/prisma/models/CodingRun.d.ts +76 -1
  141. package/dist/generated/prisma/models/HostProvider.d.ts +2176 -0
  142. package/dist/generated/prisma/models/HostProvider.js +1 -0
  143. package/dist/generated/prisma/models/HostProviderCredential.d.ts +1285 -0
  144. package/dist/generated/prisma/models/HostProviderCredential.js +1 -0
  145. package/dist/generated/prisma/models/HostProviderOperation.d.ts +1470 -0
  146. package/dist/generated/prisma/models/HostProviderOperation.js +1 -0
  147. package/dist/generated/prisma/models/HostProviderTrustedAccount.d.ts +1145 -0
  148. package/dist/generated/prisma/models/HostProviderTrustedAccount.js +1 -0
  149. package/dist/generated/prisma/models/McpServer.d.ts +1500 -0
  150. package/dist/generated/prisma/models/McpServer.js +1 -0
  151. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
  152. package/dist/generated/prisma/models/Principal.d.ts +167 -0
  153. package/dist/generated/prisma/models/ResourceGrant.d.ts +1 -1
  154. package/dist/generated/prisma/models/Run.d.ts +503 -1
  155. package/dist/generated/prisma/models/RunStep.d.ts +1453 -0
  156. package/dist/generated/prisma/models/RunStep.js +1 -0
  157. package/dist/generated/prisma/models/Secret.d.ts +387 -0
  158. package/dist/generated/prisma/models/Tool.d.ts +223 -1
  159. package/dist/generated/prisma/models.d.ts +7 -0
  160. package/dist/help/search.js +12 -3
  161. package/dist/help-index.json +812 -52
  162. package/dist/import/create.js +16 -1
  163. package/dist/import/neutral-schema.d.ts +1 -0
  164. package/dist/import/neutral-schema.js +2 -0
  165. package/dist/mcp/auth/access.d.ts +1 -0
  166. package/dist/mcp/auth/grants-cli.d.ts +6 -4
  167. package/dist/mcp/auth/grants-cli.js +42 -3
  168. package/dist/mcp/auth/resource-server.d.ts +3 -1
  169. package/dist/mcp/auth/resource-server.js +17 -2
  170. package/dist/mcp/context.d.ts +6 -0
  171. package/dist/mcp/index.js +21 -0
  172. package/dist/mcp/tools/agents.js +135 -20
  173. package/dist/mcp/tools/grants.js +66 -28
  174. package/dist/mcp/tools/host-providers.d.ts +2 -0
  175. package/dist/mcp/tools/host-providers.js +215 -0
  176. package/dist/mcp/tools/mcp-servers.d.ts +26 -0
  177. package/dist/mcp/tools/mcp-servers.js +481 -0
  178. package/dist/mcp/tools/power.js +2 -2
  179. package/dist/mcp/tools/repositories.js +50 -10
  180. package/dist/mcp/tools/run-access.d.ts +7 -0
  181. package/dist/mcp/tools/run-access.js +14 -0
  182. package/dist/mcp/tools/run-steps.d.ts +16 -0
  183. package/dist/mcp/tools/run-steps.js +85 -0
  184. package/dist/mcp/tools/runs.js +186 -18
  185. package/dist/mcp/tools/secret-elicitation.d.ts +2 -0
  186. package/dist/mcp/tools/secret-elicitation.js +25 -2
  187. package/dist/mcp/tools/secrets.js +38 -4
  188. package/dist/mcp/tools/tools.d.ts +6 -4
  189. package/dist/mcp/tools/tools.js +40 -8
  190. package/dist/mcp/tools/trigger.js +28 -6
  191. package/dist/mcp/transport/http-limits.d.ts +2 -0
  192. package/dist/mcp/transport/http-limits.js +6 -2
  193. package/dist/mcp/webhooks/ingress.js +10 -0
  194. package/dist/native-worker/gateway-server.d.ts +18 -1
  195. package/dist/native-worker/gateway-server.js +38 -9
  196. package/dist/native-worker/gateway.d.ts +5 -0
  197. package/dist/native-worker/gateway.js +13 -1
  198. package/dist/native-worker/http-server.d.ts +6 -4
  199. package/dist/native-worker/http-server.js +53 -8
  200. package/dist/native-worker/ledger.d.ts +6 -2
  201. package/dist/native-worker/ledger.js +5 -4
  202. package/dist/native-worker/protocol.d.ts +1 -0
  203. package/dist/native-worker/protocol.js +4 -1
  204. package/dist/providers/coding-proxy/capability-hash.d.ts +2 -0
  205. package/dist/providers/coding-proxy/capability-hash.js +5 -0
  206. package/dist/providers/coding-proxy/mcp-route.d.ts +34 -0
  207. package/dist/providers/coding-proxy/mcp-route.js +166 -0
  208. package/dist/providers/coding-proxy/memory-ledger.d.ts +2 -0
  209. package/dist/providers/coding-proxy/memory-ledger.js +16 -0
  210. package/dist/providers/coding-proxy/prisma-ledger.d.ts +1 -0
  211. package/dist/providers/coding-proxy/prisma-ledger.js +36 -2
  212. package/dist/providers/coding-proxy/proxy.d.ts +33 -1
  213. package/dist/providers/coding-proxy/proxy.js +266 -75
  214. package/dist/providers/coding-proxy/run-step-forwarder.d.ts +42 -0
  215. package/dist/providers/coding-proxy/run-step-forwarder.js +206 -0
  216. package/dist/providers/coding-proxy/runtime.d.ts +13 -0
  217. package/dist/providers/coding-proxy/runtime.js +87 -4
  218. package/dist/providers/coding-proxy/server.d.ts +3 -0
  219. package/dist/providers/coding-proxy/server.js +10 -0
  220. package/dist/providers/coding-proxy/types.d.ts +18 -0
  221. package/dist/providers/engine/types.d.ts +26 -0
  222. package/dist/providers/executor/composition.js +5 -0
  223. package/dist/providers/executor/container.d.ts +47 -1
  224. package/dist/providers/executor/container.js +84 -8
  225. package/dist/providers/host-tools/invoke.d.ts +37 -0
  226. package/dist/providers/host-tools/invoke.js +117 -0
  227. package/dist/providers/host-tools/operations.d.ts +65 -0
  228. package/dist/providers/host-tools/operations.js +149 -0
  229. package/dist/providers/host-tools/registry.d.ts +79 -0
  230. package/dist/providers/host-tools/registry.js +362 -0
  231. package/dist/providers/host-tools/request-guard.d.ts +17 -0
  232. package/dist/providers/host-tools/request-guard.js +99 -0
  233. package/dist/providers/host-tools/self-test.d.ts +64 -0
  234. package/dist/providers/host-tools/self-test.js +142 -0
  235. package/dist/providers/jobs/docker-isolation.d.ts +2 -2
  236. package/dist/providers/jobs/docker-isolation.js +30 -8
  237. package/dist/providers/jobs/docker.d.ts +8 -0
  238. package/dist/providers/jobs/docker.js +33 -9
  239. package/dist/providers/jobs/kubernetes-isolation.d.ts +3 -1
  240. package/dist/providers/jobs/kubernetes-isolation.js +15 -2
  241. package/dist/providers/jobs/kubernetes.d.ts +13 -0
  242. package/dist/providers/jobs/kubernetes.js +28 -5
  243. package/dist/providers/jobs/types.d.ts +6 -0
  244. package/dist/providers/review-host/types.d.ts +6 -4
  245. package/dist/providers/review-host/types.js +1 -1
  246. package/dist/providers/vcs/git.d.ts +6 -2
  247. package/dist/providers/vcs/git.js +15 -4
  248. package/dist/providers/vcs/github.d.ts +2 -71
  249. package/dist/providers/vcs/github.js +8 -11
  250. package/dist/providers/vcs/index.d.ts +1 -1
  251. package/dist/providers/vcs/index.js +1 -1
  252. package/dist/providers/vcs/remote.d.ts +4 -0
  253. package/dist/providers/vcs/remote.js +7 -1
  254. package/dist/providers/vcs/routing.d.ts +12 -6
  255. package/dist/providers/vcs/routing.js +21 -6
  256. package/dist/providers/vcs/types.d.ts +71 -3
  257. package/dist/quickstart/index.d.ts +5 -0
  258. package/dist/quickstart/index.js +21 -0
  259. package/dist/quickstart-images.json +1 -1
  260. package/dist/sandbox/eval-core.d.ts +12 -2
  261. package/dist/sandbox/eval-core.js +20 -4
  262. package/dist/sandbox/host-functions.d.ts +4 -0
  263. package/dist/sandbox/host-functions.js +7 -2
  264. package/dist/sandbox/limits.d.ts +4 -1
  265. package/dist/sandbox/limits.js +4 -1
  266. package/dist/sandbox/run-in-sandbox.d.ts +6 -0
  267. package/dist/sandbox/run-in-sandbox.js +14 -2
  268. package/dist/sandbox/safe-fetch.d.ts +2 -0
  269. package/dist/sandbox/safe-fetch.js +1 -1
  270. package/dist/sandbox/secret-broker.d.ts +1 -0
  271. package/dist/sandbox/secret-broker.js +1 -1
  272. package/dist/sandbox/tool-timeout.d.ts +32 -0
  273. package/dist/sandbox/tool-timeout.js +52 -0
  274. package/dist/sandbox/user-tool.d.ts +8 -1
  275. package/dist/sandbox/user-tool.js +9 -3
  276. package/dist/serve.js +26 -18
  277. package/dist/viewer/api-schema.d.ts +66 -0
  278. package/dist/viewer/api-schema.js +31 -0
  279. package/dist/viewer/graph.js +2 -1
  280. package/dist/viewer/openapi.js +2 -1
  281. package/dist/viewer/run-detail.d.ts +2 -0
  282. package/dist/viewer/run-detail.js +26 -1
  283. package/dist/wardby-bin.js +5 -0
  284. package/docs/README.md +11 -1
  285. package/docs/agent-recipes.md +37 -4
  286. package/docs/architecture-runtime.md +1 -1
  287. package/docs/claude-code-plugin.md +208 -0
  288. package/docs/code-review-agents.md +6 -0
  289. package/docs/coding-agent-setup.md +94 -1
  290. package/docs/coding-worker-byo-images.md +4 -2
  291. package/docs/coding-worker-isolation.md +94 -7
  292. package/docs/debugging-agent-runs.md +354 -0
  293. package/docs/getting-started-gke.md +33 -11
  294. package/docs/getting-started-identity-provider.md +43 -37
  295. package/docs/getting-started.md +8 -0
  296. package/docs/host-providers.md +294 -0
  297. package/docs/mcp-servers.md +263 -0
  298. package/docs/native-sandbox.md +31 -9
  299. package/docs/security-deployment.md +161 -31
  300. package/docs/tool-secrets.md +3 -0
  301. package/docs/viewer-api.md +27 -12
  302. package/docs/viewer-api.openapi.yml +78 -2
  303. package/help/admin-viewer.md +5 -0
  304. package/help/agent-recipes.md +33 -2
  305. package/help/brokered-secrets.md +3 -0
  306. package/help/build-claude-code-image.md +1 -1
  307. package/help/claude-code-run-pane.md +63 -0
  308. package/help/deploy-gke.md +5 -0
  309. package/help/errors/coding-mcp-gateway-unavailable.md +46 -0
  310. package/help/errors/coding-mcp-pins-unavailable.md +35 -0
  311. package/help/errors/database-auth-invalid.md +1 -1
  312. package/help/errors/host-provider-error.md +40 -0
  313. package/help/errors/host-tool-failed.md +36 -0
  314. package/help/errors/mcp-call-limit.md +22 -0
  315. package/help/errors/mcp-call-timeout.md +22 -0
  316. package/help/errors/mcp-server-auth-failed.md +22 -0
  317. package/help/errors/mcp-server-credentials-unavailable.md +45 -0
  318. package/help/errors/mcp-server-error.md +28 -0
  319. package/help/errors/mcp-server-unreachable.md +22 -0
  320. package/help/errors/mcp-servers-off.md +21 -0
  321. package/help/errors/mcp-tool-not-allowed.md +26 -0
  322. package/help/errors/mcp-tool-removed.md +22 -0
  323. package/help/errors/mcp-unavailable.md +25 -0
  324. package/help/errors/native-sandbox-capacity.md +1 -1
  325. package/help/errors/native-sandbox-deadline-exceeded.md +1 -1
  326. package/help/errors/native-sandbox-docker-failed.md +1 -1
  327. package/help/errors/native-sandbox-gateway-error.md +1 -1
  328. package/help/errors/native-sandbox-gateway-unavailable.md +1 -1
  329. package/help/errors/native-sandbox-image-not-pinned.md +1 -1
  330. package/help/errors/native-sandbox-isolation-mismatch.md +1 -1
  331. package/help/errors/native-sandbox-network-unenforced.md +1 -1
  332. package/help/errors/native-sandbox-requires-catalog.md +1 -1
  333. package/help/errors/native-sandbox-unavailable.md +1 -1
  334. package/help/errors/native-sandbox-warm-delivery-failed.md +1 -1
  335. package/help/errors/native-sandbox-worker-exited.md +1 -1
  336. package/help/errors/native-sandbox-worker-lost.md +1 -1
  337. package/help/errors/native-sandbox-worker-unready.md +1 -1
  338. package/help/errors/repository-not-listed.md +36 -0
  339. package/help/errors/repository-required.md +36 -0
  340. package/help/errors/tool-timeout.md +38 -0
  341. package/help/host-providers.md +40 -0
  342. package/help/identity-and-access.md +4 -1
  343. package/help/low-power-mode.md +19 -8
  344. package/help/mcp-servers.md +73 -0
  345. package/help/mcp.md +9 -2
  346. package/help/native-capabilities.md +27 -1
  347. package/help/native-sandbox.md +1 -1
  348. package/help/operating-agents.md +16 -0
  349. package/help/related-pull-requests.md +7 -3
  350. package/help/repo-instructions-and-skills.md +3 -1
  351. package/help/resume-runs-locally.md +7 -0
  352. package/help/run-steps.md +140 -0
  353. package/help/stop-run.md +1 -1
  354. package/help/troubleshooting/coding-workers.md +9 -1
  355. package/help/troubleshooting/debugging-agent-runs.md +29 -0
  356. package/package.json +2 -1
  357. package/prisma/migrations/20261102000000_host_providers/migration.sql +56 -0
  358. package/prisma/migrations/20261104000000_coding_agent_repository_list/migration.sql +5 -0
  359. package/prisma/migrations/20261106000000_tool_timeout/migration.sql +4 -0
  360. package/prisma/migrations/20261107000000_mcp_servers/migration.sql +33 -0
  361. package/prisma/migrations/20261108000000_coding_mcp/migration.sql +5 -0
  362. package/prisma/migrations/20261109000000_task_run_index/migration.sql +3 -0
  363. package/prisma/migrations/20261110000000_run_steps/migration.sql +26 -0
  364. package/prisma/migrations/20261111000000_run_steps_viewer_notify/migration.sql +59 -0
  365. package/prisma/migrations/20261112000000_run_steps_detail/migration.sql +9 -0
  366. package/prisma/schema.prisma +211 -14
  367. package/scripts/git-askpass.sh +1 -1
@@ -52,6 +52,11 @@ async function main() {
52
52
  const { resumeToolsCommand } = await import("./coding/transcript/resume/stand-in.js");
53
53
  await resumeToolsCommand(process.argv.slice(3));
54
54
  }
55
+ else if (command === "claude-plugin") {
56
+ // Sets up the Claude Code plugin on this machine: no environment, database, or server runtime.
57
+ const { claudePluginCommand } = await import("./claude-plugin/command.js");
58
+ process.exitCode = await claudePluginCommand(process.argv.slice(3));
59
+ }
55
60
  else if (command === "knowledge") {
56
61
  // Offline bundle validation: no environment, database, or HTTP runtime.
57
62
  const { knowledgeCommand } = await import("./knowledge/cli.js");
package/docs/README.md CHANGED
@@ -13,16 +13,26 @@
13
13
  runs are billed.
14
14
  - [Agent recipes](agent-recipes.md) gives two copyable setups, an architecture
15
15
  keeper and a per-language builder, with the prerequisites each needs.
16
+ - [Debugging an agent run](debugging-agent-runs.md) triages a run that failed,
17
+ opened no pull request, or missed what you expected.
16
18
  - [Coding-agent setup](coding-agent-setup.md) configures the local trusted proxy
17
19
  and isolated Codex or Claude Code workers.
20
+ - [Claude Code plugin](claude-code-plugin.md) (0.8.0+) installs the `wardby-runs`
21
+ pane: your runs beside the chat, grouped by pull request, with run details and
22
+ Continue locally.
18
23
  - [Architecture knowledge bundles](knowledge.md) covers `docs/knowledge/`: the
19
24
  concept format, how coding runs and reviewers use it, `wardby knowledge check`,
20
25
  and the scheduled architecture agent.
21
- - [Native sandbox](native-sandbox.md) (0.5.4+) runs a native agent's turn loop and user
26
+ - [Native sandbox](native-sandbox.md) (0.6.0+) runs a native agent's turn loop and user
22
27
  tools in a single-use, credential-free container behind a native gateway.
23
28
  - [Secrets and tools](tool-secrets.md) covers readable and brokered secrets
24
29
  (brokered secrets require 0.6.0+):
25
30
  attaching secrets to tools, `set_secret_broker`, placements, and errors.
31
+ - [Remote MCP servers](mcp-servers.md) (0.8.0+) registers a remote MCP server and
32
+ attaches an allowlist of its tools to a native agent.
33
+ - [Host providers](host-providers.md) (0.8.0+) covers adding a code host with
34
+ your own custom tools: registering, approving, testing and removing a
35
+ provider.
26
36
  - [Coding-worker isolation](coding-worker-isolation.md) documents the threat
27
37
  model and enforced worker boundary.
28
38
  - [Bring-your-own worker images](coding-worker-byo-images.md) explains how to
@@ -383,8 +383,9 @@ the lead's `maxDelegationsPerRun` (1 to 20) with `create_agent` or
383
383
  { "id": "<lead agent id>", "maxDelegationsPerRun": 6 }
384
384
  ```
385
385
 
386
- - Each `delegate_to_<name>` call still goes to a different sub-agent; a second
387
- call to the same one in the same run is refused with `already_dispatched`.
386
+ - A run delegates to each sub-agent and repository at most once: a second call
387
+ to the same sub-agent in the same run (for a coding sub-agent with a list of
388
+ repositories, in the same repository) is refused with `already_dispatched`.
388
389
  A delegation waiting for budget (see below) also holds its place against
389
390
  `maxDelegationsPerRun`: a call beyond the limit is refused with
390
391
  `already_dispatched` and a message naming both counts, e.g. "This run
@@ -507,6 +508,37 @@ the lead's `maxDelegationsPerRun` (1 to 20) with `create_agent` or
507
508
  repositories, keep that work in separate requests (separate Jira issues, or
508
509
  separate lead agents).
509
510
 
511
+ #### One coding agent, several repositories
512
+
513
+ Instead of one builder per repository, give one coding builder a list: its default in
514
+ `codingProfile.repository`, and each other repository with `link_repository`
515
+ (`access: "write"`, no triggers). The lead then names the repository on each
516
+ call, and may delegate to the same builder once per repository:
517
+
518
+ ```json
519
+ { "task": "Add the /quotes endpoint the client will call.", "repository": "your-org/api", "mergeOrder": 1 }
520
+ ```
521
+
522
+ ```json
523
+ { "task": "Add the quotes page that calls /quotes.", "repository": "your-org/web", "mergeOrder": 2 }
524
+ ```
525
+
526
+ Set `maxDelegationsPerRun` (up to 20) for the number of calls, and use
527
+ `mergeOrder` where the pull requests must land in order. A call without
528
+ `repository` is refused with `repository_required` when the builder has extra
529
+ repositories (unless it continues a prior run with `continuePriorRun`), and a
530
+ repository not on the list with `repository_not_listed`. A native sub-agent
531
+ refuses `repository` with `repository_requires_coding_agent`. The lead sees the
532
+ list in the tool definition only when it has the same owner as the builder, or
533
+ another owner with execute access to a builder that sets
534
+ `allowWebhookTaskOverride`. All repositories share the builder's toolchain,
535
+ budget and prompt.
536
+
537
+ Being on the list lets a run work in a repository; it starts nothing there. Link
538
+ the lead and the reviewer on each listed GitHub repository with the triggers
539
+ they need, or a pull request opened there gets no review, mention follow-up, fix
540
+ round or mark-ready.
541
+
510
542
  #### Follow-ups across the set
511
543
 
512
544
  A human-triggered follow-up task (an `@<app-slug>` mention, or a Jira issue
@@ -520,8 +552,9 @@ too:
520
552
  repository that already has an open sibling for this request.
521
553
 
522
554
  The usual delegation rails still apply on top of this: `maxDelegationsPerRun`
523
- caps calls per run; a second `delegate_to_<name>` call to the same sub-agent
524
- in one run is refused with `already_dispatched`; dispatch re-checks every
555
+ caps calls per run; a run delegates to each sub-agent and repository at most
556
+ once, and a second such call is refused with `already_dispatched`; dispatch
557
+ re-checks every
525
558
  `continuePriorRun` id (refusing with `continuation_refused` when this
526
559
  deployment can't continue the run it names — for example it belongs to a
527
560
  different owner's agent); every push to a sibling pull request still gets its
@@ -95,7 +95,7 @@ and GKE Autopilot overlays.
95
95
 
96
96
  ### Native agents in a sandbox
97
97
 
98
- Native sandbox requires Wardby 0.5.4 or later.
98
+ Native sandbox requires Wardby 0.6.0 or later.
99
99
 
100
100
  Native agents run in the server process by default. A native agent set to
101
101
  `nativeExecutionMode=sandbox` instead runs its turn loop and user tools in a
@@ -0,0 +1,208 @@
1
+ # Claude Code plugin: the wardby runs pane
2
+
3
+ From Wardby 0.8.0, the `wardby-runs` Claude Code plugin shows your wardby agent
4
+ runs in a pane beside the chat. It lists runs grouped by pull request, shows a
5
+ run's request, outcomes, services, errors and final answer, and can continue a
6
+ finished Claude Code run in your own terminal.
7
+
8
+ The plugin lives in this repository under `plugins/claude-code/`, and the
9
+ repository is its marketplace (`.claude-plugin/marketplace.json`). It talks only
10
+ to the wardby MCP server your Claude Code session already has, through
11
+ `list_runs`, `list_agents`, `get_run`, `get_run_steps` and `get_run_transcript`,
12
+ so it shows exactly what those tools show you and needs no token of its own.
13
+
14
+ ## Install
15
+
16
+ ### With the wardby CLI
17
+
18
+ ```sh
19
+ npx @wardby/cli@latest claude-plugin install
20
+ ```
21
+
22
+ This installs the plugin from `wardby/wardby` and offers to allow the pane's
23
+ read-only tools for auto mode (see [Permissions](#permissions)). Options:
24
+
25
+ | Option | What it does |
26
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
27
+ | `--server-url <url>` | Registers the wardby MCP server at this `https` URL (for example `https://wardby.example.com/mcp`) when Claude Code has none named `wardby` |
28
+ | `--server-name <name>` | The MCP server the pane uses, as `/mcp` lists it (default `wardby`); the allow rules it adds follow the name, for example `mcp__wardby-prod__list_runs` |
29
+ | `--marketplace <src>` | Installs from another marketplace: an operator's own repository (`your-org/claude-plugins`) or a local folder |
30
+ | `--allow-tools` | Allows the pane's read-only tools without asking; `--no-allow-tools` leaves permission rules alone |
31
+ | `--fullscreen` | Also switches Claude Code's terminal to its fullscreen view (see [Terminal](#in-the-terminal)); it applies to every session |
32
+ | `--yes` | Answers yes to every question |
33
+
34
+ `wardby quickstart` offers the same install once it has connected Claude Code
35
+ (`--claude-plugin` installs it without asking, `--no-claude-plugin` skips it),
36
+ and `wardby doctor` lists the plugin, the MCP server and the allow rules
37
+ alongside its other checks, without failing when the optional pane is missing.
38
+
39
+ `wardby claude-plugin status` reports whether the plugin, the MCP server and
40
+ the allow rules are in place. `wardby claude-plugin uninstall` removes the
41
+ plugin and only the settings install added: the rules it added and the
42
+ fullscreen view if it switched it on. It leaves the MCP server in place.
43
+
44
+ The CLI writes to the settings file of the Claude Code it finds:
45
+ `$CLAUDE_CONFIG_DIR/settings.json`, else `~/.claude/settings.json`. It refuses a
46
+ settings file that isn't valid JSON instead of overwriting it.
47
+
48
+ ### In Claude Code
49
+
50
+ At the prompt of a terminal session:
51
+
52
+ ```
53
+ /plugin install wardby-runs --marketplace wardby/wardby
54
+ ```
55
+
56
+ In the desktop app, where `/plugin` doesn't run: click **+** next to the prompt
57
+ box, then **Plugins**, **Add marketplace** with `wardby/wardby`, then **Add
58
+ plugin**. A plugin installed from a terminal at user scope also loads in the
59
+ desktop app's local Code sessions that read the same Claude Code configuration.
60
+
61
+ Open the pane with `/wardby-runs`; `/wardby-runs close` closes it and
62
+ `/wardby-runs clear` clears its filters.
63
+
64
+ ### The MCP server
65
+
66
+ The pane needs an MCP server named `wardby` in Claude Code. `wardby quickstart`
67
+ registers one; for a deployed instance, add it with `--server-url` above or:
68
+
69
+ ```sh
70
+ claude mcp add --transport http --scope user wardby https://wardby.example.com/mcp
71
+ ```
72
+
73
+ then sign in with `/mcp`. Another name works too: set the plugin's **wardby MCP
74
+ server** option to it. A server added through the Claude apps' **Connectors**
75
+ settings is not a Claude Code MCP server and the pane doesn't use it. With another
76
+ name, install with `--server-name <name>` so the allow rules match it, and the
77
+ pane's own hints name it too.
78
+
79
+ ## Permissions
80
+
81
+ The pane reads only, with the caller's own access:
82
+
83
+ | Pane feature | MCP tool | Scope | What you see |
84
+ | -------------------- | -------------------- | ------------- | ------------------------------------------------------------------------------ |
85
+ | Run list | `list_runs` | `agents:read` | All runs of agents you own, and the runs you started on agents shared with you |
86
+ | Agent names, budgets | `list_agents` | `agents:read` | Agents you can see (the pane asks for `summary: true`) |
87
+ | Run detail | `get_run` | `agents:read` | Runs you started, or of agents you own |
88
+ | Recent steps, Steps | `get_run_steps` | `agents:read` | Same as `get_run` |
89
+ | Continue locally | `get_run_transcript` | `agents:read` | Same as `get_run` |
90
+
91
+ Under Claude Code's auto mode, a plugin's MCP calls go through the same safety
92
+ check as any other, and calls the pane makes on its own timer are refused
93
+ unless allowed. Allow these in `/permissions` (or let `wardby claude-plugin
94
+ install` add them): `mcp__wardby__list_runs`, `mcp__wardby__list_agents`,
95
+ `mcp__wardby__get_run`, `mcp__wardby__get_run_transcript` and
96
+ `mcp__wardby__get_run_steps`. The pane never calls `stop_run` or any other tool
97
+ that changes something. When a call is refused, the pane says which rules to
98
+ add.
99
+
100
+ Plugins are not sandboxed: they run as you. **Continue locally** runs
101
+ `npx @wardby/cli@latest resume - --print` in the folder you give it, passing the
102
+ transcript's download link on standard input; the link is never drawn, stored
103
+ or logged. The import writes only under `~/.wardby/` and the new worktree.
104
+
105
+ ## Using the pane
106
+
107
+ - **Ledger** (desktop): runs grouped by pull request (or Jira issue), each group
108
+ one row with its state and total cost, folded once every run in it finished.
109
+ A pull request with one run is one line. Runs that touch no pull request are
110
+ under **Other**. The newest run comes first: groups (Other too) are ordered by
111
+ their newest run, and so are the runs in a group. Each line names its step (opened, review, fix 1, …), with
112
+ sub-agent runs under their lead, and shows the run's status as a coloured
113
+ pill, its spend as "$x of $y", what started it, its task and how long it
114
+ ran, over a thin budget bar.
115
+ - **Strips** (desktop): one card per pull request, its steps drawn as a row of
116
+ dots; click a step's name to see it.
117
+ - **Filters**: show all, active, failed or finished runs, or type to match an
118
+ agent, status, trigger or task.
119
+ - **Run detail**: a header with the run's status, short id, repository, model,
120
+ duration and budget bar, then a card each for what started the run (with its
121
+ request), what it produced, the run tree, services (ready, starting or
122
+ failed), steps, the final answer and **Continue locally** for finished Claude
123
+ Code runs with `sessionResume` on (see [Resume Claude Code runs locally](coding-agent-setup.md#resume-a-run-locally)).
124
+ Each kind of card has its own colour, the same on every run: a thin bar
125
+ along its top on the desktop, its rounded border in the terminal.
126
+ The request and final answer show about three lines, as markdown, then how
127
+ many more; **Show full text** shows all of it. The pull request link and the
128
+ other actions sit at the bottom.
129
+ - **Copy**: on the desktop, each card (and an error, and an open step's detail)
130
+ has a **Copy** button that copies its full text as the server sent it. In the
131
+ terminal, **Copy section** (`y`) copies the open step's detail; **Copy run
132
+ id** is on both.
133
+ - **Recent steps** (a running run's detail): its last 8 steps, refreshed with
134
+ the run. A tool step is one row: its result at the left (✓ when it passed,
135
+ the exit code of a failed command, or ! for an error), then the tool and its
136
+ command or file; on the desktop a long command is cut with "…". What the
137
+ model said wraps to about two lines.
138
+ - **Steps** (a finished run's detail): every recorded step, 200 at a time;
139
+ **More steps** loads the next 200.
140
+ - **Step detail**: From 0.9.0, a step with detail, or a longer message, has a
141
+ ▸ at its right that opens it (▾ closes it); in the terminal, `j`/`k` also
142
+ move between such steps and `e` shows or hides one. One step is open at a
143
+ time. An open command shows "$ command", its exit status and its output;
144
+ Codex's framing lines (chunk id, wall time, token count) are left out, and
145
+ **Copy** still copies the detail exactly as stored. Detail appears only for
146
+ the agent's owner and the run's starter (and the stdio operator), on a
147
+ server at the detail level. An open detail shows its last 40 lines, with a
148
+ count of the lines above them.
149
+ - **Last step**: in the list, a running or failed run shows its newest step
150
+ under the agent's name.
151
+
152
+ Steps come from the server's run steps (see
153
+ [Run steps](debugging-agent-runs.md#run-steps)): they need a server that has
154
+ `get_run_steps` and records steps (Wardby 0.9.0 or later). Against an older
155
+ server the pane shows no steps and checks again every few refreshes. When the
156
+ server has steps off (`WARDBY_RUN_STEPS=off`) the detail says "Steps are off on
157
+ this server." A run with no recorded steps shows none. If you installed the pane
158
+ before run steps, run `wardby claude-plugin install` again (or allow
159
+ `mcp__wardby__get_run_steps` in `/permissions`): under auto mode the pane
160
+ otherwise shows which rule to add in place of the steps. `wardby claude-plugin
161
+ status` and `wardby doctor` name the missing rule.
162
+
163
+ The pane refreshes every 10 seconds while a run is active and every 60 seconds
164
+ otherwise (the plugin's **pollSeconds** and **idleSeconds** options), asks only
165
+ for what changed since its last refresh, backs off when the server fails, and
166
+ polls only while it is open.
167
+
168
+ ### In the terminal
169
+
170
+ Claude Code's classic terminal view draws a plugin pane as a band above the
171
+ prompt and doesn't pass mouse clicks to plugins: use the keyboard (ctrl+x tab
172
+ focuses the pane, then `1`–`9` open a run, `r` refreshes, `b` goes back, `m`
173
+ shows full text, `y` copies an open step's detail, `x` or Escape closes). In the fullscreen view the pane is a side bar beside the chat
174
+ and takes clicks. Turn it on with `"tui": "fullscreen"` in your Claude Code
175
+ settings (or `--fullscreen` above, or `CLAUDE_CODE_NO_FLICKER=1`), then restart
176
+ Claude Code. The desktop app needs none of this.
177
+
178
+ ## Add it to your own marketplace
179
+
180
+ The plugin keeps everything it needs in `plugins/claude-code/` and has no
181
+ instance-specific values, so an operator can list it in their organization's
182
+ marketplace. Point an entry at this repository's subfolder, pinned to a
183
+ release:
184
+
185
+ ```json
186
+ {
187
+ "name": "wardby-runs",
188
+ "source": {
189
+ "source": "git-subdir",
190
+ "url": "wardby/wardby",
191
+ "path": "plugins/claude-code",
192
+ "ref": "v0.8.0"
193
+ }
194
+ }
195
+ ```
196
+
197
+ Preset its options for your users in managed settings under
198
+ `pluginConfigs["wardby-runs@<your marketplace>"].options` (for example the MCP
199
+ server's name), and ship the allow rules above in the same managed settings.
200
+ When managed settings set `allowManagedHooksOnly`, a plugin a user installs
201
+ loads no hooks: install it through managed settings instead.
202
+
203
+ ## Limits
204
+
205
+ - Plugins draw in the Claude Code terminal, the desktop app's Code tab and VS
206
+ Code; not in claude.ai/code, `claude -p`, the Agent SDK or WSL.
207
+ - The pane polls; there is no push.
208
+ - A run's live steps and a readable transcript are not shown yet.
@@ -574,6 +574,12 @@ requires more than owning the agent:
574
574
  - **A repository is the owner's binding.** Principals the agent is shared
575
575
  with (`grant_access`) can't link, unlink or change its repository, even at
576
576
  `write`.
577
+ - **A coding agent's extra repositories follow the same rules.** A
578
+ `link_repository` call with `access: "write"` and no triggers on a coding
579
+ agent adds a repository its runs may work in; it needs the same GitHub write
580
+ access or admin approval as the default repository. Unlinking it
581
+ refuses queued runs for that repository when they start, and a run already under way is refused at
582
+ its final push check (`repo_access`), so nothing is pushed.
577
583
 
578
584
  The authorization is stamped on the link (`authorizedVia`: `host_permission`,
579
585
  `admin`, or `grandfathered`) and **checked again every time it is used**: on
@@ -69,6 +69,81 @@ request currently targets, and the agent resolves any conflicts — see
69
69
  Over stdio, the local operator holds every role, so `repositoryAdminOverride`
70
70
  is the way to approve a repository there.
71
71
 
72
+ ## A coding agent's repositories
73
+
74
+ A coding agent works in one repository per run, chosen from its list:
75
+
76
+ - `codingProfile.repository` is the **default** repository.
77
+ - `link_repository` adds more. A link on a coding agent takes
78
+ `access: "write"`, no triggers, no `checkName` and an optional `baseRef`
79
+ (the base branch for runs in that repository; default: the profile's
80
+ `baseRef`). The repository must be on GitHub or a `local:` path. Linking the
81
+ default repository again is refused.
82
+ - `unlink_repository` removes one.
83
+
84
+ ```json
85
+ { "agentId": "<agent id>", "repository": "your-org/other-repo", "access": "write", "baseRef": "main" }
86
+ ```
87
+
88
+ Only the agent's owner (or an admin approving explicitly with `adminOverride`)
89
+ can add a repository, and the same authorization applies as for the default;
90
+ see [Repository authorization](#repository-authorization).
91
+
92
+ The repository is chosen when the run starts and never changes during it:
93
+
94
+ - `trigger_agent` takes an optional `repository`. Leave it out and the run uses
95
+ the default repository. Name one that is not on the list and the call is
96
+ refused with `repository_not_listed`. Only the agent's owner can pass
97
+ `repository`, unless `codingProfile.allowWebhookTaskOverride` is on; anyone
98
+ else is refused with a 403.
99
+ - A webhook body can carry `wardbyRepository` the same way (not `repository`,
100
+ which forwarded payloads already use). A refused value is a 400
101
+ `{ "error": "invalid_repository" }`. A webhook can carry `wardbyRepository`
102
+ only when `codingProfile.allowWebhookTaskOverride` is on, whoever created
103
+ the webhook. With the flag off a well-formed value is refused with 403
104
+ `{ "error": "disabled" }`, before it is compared with the list; a malformed
105
+ one (not a string, empty, or over 300 characters) is a 400 either way.
106
+ - A lead's `delegate_to_<name>` call takes `repository`. When the sub-agent has
107
+ more than its default repository the call must name one, unless
108
+ `continuePriorRun` is given: a follow-up works in the repository of the run
109
+ it continues. Without a choice the call is refused with
110
+ `repository_required`.
111
+
112
+ Everything else about the agent is shared across its repositories: toolchain,
113
+ worker image, services, system prompt, budget, protected paths and the package
114
+ allowlist. If two repositories need different ones, use two agents.
115
+
116
+ Being on the list lets a run work in a repository; it starts nothing there.
117
+ Reviews, mention follow-ups, fix rounds and mark-ready route by repository and
118
+ trigger, so a pull request opened in a linked repository gets none of them by
119
+ itself. For follow-ups, link the lead and the reviewer on each listed GitHub
120
+ repository with the triggers they need.
121
+
122
+ An agent with no repository links works only in its default repository.
123
+ Changing an agent's `kind` is refused while it has write links without
124
+ triggers; unlink them first.
125
+
126
+ Every write link without triggers on a coding agent is on its list, whenever it
127
+ was made. An agent converted from native to coding can hold such links from its
128
+ native configuration: run `list_repositories` on converted agents and unlink any
129
+ repository their runs should not work in.
130
+
131
+ For the refusals, see [Repository required](../help/errors/repository-required.md)
132
+ and [Repository not on the agent's list](../help/errors/repository-not-listed.md).
133
+
134
+ ## See what a run was asked to do
135
+
136
+ `get_run` returns a coding run's `request`: the task it received from
137
+ `trigger_agent`, a webhook or a lead, or the agent's default task. It leaves out
138
+ the agent's standing instructions. On a delegated run, this shows what the lead
139
+ told the coding agent, so you can tell a vague task from a run that missed a
140
+ clear one.
141
+
142
+ The value is masked when it's read: the values of the agent's attached secrets
143
+ and token-shaped values are replaced. If the agent's secrets can't be read,
144
+ `get_run` returns `requestUnavailable: true` instead of the text. Runs from
145
+ before this field have no `request`.
146
+
72
147
  ## Local repositories
73
148
 
74
149
  A coding agent (or a review agent) can work on a git repository on the same
@@ -313,7 +388,8 @@ agents.
313
388
  - **`false`.** Bare mode is off. Claude Code loads `CLAUDE.md` and skills
314
389
  itself, through its native Skill tool, instead of reading them from the
315
390
  system prompt. Repository settings, hooks, MCP configuration, agents, and
316
- commands are still never loaded in either mode; native loading also locks
391
+ commands are still never loaded in either mode (the only MCP tools a coding
392
+ run has are those of [attached MCP servers](mcp-servers.md#coding-agents)); native loading also locks
317
393
  Claude Code's own hooks to wardby's managed set.
318
394
 
319
395
  If the worker can't write the native-mode context to disk for a run, that
@@ -911,6 +987,23 @@ run's repository and refs, as base64url JSON). A refused download returns
911
987
  JSON `{ "error": "<code>" }`; `wardby resume` explains each code (see the
912
988
  `errors/run-transcript-download` help article).
913
989
 
990
+ ## Run steps
991
+
992
+ Claude Code and Codex runs record their steps (each command with its status, and
993
+ what the model said, one short line each) when the server's run-steps listener is
994
+ set up: `WARDBY_RUN_STEPS_LISTEN` on `wardby serve` and `WARDBY_RUN_STEPS_URL` on
995
+ the coding proxy. Without them, coding runs record no steps. Read the steps with
996
+ `get_run_steps`. The Docker quickstart registers the stdio `wardby mcp` server,
997
+ which never runs the listener, so setting `WARDBY_RUN_STEPS_URL` on its proxy
998
+ alone does nothing: coding runs' steps need a `wardby serve` with
999
+ `WARDBY_RUN_STEPS_LISTEN`. The proxy takes `WARDBY_RUN_STEPS_URL` from the
1000
+ environment (for example `http://host.docker.internal:8792`); see
1001
+ [Run steps](debugging-agent-runs.md#run-steps) and, for binding the listener
1002
+ safely, [Run steps in Security deployment](security-deployment.md#run-steps).
1003
+ For a coding agent whose owner sets `runSteps` to `detail`, also set
1004
+ `WARDBY_RUN_STEPS=detail` on the proxy, or no tool output is sent; see
1005
+ [Run steps](debugging-agent-runs.md#run-steps).
1006
+
914
1007
  ## Stop the setup
915
1008
 
916
1009
  ```sh
@@ -95,8 +95,10 @@ the exact command.
95
95
  On a local quickstart install with the Docker launcher, `workerImageRef` can be
96
96
  the local image ID (`docker image inspect --format '{{.Id}}' <your-tag>`).
97
97
  Otherwise, build it, push it to your own registry, and note the resulting digest —
98
- `docker inspect --format '{{index .RepoDigests 0}}' <your-tag>` after a push,
99
- or read it straight from `docker buildx build --push`'s output.
98
+ `docker inspect --format '{{range .RepoDigests}}{{println .}}{{end}}' <your-tag>`
99
+ after a push lists one digest per registry the image is in: take the one in
100
+ the registry your cluster pulls from, not simply the first. Or read it straight
101
+ from `docker buildx build --push`'s output.
100
102
 
101
103
  ## Pointing an agent at it
102
104
 
@@ -143,7 +143,8 @@ deeply to process is refused with `request_nesting_too_deep`.
143
143
 
144
144
  - **Anthropic Messages** (`parseAnthropicRequest`): a fixed set of keys,
145
145
  text/`tool_use`/`tool_result`/thinking blocks, exactly the two Wardby tool
146
- names, the reviewed beta values, the thinking mode the run's model catalog
146
+ names plus the run's own MCP tool names (see
147
+ [Remote MCP tools](#remote-mcp-tools)), the reviewed beta values, the thinking mode the run's model catalog
147
148
  entry names, and only effort levels that entry lists in `efforts` (top-level,
148
149
  or on an effort-only system message for models that change effort per turn).
149
150
  - **OpenAI Responses** (`parseOpenAiRequest`), built from what the pinned
@@ -157,8 +158,15 @@ deeply to process is refused with `request_nesting_too_deep`.
157
158
  `previous_response_id`, `conversation` and `metadata`, is refused with
158
159
  `openai_request_key_not_allowed:<key>`.
159
160
  - Tools: `function` and `custom` definitions, and `namespace` groups of
160
- them, either in `tools` or in Codex's `additional_tools` input item. Every
161
- other tool type, including all hosted tools (`web_search`, `mcp`,
161
+ them, either in `tools` or in Codex's `additional_tools` input item. A
162
+ `tool_search` tool is accepted only in the top-level `tools`, only with
163
+ `execution: "client"` (Codex runs the search over its own tools) and only
164
+ with `type`, `execution`, `description` and `parameters`; a
165
+ server-executed search is refused with
166
+ `openai_tool_not_allowed:tool_search`. Each tool list holds at most 512
167
+ tools, and a request at most 512 distinct tools in all; a definition
168
+ repeated in replayed tool search results counts once. Every other tool
169
+ type, including all hosted tools (`web_search`, `mcp`,
162
170
  `code_interpreter`, `image_generation`, `file_search`, `local_shell`, and
163
171
  so on), is refused with `openai_tool_not_allowed:<type>`. Tool names are
164
172
  checked for shape (`[A-Za-z0-9_-]{1,128}`) but not against a fixed list:
@@ -169,10 +177,17 @@ deeply to process is refused with `request_nesting_too_deep`.
169
177
  - Input items: `message` (`input_text`/`input_image` for user, developer
170
178
  and system; `output_text` for assistant), `reasoning`, `function_call`,
171
179
  `function_call_output`, `custom_tool_call`, `custom_tool_call_output`,
172
- `agent_message` and `additional_tools`, each with only the keys Codex
173
- sends. Anything else (`input_file`, `input_audio`, `item_reference`,
174
- replayed hosted-tool calls, `compaction`, `local_shell_call`) is refused
175
- with `openai_input_not_allowed:<type>`. An `input_image` must be an inline
180
+ `agent_message`, `additional_tools`, `tool_search_call` and
181
+ `tool_search_output`, each with only the keys Codex sends. The two tool
182
+ search items must say `execution: "client"`. A `tool_search_call` may
183
+ carry only a string `query` and a positive integer `limit` as its
184
+ arguments. Every tool a `tool_search_output` brings into the conversation
185
+ passes the same checks as a top-level tool, except another `tool_search`;
186
+ a `function` there may also carry `defer_loading: true`, which Codex sets
187
+ on the tools it loads through tool search, and nowhere else. Anything
188
+ else (`input_file`, `input_audio`, `item_reference`, replayed hosted-tool
189
+ calls, `compaction`, `local_shell_call`) is refused with
190
+ `openai_input_not_allowed:<type>`. An `input_image` must be an inline
176
191
  `data:image/{png,jpeg,gif,webp};base64,` URL, as Codex's `view_image`
177
192
  produces; a remote URL or a `file_id` is refused with
178
193
  `openai_remote_input_not_allowed`.
@@ -218,6 +233,62 @@ rather than silently widening what reaches OpenAI. Upgrading the pinned
218
233
  then widen `parseOpenAiRequest` only for what that review accepts, and
219
234
  document it in the list above.
220
235
 
236
+ ### Remote MCP tools
237
+
238
+ A coding agent can have [remote MCP server](mcp-servers.md#coding-agents) tools
239
+ attached. The worker still reaches only the proxy:
240
+
241
+ 1. When a run has MCP tools, the control plane mints a per-run MCP token
242
+ (`rmt_` plus 32 random bytes, base64url). Only its SHA-256 hash is stored
243
+ with the run's proxy session; the token reaches the worker only as
244
+ `WARDBY_MCP_TOKEN`, and is never logged. It is valid only on the proxy's
245
+ `/mcp` route, and only while the session is active and before its deadline.
246
+ It is not the run capability, and it is not accepted by the model routes.
247
+ 2. The worker (Claude Code or Codex, over HTTP) calls `POST /mcp` on the proxy
248
+ with `Authorization: Bearer <token>`. The proxy checks the token and
249
+ forwards the request to the native gateway's `/coding-mcp` route
250
+ (`WARDBY_MCP_GATEWAY_URL`). The proxy never sees an MCP server's URL or
251
+ secrets. Without `WARDBY_MCP_GATEWAY_URL`, `/mcp` answers `503`
252
+ `mcp_unavailable`. A bad or expired token gets a `401` without a
253
+ `WWW-Authenticate` header, so a client doesn't start OAuth discovery.
254
+ 3. The gateway checks the token again (the proxy is not trusted), checks the
255
+ live attachment on every call, counts the call against the run's limit
256
+ (`WARDBY_MCP_MAX_CALLS_PER_RUN`, default 100; failed calls count), runs it,
257
+ and removes the server's secret values from the result before it leaves.
258
+ Logs for the route carry the method, status and session id, never bodies,
259
+ arguments, results or the token.
260
+
261
+ The proxy can reach the gateway's HTTP port. It holds no gateway credentials,
262
+ and each route authenticates separately. The Anthropic allowlist accepts the
263
+ run's own MCP tools as plain client tools named
264
+ `mcp__wardby_mcp__<server>__<tool>`, and only those the run pinned.
265
+
266
+ Where the token is exposed:
267
+
268
+ - **Claude Code.** The agent container receives the MCP configuration, its
269
+ bearer header included, on Claude Code's command line. That container runs no
270
+ model commands and shares no PID namespace with the tool runner, so commands
271
+ the model runs can't read it.
272
+ - **Codex.** Shell commands run in the same container as Codex, and can read
273
+ the token through `/proc`. For that reason a Codex agent may use only tools
274
+ the server marks `readOnlyHint: true`: Wardby refuses any other tool when you
275
+ attach, when a run loads its tools, and on every call. `readOnlyHint` is the
276
+ server's own claim, which Wardby can't verify, so the allowlist remains the
277
+ owner's control. A leaked token is limited to this run's allowed tools, the
278
+ call limit and the run's deadline.
279
+
280
+ A repository's own MCP configuration is never loaded. MCP tools need this
281
+ release's Claude worker image and a new Codex driver image; an older image
282
+ ignores the token and gets no MCP tools, and the run does not fail. Codex
283
+ models that use tool search get their MCP tools through `tool_search_output`
284
+ items; the proxy checks every tool in them like a top-level tool (see
285
+ [Model request allowlist](#model-request-allowlist)).
286
+
287
+ The read-only rule follows the provider a run was started with
288
+ (`CodingRun.provider`), at pin time and on every call, not the agent's current
289
+ profile. At attach, a coding agent counts as Codex unless its provider is
290
+ exactly `claude-code`, so an agent without a profile is held to the rule too.
291
+
221
292
  The proxy also binds a second listener, the **deny port** (`8788`,
222
293
  `CODING_PROXY_DENY_PORT`), which serves nothing: it accepts a connection,
223
294
  sends no bytes and closes it immediately
@@ -233,6 +304,22 @@ port-level policy — that is harmless, because the listener accepts the
233
304
  connection, sends nothing and closes it. It is not a leak; it is a fact about
234
305
  reachability that the Kubernetes launcher turns into evidence.
235
306
 
307
+ ### Run steps
308
+
309
+ The worker is not involved: after relaying each model reply unchanged, the proxy
310
+ reads it (and the newest tool results of the request) and makes one short line
311
+ per tool call or model message. It posts the lines to the control plane's
312
+ run-steps listener (`WARDBY_RUN_STEPS_URL`), authenticated by the run capability;
313
+ the control plane removes the agent's secret values before storing them. Reading
314
+ a reply for steps never delays or fails the relay: a frame the proxy can't read
315
+ gives no step, and a full queue or an unreachable server drops steps.
316
+
317
+ The worker holds the same capability, so the network keeps it off the listener:
318
+ on Kubernetes, ingress to port 8792 only from proxy pods; on Docker, the run's
319
+ isolated network. The worker's own egress is unchanged: it reaches only the
320
+ proxy. See [Run steps](security-deployment.md#run-steps) and
321
+ [Run steps](debugging-agent-runs.md#run-steps).
322
+
236
323
  ## Debug trace
237
324
 
238
325
  When a fixed code is not enough to tell why a coding agent's runs fail, an