@wardby/cli 0.5.3 → 0.6.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 (370) hide show
  1. package/.env.example +33 -0
  2. package/README.md +25 -14
  3. package/dist/claude-coding-worker/context.d.ts +22 -0
  4. package/dist/claude-coding-worker/context.js +92 -0
  5. package/dist/claude-coding-worker/driver.d.ts +7 -1
  6. package/dist/claude-coding-worker/driver.js +38 -5
  7. package/dist/claude-coding-worker/sdk.js +13 -4
  8. package/dist/cli-help.d.ts +1 -1
  9. package/dist/cli-help.js +5 -2
  10. package/dist/cli-native-mode.d.ts +9 -0
  11. package/dist/cli-native-mode.js +20 -0
  12. package/dist/cli.d.ts +3 -1
  13. package/dist/cli.js +141 -5
  14. package/dist/coding/claude-context.d.ts +45 -0
  15. package/dist/coding/claude-context.js +434 -0
  16. package/dist/coding/profile.d.ts +12 -0
  17. package/dist/coding/profile.js +6 -0
  18. package/dist/coding/protocol.d.ts +104 -0
  19. package/dist/coding/protocol.js +87 -3
  20. package/dist/coding-worker/artifact.d.ts +8 -0
  21. package/dist/coding-worker/artifact.js +2 -2
  22. package/dist/coding-worker/driver.js +2 -0
  23. package/dist/coding-worker/sdk.d.ts +6 -0
  24. package/dist/coding-worker/sdk.js +1 -0
  25. package/dist/coding-worker/skills.d.ts +23 -0
  26. package/dist/coding-worker/skills.js +117 -0
  27. package/dist/coding-worker/types.d.ts +2 -0
  28. package/dist/config/github-allowed-accounts.d.ts +15 -0
  29. package/dist/config/github-allowed-accounts.js +36 -0
  30. package/dist/config/low-power.d.ts +12 -0
  31. package/dist/config/low-power.js +18 -0
  32. package/dist/config/mobile.d.ts +12 -0
  33. package/dist/config/mobile.js +18 -0
  34. package/dist/config/providers.d.ts +53 -0
  35. package/dist/config/providers.js +92 -6
  36. package/dist/core/db.d.ts +16 -6
  37. package/dist/core/db.js +12 -10
  38. package/dist/core/dispatch.d.ts +11 -0
  39. package/dist/core/dispatch.js +36 -1
  40. package/dist/core/engine-native.js +9 -5
  41. package/dist/core/host-events.d.ts +49 -3
  42. package/dist/core/host-events.js +289 -15
  43. package/dist/core/issue-bridge.js +42 -2
  44. package/dist/core/issue-events.js +12 -1
  45. package/dist/core/issue-status.js +14 -3
  46. package/dist/core/merge-order-check.d.ts +129 -0
  47. package/dist/core/merge-order-check.js +336 -0
  48. package/dist/core/notification-dispatcher.d.ts +70 -0
  49. package/dist/core/notification-dispatcher.js +368 -0
  50. package/dist/core/notification-templates.d.ts +25 -0
  51. package/dist/core/notification-templates.js +105 -0
  52. package/dist/core/notifications.d.ts +10 -0
  53. package/dist/core/notifications.js +38 -0
  54. package/dist/core/pg-auth.d.ts +22 -0
  55. package/dist/core/pg-auth.js +152 -0
  56. package/dist/core/power-composition.d.ts +16 -0
  57. package/dist/core/power-composition.js +37 -0
  58. package/dist/core/power-idle.d.ts +14 -0
  59. package/dist/core/power-idle.js +30 -0
  60. package/dist/core/power.d.ts +71 -0
  61. package/dist/core/power.js +202 -0
  62. package/dist/core/reconciler.d.ts +4 -2
  63. package/dist/core/reconciler.js +29 -5
  64. package/dist/core/related-pull-requests.d.ts +48 -4
  65. package/dist/core/related-pull-requests.js +113 -11
  66. package/dist/core/repo-access.d.ts +15 -0
  67. package/dist/core/repo-access.js +66 -0
  68. package/dist/core/review-fix.d.ts +37 -0
  69. package/dist/core/review-fix.js +207 -6
  70. package/dist/core/review-host-tools.d.ts +20 -0
  71. package/dist/core/review-host-tools.js +58 -2
  72. package/dist/core/runner.d.ts +336 -3
  73. package/dist/core/runner.js +894 -317
  74. package/dist/core/secret-broker-config.d.ts +103 -0
  75. package/dist/core/secret-broker-config.js +112 -0
  76. package/dist/core/secrets.d.ts +39 -4
  77. package/dist/core/secrets.js +148 -40
  78. package/dist/core/workflow-event-recorder.d.ts +14 -0
  79. package/dist/core/workflow-event-recorder.js +120 -0
  80. package/dist/core/workflow-events.d.ts +82 -0
  81. package/dist/core/workflow-events.js +44 -0
  82. package/dist/core/workflow-run-events.d.ts +16 -0
  83. package/dist/core/workflow-run-events.js +40 -0
  84. package/dist/generated/prisma/browser.d.ts +58 -0
  85. package/dist/generated/prisma/client.d.ts +58 -0
  86. package/dist/generated/prisma/commonInputTypes.d.ts +150 -0
  87. package/dist/generated/prisma/enums.d.ts +27 -0
  88. package/dist/generated/prisma/enums.js +23 -0
  89. package/dist/generated/prisma/internal/class.d.ts +88 -0
  90. package/dist/generated/prisma/internal/class.js +4 -4
  91. package/dist/generated/prisma/internal/prismaNamespace.d.ts +772 -1
  92. package/dist/generated/prisma/internal/prismaNamespace.js +135 -4
  93. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +139 -0
  94. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +135 -4
  95. package/dist/generated/prisma/models/Agent.d.ts +360 -1
  96. package/dist/generated/prisma/models/CodingAgentProfile.d.ts +73 -1
  97. package/dist/generated/prisma/models/CodingRun.d.ts +205 -1
  98. package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
  99. package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1675 -0
  100. package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
  101. package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1517 -0
  102. package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
  103. package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
  104. package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
  105. package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
  106. package/dist/generated/prisma/models/NotificationChannel.js +1 -0
  107. package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
  108. package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
  109. package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
  110. package/dist/generated/prisma/models/NotificationThread.js +1 -0
  111. package/dist/generated/prisma/models/Run.d.ts +826 -1
  112. package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
  113. package/dist/generated/prisma/models/Secret.d.ts +37 -1
  114. package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
  115. package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
  116. package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
  117. package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
  118. package/dist/generated/prisma/models.d.ts +8 -0
  119. package/dist/help/build.js +4 -2
  120. package/dist/help/catalog.d.ts +1 -1
  121. package/dist/help/catalog.js +31 -6
  122. package/dist/help-index.json +1363 -176
  123. package/dist/import/create.js +17 -0
  124. package/dist/import/neutral-schema.d.ts +6 -2
  125. package/dist/import/neutral-schema.js +2 -0
  126. package/dist/mcp/auth/access.d.ts +1 -0
  127. package/dist/mcp/auth/repo-authorization.js +14 -0
  128. package/dist/mcp/auth/resource-server.d.ts +2 -1
  129. package/dist/mcp/auth/resource-server.js +7 -2
  130. package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
  131. package/dist/mcp/auth/self-hosted/browser.js +19 -6
  132. package/dist/mcp/context.d.ts +6 -0
  133. package/dist/mcp/host-events/github-ingress.d.ts +23 -1
  134. package/dist/mcp/host-events/github-ingress.js +68 -0
  135. package/dist/mcp/index.d.ts +13 -0
  136. package/dist/mcp/index.js +59 -10
  137. package/dist/mcp/tools/agents.js +82 -11
  138. package/dist/mcp/tools/notification-channels.d.ts +2 -0
  139. package/dist/mcp/tools/notification-channels.js +293 -0
  140. package/dist/mcp/tools/power.d.ts +2 -0
  141. package/dist/mcp/tools/power.js +77 -0
  142. package/dist/mcp/tools/runs.d.ts +0 -6
  143. package/dist/mcp/tools/runs.js +7 -2
  144. package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
  145. package/dist/mcp/tools/secret-broker-compat.js +23 -0
  146. package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
  147. package/dist/mcp/tools/secret-elicitation-form.js +200 -10
  148. package/dist/mcp/tools/secret-elicitation-server.js +8 -1
  149. package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
  150. package/dist/mcp/tools/secret-elicitation.js +110 -12
  151. package/dist/mcp/tools/secrets.js +184 -7
  152. package/dist/mcp/tools/tools.d.ts +1 -1
  153. package/dist/mcp/tools/tools.js +22 -2
  154. package/dist/native-worker/composition.d.ts +23 -0
  155. package/dist/native-worker/composition.js +77 -0
  156. package/dist/native-worker/docker-isolation.d.ts +65 -0
  157. package/dist/native-worker/docker-isolation.js +183 -0
  158. package/dist/native-worker/docker-launcher.d.ts +74 -0
  159. package/dist/native-worker/docker-launcher.js +237 -0
  160. package/dist/native-worker/gateway-server.d.ts +39 -0
  161. package/dist/native-worker/gateway-server.js +315 -0
  162. package/dist/native-worker/gateway.d.ts +44 -0
  163. package/dist/native-worker/gateway.js +197 -0
  164. package/dist/native-worker/http-server.d.ts +22 -0
  165. package/dist/native-worker/http-server.js +109 -0
  166. package/dist/native-worker/http-transport.d.ts +17 -0
  167. package/dist/native-worker/http-transport.js +88 -0
  168. package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
  169. package/dist/native-worker/kubernetes-isolation.js +218 -0
  170. package/dist/native-worker/kubernetes-launcher.d.ts +102 -0
  171. package/dist/native-worker/kubernetes-launcher.js +335 -0
  172. package/dist/native-worker/launch.d.ts +45 -0
  173. package/dist/native-worker/launch.js +44 -0
  174. package/dist/native-worker/ledger.d.ts +109 -0
  175. package/dist/native-worker/ledger.js +192 -0
  176. package/dist/native-worker/loopback.d.ts +12 -0
  177. package/dist/native-worker/loopback.js +49 -0
  178. package/dist/native-worker/main.d.ts +7 -0
  179. package/dist/native-worker/main.js +74 -0
  180. package/dist/native-worker/protocol.d.ts +744 -0
  181. package/dist/native-worker/protocol.js +200 -0
  182. package/dist/native-worker/sandbox-executor.d.ts +68 -0
  183. package/dist/native-worker/sandbox-executor.js +210 -0
  184. package/dist/native-worker/stdio.d.ts +29 -0
  185. package/dist/native-worker/stdio.js +188 -0
  186. package/dist/native-worker/warm-delivery.d.ts +16 -0
  187. package/dist/native-worker/warm-delivery.js +33 -0
  188. package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
  189. package/dist/native-worker/warm-pool-ledger.js +73 -0
  190. package/dist/native-worker/warm-pool.d.ts +107 -0
  191. package/dist/native-worker/warm-pool.js +283 -0
  192. package/dist/native-worker/worker.d.ts +17 -0
  193. package/dist/native-worker/worker.js +115 -0
  194. package/dist/providers/auth/authorization-server.d.ts +3 -0
  195. package/dist/providers/auth/index.js +2 -0
  196. package/dist/providers/auth/self-hosted.d.ts +13 -1
  197. package/dist/providers/auth/self-hosted.js +54 -4
  198. package/dist/providers/chat/fake.d.ts +46 -0
  199. package/dist/providers/chat/fake.js +39 -0
  200. package/dist/providers/chat/index.d.ts +4 -0
  201. package/dist/providers/chat/index.js +8 -0
  202. package/dist/providers/chat/slack.d.ts +37 -0
  203. package/dist/providers/chat/slack.js +105 -0
  204. package/dist/providers/chat/types.d.ts +42 -0
  205. package/dist/providers/chat/types.js +19 -0
  206. package/dist/providers/engine/types.d.ts +19 -0
  207. package/dist/providers/engine/types.js +22 -0
  208. package/dist/providers/executor/composition.d.ts +24 -1
  209. package/dist/providers/executor/composition.js +39 -6
  210. package/dist/providers/executor/container.d.ts +24 -1
  211. package/dist/providers/executor/container.js +101 -11
  212. package/dist/providers/executor/dbos.d.ts +42 -0
  213. package/dist/providers/executor/dbos.js +118 -12
  214. package/dist/providers/executor/deferred.d.ts +56 -0
  215. package/dist/providers/executor/deferred.js +119 -0
  216. package/dist/providers/executor/routing.d.ts +37 -10
  217. package/dist/providers/executor/routing.js +73 -32
  218. package/dist/providers/executor/types.d.ts +12 -0
  219. package/dist/providers/jobs/docker.js +3 -3
  220. package/dist/providers/jobs/fake-kubernetes-api.d.ts +21 -2
  221. package/dist/providers/jobs/fake-kubernetes-api.js +42 -1
  222. package/dist/providers/jobs/kubernetes-api.d.ts +17 -1
  223. package/dist/providers/jobs/kubernetes-api.js +7 -0
  224. package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
  225. package/dist/providers/jobs/kubernetes-client.js +52 -3
  226. package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
  227. package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
  228. package/dist/providers/jobs/kubernetes-isolation.d.ts +3 -1
  229. package/dist/providers/jobs/kubernetes-isolation.js +6 -0
  230. package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
  231. package/dist/providers/jobs/kubernetes-platform.js +38 -1
  232. package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
  233. package/dist/providers/jobs/kubernetes-preflight.js +4 -2
  234. package/dist/providers/jobs/kubernetes.d.ts +36 -1
  235. package/dist/providers/jobs/kubernetes.js +74 -4
  236. package/dist/providers/jobs/metadata-probes.d.ts +11 -0
  237. package/dist/providers/jobs/metadata-probes.js +13 -0
  238. package/dist/providers/jobs/types.d.ts +9 -0
  239. package/dist/providers/review-host/github.d.ts +11 -1
  240. package/dist/providers/review-host/github.js +50 -0
  241. package/dist/providers/review-host/types.d.ts +23 -0
  242. package/dist/providers/vcs/github.d.ts +32 -6
  243. package/dist/providers/vcs/github.js +74 -16
  244. package/dist/quickstart/coding-seed.d.ts +10 -3
  245. package/dist/quickstart/coding-seed.js +74 -3
  246. package/dist/quickstart/images.d.ts +2 -0
  247. package/dist/quickstart/images.js +7 -1
  248. package/dist/quickstart/reviewer-prompt.d.ts +1 -1
  249. package/dist/quickstart/reviewer-prompt.js +1 -1
  250. package/dist/quickstart-images.json +1 -1
  251. package/dist/sandbox/brokered-fetch.d.ts +23 -0
  252. package/dist/sandbox/brokered-fetch.js +37 -0
  253. package/dist/sandbox/host-functions.d.ts +34 -0
  254. package/dist/sandbox/host-functions.js +144 -80
  255. package/dist/sandbox/prelude.js +7 -1
  256. package/dist/sandbox/run-in-sandbox.d.ts +19 -0
  257. package/dist/sandbox/run-in-sandbox.js +28 -10
  258. package/dist/sandbox/safe-fetch.d.ts +2 -0
  259. package/dist/sandbox/safe-fetch.js +3 -1
  260. package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
  261. package/dist/sandbox/secret-broker-sigv4.js +49 -0
  262. package/dist/sandbox/secret-broker.d.ts +34 -0
  263. package/dist/sandbox/secret-broker.js +162 -0
  264. package/dist/sandbox/user-tool.d.ts +14 -0
  265. package/dist/sandbox/user-tool.js +32 -0
  266. package/dist/serve.js +18 -0
  267. package/dist/viewer/api-schema.d.ts +210 -14
  268. package/dist/viewer/api-schema.js +22 -0
  269. package/dist/viewer/build-schemas.js +4 -1
  270. package/dist/viewer/event-bus.d.ts +6 -0
  271. package/dist/viewer/event-bus.js +16 -7
  272. package/dist/viewer/graph.d.ts +5 -2
  273. package/dist/viewer/graph.js +7 -2
  274. package/dist/viewer/http.d.ts +0 -1
  275. package/dist/viewer/http.js +2 -2
  276. package/dist/viewer/infra.js +25 -2
  277. package/dist/viewer/limits.d.ts +4 -0
  278. package/dist/viewer/limits.js +4 -0
  279. package/dist/viewer/openapi.d.ts +15 -0
  280. package/dist/viewer/openapi.js +172 -0
  281. package/docs/README.md +7 -0
  282. package/docs/agent-recipes.md +57 -8
  283. package/docs/architecture-runtime.md +16 -1
  284. package/docs/code-review-agents.md +139 -5
  285. package/docs/coding-agent-setup.md +113 -5
  286. package/docs/coding-packages.md +4 -2
  287. package/docs/coding-services.md +3 -1
  288. package/docs/coding-worker-byo-images.md +198 -6
  289. package/docs/coding-worker-isolation.md +68 -14
  290. package/docs/getting-started-gke.md +225 -9
  291. package/docs/getting-started-identity-provider.md +21 -10
  292. package/docs/getting-started.md +5 -4
  293. package/docs/jira-agents.md +5 -1
  294. package/docs/native-sandbox.md +635 -0
  295. package/docs/release-verification.md +9 -0
  296. package/docs/security-deployment.md +113 -12
  297. package/docs/slack-notifications.md +252 -0
  298. package/docs/tool-secrets.md +252 -0
  299. package/docs/viewer-api.md +46 -5
  300. package/docs/viewer-api.openapi.yml +1404 -0
  301. package/help/admin-viewer.md +6 -2
  302. package/help/agent-recipes.md +27 -0
  303. package/help/architecture-agent.md +1 -1
  304. package/help/brokered-secrets.md +79 -0
  305. package/help/build-claude-code-image.md +131 -0
  306. package/help/build-worker-image.md +3 -6
  307. package/help/code-review-agents.md +68 -6
  308. package/help/deploy-gke.md +8 -1
  309. package/help/deployment-targets.md +25 -14
  310. package/help/errors/coding-provider-not-configured.md +2 -2
  311. package/help/errors/database-auth-invalid.md +28 -0
  312. package/help/errors/github-account-not-allowed.md +25 -0
  313. package/help/errors/low-power-disabled.md +29 -0
  314. package/help/errors/low-power-scale-forbidden.md +35 -0
  315. package/help/errors/low-power-wake-timeout.md +30 -0
  316. package/help/errors/mobile-disabled.md +31 -0
  317. package/help/errors/native-sandbox-capacity.md +22 -0
  318. package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
  319. package/help/errors/native-sandbox-docker-failed.md +20 -0
  320. package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
  321. package/help/errors/native-sandbox-image-not-pinned.md +19 -0
  322. package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
  323. package/help/errors/native-sandbox-network-unenforced.md +22 -0
  324. package/help/errors/native-sandbox-requires-catalog.md +31 -0
  325. package/help/errors/native-sandbox-unavailable.md +19 -0
  326. package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
  327. package/help/errors/native-sandbox-worker-exited.md +20 -0
  328. package/help/errors/native-sandbox-worker-lost.md +20 -0
  329. package/help/errors/native-sandbox-worker-unready.md +22 -0
  330. package/help/errors/secret-broker-body-invalid.md +26 -0
  331. package/help/errors/secret-broker-changed.md +20 -0
  332. package/help/errors/secret-broker-config-invalid.md +30 -0
  333. package/help/errors/secret-broker-conflict.md +27 -0
  334. package/help/errors/secret-broker-destination-denied.md +28 -0
  335. package/help/errors/secret-broker-value-invalid.md +28 -0
  336. package/help/errors/secret-brokered.md +24 -0
  337. package/help/errors/secret-not-brokered.md +25 -0
  338. package/help/errors/slack-auth-failed.md +48 -0
  339. package/help/errors/slack-channel-unreachable.md +39 -0
  340. package/help/errors/slack-not-configured.md +33 -0
  341. package/help/getting-started.md +4 -5
  342. package/help/github.md +18 -1
  343. package/help/identity-and-access.md +5 -1
  344. package/help/local-repositories.md +2 -3
  345. package/help/low-power-mode.md +125 -0
  346. package/help/merge-order-check.md +117 -0
  347. package/help/mobile-app.md +54 -0
  348. package/help/native-sandbox.md +136 -0
  349. package/help/observability.md +8 -0
  350. package/help/related-pull-requests.md +70 -9
  351. package/help/repo-instructions-and-skills.md +91 -0
  352. package/help/review-fix-rounds.md +10 -0
  353. package/help/slack-notifications.md +62 -0
  354. package/help/troubleshooting/coding-workers.md +21 -0
  355. package/package.json +11 -4
  356. package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
  357. package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
  358. package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
  359. package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
  360. package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
  361. package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
  362. package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
  363. package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
  364. package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
  365. package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
  366. package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
  367. package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
  368. package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
  369. package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
  370. package/prisma/schema.prisma +362 -91
@@ -104,8 +104,8 @@ JOB_LAUNCHER=docker
104
104
  folder as missing. The machine needs git 2.24 or newer.
105
105
  - **Worker images.** Use worker images from the same release as the control
106
106
  plane. An older worker image rejects `local:` repositories (the run fails with
107
- `worker_input_failed`), including a bring-your-own `workerImageRef` image,
108
- which must be rebuilt on a current driver image.
107
+ `worker_input_failed`), including a Codex agent's bring-your-own
108
+ `workerImageRef` image, which must be rebuilt on a current driver image.
109
109
 
110
110
  ### What a coding run does
111
111
 
@@ -146,9 +146,9 @@ The server selects the image from `CODING_WORKER_IMAGE_NODE_PYTHON_3_12`
146
146
  at its committed root; see
147
147
  [Python projects](getting-started.md#python-projects).
148
148
 
149
- For any other language, point a Codex agent at your own image with
150
- `workerImageRef` ([Bring-your-own worker images](coding-worker-byo-images.md)).
151
- Claude Code agents cannot use a custom toolchain yet.
149
+ For any other language, use `codingProfile.workerImageRef` (admin only). It is
150
+ a custom image for the container that runs the agent's commands, for Codex and
151
+ for Claude Code; see [Bring-your-own worker images](coding-worker-byo-images.md).
152
152
 
153
153
  ### Review agents
154
154
 
@@ -219,6 +219,8 @@ GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVA
219
219
  `npm run claude:images:local` builds the Claude agent image and both tool-runner
220
220
  images (`wardby-claude-tool-runner:phase5`, and
221
221
  `wardby-claude-tool-runner:phase5-node-python` for the `node-python` toolchain).
222
+ It also builds `wardby-claude-tool-runner-custom:phase5`, a test-only custom
223
+ tool runner that `npm run test:claude-docker` needs.
222
224
  This local, immutable-`sha256:` ID form of the `CODING_CLAUDE_*` images is only
223
225
  accepted by the Docker launcher.
224
226
  `JOB_LAUNCHER=kubernetes` needs both images pushed to a registry and set as
@@ -262,6 +264,112 @@ See [release verification](release-verification.md) for the complete gate.
262
264
  If the repository has `docs/knowledge/index.md`, every coding run's prompt
263
265
  includes it. See [Architecture knowledge bundles](knowledge.md).
264
266
 
267
+ ## Repository instructions
268
+
269
+ Every coding run loads the repository's own instructions; there is no
270
+ `codingProfile` setting to turn this off. Codex reads the repository's
271
+ `AGENTS.md` itself, directly from the checkout. Claude Code is handed
272
+ `CLAUDE.md`, `.claude/CLAUDE.md`, and whatever either file pulls in with
273
+ `@path` imports, up to 5 import levels deep; a repository that only has
274
+ `AGENTS.md` gets a one-line `CLAUDE.md` that imports it, so a repository
275
+ written for another coding agent still has its instructions in Claude Code.
276
+ Subdirectory `CLAUDE.md` files (anything other than the repository root and
277
+ `.claude/CLAUDE.md`) are not loaded unless an imported file pulls them in.
278
+
279
+ Claude Code's instructions and skills are read from the checkout and bounded:
280
+ at most 64 KiB per file, 200 files, and 256 KiB combined; symlinks and
281
+ non-UTF-8 files are refused. A file that doesn't pass, or that would push
282
+ the run's input past its 512 KiB size limit once encoded (skills and the
283
+ deepest imports are dropped first), is left out and logged as
284
+ `coding.claude_context_skipped` (the first 50 individually, then one
285
+ aggregate line with an overflow count); when the repository's context can't
286
+ be read at all, the run continues without it and logs
287
+ `coding.claude_context_unavailable`. A run never fails because its
288
+ repository context couldn't be loaded.
289
+
290
+ Claude Code never receives the repository's `.claude/settings.json`, hooks,
291
+ `.mcp.json`, agents, or commands — only Markdown instruction files and
292
+ `.claude/skills/<name>/SKILL.md` files pass the allowlist, whatever an
293
+ instruction file imports. Repository instructions and skills are untrusted
294
+ guidance: they can shape a run's work but never relax the worker's sandbox
295
+ rules.
296
+
297
+ ## Claude Code loading mode
298
+
299
+ `codingProfile.claudeBareMode` controls how Claude Code uses the repository
300
+ instructions above. It defaults to `true` and only affects Claude Code
301
+ agents.
302
+
303
+ - **`true` (default, bare mode).** Claude Code keeps its hardened bare mode.
304
+ Wardby adds the repository's instruction files to the system prompt in
305
+ full, and lists each skill by name, description, and path; the model reads
306
+ a skill's full `SKILL.md` itself with `run_command`.
307
+ - **`false`.** Bare mode is off. Claude Code loads `CLAUDE.md` and skills
308
+ itself, through its native Skill tool, instead of reading them from the
309
+ system prompt. Repository settings, hooks, MCP configuration, agents, and
310
+ commands are still never loaded in either mode; native loading also locks
311
+ Claude Code's own hooks to wardby's managed set.
312
+
313
+ If the worker can't write the native-mode context to disk for a run, that
314
+ run falls back to bare mode instead of failing, and the worker logs a
315
+ `claude_context_unavailable` warning.
316
+
317
+ The agent owner or an admin can change it:
318
+
319
+ ```json
320
+ { "id": "<agent-id>", "codingProfile": { "claudeBareMode": false } }
321
+ ```
322
+
323
+ ## Repository skills
324
+
325
+ `codingProfile.repoSkills` loads the repository's own agent skills into a
326
+ run. It defaults to `true`.
327
+
328
+ | Builder | Reads skills from | `repoSkills: true` (default) | `repoSkills: false` |
329
+ | ----------- | ----------------------------------- | --------------------------------------------------- | ---------------------------------- |
330
+ | Codex | `.agents/skills/`, `.codex/skills/` | Repository skills load | Every repository skill is disabled |
331
+ | Claude Code | `.claude/skills/<name>/SKILL.md` | Repository skills load (bare or native mode, above) | No skill context is collected |
332
+
333
+ Codex's own four built-in skills (`imagegen`, `openai-docs`, `skill-creator`,
334
+ `skill-installer`) are always disabled, whatever `repoSkills` is set to —
335
+ wardby's coding runs never offer them. With `repoSkills: false`, the Codex
336
+ worker scans both roots for the skill names to disable; that scan stops after
337
+ 2000 directory entries, to bound the work an adversarial skills tree could
338
+ cause, logs `codex_skill_scan_truncated`, and disables whatever names it found
339
+ so far rather than failing the run.
340
+
341
+ Claude Code skills ship to the worker as their `SKILL.md` only. A skill's
342
+ other files (scripts, references, data) stay in the repository checkout and
343
+ are read or run through the command runner at
344
+ `/workspace/.claude/skills/<name>/`.
345
+
346
+ Turn repository skills off for an agent:
347
+
348
+ ```json
349
+ { "id": "<agent-id>", "codingProfile": { "repoSkills": false } }
350
+ ```
351
+
352
+ **Upgrading.** `repoSkills` and `claudeBareMode` both default to `true`, so
353
+ upgrading changes behavior for existing agents: Claude Code agents start
354
+ loading `CLAUDE.md` and `.claude/skills/` (previously neither was loaded),
355
+ and Codex agents stop getting Codex's own built-in skills (previously always
356
+ offered). Set `repoSkills: false` on an agent to keep its repository's
357
+ skills out of its runs; there is no setting that keeps repository
358
+ instructions themselves out, for either builder.
359
+
360
+ Use the worker images (`CODING_WORKER_IMAGE` and `CODING_CLAUDE_WORKER_IMAGE`)
361
+ from the same release as the control plane. On an older Claude Code worker
362
+ image, runs fail with `worker_input_failed` once the repository has a
363
+ `CLAUDE.md`, `AGENTS.md`, or skill to load, or the agent sets `repoSkills` or
364
+ `claudeBareMode` to `false`; on an older Codex worker image, runs of agents with
365
+ `repoSkills: false` fail the same way. A `workerImageRef` image must also be
366
+ rebuilt for this release: on this release's driver image for a Codex agent, or
367
+ on this release's tool runner image for a Claude Code agent. On a Claude Code
368
+ agent, `workerImageRef` replaces only the tool runner (the container that runs
369
+ the agent's commands); Claude Code itself always runs on
370
+ `CODING_CLAUDE_WORKER_IMAGE`. See
371
+ [Bring-Your-Own Coding-Worker Images](coding-worker-byo-images.md).
372
+
265
373
  ## Budgets
266
374
 
267
375
  A coding run's budget is reserved when it is dispatched: the agent's own
@@ -42,8 +42,10 @@ request never names the internal proxy.
42
42
  image to build or maintain; the agent installs what it needs at run time.
43
43
  2. **A custom `workerImageRef` with dependencies baked in.** Still supported:
44
44
  point the agent's profile at your own image, built on wardby's driver base
45
- image (see [Bring-your-own worker images](coding-worker-byo-images.md)),
46
- with everything preinstalled. Setting `workerImageRef` needs `agents:admin`
45
+ image for a Codex agent, or `FROM` the same release's tool runner image for
46
+ a Claude Code agent (see
47
+ [Bring-your-own worker images](coding-worker-byo-images.md)), with
48
+ everything preinstalled. Setting `workerImageRef` needs `agents:admin`
47
49
  and the admin role, and the image must be pinned by digest.
48
50
  3. **Both together.** Use a custom image for a toolchain or system libraries
49
51
  the registry can't provide (a compiler, a non-Node/Python runtime, apt
@@ -194,7 +194,9 @@ to an agent that allows at least one service.
194
194
 
195
195
  A [bring-your-own worker image](coding-worker-byo-images.md) must be built on
196
196
  driver v11 or later to run with services; an agent whose `workerImageRef`
197
- predates driver v11 rejects the run input once services are on it.
197
+ predates driver v11 rejects the run input once services are on it. For a
198
+ Claude Code agent, build the custom image `FROM` the tool runner image of the
199
+ same wardby release.
198
200
 
199
201
  ## Letting a coding agent change the declaration
200
202
 
@@ -7,6 +7,9 @@ wardby's published **driver base image** and point your agent's
7
7
  `workerImageRef` at it, instead of waiting for wardby to hand-author a new
8
8
  `Dockerfile.<toolchain>`.
9
9
 
10
+ The driver image is for Codex agents. A Claude Code agent's image starts from a
11
+ different base; see [Codex and Claude Code](#codex-and-claude-code).
12
+
10
13
  ## The driver image
11
14
 
12
15
  `ghcr.io/wardby/wardby/wardby-coding-worker-driver` contains wardby's
@@ -112,13 +115,188 @@ point one at an arbitrary image without the step-up scope. The scope alone
112
115
  isn't enough: the caller must also hold the admin role (see
113
116
  [roles and privileged operations](security-deployment.md#roles-and-privileged-operations)).
114
117
 
115
- ## Codex only
118
+ ## Codex and Claude Code
119
+
120
+ A Codex agent runs in one container, and its commands run there too. A Claude
121
+ Code agent uses two containers: one runs Claude Code and holds its API key; the
122
+ other runs the agent's commands and has your repository. `workerImageRef` always
123
+ replaces the container that runs commands.
124
+
125
+ | | Codex agent | Claude Code agent |
126
+ | ------------------------------ | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
127
+ | What `workerImageRef` replaces | the agent's only container | the container that runs commands |
128
+ | Build your image `FROM` | [the coding-worker driver image](#the-driver-image) (`driver-vN`) | the `wardby-claude-tool-runner` image from the same wardby release (or `wardby-claude-tool-runner-node-python`) |
129
+ | Rebuild when | the driver image changes | you upgrade wardby |
130
+ | Claude Code itself runs on | — | wardby's standard image, never yours |
131
+
132
+ The driver image sections above are for Codex. The subsections below are for
133
+ Claude Code. In them, "tool runner" means the container that runs a Claude Code
134
+ agent's commands.
135
+
136
+ ### Build a custom image for a Claude Code agent
137
+
138
+ 1. **Find your release's tool runner image.** It is the value of
139
+ `CODING_CLAUDE_TOOL_RUNNER_IMAGE` on your server. To start from Node and
140
+ Python, use `CODING_CLAUDE_TOOL_RUNNER_IMAGE_NODE_PYTHON_3_12` instead. A
141
+ release value looks like
142
+ `ghcr.io/wardby/wardby/wardby-claude-tool-runner@sha256:<digest>`. If the
143
+ value is a local image ID (`sha256:...` only), give it a name first, because
144
+ Docker cannot build `FROM` a bare ID:
145
+ `docker tag sha256:<id> wardby-tool-runner-base:local`.
146
+ 2. **Make a build folder.** Use a small folder of your own, outside your
147
+ repository. Put in it the Dockerfile and only the files the Dockerfile
148
+ copies.
149
+ 3. **Write the Dockerfile.** Start from the image in step 1, install your tools
150
+ as `root`, then switch back to the tool runner's user:
151
+
152
+ ```dockerfile
153
+ FROM <image from step 1>
154
+ USER root
155
+ RUN apt-get update \
156
+ && apt-get install -y --no-install-recommends <your packages> \
157
+ && rm -rf /var/lib/apt/lists/*
158
+ USER 10001:10001
159
+ ```
160
+
161
+ Keep these rules:
162
+ - The last `USER` line is `USER 10001:10001`.
163
+ - Do not set `ENTRYPOINT` or `CMD`. The tool runner starts with the base
164
+ image's own entrypoint.
165
+ - Install everything at build time. A run cannot install system packages.
166
+ - Put tools in `/usr/local/bin` or `/usr/bin`. Do not put anything under
167
+ `/tmp` or `/home/wardby`: a run hides both.
168
+ - Put environment settings your commands need in a file under
169
+ `/etc/profile.d/` (see "How the tool runner runs commands" below). `ENV`
170
+ lines in the Dockerfile do not reach the agent's commands.
171
+
172
+ 4. **Build it:** `docker build --tag <name> <build folder>`. Release images are
173
+ `linux/amd64`. On an ARM machine, add `--platform linux/amd64` here and to
174
+ `docker run` in step 5.
175
+ 5. **Run the tests the way a run would.** Clone the repository to a throwaway
176
+ folder (on Linux, make it writable: `chmod -R a+rwX <clone>`). Then run the
177
+ project's test command with a run's restrictions and its fixed environment,
178
+ so `ENV` lines in the image do not apply:
179
+
180
+ ```sh
181
+ docker run --rm --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m --tmpfs /home/wardby:rw,noexec,nosuid,size=64m,uid=10001,gid=10001,mode=0700 --network none --user 10001:10001 --cap-drop ALL --security-opt no-new-privileges -v <clone>:/workspace -w /workspace --entrypoint env <name> -i HOME=/home/wardby LANG=C.UTF-8 PATH=/opt/wardby/bin:/usr/local/bin:/usr/bin:/bin sh -lc '<test command>'
182
+ ```
183
+
184
+ On an ARM machine, add `--platform linux/amd64` after `docker run`. Fix the
185
+ Dockerfile until the tests pass, then delete the clone.
186
+
187
+ 6. **Get an immutable reference.** A tag is refused.
188
+ - **Docker launcher** (wardby runs coding jobs with Docker on a single
189
+ machine): use the local image ID,
190
+ `docker image inspect --format '{{.Id}}' <name>`. Build on that machine.
191
+ Wardby never pulls these images.
192
+ - **Kubernetes:** push the image to a registry your cluster can pull from,
193
+ and use `<registry>/<name>@sha256:<digest>`.
194
+ 7. **Point the agent at it.** Call `update_agent` with the agent's id. This
195
+ needs the `agents:admin` scope and the admin role:
196
+
197
+ ```json
198
+ {
199
+ "id": "<agent id>",
200
+ "codingProfile": { "workerImageRef": "<reference from step 6>" }
201
+ }
202
+ ```
203
+
204
+ 8. **Try it.** Trigger a small task that uses your tools, such as "Run the
205
+ project's tests and report the results. Change nothing."
206
+
207
+ To undo it, set `codingProfile.workerImageRef` to `null`. The agent then uses
208
+ the standard tool runner for its `toolchain`.
209
+
210
+ ### Languages other than Node and Python
211
+
212
+ A run can download packages only from wardby's package registry, which serves
213
+ npm and PyPI. Packages for any other language must be in the image. If a
214
+ package compiles native code, compile it in an earlier build stage and copy
215
+ only the results into the final image. The final image then needs no compiler.
216
+
217
+ The tool runner is based on Debian 12 (bookworm). Build stages that compile
218
+ code must use a bookworm-based image too, so the results work with the tool
219
+ runner's system libraries.
116
220
 
117
- `workerImageRef` applies to Codex agents. A Claude Code agent's commands run in
118
- the Claude tool runner, which `workerImageRef` does not change, so Claude Code
119
- agents cannot use a custom toolchain yet. They can use wardby's curated
120
- `node-python` toolchain (set the matching
121
- `CODING_CLAUDE_TOOL_RUNNER_IMAGE_NODE_PYTHON_3_12` image).
221
+ This example adds Ruby and a project's gems. It is a starting point to adapt,
222
+ not a tested recipe. Copy the project's `Gemfile` and `Gemfile.lock` into the
223
+ build folder first.
224
+
225
+ ```dockerfile
226
+ # Stage 1: install Ruby and the project's gems, compiling any native code.
227
+ FROM ruby:3.3-slim-bookworm AS builder
228
+ RUN apt-get update \
229
+ && apt-get install -y --no-install-recommends build-essential \
230
+ && rm -rf /var/lib/apt/lists/*
231
+ ENV BUNDLE_PATH=/usr/local/bundle \
232
+ BUNDLE_DEPLOYMENT=true
233
+ WORKDIR /build
234
+ COPY Gemfile Gemfile.lock ./
235
+ RUN bundle install
236
+
237
+ # Stage 2: the tool runner from your wardby release, plus Ruby and the gems.
238
+ FROM <tool runner image from step 1>
239
+ USER root
240
+ # Shared libraries Ruby needs at run time, plus any library your native gems
241
+ # link to (for example libpq5 for pg).
242
+ RUN apt-get update \
243
+ && apt-get install -y --no-install-recommends libffi8 libgmp10 libssl3 libyaml-0-2 zlib1g \
244
+ && rm -rf /var/lib/apt/lists/*
245
+ # Ruby lives in /usr/local, and the gems in /usr/local/bundle.
246
+ COPY --from=builder /usr/local /usr/local
247
+ # Settings for the agent's commands (Dockerfile ENV lines do not reach them).
248
+ RUN ldconfig \
249
+ && printf '%s\n' \
250
+ 'export GEM_HOME=/usr/local/bundle' \
251
+ 'export BUNDLE_PATH=/usr/local/bundle' \
252
+ 'export BUNDLE_APP_CONFIG=/usr/local/bundle' \
253
+ 'export BUNDLE_DEPLOYMENT=true' \
254
+ > /etc/profile.d/ruby.sh \
255
+ && sh -lc 'ruby --version && bundle --version'
256
+ USER 10001:10001
257
+ ```
258
+
259
+ Pin the `ruby` image by digest for repeatable builds. Rebuild the image when
260
+ the project's `Gemfile.lock` changes.
261
+
262
+ ### If a run fails
263
+
264
+ | What you see | What it usually means |
265
+ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
266
+ | `worker_tool_runner_unreachable` | The image was not built `FROM` the tool runner of the same wardby release, or the Dockerfile changed its `USER` or `ENTRYPOINT`. |
267
+ | A command is "not found" | The tool is not in the image, or a setting it needs is in an `ENV` line instead of `/etc/profile.d/`. |
268
+ | "Permission denied" when running a file | On Docker, something writes a program to `/tmp` or `/home/wardby` and runs it. Point that tool's temporary or cache folder under `/workspace/.cache/`. |
269
+
270
+ ### How the tool runner runs commands
271
+
272
+ These details explain the rules above.
273
+
274
+ - **User and privileges.** Commands always run as user `10001`, with no Linux
275
+ capabilities and `no-new-privileges`. `root` and setuid programs do not work
276
+ at run time.
277
+ - **Filesystem.** The root filesystem is read-only. `/tmp` and `/home/wardby`
278
+ are small, empty scratch space; anything the image put there is hidden. On
279
+ Docker, files there cannot be run. `/workspace` holds the repository; put
280
+ caches, build output and temporary files under `/workspace/.cache/`.
281
+ - **Shell and environment.** Each command runs as `sh -lc "<command>"` with a
282
+ fixed environment: `HOME=/home/wardby`, `LANG=C.UTF-8`, `TMPDIR` under
283
+ `/workspace/.cache/`, wardby's package registry settings, and
284
+ `PATH=/opt/wardby/bin:/usr/local/bin:/usr/bin:/bin`. The login shell reads
285
+ `/etc/profile` and the files in `/etc/profile.d/`, so that is where your own
286
+ settings go. `/etc/profile` resets `PATH` to Debian's default, so add any
287
+ other folder to `PATH` in your `/etc/profile.d/` file.
288
+ - **Network.** The tool runner reaches only wardby's package registry (npm and
289
+ PyPI).
290
+ - **Images on the Docker launcher are never pulled.** When wardby runs coding
291
+ jobs with Docker on a single machine, the image must already be on that
292
+ machine. Kubernetes needs a registry digest
293
+ (`repo@sha256:<64 hex>`).
294
+ - **Server settings.** Claude Code itself always runs on
295
+ `CODING_CLAUDE_WORKER_IMAGE`. The server still needs both
296
+ `CODING_CLAUDE_WORKER_IMAGE` and `CODING_CLAUDE_TOOL_RUNNER_IMAGE` set, even
297
+ for agents with their own `workerImageRef`.
298
+ - **Toolchain.** While `workerImageRef` is set, `toolchain` and
299
+ `toolchainVersion` do not choose the image, for either builder.
122
300
 
123
301
  ## Running services with a BYO image
124
302
 
@@ -130,6 +308,20 @@ a worker built on an older driver base doesn't recognize the input's
130
308
  without them. Rebuild your image on a current `driver-vN` digest (see "The
131
309
  driver image" above) before allowing any service on an agent that uses it.
132
310
 
311
+ ## Repository skills need a current driver
312
+
313
+ On a Codex agent, a `workerImageRef` image never receives Claude Code's
314
+ repository context (`claudeContext`) or `claudeBareMode`. The one new input key
315
+ it can see is `repoSkills`, which wardby writes only when an agent sets
316
+ `repoSkills: false`. A worker built on
317
+ an older driver base validates its input with a strict schema, so it rejects
318
+ runs of agents with `repoSkills: false` (the run fails with
319
+ `worker_input_failed`), and it keeps offering Codex's built-in skills
320
+ (`imagegen`, `openai-docs`, `skill-creator`, `skill-installer`), which a
321
+ current driver always disables. Rebuild any `workerImageRef` image on a
322
+ current `driver-vN` digest (see "The driver image" above) before relying on
323
+ either behavior.
324
+
133
325
  ## What this doesn't cover
134
326
 
135
327
  wardby does not re-validate the contents of your built image beyond the
@@ -1,16 +1,24 @@
1
1
  # Coding Worker Isolation
2
2
 
3
- Wardby supports isolated Codex execution with Docker or Kubernetes and
4
- credential-separated Claude Code execution with Docker. Both launchers fail
5
- closed when the effective runtime does not match the reviewed policy.
3
+ Wardby runs Codex and Claude Code coding workers through Docker or Kubernetes
4
+ launchers. Both fail closed when the effective runtime does not match the
5
+ reviewed policy. Claude Code separates its model-facing worker from its
6
+ workspace-facing tool runner: Docker uses companion containers, while
7
+ Kubernetes uses a native sidecar in the run pod.
6
8
 
7
9
  ## Security Boundary
8
10
 
9
- Coding-agent repositories and instructions are untrusted. The Docker daemon,
10
- host kernel, Wardby control plane, immutable worker image, and dedicated coding
11
- proxy are trusted. Containers are defense in depth rather than a VM boundary;
12
- production should run the Docker host on a dedicated worker node or VM with no
13
- production credentials beyond those required by the proxy.
11
+ Coding-agent repositories and instructions are untrusted. The Wardby control
12
+ plane, immutable worker images, dedicated coding proxy, and the platform
13
+ enforcing container and network policies are trusted.
14
+
15
+ ### Docker launcher
16
+
17
+ The Docker daemon and host kernel are trusted. Docker containers are defense
18
+ in depth rather than a VM boundary. Production should run the Docker host on a
19
+ dedicated worker node or VM with no production credentials beyond those
20
+ required by the proxy. The Kubernetes launcher section below describes the
21
+ corresponding pod and network rules.
14
22
 
15
23
  The Codex worker has one network attachment: a unique per-run internal bridge using
16
24
  Docker's isolated gateway mode. It has no default external route, published
@@ -588,6 +596,7 @@ Kubernetes-specific settings (`src/config/providers.ts`,
588
596
  | `KUBERNETES_CONTEXT` | (unset → in-cluster/default kubeconfig context) | Which kubeconfig context `ClientNodeKubernetesApi` connects with. |
589
597
  | `KUBERNETES_RUNTIME_CLASS` | (unset) | e.g. `gvisor` on GKE. Unset means pods run without a sandboxing runtime class — logged once per launch as `kubernetes_runtime_class_unset` and development-only. |
590
598
  | `KUBERNETES_RESOURCE_QUOTA` | (unset) | Name of the namespace ResourceQuota run pods count against, e.g. `wardby-coding` in the GKE overlay. When set, a run whose pod would not fit the quota's free room waits in the coding queue instead of failing at pod create. Needs `get` on that one `resourcequotas` object. Unset means no check. |
599
+ | `KUBERNETES_PLATFORM` | `generic` | `generic`, `gke-autopilot` or `eks`. Selects the cluster's admission rules that run pods are conformed to. `gke-autopilot` and `eks` both require `KUBERNETES_RUNTIME_CLASS=gvisor`; see the platform profile section below. |
591
600
  | `KUBERNETES_RUN_PRIORITY_CLASS` | (unset) | PriorityClass for run pods and the preflight canary, e.g. `wardby-coding-run` in the GKE overlay. Must be an existing class and a DNS-1123 subdomain; `system-` classes are refused. Unset means no class (priority 0). |
592
601
 
593
602
  The `CODING_CPUS` / `CODING_MEMORY_MB` / `CODING_PIDS` / `CODING_DISK_MB` /
@@ -798,6 +807,16 @@ landed on — cannot appear in it. That case reached a live Autopilot launch wit
798
807
  every dry-run-derived check passing, and is now pinned by tests. Treat a
799
808
  captured fixture as a lower bound on what a platform mutates.
800
809
 
810
+ The `eks` profile is for Amazon EKS clusters with a dedicated gVisor node group.
811
+ EKS has no managed sandbox runtime, so the cluster must provide a RuntimeClass
812
+ named `gvisor` with handler `runsc` whose `scheduling` block selects nodes
813
+ labelled `wardby.dev/sandbox=gvisor` and tolerates the taint
814
+ `sandbox=gvisor:NoSchedule` on those nodes. Kubernetes' RuntimeClass admission
815
+ merges that block into each pod; Wardby sets neither the node selector nor the
816
+ toleration itself, and the `eks` profile forgives exactly that nodeSelector and
817
+ that toleration and nothing else. Pod resources follow the generic rules, plus
818
+ an explicit ephemeral-storage request and limit.
819
+
801
820
  ### The enforcement gate
802
821
 
803
822
  The Kubernetes API can create a NetworkPolicy object without that policy
@@ -911,9 +930,9 @@ default 90,000ms):
911
930
  1. `platform` — pure configuration, checked before any cluster API call:
912
931
  `assertPlatformConfig` (`src/providers/jobs/kubernetes-platform.ts`) refuses
913
932
  a deployment that cannot work under `KUBERNETES_PLATFORM`. Under
914
- `gke-autopilot` this means `KUBERNETES_RUNTIME_CLASS` must be `gvisor`
915
- (gVisor is mandatory there — an unset or different runtime class is refused,
916
- not warned about), and the effective `CODING_MAX_DISK_MB` must leave room
933
+ `gke-autopilot` and `eks`, `KUBERNETES_RUNTIME_CLASS` must be `gvisor` (an
934
+ unset or different runtime class is refused, not warned about). Under
935
+ `gke-autopilot` the effective `CODING_MAX_DISK_MB` must also leave room
917
936
  for the worker container's 1 GiB reservation inside Autopilot's 10 GiB pod
918
937
  ephemeral-storage ceiling. The same assertion runs again at process
919
938
  start-up in `buildConfiguredExecutor`
@@ -942,20 +961,55 @@ default 90,000ms):
942
961
  5. `canary` — creates a real run pod + NetworkPolicy from the same builders
943
962
  as a live run, running a script that waits for policy enforcement (as
944
963
  above) then attempts DNS resolution, a connect to the proxy's deny port,
945
- the internet (`1.1.1.1:443`), the metadata server, and the proxy itself —
946
- requiring every one of the first four to fail and the proxy connect to
964
+ the internet (`1.1.1.1:443`), the cloud metadata endpoints (`169.254.169.254:80`,
965
+ the EKS Pod Identity agent `169.254.170.23:80` and its IPv6 address
966
+ `[fd00:ec2::23]:80`, and EC2's IPv6 metadata address `[fd00:ec2::254]:80`), and the proxy itself —
967
+ requiring every one of the first four kinds to fail and the proxy connect to
947
968
  succeed. Any other outcome, or a canary pod that itself fails to
948
969
  schedule/run, is `kubernetes_isolation_unsupported:canary`.
949
970
 
950
971
  This whole preflight is **memoized per launcher instance and its failure is
951
972
  sticky**: `KubernetesJobLauncher.runPreflight()` caches the first call's
952
- promise (`this.preflightResult ??= ...`, `kubernetes.ts:472-487`), including
973
+ promise (`this.preflightResult ??= ...`, `kubernetes.ts:790`), including
953
974
  a rejection — so once a launcher process has seen preflight fail, every
954
975
  subsequent `launch()` in that process fails immediately with the same error
955
976
  without re-probing the cluster. A fresh preflight requires a new process
956
977
  (or, from the CLI, a fresh `wardby coding preflight` invocation, which is
957
978
  not memoized).
958
979
 
980
+ **A long-running server process starts this same memoized preflight at
981
+ start-up, not on the first coding run.** `wardby serve`, `wardby mcp` (both
982
+ transports), and `wardby scheduler` each call `KubernetesJobLauncher.warmUp()`
983
+ right after the executor is built, fire-and-forget: it runs the identical
984
+ preflight `launch()` would otherwise run lazily, so the first coding run
985
+ after a restart doesn't pay the preflight's own cost (a canary pod, routinely
986
+ tens of seconds on a resource-constrained cluster such as `kind`).
987
+ `wardby scheduler` needs this just as much as the other two — it dispatches
988
+ scheduled coding runs through its own Kubernetes executor without ever
989
+ starting an MCP server, so without this it would still pay the lazy cost on
990
+ its first scheduled run. The result is logged once at start-up — an info
991
+ line on success, a warning naming the failure code (e.g.
992
+ `kubernetes_isolation_unsupported:<check>`) otherwise.
993
+
994
+ **A start-up warm-up's failure is logged and retried on the next run, not
995
+ left stuck until restart.** This is the one way a preflight failure is
996
+ _not_ memoized: a transient cluster problem at process start (the API
997
+ server briefly unreachable, a slow CNI not yet programmed, and the like)
998
+ must not fail every coding run for the rest of that process's life, so a
999
+ failed warm-up clears its own failed attempt once it has logged it, and the
1000
+ _next_ `launch()` runs the preflight fresh — succeeding if the cluster has
1001
+ since recovered. A `launch()` that was already waiting on that same
1002
+ in-flight warm-up attempt still fails with that attempt's error (it shares
1003
+ the same preflight call), exactly as it always has; it's only the attempt
1004
+ _after_ that one which retries. A preflight failure `launch()` triggers
1005
+ itself — because no warm-up ran, or because a warm-up's cleared failure was
1006
+ never retried before the next `launch()` found the cluster still broken —
1007
+ keeps the original behavior exactly: it stays memoized, failing every
1008
+ subsequent `launch()` in that process until it is restarted. This never
1009
+ runs for a one-shot CLI command (`wardby run`, `wardby coding preflight`,
1010
+ migrations, imports) — only for a process that stays up to serve or
1011
+ dispatch runs.
1012
+
959
1013
  **A hung pod create during preflight can leave a preflight pod and its
960
1014
  NetworkPolicy behind.** If `createPod` never settles (rather than failing),
961
1015
  the preflight's own timeout still fires and the caller sees `:timeout`, but