@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.
- package/.env.example +5 -5
- package/README.md +6 -1
- package/deploy/local/docker-compose.quickstart-coding.yml +11 -0
- package/dist/claude-coding-worker/driver.d.ts +12 -0
- package/dist/claude-coding-worker/driver.js +29 -7
- package/dist/claude-coding-worker/main.js +5 -1
- package/dist/claude-coding-worker/sdk.js +17 -1
- package/dist/claude-plugin/command.d.ts +64 -0
- package/dist/claude-plugin/command.js +379 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +2 -1
- package/dist/cli.js +71 -3
- package/dist/coding/code-host.d.ts +16 -0
- package/dist/coding/code-host.js +60 -0
- package/dist/coding/mcp-token.d.ts +12 -0
- package/dist/coding/mcp-token.js +26 -0
- package/dist/coding/protocol.js +2 -0
- package/dist/coding/redact.js +6 -1
- package/dist/coding/transcript/recorder.d.ts +5 -4
- package/dist/coding/transcript/recorder.js +3 -9
- package/dist/coding-worker/debug-trace.d.ts +3 -1
- package/dist/coding-worker/debug-trace.js +4 -2
- package/dist/coding-worker/driver.js +8 -1
- package/dist/coding-worker/main.js +5 -1
- package/dist/coding-worker/mcp-config.d.ts +27 -0
- package/dist/coding-worker/mcp-config.js +32 -0
- package/dist/coding-worker/sdk.d.ts +36 -0
- package/dist/coding-worker/sdk.js +28 -1
- package/dist/coding-worker/types.d.ts +4 -0
- package/dist/config/mcp-call-limit.d.ts +8 -0
- package/dist/config/mcp-call-limit.js +18 -0
- package/dist/config/mcp-servers.d.ts +8 -0
- package/dist/config/mcp-servers.js +12 -0
- package/dist/config/test-simulators.d.ts +10 -0
- package/dist/config/test-simulators.js +28 -0
- package/dist/config/tool-timeout.d.ts +1 -0
- package/dist/config/tool-timeout.js +18 -0
- package/dist/core/coding-mcp.d.ts +36 -0
- package/dist/core/coding-mcp.js +253 -0
- package/dist/core/coding-repository.d.ts +46 -0
- package/dist/core/coding-repository.js +92 -0
- package/dist/core/delegation-slots.d.ts +27 -0
- package/dist/core/delegation-slots.js +44 -0
- package/dist/core/dispatch.d.ts +6 -2
- package/dist/core/dispatch.js +39 -11
- package/dist/core/engine-native.d.ts +2 -0
- package/dist/core/engine-native.js +13 -0
- package/dist/core/error-code.js +2 -0
- package/dist/core/grants.d.ts +28 -3
- package/dist/core/grants.js +46 -4
- package/dist/core/host-events.js +7 -3
- package/dist/core/host-status.js +2 -2
- package/dist/core/issue-status.js +4 -3
- package/dist/core/listen-address.d.ts +10 -0
- package/dist/core/listen-address.js +14 -0
- package/dist/core/mark-ready.d.ts +1 -1
- package/dist/core/mark-ready.js +1 -1
- package/dist/core/mcp-client/client.d.ts +47 -0
- package/dist/core/mcp-client/client.js +141 -0
- package/dist/core/mcp-client/jsonrpc.d.ts +15 -0
- package/dist/core/mcp-client/jsonrpc.js +54 -0
- package/dist/core/mcp-client/results.d.ts +13 -0
- package/dist/core/mcp-client/results.js +42 -0
- package/dist/core/mcp-servers.d.ts +90 -0
- package/dist/core/mcp-servers.js +230 -0
- package/dist/core/mcp-tools.d.ts +108 -0
- package/dist/core/mcp-tools.js +287 -0
- package/dist/core/merge-order-check.js +38 -19
- package/dist/core/notification-dispatcher.js +2 -1
- package/dist/core/power-idle.d.ts +8 -2
- package/dist/core/power-idle.js +17 -3
- package/dist/core/power.d.ts +5 -0
- package/dist/core/power.js +5 -0
- package/dist/core/related-pull-requests.js +26 -10
- package/dist/core/retention-days.d.ts +5 -0
- package/dist/core/retention-days.js +14 -0
- package/dist/core/review-fix.js +2 -2
- package/dist/core/review-host-tools.js +3 -1
- package/dist/core/run-steps/config.d.ts +25 -0
- package/dist/core/run-steps/config.js +40 -0
- package/dist/core/run-steps/control-chars.d.ts +16 -0
- package/dist/core/run-steps/control-chars.js +26 -0
- package/dist/core/run-steps/detail.d.ts +32 -0
- package/dist/core/run-steps/detail.js +240 -0
- package/dist/core/run-steps/extract.d.ts +52 -0
- package/dist/core/run-steps/extract.js +467 -0
- package/dist/core/run-steps/ingress.d.ts +51 -0
- package/dist/core/run-steps/ingress.js +160 -0
- package/dist/core/run-steps/last-step.d.ts +15 -0
- package/dist/core/run-steps/last-step.js +35 -0
- package/dist/core/run-steps/native.d.ts +48 -0
- package/dist/core/run-steps/native.js +164 -0
- package/dist/core/run-steps/seen.d.ts +16 -0
- package/dist/core/run-steps/seen.js +35 -0
- package/dist/core/run-steps/summarize.d.ts +57 -0
- package/dist/core/run-steps/summarize.js +304 -0
- package/dist/core/run-steps/sweep.d.ts +21 -0
- package/dist/core/run-steps/sweep.js +41 -0
- package/dist/core/run-steps/types.d.ts +89 -0
- package/dist/core/run-steps/types.js +39 -0
- package/dist/core/run-steps/wire.d.ts +35 -0
- package/dist/core/run-steps/wire.js +47 -0
- package/dist/core/run-steps/writer.d.ts +49 -0
- package/dist/core/run-steps/writer.js +279 -0
- package/dist/core/runner.d.ts +70 -16
- package/dist/core/runner.js +296 -74
- package/dist/core/secret-broker-config.d.ts +2 -0
- package/dist/core/secret-broker-config.js +1 -1
- package/dist/core/secret-guard.d.ts +5 -2
- package/dist/core/secret-guard.js +22 -7
- package/dist/core/secrets.d.ts +11 -1
- package/dist/core/secrets.js +27 -1
- package/dist/core/serializable-retry.d.ts +18 -0
- package/dist/core/serializable-retry.js +43 -0
- package/dist/core/tool-admin.d.ts +5 -1
- package/dist/core/tool-admin.js +7 -2
- package/dist/core/tool-names.d.ts +13 -0
- package/dist/core/tool-names.js +20 -0
- package/dist/core/webhooks.d.ts +4 -0
- package/dist/core/webhooks.js +68 -49
- package/dist/core/workflow-run-events.js +2 -1
- package/dist/generated/prisma/browser.d.ts +39 -0
- package/dist/generated/prisma/client.d.ts +39 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +80 -50
- package/dist/generated/prisma/enums.d.ts +6 -0
- package/dist/generated/prisma/enums.js +5 -0
- package/dist/generated/prisma/internal/class.d.ts +77 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +632 -1
- package/dist/generated/prisma/internal/prismaNamespace.js +94 -3
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +98 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +94 -3
- package/dist/generated/prisma/models/Agent.d.ts +372 -1
- package/dist/generated/prisma/models/AgentMcpServer.d.ts +1412 -0
- package/dist/generated/prisma/models/AgentMcpServer.js +1 -0
- package/dist/generated/prisma/models/AgentRepository.d.ts +40 -1
- package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +0 -7
- package/dist/generated/prisma/models/CodingProxySession.d.ts +159 -2
- package/dist/generated/prisma/models/CodingRun.d.ts +76 -1
- package/dist/generated/prisma/models/HostProvider.d.ts +2176 -0
- package/dist/generated/prisma/models/HostProvider.js +1 -0
- package/dist/generated/prisma/models/HostProviderCredential.d.ts +1285 -0
- package/dist/generated/prisma/models/HostProviderCredential.js +1 -0
- package/dist/generated/prisma/models/HostProviderOperation.d.ts +1470 -0
- package/dist/generated/prisma/models/HostProviderOperation.js +1 -0
- package/dist/generated/prisma/models/HostProviderTrustedAccount.d.ts +1145 -0
- package/dist/generated/prisma/models/HostProviderTrustedAccount.js +1 -0
- package/dist/generated/prisma/models/McpServer.d.ts +1500 -0
- package/dist/generated/prisma/models/McpServer.js +1 -0
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
- package/dist/generated/prisma/models/Principal.d.ts +167 -0
- package/dist/generated/prisma/models/ResourceGrant.d.ts +1 -1
- package/dist/generated/prisma/models/Run.d.ts +503 -1
- package/dist/generated/prisma/models/RunStep.d.ts +1453 -0
- package/dist/generated/prisma/models/RunStep.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +387 -0
- package/dist/generated/prisma/models/Tool.d.ts +223 -1
- package/dist/generated/prisma/models.d.ts +7 -0
- package/dist/help/search.js +12 -3
- package/dist/help-index.json +812 -52
- package/dist/import/create.js +16 -1
- package/dist/import/neutral-schema.d.ts +1 -0
- package/dist/import/neutral-schema.js +2 -0
- package/dist/mcp/auth/access.d.ts +1 -0
- package/dist/mcp/auth/grants-cli.d.ts +6 -4
- package/dist/mcp/auth/grants-cli.js +42 -3
- package/dist/mcp/auth/resource-server.d.ts +3 -1
- package/dist/mcp/auth/resource-server.js +17 -2
- package/dist/mcp/context.d.ts +6 -0
- package/dist/mcp/index.js +21 -0
- package/dist/mcp/tools/agents.js +135 -20
- package/dist/mcp/tools/grants.js +66 -28
- package/dist/mcp/tools/host-providers.d.ts +2 -0
- package/dist/mcp/tools/host-providers.js +215 -0
- package/dist/mcp/tools/mcp-servers.d.ts +26 -0
- package/dist/mcp/tools/mcp-servers.js +481 -0
- package/dist/mcp/tools/power.js +2 -2
- package/dist/mcp/tools/repositories.js +50 -10
- package/dist/mcp/tools/run-access.d.ts +7 -0
- package/dist/mcp/tools/run-access.js +14 -0
- package/dist/mcp/tools/run-steps.d.ts +16 -0
- package/dist/mcp/tools/run-steps.js +85 -0
- package/dist/mcp/tools/runs.js +186 -18
- package/dist/mcp/tools/secret-elicitation.d.ts +2 -0
- package/dist/mcp/tools/secret-elicitation.js +25 -2
- package/dist/mcp/tools/secrets.js +38 -4
- package/dist/mcp/tools/tools.d.ts +6 -4
- package/dist/mcp/tools/tools.js +40 -8
- package/dist/mcp/tools/trigger.js +28 -6
- package/dist/mcp/transport/http-limits.d.ts +2 -0
- package/dist/mcp/transport/http-limits.js +6 -2
- package/dist/mcp/webhooks/ingress.js +10 -0
- package/dist/native-worker/gateway-server.d.ts +18 -1
- package/dist/native-worker/gateway-server.js +38 -9
- package/dist/native-worker/gateway.d.ts +5 -0
- package/dist/native-worker/gateway.js +13 -1
- package/dist/native-worker/http-server.d.ts +6 -4
- package/dist/native-worker/http-server.js +53 -8
- package/dist/native-worker/ledger.d.ts +6 -2
- package/dist/native-worker/ledger.js +5 -4
- package/dist/native-worker/protocol.d.ts +1 -0
- package/dist/native-worker/protocol.js +4 -1
- package/dist/providers/coding-proxy/capability-hash.d.ts +2 -0
- package/dist/providers/coding-proxy/capability-hash.js +5 -0
- package/dist/providers/coding-proxy/mcp-route.d.ts +34 -0
- package/dist/providers/coding-proxy/mcp-route.js +166 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +2 -0
- package/dist/providers/coding-proxy/memory-ledger.js +16 -0
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +1 -0
- package/dist/providers/coding-proxy/prisma-ledger.js +36 -2
- package/dist/providers/coding-proxy/proxy.d.ts +33 -1
- package/dist/providers/coding-proxy/proxy.js +266 -75
- package/dist/providers/coding-proxy/run-step-forwarder.d.ts +42 -0
- package/dist/providers/coding-proxy/run-step-forwarder.js +206 -0
- package/dist/providers/coding-proxy/runtime.d.ts +13 -0
- package/dist/providers/coding-proxy/runtime.js +87 -4
- package/dist/providers/coding-proxy/server.d.ts +3 -0
- package/dist/providers/coding-proxy/server.js +10 -0
- package/dist/providers/coding-proxy/types.d.ts +18 -0
- package/dist/providers/engine/types.d.ts +26 -0
- package/dist/providers/executor/composition.js +5 -0
- package/dist/providers/executor/container.d.ts +47 -1
- package/dist/providers/executor/container.js +84 -8
- package/dist/providers/host-tools/invoke.d.ts +37 -0
- package/dist/providers/host-tools/invoke.js +117 -0
- package/dist/providers/host-tools/operations.d.ts +65 -0
- package/dist/providers/host-tools/operations.js +149 -0
- package/dist/providers/host-tools/registry.d.ts +79 -0
- package/dist/providers/host-tools/registry.js +362 -0
- package/dist/providers/host-tools/request-guard.d.ts +17 -0
- package/dist/providers/host-tools/request-guard.js +99 -0
- package/dist/providers/host-tools/self-test.d.ts +64 -0
- package/dist/providers/host-tools/self-test.js +142 -0
- package/dist/providers/jobs/docker-isolation.d.ts +2 -2
- package/dist/providers/jobs/docker-isolation.js +30 -8
- package/dist/providers/jobs/docker.d.ts +8 -0
- package/dist/providers/jobs/docker.js +33 -9
- package/dist/providers/jobs/kubernetes-isolation.d.ts +3 -1
- package/dist/providers/jobs/kubernetes-isolation.js +15 -2
- package/dist/providers/jobs/kubernetes.d.ts +13 -0
- package/dist/providers/jobs/kubernetes.js +28 -5
- package/dist/providers/jobs/types.d.ts +6 -0
- package/dist/providers/review-host/types.d.ts +6 -4
- package/dist/providers/review-host/types.js +1 -1
- package/dist/providers/vcs/git.d.ts +6 -2
- package/dist/providers/vcs/git.js +15 -4
- package/dist/providers/vcs/github.d.ts +2 -71
- package/dist/providers/vcs/github.js +8 -11
- package/dist/providers/vcs/index.d.ts +1 -1
- package/dist/providers/vcs/index.js +1 -1
- package/dist/providers/vcs/remote.d.ts +4 -0
- package/dist/providers/vcs/remote.js +7 -1
- package/dist/providers/vcs/routing.d.ts +12 -6
- package/dist/providers/vcs/routing.js +21 -6
- package/dist/providers/vcs/types.d.ts +71 -3
- package/dist/quickstart/index.d.ts +5 -0
- package/dist/quickstart/index.js +21 -0
- package/dist/quickstart-images.json +1 -1
- package/dist/sandbox/eval-core.d.ts +12 -2
- package/dist/sandbox/eval-core.js +20 -4
- package/dist/sandbox/host-functions.d.ts +4 -0
- package/dist/sandbox/host-functions.js +7 -2
- package/dist/sandbox/limits.d.ts +4 -1
- package/dist/sandbox/limits.js +4 -1
- package/dist/sandbox/run-in-sandbox.d.ts +6 -0
- package/dist/sandbox/run-in-sandbox.js +14 -2
- package/dist/sandbox/safe-fetch.d.ts +2 -0
- package/dist/sandbox/safe-fetch.js +1 -1
- package/dist/sandbox/secret-broker.d.ts +1 -0
- package/dist/sandbox/secret-broker.js +1 -1
- package/dist/sandbox/tool-timeout.d.ts +32 -0
- package/dist/sandbox/tool-timeout.js +52 -0
- package/dist/sandbox/user-tool.d.ts +8 -1
- package/dist/sandbox/user-tool.js +9 -3
- package/dist/serve.js +26 -18
- package/dist/viewer/api-schema.d.ts +66 -0
- package/dist/viewer/api-schema.js +31 -0
- package/dist/viewer/graph.js +2 -1
- package/dist/viewer/openapi.js +2 -1
- package/dist/viewer/run-detail.d.ts +2 -0
- package/dist/viewer/run-detail.js +26 -1
- package/dist/wardby-bin.js +5 -0
- package/docs/README.md +11 -1
- package/docs/agent-recipes.md +37 -4
- package/docs/architecture-runtime.md +1 -1
- package/docs/claude-code-plugin.md +208 -0
- package/docs/code-review-agents.md +6 -0
- package/docs/coding-agent-setup.md +94 -1
- package/docs/coding-worker-byo-images.md +4 -2
- package/docs/coding-worker-isolation.md +94 -7
- package/docs/debugging-agent-runs.md +354 -0
- package/docs/getting-started-gke.md +33 -11
- package/docs/getting-started-identity-provider.md +43 -37
- package/docs/getting-started.md +8 -0
- package/docs/host-providers.md +294 -0
- package/docs/mcp-servers.md +263 -0
- package/docs/native-sandbox.md +31 -9
- package/docs/security-deployment.md +161 -31
- package/docs/tool-secrets.md +3 -0
- package/docs/viewer-api.md +27 -12
- package/docs/viewer-api.openapi.yml +78 -2
- package/help/admin-viewer.md +5 -0
- package/help/agent-recipes.md +33 -2
- package/help/brokered-secrets.md +3 -0
- package/help/build-claude-code-image.md +1 -1
- package/help/claude-code-run-pane.md +63 -0
- package/help/deploy-gke.md +5 -0
- package/help/errors/coding-mcp-gateway-unavailable.md +46 -0
- package/help/errors/coding-mcp-pins-unavailable.md +35 -0
- package/help/errors/database-auth-invalid.md +1 -1
- package/help/errors/host-provider-error.md +40 -0
- package/help/errors/host-tool-failed.md +36 -0
- package/help/errors/mcp-call-limit.md +22 -0
- package/help/errors/mcp-call-timeout.md +22 -0
- package/help/errors/mcp-server-auth-failed.md +22 -0
- package/help/errors/mcp-server-credentials-unavailable.md +45 -0
- package/help/errors/mcp-server-error.md +28 -0
- package/help/errors/mcp-server-unreachable.md +22 -0
- package/help/errors/mcp-servers-off.md +21 -0
- package/help/errors/mcp-tool-not-allowed.md +26 -0
- package/help/errors/mcp-tool-removed.md +22 -0
- package/help/errors/mcp-unavailable.md +25 -0
- package/help/errors/native-sandbox-capacity.md +1 -1
- package/help/errors/native-sandbox-deadline-exceeded.md +1 -1
- package/help/errors/native-sandbox-docker-failed.md +1 -1
- package/help/errors/native-sandbox-gateway-error.md +1 -1
- package/help/errors/native-sandbox-gateway-unavailable.md +1 -1
- package/help/errors/native-sandbox-image-not-pinned.md +1 -1
- package/help/errors/native-sandbox-isolation-mismatch.md +1 -1
- package/help/errors/native-sandbox-network-unenforced.md +1 -1
- package/help/errors/native-sandbox-requires-catalog.md +1 -1
- package/help/errors/native-sandbox-unavailable.md +1 -1
- package/help/errors/native-sandbox-warm-delivery-failed.md +1 -1
- package/help/errors/native-sandbox-worker-exited.md +1 -1
- package/help/errors/native-sandbox-worker-lost.md +1 -1
- package/help/errors/native-sandbox-worker-unready.md +1 -1
- package/help/errors/repository-not-listed.md +36 -0
- package/help/errors/repository-required.md +36 -0
- package/help/errors/tool-timeout.md +38 -0
- package/help/host-providers.md +40 -0
- package/help/identity-and-access.md +4 -1
- package/help/low-power-mode.md +19 -8
- package/help/mcp-servers.md +73 -0
- package/help/mcp.md +9 -2
- package/help/native-capabilities.md +27 -1
- package/help/native-sandbox.md +1 -1
- package/help/operating-agents.md +16 -0
- package/help/related-pull-requests.md +7 -3
- package/help/repo-instructions-and-skills.md +3 -1
- package/help/resume-runs-locally.md +7 -0
- package/help/run-steps.md +140 -0
- package/help/stop-run.md +1 -1
- package/help/troubleshooting/coding-workers.md +9 -1
- package/help/troubleshooting/debugging-agent-runs.md +29 -0
- package/package.json +2 -1
- package/prisma/migrations/20261102000000_host_providers/migration.sql +56 -0
- package/prisma/migrations/20261104000000_coding_agent_repository_list/migration.sql +5 -0
- package/prisma/migrations/20261106000000_tool_timeout/migration.sql +4 -0
- package/prisma/migrations/20261107000000_mcp_servers/migration.sql +33 -0
- package/prisma/migrations/20261108000000_coding_mcp/migration.sql +5 -0
- package/prisma/migrations/20261109000000_task_run_index/migration.sql +3 -0
- package/prisma/migrations/20261110000000_run_steps/migration.sql +26 -0
- package/prisma/migrations/20261111000000_run_steps_viewer_notify/migration.sql +59 -0
- package/prisma/migrations/20261112000000_run_steps_detail/migration.sql +9 -0
- package/prisma/schema.prisma +211 -14
- package/scripts/git-askpass.sh +1 -1
package/dist/help-index.json
CHANGED
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
],
|
|
22
22
|
"appliesTo": ">=0.4.0",
|
|
23
23
|
"sourcePath": "admin-viewer.md",
|
|
24
|
-
"markdown": "\n# Watch live runs with the admin viewer API\n\nThe admin viewer API is a read-only HTTP API for dashboards and desktop\nviewers. It shows every owner's runs across the deployment: sub-agent trees,\nwhat triggered each run, its outcomes (pull requests, comments, checks), and\ncoding-run services, with a live event stream.\n\nIt requires the Wardby `admin` role and the `admin:view` scope, which only the\n`admin` role grants. In delegating mode, define `admin:view` in your identity\nprovider and map it like `agents:admin`. See\n[Configure identity and privileged access](identity-and-access.md).\n\nEndpoints, all `GET`:\n\n- `/admin/api/graph?since=1h&limit=500`: a snapshot of runs in a time window.\n- `/admin/api/runs/<id>`: one run in full, including its final text and error.\n- `/admin/api/infra`: how this deployment runs coding jobs (launcher, Kubernetes namespace, platform, run labels).\n- `/admin/api/events`: a Server-Sent Events stream of live changes.\n\nThe stream has no replay: open the event stream first, then load the graph,\nand refetch the graph on every `resync` event and after any reconnect. `hello`\nand `status` events report whether live events are flowing. Proxies and load balancers in front of Wardby\nmust allow long-lived responses and not buffer `text/event-stream`.\n\nA desktop viewer for macOS is included in the source tree (`apps/viewer`). Add\nyour server's canonical URI, sign in with an `admin` user in the browser, and it\nshows the live graph. Each GitHub release has an unsigned macOS build of the viewer attached (see the README for opening it past Gatekeeper). Its README covers setup, and what an external identity\nprovider client needs when the server runs in delegating mode.\n\n## Viewer sign-in with an external identity provider\n\nIn delegating mode, the viewer signs in through your identity provider's\npublic (native) client. That client must:\n\n- register the exact redirect URI `http://127.0.0.1:8585/callback`. The viewer\n always listens on port 8585, and some providers (Okta, for example) match a\n loopback redirect by its exact port, so a port-less or wildcard loopback\n entry may not match;\n- allow the `admin:view` scope for the Wardby resource;\n- enable the refresh-token grant and allow the `offline_access` scope. The\n viewer requests it so the provider returns a refresh token, and sign-in\n fails with \"server issued no refresh token\" without one.\n\nThe viewer prints its callback URL to stderr at startup. If sign-in reports\nthat it could not open the local callback listener on `127.0.0.1:8585`,\nanother program is using that port: close it and sign in again. In\nself-hosted mode the viewer registers itself, so there is no client to set up.\n\nFrom Wardby 0.6.0, admins can also sign in to a mobile app for the same read-only live view; see the help article `mobile-app`.\n\nThe Infrastructure tab shows the Kubernetes pods where your deployment runs\ncoding jobs, read-only. It uses your kubeconfig (switchable per server) and\nrequires a minimal read-only Kubernetes role. See the Infrastructure view\nsection of the [viewer README](../apps/viewer/README.md#infrastructure-view) for\nsetup. Its Map shows the request path (entry, protection layer such as Cloud\nArmor, routes), each NetworkPolicy with a plain-English summary, and on GKE a\nlink from each pod to the Google Cloud console. In low-power mode the sleeping\ncoding proxy and native gateway show as asleep (with when they last woke), and\na failed old replica next to a healthy one is greyed out rather than shown as a\nfailure. The run graph's zoom controls\ninclude **Fit width**, which fills the canvas with the graph's width.\n\nFrom Wardby 0.6.0 the API is also published as OpenAPI 3.1 (`docs/viewer-api.openapi.yml` in the package), an API contract you can feed to client generators such as `openapi-typescript`.\n\nFor parameters, status codes, frame formats and schemas, follow\n[`docs/viewer-api.md`](../docs/viewer-api.md).\n",
|
|
25
|
-
"plainText": "Watch live runs with the admin viewer API The admin viewer API is a read-only HTTP API for dashboards and desktop viewers. It shows every owner's runs across the deployment: sub-agent trees, what triggered each run, its outcomes (pull requests, comments, checks), and coding-run services, with a live event stream. It requires the Wardby admin role and the admin:view scope, which only the admin role grants. In delegating mode, define admin:view in your identity provider and map it like agents:admin. See Configure identity and privileged access. Endpoints, all GET: /admin/api/graph?since=1h&limit=500: a snapshot of runs in a time window. /admin/api/runs/<id: one run in full, including its final text and error. /admin/api/infra: how this deployment runs coding jobs (launcher, Kubernetes namespace, platform, run labels). /admin/api/events: a Server-Sent Events stream of live changes. The stream has no replay: open the event stream first, then load the graph, and refetch the graph on every resync event and after any reconnect. hello and status events report whether live events are flowing. Proxies and load balancers in front of Wardby must allow long-lived responses and not buffer text/event-stream. A desktop viewer for macOS is included in the source tree (apps/viewer). Add your server's canonical URI, sign in with an admin user in the browser, and it shows the live graph. Each GitHub release has an unsigned macOS build of the viewer attached (see the README for opening it past Gatekeeper). Its README covers setup, and what an external identity provider client needs when the server runs in delegating mode. Viewer sign-in with an external identity provider In delegating mode, the viewer signs in through your identity provider's public (native) client. That client must: register the exact redirect URI http://127.0.0.1:8585/callback. The viewer always listens on port 8585, and some providers (Okta, for example) match a loopback redirect by its exact port, so a port-less or wildcard loopback entry may not match; allow the admin:view scope for the Wardby resource; enable the refresh-token grant and allow the offlineaccess scope. The viewer requests it so the provider returns a refresh token, and sign-in fails with \"server issued no refresh token\" without one. The viewer prints its callback URL to stderr at startup. If sign-in reports that it could not open the local callback listener on 127.0.0.1:8585, another program is using that port: close it and sign in again. In self-hosted mode the viewer registers itself, so there is no client to set up. From Wardby 0.6.0, admins can also sign in to a mobile app for the same read-only live view; see the help article mobile-app. The Infrastructure tab shows the Kubernetes pods where your deployment runs coding jobs, read-only. It uses your kubeconfig (switchable per server) and requires a minimal read-only Kubernetes role. See the Infrastructure view section of the viewer README for setup. Its Map shows the request path (entry, protection layer such as Cloud Armor, routes), each NetworkPolicy with a plain-English summary, and on GKE a link from each pod to the Google Cloud console. In low-power mode the sleeping coding proxy and native gateway show as asleep (with when they last woke), and a failed old replica next to a healthy one is greyed out rather than shown as a failure. The run graph's zoom controls include Fit width, which fills the canvas with the graph's width. From Wardby 0.6.0 the API is also published as OpenAPI 3.1 (docs/viewer-api.openapi.yml in the package), an API contract you can feed to client generators such as openapi-typescript. For parameters, status codes, frame formats and schemas, follow docs/viewer-api.md.",
|
|
24
|
+
"markdown": "\n# Watch live runs with the admin viewer API\n\nThe admin viewer API is a read-only HTTP API for dashboards and desktop\nviewers. It shows every owner's runs across the deployment: sub-agent trees,\nwhat triggered each run, its outcomes (pull requests, comments, checks), and\ncoding-run services, with a live event stream.\n\nIt requires the Wardby `admin` role and the `admin:view` scope, which only the\n`admin` role grants. In delegating mode, define `admin:view` in your identity\nprovider and map it like `agents:admin`. See\n[Configure identity and privileged access](identity-and-access.md).\n\nFrom an MCP client, an admin gets the same deployment-wide listing with\n`list_agents` and `list_runs` and `all: true` (Wardby 0.8.0 and later; also\n`admin:view`). Without the role the call is refused.\n\nEndpoints, all `GET`:\n\n- `/admin/api/graph?since=1h&limit=500`: a snapshot of runs in a time window.\n- `/admin/api/runs/<id>`: one run in full, including its final text and error.\n From Wardby 0.9.0 it also lists the run's newest 200 steps (see `run-steps`).\n- `/admin/api/infra`: how this deployment runs coding jobs (launcher, Kubernetes namespace, platform, run labels).\n- `/admin/api/events`: a Server-Sent Events stream of live changes.\n\nThe stream has no replay: open the event stream first, then load the graph,\nand refetch the graph on every `resync` event and after any reconnect. `hello`\nand `status` events report whether live events are flowing. Proxies and load balancers in front of Wardby\nmust allow long-lived responses and not buffer `text/event-stream`.\n\nA desktop viewer for macOS is included in the source tree (`apps/viewer`). Add\nyour server's canonical URI, sign in with an `admin` user in the browser, and it\nshows the live graph. Each GitHub release has an unsigned macOS build of the viewer attached (see the README for opening it past Gatekeeper). Its README covers setup, and what an external identity\nprovider client needs when the server runs in delegating mode.\n\n## Viewer sign-in with an external identity provider\n\nIn delegating mode, the viewer signs in through your identity provider's\npublic (native) client. That client must:\n\n- register the exact redirect URI `http://127.0.0.1:8585/callback`. The viewer\n always listens on port 8585, and some providers (Okta, for example) match a\n loopback redirect by its exact port, so a port-less or wildcard loopback\n entry may not match;\n- allow the `admin:view` scope for the Wardby resource;\n- enable the refresh-token grant and allow the `offline_access` scope. The\n viewer requests it so the provider returns a refresh token, and sign-in\n fails with \"server issued no refresh token\" without one.\n\nThe viewer prints its callback URL to stderr at startup. If sign-in reports\nthat it could not open the local callback listener on `127.0.0.1:8585`,\nanother program is using that port: close it and sign in again. In\nself-hosted mode the viewer registers itself, so there is no client to set up.\n\nFrom Wardby 0.6.0, admins can also sign in to a mobile app for the same read-only live view; see the help article `mobile-app`.\n\nThe Infrastructure tab shows the Kubernetes pods where your deployment runs\ncoding jobs, read-only. It uses your kubeconfig (switchable per server) and\nrequires a minimal read-only Kubernetes role. See the Infrastructure view\nsection of the [viewer README](../apps/viewer/README.md#infrastructure-view) for\nsetup. Its Map shows the request path (entry, protection layer such as Cloud\nArmor, routes), each NetworkPolicy with a plain-English summary, and on GKE a\nlink from each pod to the Google Cloud console. In low-power mode the sleeping\ncoding proxy and native gateway show as asleep (with when they last woke), and\na failed old replica next to a healthy one is greyed out rather than shown as a\nfailure. The run graph's zoom controls\ninclude **Fit width**, which fills the canvas with the graph's width.\n\nFrom Wardby 0.6.0 the API is also published as OpenAPI 3.1 (`docs/viewer-api.openapi.yml` in the package), an API contract you can feed to client generators such as `openapi-typescript`.\n\nFor parameters, status codes, frame formats and schemas, follow\n[`docs/viewer-api.md`](../docs/viewer-api.md).\n",
|
|
25
|
+
"plainText": "Watch live runs with the admin viewer API The admin viewer API is a read-only HTTP API for dashboards and desktop viewers. It shows every owner's runs across the deployment: sub-agent trees, what triggered each run, its outcomes (pull requests, comments, checks), and coding-run services, with a live event stream. It requires the Wardby admin role and the admin:view scope, which only the admin role grants. In delegating mode, define admin:view in your identity provider and map it like agents:admin. See Configure identity and privileged access. From an MCP client, an admin gets the same deployment-wide listing with listagents and listruns and all: true (Wardby 0.8.0 and later; also admin:view). Without the role the call is refused. Endpoints, all GET: /admin/api/graph?since=1h&limit=500: a snapshot of runs in a time window. /admin/api/runs/<id: one run in full, including its final text and error. From Wardby 0.9.0 it also lists the run's newest 200 steps (see run-steps). /admin/api/infra: how this deployment runs coding jobs (launcher, Kubernetes namespace, platform, run labels). /admin/api/events: a Server-Sent Events stream of live changes. The stream has no replay: open the event stream first, then load the graph, and refetch the graph on every resync event and after any reconnect. hello and status events report whether live events are flowing. Proxies and load balancers in front of Wardby must allow long-lived responses and not buffer text/event-stream. A desktop viewer for macOS is included in the source tree (apps/viewer). Add your server's canonical URI, sign in with an admin user in the browser, and it shows the live graph. Each GitHub release has an unsigned macOS build of the viewer attached (see the README for opening it past Gatekeeper). Its README covers setup, and what an external identity provider client needs when the server runs in delegating mode. Viewer sign-in with an external identity provider In delegating mode, the viewer signs in through your identity provider's public (native) client. That client must: register the exact redirect URI http://127.0.0.1:8585/callback. The viewer always listens on port 8585, and some providers (Okta, for example) match a loopback redirect by its exact port, so a port-less or wildcard loopback entry may not match; allow the admin:view scope for the Wardby resource; enable the refresh-token grant and allow the offlineaccess scope. The viewer requests it so the provider returns a refresh token, and sign-in fails with \"server issued no refresh token\" without one. The viewer prints its callback URL to stderr at startup. If sign-in reports that it could not open the local callback listener on 127.0.0.1:8585, another program is using that port: close it and sign in again. In self-hosted mode the viewer registers itself, so there is no client to set up. From Wardby 0.6.0, admins can also sign in to a mobile app for the same read-only live view; see the help article mobile-app. The Infrastructure tab shows the Kubernetes pods where your deployment runs coding jobs, read-only. It uses your kubeconfig (switchable per server) and requires a minimal read-only Kubernetes role. See the Infrastructure view section of the viewer README for setup. Its Map shows the request path (entry, protection layer such as Cloud Armor, routes), each NetworkPolicy with a plain-English summary, and on GKE a link from each pod to the Google Cloud console. In low-power mode the sleeping coding proxy and native gateway show as asleep (with when they last woke), and a failed old replica next to a healthy one is greyed out rather than shown as a failure. The run graph's zoom controls include Fit width, which fills the canvas with the graph's width. From Wardby 0.6.0 the API is also published as OpenAPI 3.1 (docs/viewer-api.openapi.yml in the package), an API contract you can feed to client generators such as openapi-typescript. For parameters, status codes, frame formats and schemas, follow docs/viewer-api.md.",
|
|
26
26
|
"headings": [
|
|
27
27
|
{
|
|
28
28
|
"level": 1,
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
],
|
|
59
59
|
"appliesTo": ">=0.4.0",
|
|
60
60
|
"sourcePath": "agent-recipes.md",
|
|
61
|
-
"markdown": "\n# Agent recipes\n\nTwo complete setups: an **architecture keeper** (a scheduled architect coding\nagent, a merge watcher with the `push` trigger, and a reviewer step that uses\n`docs/knowledge/`) and a **builder** (a native router linked with `mention` that\ndelegates to a coding builder, for Node/TypeScript, Python, or a\nbring-your-own-image toolchain).\n\nThey go beyond the quickstart. Its optional coding step sets up a builder and a\nreviewer on a local git repository, with no GitHub App (see the\n`local-repositories` article). These recipes react to GitHub events (`push`,\n`mention`, pull requests), so they require Wardby 0.4.0 or later, plus the\nGitHub App, worker image, and job launcher from coding-agent setup. The full recipes, with every configuration and prompt, are\nin [`docs/agent-recipes.md`](../docs/agent-recipes.md).\n\nIf you are an assistant connected to Wardby over MCP, follow these steps. Do\nthem in order, ask the user instead of guessing, and stop at the first failed\nprerequisite.\n\n## Step 0: choose\n\nAsk the user:\n\n1. Which recipe: \"architecture keeper\" or \"builder\"?\n2. Which repository, as `owner/name`?\n3. The coding provider, `codex` or `claude-code`, for both recipes (the\n architect is a coding agent too). Never guess it.\n4. For the builder only: the language or stack, which decides `toolchain`\n (`node` for Node/TypeScript, `node-python` with `toolchainVersion: \"3.12\"`\n for Python, or a bring-your-own worker image for anything else).\n\nAgent names are unique across the whole instance, so the recipes use\nrepo-scoped names: `<repo>-architect`, `<repo>-merge-watcher`, `<repo>-builder`,\nand `<repo>-router`, where `<repo>` is the repository name from `owner/name`.\nCall `list_agents` first; if a name is taken, ask the user for another. Keep the\n`boundName` values `architect` and `builder` unchanged, so the delegate tools\nstay `delegate_to_architect` and `delegate_to_builder`.\n\n## Step 1: check prerequisites\n\nCheck these before creating anything.\n\n1. **Local install.** Over the local stdio connection `link_host_account` is\n not available (it needs Wardby's HTTP transport), and a quickstart-only\n install has no GitHub App or coding workers. If that is your situation,\n explain it to the user and point them to\n [`docs/coding-agent-setup.md`](../docs/coding-agent-setup.md) instead of\n trying.\n2. **GitHub account link.** Call `get_host_account`. If `accounts` is empty,\n call `link_host_account` with no arguments, give the user the `authorizeUrl`,\n and when they return the one-time code, call `link_host_account` again with\n `confirmationCode`.\n3. **Repository access.** No tool lists the repositories the GitHub App can\n see. The linked account needs write access to the repository, and both\n `create_agent` (with a `codingProfile`) and `link_repository` check this and\n refuse with a clear error if it is missing. Ask the user to confirm the GitHub\n App is installed on the repository. Do not use `adminOverride` or\n `repositoryAdminOverride` unless the user is an admin and asks for it.\n4. **Models.** Call `list_models` and pick ids whose `routable` is true: a\n capable coding model that the chosen provider supports, and a small fast model\n for the native agent.\n5. **Coding-agent setup.** If coding agents are not set up yet, tell the user to\n run `wardby coding preflight` (CLI) and finish coding-agent setup first. See\n [`docs/coding-agent-setup.md`](../docs/coding-agent-setup.md).\n6. **Webhooks.** Event triggers need GitHub to reach the instance at a public\n HTTPS URL, with the App's events ticked: **Push** for the merge watcher;\n **Issue comment**, **Pull request review comment**, and **Issues** for\n mentions. Scheduled and manual runs need no webhook.\n\nIf a prerequisite fails, stop and tell the user what to do. Do not create agents.\n\n## Step 2A: architecture keeper\n\n1. Call `get_help_article` with `id: \"architecture-agent\"`. It holds the\n architect system prompt (\"System prompt\"), the watcher prompt, and the\n reviewer step. Use them unchanged.\n2. Call `create_agent` for the architect: `name: \"<repo>-architect\"`, `kind: \"coding\"`,\n `model` a capable coding model, `budgetUsd: 3`, `systemPrompt` the architect\n prompt, and `codingProfile` with `provider`, `repository`, `baseRef` (the\n default branch), and `defaultTask`: `Weekly knowledge review. Run the full\ncycle described in your instructions for this repository. Your file changes\nare collected into a pull request for review; don't try to commit or open one\nyourself.`\n3. Tell the user the run is billed up to the agent's budget ($3) and get their\n confirmation. Then call `trigger_agent` once with the architect's `agentId`\n and show them the run (`get_run`). If the run failed or produced no pull\n request, stop and show the error or summary; never call `set_schedule` after a\n failed run. Otherwise **stop** and ask them to review and merge the first\n draft pull request before continuing.\n4. When they say to continue, call `set_schedule` with the architect's\n `agentId`, `schedule: \"0 6 * * 1\"`, and the user's `timezone`.\n5. Call `create_agent` for the watcher: `name: \"<repo>-merge-watcher\"`,\n `kind: \"native\"`, a small fast `model`, the watcher prompt as `systemPrompt`,\n and a `budgetUsd` of at least 3 plus a little (the run tree shares one\n budget).\n6. Call `attach_subagent` with `parentAgentId` the watcher, `childAgentId` the\n architect, and `boundName: \"architect\"`.\n7. Ask the user to tick **Push** in the GitHub App's event settings (and keep\n Contents: read). Wait for their confirmation.\n8. Call `link_repository` with `agentId` the watcher, `repository`,\n `access: \"write\"`, and `triggers: [\"push\"]`. Send no `checkName`.\n9. Offer the reviewer step: if the user has a code-review agent, offer to append\n the \"Reviewer step\" from the same article to its prompt with `update_agent`\n (read it first with `get_agent`, and keep its existing prompt).\n\n## Step 2B: builder\n\n1. **Check for a mention conflict first**, before creating anything. Call\n `list_agents`, then `list_repositories` for each native agent you can see, to\n find one linked to the repository with the `mention` trigger (only one agent\n per repository may handle mentions). If one exists, reuse it as the router\n only if the user owns it and agrees; then attach the builder to it and skip\n creating a router. Never unlink or relink another agent.\n2. Ask the user to confirm the GitHub App subscribes to **Issue comment**,\n **Pull request review comment**, and **Issues** events.\n3. Call `create_agent` for the builder: `name: \"<repo>-builder\"`,\n `kind: \"coding\"`, a `model` the chosen provider supports, `budgetUsd` such as\n `5`, `systemPrompt` the prompt from `get_help_article` with\n `id: \"builder-agent\"` (section \"Builder prompt\"), and a `codingProfile` with\n `provider`, `repository`, `baseRef`, and `timeoutSec` (for example `1800`),\n plus the stack settings:\n - Node/TypeScript: `toolchain: \"node\"`, with `packageAllowlist` such as\n `{ \"npm\": [\"react@^19\", \"vitest\"] }`.\n - Python: `toolchain: \"node-python\"`, `toolchainVersion: \"3.12\"`, with\n `packageAllowlist` such as `{ \"pypi\": [\"flask>=3\"] }` (wheels only; list a\n wheel package's own name, not an extra). Add `services: [\"postgres\"]` if\n tests need a database: the repository must commit `.wardby/services.yaml`\n declaring it, and the name must be in the catalog (`list_services`), or\n `create_agent` returns 400.\n - Other: `toolchain: \"node\"` plus a digest-pinned `workerImageRef`. Ask the\n user for the image reference; never invent one. It needs the `agents:admin`\n scope; if the user lacks it, stop and say so.\n\n A `packageAllowlist` needs `packages:approve` or `agents:admin`.\n\n4. If you are not reusing a router, call `create_agent` with\n `name: \"<repo>-router\"`, `kind: \"native\"`, a small fast `model`, a `budgetUsd`\n of the builder's budget plus a little, and the router prompt from\n `get_help_article` with `id: \"builder-agent\"` (section \"Router prompt\").\n5. Call `attach_subagent` with `parentAgentId` the router, `childAgentId` the\n builder, and `boundName: \"builder\"`.\n6. Call `link_repository` with `agentId` the router, `repository`,\n `access: \"write\"`, and `triggers: [\"mention\"]`. If it returns the 409\n \"Another agent already handles @-mentions\", **stop** and tell the user, and\n list the agents you created. Never unlink or relink another agent. If linking\n fails for any reason after you created agents, tell the user what was created.\n7. Ask the user to try one `@<app-slug>` request on an issue, where\n `<app-slug>` is the GitHub App's name. A test run is billed up to the\n builder's budget; say so first.\n\n## Step 2C (optional): a lead that fans out\n\nA router delegates once per run by default. For one native agent that splits a\nrequest across several repositories, attach one builder per repository and set\nthe lead's `maxDelegationsPerRun` (1 to 20) with `create_agent` or\n`update_agent`. Each `delegate_to_<name>` call must go to a different\nsub-agent; the calls run one after another unless you also set\n`parallelDelegations: true`, which starts only the **consecutive**\n`delegate_to_*` calls of one turn together — a non-delegation call between\ntwo delegations splits them, nothing is reordered, and results return to the\nlead in call order (tell the lead to make its independent delegations\nconsecutively, in one turn; coding builders beyond `CODING_MAX_CONCURRENT`\nqueue); the run tree shares the lead's budget, so size `budgetUsd` for every\nbuilder it may start. Builders started together each reserve their budget up\nfront, so size the lead's `budgetUsd` for all of them, with headroom since\nthe lead's own unspent budget isn't reserved against them; a builder refused\nfor budget while a sibling still runs waits for it and retries (otherwise the\nrefusal is immediate). Cancelling the lead stops a running coding sub-agent\nbut not a running native one. Put the full cross-repository contract in each\nbuilder's task, since each builder sees only its own repository. Each\nbuilder's result includes `pullRequest` (`outcome`,\n`repository`, `number`, `url`) from Wardby's own record when it opened or\npushed to one, so the lead can report the links.\n\nWhen the builders' changes must land in a particular order, pass `mergeOrder`\n(1 to 99, 1 first) in each `delegate_to_<name>` call — give a dependency a\nlower number than what calls it, and give two changes the same number when\nthere is no order between them:\n\n```json\n{ \"task\": \"Add the /quotes endpoint the client will call.\", \"mergeOrder\": 1 }\n```\n\n```json\n{ \"task\": \"Add the quotes page that calls /quotes.\", \"mergeOrder\": 2 }\n```\n\nLeave `mergeOrder` out and the pull requests' **Related pull requests**\nsection lists them in delegation order instead, labelled as a suggestion\nrather than a set order. It applies only to coding sub-agents; a native\nsub-agent ignores it. A follow-up that continues one of these pull requests\nwith `continuePriorRun` and no `mergeOrder` of its own keeps the pull\nrequest's current value (the one most recently set for it, by the run that\nopened it or a later continuation); one that passes `mergeOrder` replaces\nit.\n\nWith Wardby 0.6.0 or later, once a set has more than one `mergeOrder`, each\npull request in it also gets a `wardby merge order` check run showing\nwhether its earlier steps have merged yet; search help for \"merge order\ncheck\" for its states and for requiring it in branch protection.\n\n## Step 3: confirm\n\nSummarize what you created: each agent's name and id, the sub-agent bindings,\nthe repository links and their triggers, and the schedule. Then state the next\nmanual step for the user: merge the first knowledge pull request, tick any App\nevents still missing, or try the first `@` mention. Remind them that Wardby never\nmerges pull requests for them.\n\nRelated: [Builder and router prompts](help://builder-agent),\n[Set up an architecture agent](help://architecture-agent),\n[Architecture knowledge bundles](help://knowledge),\n[Choose a native or coding agent](help://creating-agents),\n[Connect GitHub repositories](help://github-integration),\n[Run GitHub code-review agents](help://code-review-agents),\n[Approve packages for coding agents](help://coding-packages), and\n[Services for coding runs](help://coding-services).\n",
|
|
62
|
-
"plainText": "Agent recipes Two complete setups: an architecture keeper (a scheduled architect coding agent, a merge watcher with the push trigger, and a reviewer step that uses docs/knowledge/) and a builder (a native router linked with mention that delegates to a coding builder, for Node/TypeScript, Python, or a bring-your-own-image toolchain). They go beyond the quickstart. Its optional coding step sets up a builder and a reviewer on a local git repository, with no GitHub App (see the local-repositories article). These recipes react to GitHub events (push, mention, pull requests), so they require Wardby 0.4.0 or later, plus the GitHub App, worker image, and job launcher from coding-agent setup. The full recipes, with every configuration and prompt, are in docs/agent-recipes.md. If you are an assistant connected to Wardby over MCP, follow these steps. Do them in order, ask the user instead of guessing, and stop at the first failed prerequisite. Step 0: choose Ask the user: Which recipe: \"architecture keeper\" or \"builder\"? Which repository, as owner/name? The coding provider, codex or claude-code, for both recipes (the architect is a coding agent too). Never guess it. For the builder only: the language or stack, which decides toolchain (node for Node/TypeScript, node-python with toolchainVersion: \"3.12\" for Python, or a bring-your-own worker image for anything else). Agent names are unique across the whole instance, so the recipes use repo-scoped names: <repo-architect, <repo-merge-watcher, <repo-builder, and <repo-router, where <repo is the repository name from owner/name. Call listagents first; if a name is taken, ask the user for another. Keep the boundName values architect and builder unchanged, so the delegate tools stay delegatetoarchitect and delegatetobuilder. Step 1: check prerequisites Check these before creating anything. Local install. Over the local stdio connection linkhostaccount is not available (it needs Wardby's HTTP transport), and a quickstart-only install has no GitHub App or coding workers. If that is your situation, explain it to the user and point them to docs/coding-agent-setup.md instead of trying. GitHub account link. Call gethostaccount. If accounts is empty, call linkhostaccount with no arguments, give the user the authorizeUrl, and when they return the one-time code, call linkhostaccount again with confirmationCode. Repository access. No tool lists the repositories the GitHub App can see. The linked account needs write access to the repository, and both createagent (with a codingProfile) and linkrepository check this and refuse with a clear error if it is missing. Ask the user to confirm the GitHub App is installed on the repository. Do not use adminOverride or repositoryAdminOverride unless the user is an admin and asks for it. Models. Call listmodels and pick ids whose routable is true: a capable coding model that the chosen provider supports, and a small fast model for the native agent. Coding-agent setup. If coding agents are not set up yet, tell the user to run wardby coding preflight (CLI) and finish coding-agent setup first. See docs/coding-agent-setup.md. Webhooks. Event triggers need GitHub to reach the instance at a public HTTPS URL, with the App's events ticked: Push for the merge watcher; Issue comment, Pull request review comment, and Issues for mentions. Scheduled and manual runs need no webhook. If a prerequisite fails, stop and tell the user what to do. Do not create agents. Step 2A: architecture keeper Call gethelparticle with id: \"architecture-agent\". It holds the architect system prompt (\"System prompt\"), the watcher prompt, and the reviewer step. Use them unchanged. Call createagent for the architect: name: \"<repo-architect\", kind: \"coding\", model a capable coding model, budgetUsd: 3, systemPrompt the architect prompt, and codingProfile with provider, repository, baseRef (the default branch), and defaultTask: Weekly knowledge review. Run the full cycle described in your instructions for this repository. Your file changes are collected into a pull request for review; don't try to commit or open one yourself. Tell the user the run is billed up to the agent's budget ($3) and get their confirmation. Then call triggeragent once with the architect's agentId and show them the run (getrun). If the run failed or produced no pull request, stop and show the error or summary; never call setschedule after a failed run. Otherwise stop and ask them to review and merge the first draft pull request before continuing. When they say to continue, call setschedule with the architect's agentId, schedule: \"0 6 1\", and the user's timezone. Call createagent for the watcher: name: \"<repo-merge-watcher\", kind: \"native\", a small fast model, the watcher prompt as systemPrompt, and a budgetUsd of at least 3 plus a little (the run tree shares one budget). Call attachsubagent with parentAgentId the watcher, childAgentId the architect, and boundName: \"architect\". Ask the user to tick Push in the GitHub App's event settings (and keep Contents: read). Wait for their confirmation. Call linkrepository with agentId the watcher, repository, access: \"write\", and triggers: [\"push\"]. Send no checkName. Offer the reviewer step: if the user has a code-review agent, offer to append the \"Reviewer step\" from the same article to its prompt with updateagent (read it first with getagent, and keep its existing prompt). Step 2B: builder Check for a mention conflict first, before creating anything. Call listagents, then listrepositories for each native agent you can see, to find one linked to the repository with the mention trigger (only one agent per repository may handle mentions). If one exists, reuse it as the router only if the user owns it and agrees; then attach the builder to it and skip creating a router. Never unlink or relink another agent. Ask the user to confirm the GitHub App subscribes to Issue comment, Pull request review comment, and Issues events. Call createagent for the builder: name: \"<repo-builder\", kind: \"coding\", a model the chosen provider supports, budgetUsd such as 5, systemPrompt the prompt from gethelparticle with id: \"builder-agent\" (section \"Builder prompt\"), and a codingProfile with provider, repository, baseRef, and timeoutSec (for example 1800), plus the stack settings: Node/TypeScript: toolchain: \"node\", with packageAllowlist such as { \"npm\": [\"react@^19\", \"vitest\"] }. Python: toolchain: \"node-python\", toolchainVersion: \"3.12\", with packageAllowlist such as { \"pypi\": [\"flask=3\"] } (wheels only; list a wheel package's own name, not an extra). Add services: [\"postgres\"] if tests need a database: the repository must commit .wardby/services.yaml declaring it, and the name must be in the catalog (listservices), or createagent returns 400. Other: toolchain: \"node\" plus a digest-pinned workerImageRef. Ask the user for the image reference; never invent one. It needs the agents:admin scope; if the user lacks it, stop and say so. A packageAllowlist needs packages:approve or agents:admin. If you are not reusing a router, call createagent with name: \"<repo-router\", kind: \"native\", a small fast model, a budgetUsd of the builder's budget plus a little, and the router prompt from gethelparticle with id: \"builder-agent\" (section \"Router prompt\"). Call attachsubagent with parentAgentId the router, childAgentId the builder, and boundName: \"builder\". Call linkrepository with agentId the router, repository, access: \"write\", and triggers: [\"mention\"]. If it returns the 409 \"Another agent already handles @-mentions\", stop and tell the user, and list the agents you created. Never unlink or relink another agent. If linking fails for any reason after you created agents, tell the user what was created. Ask the user to try one @<app-slug request on an issue, where <app-slug is the GitHub App's name. A test run is billed up to the builder's budget; say so first. Step 2C (optional): a lead that fans out A router delegates once per run by default. For one native agent that splits a request across several repositories, attach one builder per repository and set the lead's maxDelegationsPerRun (1 to 20) with createagent or updateagent. Each delegateto<name call must go to a different sub-agent; the calls run one after another unless you also set parallelDelegations: true, which starts only the consecutive delegateto calls of one turn together — a non-delegation call between two delegations splits them, nothing is reordered, and results return to the lead in call order (tell the lead to make its independent delegations consecutively, in one turn; coding builders beyond CODINGMAXCONCURRENT queue); the run tree shares the lead's budget, so size budgetUsd for every builder it may start. Builders started together each reserve their budget up front, so size the lead's budgetUsd for all of them, with headroom since the lead's own unspent budget isn't reserved against them; a builder refused for budget while a sibling still runs waits for it and retries (otherwise the refusal is immediate). Cancelling the lead stops a running coding sub-agent but not a running native one. Put the full cross-repository contract in each builder's task, since each builder sees only its own repository. Each builder's result includes pullRequest (outcome, repository, number, url) from Wardby's own record when it opened or pushed to one, so the lead can report the links. When the builders' changes must land in a particular order, pass mergeOrder (1 to 99, 1 first) in each delegateto<name call — give a dependency a lower number than what calls it, and give two changes the same number when there is no order between them: { \"task\": \"Add the /quotes endpoint the client will call.\", \"mergeOrder\": 1 } { \"task\": \"Add the quotes page that calls /quotes.\", \"mergeOrder\": 2 } Leave mergeOrder out and the pull requests' Related pull requests section lists them in delegation order instead, labelled as a suggestion rather than a set order. It applies only to coding sub-agents; a native sub-agent ignores it. A follow-up that continues one of these pull requests with continuePriorRun and no mergeOrder of its own keeps the pull request's current value (the one most recently set for it, by the run that opened it or a later continuation); one that passes mergeOrder replaces it. With Wardby 0.6.0 or later, once a set has more than one mergeOrder, each pull request in it also gets a wardby merge order check run showing whether its earlier steps have merged yet; search help for \"merge order check\" for its states and for requiring it in branch protection. Step 3: confirm Summarize what you created: each agent's name and id, the sub-agent bindings, the repository links and their triggers, and the schedule. Then state the next manual step for the user: merge the first knowledge pull request, tick any App events still missing, or try the first @ mention. Remind them that Wardby never merges pull requests for them. Related: Builder and router prompts, Set up an architecture agent, Architecture knowledge bundles, Choose a native or coding agent, Connect GitHub repositories, Run GitHub code-review agents, Approve packages for coding agents, and Services for coding runs.",
|
|
61
|
+
"markdown": "\n# Agent recipes\n\nTwo complete setups: an **architecture keeper** (a scheduled architect coding\nagent, a merge watcher with the `push` trigger, and a reviewer step that uses\n`docs/knowledge/`) and a **builder** (a native router linked with `mention` that\ndelegates to a coding builder, for Node/TypeScript, Python, or a\nbring-your-own-image toolchain).\n\nThey go beyond the quickstart. Its optional coding step sets up a builder and a\nreviewer on a local git repository, with no GitHub App (see the\n`local-repositories` article). These recipes react to GitHub events (`push`,\n`mention`, pull requests), so they require Wardby 0.4.0 or later, plus the\nGitHub App, worker image, and job launcher from coding-agent setup. The full recipes, with every configuration and prompt, are\nin [`docs/agent-recipes.md`](../docs/agent-recipes.md).\n\nIf you are an assistant connected to Wardby over MCP, follow these steps. Do\nthem in order, ask the user instead of guessing, and stop at the first failed\nprerequisite.\n\n## Step 0: choose\n\nAsk the user:\n\n1. Which recipe: \"architecture keeper\" or \"builder\"?\n2. Which repository, as `owner/name`?\n3. The coding provider, `codex` or `claude-code`, for both recipes (the\n architect is a coding agent too). Never guess it.\n4. For the builder only: the language or stack, which decides `toolchain`\n (`node` for Node/TypeScript, `node-python` with `toolchainVersion: \"3.12\"`\n for Python, or a bring-your-own worker image for anything else).\n\nAgent names are unique across the whole instance, so the recipes use\nrepo-scoped names: `<repo>-architect`, `<repo>-merge-watcher`, `<repo>-builder`,\nand `<repo>-router`, where `<repo>` is the repository name from `owner/name`.\nCall `list_agents` first; if a name is taken, ask the user for another. Keep the\n`boundName` values `architect` and `builder` unchanged, so the delegate tools\nstay `delegate_to_architect` and `delegate_to_builder`.\n\n## Step 1: check prerequisites\n\nCheck these before creating anything.\n\n1. **Local install.** Over the local stdio connection `link_host_account` is\n not available (it needs Wardby's HTTP transport), and a quickstart-only\n install has no GitHub App or coding workers. If that is your situation,\n explain it to the user and point them to\n [`docs/coding-agent-setup.md`](../docs/coding-agent-setup.md) instead of\n trying.\n2. **GitHub account link.** Call `get_host_account`. If `accounts` is empty,\n call `link_host_account` with no arguments, give the user the `authorizeUrl`,\n and when they return the one-time code, call `link_host_account` again with\n `confirmationCode`.\n3. **Repository access.** No tool lists the repositories the GitHub App can\n see. The linked account needs write access to the repository, and both\n `create_agent` (with a `codingProfile`) and `link_repository` check this and\n refuse with a clear error if it is missing. Ask the user to confirm the GitHub\n App is installed on the repository. Do not use `adminOverride` or\n `repositoryAdminOverride` unless the user is an admin and asks for it.\n4. **Models.** Call `list_models` and pick ids whose `routable` is true: a\n capable coding model that the chosen provider supports, and a small fast model\n for the native agent.\n5. **Coding-agent setup.** If coding agents are not set up yet, tell the user to\n run `wardby coding preflight` (CLI) and finish coding-agent setup first. See\n [`docs/coding-agent-setup.md`](../docs/coding-agent-setup.md).\n6. **Webhooks.** Event triggers need GitHub to reach the instance at a public\n HTTPS URL, with the App's events ticked: **Push** for the merge watcher;\n **Issue comment**, **Pull request review comment**, and **Issues** for\n mentions. Scheduled and manual runs need no webhook.\n\nIf a prerequisite fails, stop and tell the user what to do. Do not create agents.\n\n## Step 2A: architecture keeper\n\n1. Call `get_help_article` with `id: \"architecture-agent\"`. It holds the\n architect system prompt (\"System prompt\"), the watcher prompt, and the\n reviewer step. Use them unchanged.\n2. Call `create_agent` for the architect: `name: \"<repo>-architect\"`, `kind: \"coding\"`,\n `model` a capable coding model, `budgetUsd: 3`, `systemPrompt` the architect\n prompt, and `codingProfile` with `provider`, `repository`, `baseRef` (the\n default branch), and `defaultTask`: `Weekly knowledge review. Run the full\ncycle described in your instructions for this repository. Your file changes\nare collected into a pull request for review; don't try to commit or open one\nyourself.`\n3. Tell the user the run is billed up to the agent's budget ($3) and get their\n confirmation. Then call `trigger_agent` once with the architect's `agentId`\n and show them the run (`get_run`). If the run failed or produced no pull\n request, stop and show the error or summary; never call `set_schedule` after a\n failed run. Otherwise **stop** and ask them to review and merge the first\n draft pull request before continuing.\n4. When they say to continue, call `set_schedule` with the architect's\n `agentId`, `schedule: \"0 6 * * 1\"`, and the user's `timezone`.\n5. Call `create_agent` for the watcher: `name: \"<repo>-merge-watcher\"`,\n `kind: \"native\"`, a small fast `model`, the watcher prompt as `systemPrompt`,\n and a `budgetUsd` of at least 3 plus a little (the run tree shares one\n budget).\n6. Call `attach_subagent` with `parentAgentId` the watcher, `childAgentId` the\n architect, and `boundName: \"architect\"`.\n7. Ask the user to tick **Push** in the GitHub App's event settings (and keep\n Contents: read). Wait for their confirmation.\n8. Call `link_repository` with `agentId` the watcher, `repository`,\n `access: \"write\"`, and `triggers: [\"push\"]`. Send no `checkName`.\n9. Offer the reviewer step: if the user has a code-review agent, offer to append\n the \"Reviewer step\" from the same article to its prompt with `update_agent`\n (read it first with `get_agent`, and keep its existing prompt).\n\n## Step 2B: builder\n\n1. **Check for a mention conflict first**, before creating anything. Call\n `list_agents`, then `list_repositories` for each native agent you can see, to\n find one linked to the repository with the `mention` trigger (only one agent\n per repository may handle mentions). If one exists, reuse it as the router\n only if the user owns it and agrees; then attach the builder to it and skip\n creating a router. Never unlink or relink another agent.\n2. Ask the user to confirm the GitHub App subscribes to **Issue comment**,\n **Pull request review comment**, and **Issues** events.\n3. Call `create_agent` for the builder: `name: \"<repo>-builder\"`,\n `kind: \"coding\"`, a `model` the chosen provider supports, `budgetUsd` such as\n `5`, `systemPrompt` the prompt from `get_help_article` with\n `id: \"builder-agent\"` (section \"Builder prompt\"), and a `codingProfile` with\n `provider`, `repository`, `baseRef`, and `timeoutSec` (for example `1800`),\n plus the stack settings:\n - Node/TypeScript: `toolchain: \"node\"`, with `packageAllowlist` such as\n `{ \"npm\": [\"react@^19\", \"vitest\"] }`.\n - Python: `toolchain: \"node-python\"`, `toolchainVersion: \"3.12\"`, with\n `packageAllowlist` such as `{ \"pypi\": [\"flask>=3\"] }` (wheels only; list a\n wheel package's own name, not an extra). Add `services: [\"postgres\"]` if\n tests need a database: the repository must commit `.wardby/services.yaml`\n declaring it, and the name must be in the catalog (`list_services`), or\n `create_agent` returns 400.\n - Other: `toolchain: \"node\"` plus a digest-pinned `workerImageRef`. Ask the\n user for the image reference; never invent one. It needs the `agents:admin`\n scope; if the user lacks it, stop and say so.\n\n A `packageAllowlist` needs `packages:approve` or `agents:admin`.\n\n4. If you are not reusing a router, call `create_agent` with\n `name: \"<repo>-router\"`, `kind: \"native\"`, a small fast `model`, a `budgetUsd`\n of the builder's budget plus a little, and the router prompt from\n `get_help_article` with `id: \"builder-agent\"` (section \"Router prompt\").\n5. Call `attach_subagent` with `parentAgentId` the router, `childAgentId` the\n builder, and `boundName: \"builder\"`.\n6. Call `link_repository` with `agentId` the router, `repository`,\n `access: \"write\"`, and `triggers: [\"mention\"]`. If it returns the 409\n \"Another agent already handles @-mentions\", **stop** and tell the user, and\n list the agents you created. Never unlink or relink another agent. If linking\n fails for any reason after you created agents, tell the user what was created.\n7. Ask the user to try one `@<app-slug>` request on an issue, where\n `<app-slug>` is the GitHub App's name. A test run is billed up to the\n builder's budget; say so first.\n\n## Step 2C (optional): a lead that fans out\n\nA router delegates once per run by default. For one native agent that splits a\nrequest across several repositories, attach one builder per repository and set\nthe lead's `maxDelegationsPerRun` (1 to 20) with `create_agent` or\n`update_agent`. A run delegates to each sub-agent and repository at most\nonce; the calls run one after another unless you also set\n`parallelDelegations: true`, which starts only the **consecutive**\n`delegate_to_*` calls of one turn together — a non-delegation call between\ntwo delegations splits them, nothing is reordered, and results return to the\nlead in call order (tell the lead to make its independent delegations\nconsecutively, in one turn; coding builders beyond `CODING_MAX_CONCURRENT`\nqueue); the run tree shares the lead's budget, so size `budgetUsd` for every\nbuilder it may start. Builders started together each reserve their budget up\nfront, so size the lead's `budgetUsd` for all of them, with headroom since\nthe lead's own unspent budget isn't reserved against them; a builder refused\nfor budget while a sibling still runs waits for it and retries (otherwise the\nrefusal is immediate). Cancelling the lead stops a running coding sub-agent\nbut not a running native one. Put the full cross-repository contract in each\nbuilder's task, since each builder sees only its own repository. Each\nbuilder's result includes `pullRequest` (`outcome`,\n`repository`, `number`, `url`) from Wardby's own record when it opened or\npushed to one, so the lead can report the links.\n\nWhen the builders' changes must land in a particular order, pass `mergeOrder`\n(1 to 99, 1 first) in each `delegate_to_<name>` call — give a dependency a\nlower number than what calls it, and give two changes the same number when\nthere is no order between them:\n\n```json\n{ \"task\": \"Add the /quotes endpoint the client will call.\", \"mergeOrder\": 1 }\n```\n\n```json\n{ \"task\": \"Add the quotes page that calls /quotes.\", \"mergeOrder\": 2 }\n```\n\nLeave `mergeOrder` out and the pull requests' **Related pull requests**\nsection lists them in delegation order instead, labelled as a suggestion\nrather than a set order. It applies only to coding sub-agents; a native\nsub-agent ignores it. A follow-up that continues one of these pull requests\nwith `continuePriorRun` and no `mergeOrder` of its own keeps the pull\nrequest's current value (the one most recently set for it, by the run that\nopened it or a later continuation); one that passes `mergeOrder` replaces\nit.\n\nWith Wardby 0.6.0 or later, once a set has more than one `mergeOrder`, each\npull request in it also gets a `wardby merge order` check run showing\nwhether its earlier steps have merged yet; search help for \"merge order\ncheck\" for its states and for requiring it in branch protection.\n\n**One coding agent across several repositories.** Instead of one builder per\nrepository, give one coding builder a list: its default in\n`codingProfile.repository`, and each other repository with `link_repository`\n(`access: \"write\"`, no triggers). The lead then names the repository on each\ncall, and may delegate to the same builder once per repository:\n\n```json\n{ \"task\": \"Add the /quotes endpoint the client will call.\", \"repository\": \"your-org/api\", \"mergeOrder\": 1 }\n```\n\n```json\n{ \"task\": \"Add the quotes page that calls /quotes.\", \"repository\": \"your-org/web\", \"mergeOrder\": 2 }\n```\n\nSet `maxDelegationsPerRun` (up to 20) for the number of calls, and use\n`mergeOrder` where the pull requests must land in order. A call without\n`repository` is refused with `repository_required` (unless it continues a prior\nrun with `continuePriorRun`), and a repository not on the list with\n`repository_not_listed`. A native sub-agent refuses `repository` with\n`repository_requires_coding_agent`. The lead sees the list in the tool\ndefinition only when it has the same owner as the builder, or another owner\nwith execute access to a builder that sets `allowWebhookTaskOverride`. All\nrepositories share the builder's toolchain, budget and prompt.\n\nBeing on the list lets a run work in a repository; it starts nothing there. Link\nthe lead and the reviewer on each listed GitHub repository with the triggers\nthey need, or a pull request opened there gets no review, mention follow-up, fix\nround or mark-ready.\n\nSearch help for `repository_required` or `repository_not_listed` for what to do about those refusals.\n\n## Step 3: confirm\n\nSummarize what you created: each agent's name and id, the sub-agent bindings,\nthe repository links and their triggers, and the schedule. Then state the next\nmanual step for the user: merge the first knowledge pull request, tick any App\nevents still missing, or try the first `@` mention. Remind them that Wardby never\nmerges pull requests for them.\n\nRelated: [Builder and router prompts](help://builder-agent),\n[Set up an architecture agent](help://architecture-agent),\n[Architecture knowledge bundles](help://knowledge),\n[Choose a native or coding agent](help://creating-agents),\n[Connect GitHub repositories](help://github-integration),\n[Run GitHub code-review agents](help://code-review-agents),\n[Approve packages for coding agents](help://coding-packages), and\n[Services for coding runs](help://coding-services).\n",
|
|
62
|
+
"plainText": "Agent recipes Two complete setups: an architecture keeper (a scheduled architect coding agent, a merge watcher with the push trigger, and a reviewer step that uses docs/knowledge/) and a builder (a native router linked with mention that delegates to a coding builder, for Node/TypeScript, Python, or a bring-your-own-image toolchain). They go beyond the quickstart. Its optional coding step sets up a builder and a reviewer on a local git repository, with no GitHub App (see the local-repositories article). These recipes react to GitHub events (push, mention, pull requests), so they require Wardby 0.4.0 or later, plus the GitHub App, worker image, and job launcher from coding-agent setup. The full recipes, with every configuration and prompt, are in docs/agent-recipes.md. If you are an assistant connected to Wardby over MCP, follow these steps. Do them in order, ask the user instead of guessing, and stop at the first failed prerequisite. Step 0: choose Ask the user: Which recipe: \"architecture keeper\" or \"builder\"? Which repository, as owner/name? The coding provider, codex or claude-code, for both recipes (the architect is a coding agent too). Never guess it. For the builder only: the language or stack, which decides toolchain (node for Node/TypeScript, node-python with toolchainVersion: \"3.12\" for Python, or a bring-your-own worker image for anything else). Agent names are unique across the whole instance, so the recipes use repo-scoped names: <repo-architect, <repo-merge-watcher, <repo-builder, and <repo-router, where <repo is the repository name from owner/name. Call listagents first; if a name is taken, ask the user for another. Keep the boundName values architect and builder unchanged, so the delegate tools stay delegatetoarchitect and delegatetobuilder. Step 1: check prerequisites Check these before creating anything. Local install. Over the local stdio connection linkhostaccount is not available (it needs Wardby's HTTP transport), and a quickstart-only install has no GitHub App or coding workers. If that is your situation, explain it to the user and point them to docs/coding-agent-setup.md instead of trying. GitHub account link. Call gethostaccount. If accounts is empty, call linkhostaccount with no arguments, give the user the authorizeUrl, and when they return the one-time code, call linkhostaccount again with confirmationCode. Repository access. No tool lists the repositories the GitHub App can see. The linked account needs write access to the repository, and both createagent (with a codingProfile) and linkrepository check this and refuse with a clear error if it is missing. Ask the user to confirm the GitHub App is installed on the repository. Do not use adminOverride or repositoryAdminOverride unless the user is an admin and asks for it. Models. Call listmodels and pick ids whose routable is true: a capable coding model that the chosen provider supports, and a small fast model for the native agent. Coding-agent setup. If coding agents are not set up yet, tell the user to run wardby coding preflight (CLI) and finish coding-agent setup first. See docs/coding-agent-setup.md. Webhooks. Event triggers need GitHub to reach the instance at a public HTTPS URL, with the App's events ticked: Push for the merge watcher; Issue comment, Pull request review comment, and Issues for mentions. Scheduled and manual runs need no webhook. If a prerequisite fails, stop and tell the user what to do. Do not create agents. Step 2A: architecture keeper Call gethelparticle with id: \"architecture-agent\". It holds the architect system prompt (\"System prompt\"), the watcher prompt, and the reviewer step. Use them unchanged. Call createagent for the architect: name: \"<repo-architect\", kind: \"coding\", model a capable coding model, budgetUsd: 3, systemPrompt the architect prompt, and codingProfile with provider, repository, baseRef (the default branch), and defaultTask: Weekly knowledge review. Run the full cycle described in your instructions for this repository. Your file changes are collected into a pull request for review; don't try to commit or open one yourself. Tell the user the run is billed up to the agent's budget ($3) and get their confirmation. Then call triggeragent once with the architect's agentId and show them the run (getrun). If the run failed or produced no pull request, stop and show the error or summary; never call setschedule after a failed run. Otherwise stop and ask them to review and merge the first draft pull request before continuing. When they say to continue, call setschedule with the architect's agentId, schedule: \"0 6 1\", and the user's timezone. Call createagent for the watcher: name: \"<repo-merge-watcher\", kind: \"native\", a small fast model, the watcher prompt as systemPrompt, and a budgetUsd of at least 3 plus a little (the run tree shares one budget). Call attachsubagent with parentAgentId the watcher, childAgentId the architect, and boundName: \"architect\". Ask the user to tick Push in the GitHub App's event settings (and keep Contents: read). Wait for their confirmation. Call linkrepository with agentId the watcher, repository, access: \"write\", and triggers: [\"push\"]. Send no checkName. Offer the reviewer step: if the user has a code-review agent, offer to append the \"Reviewer step\" from the same article to its prompt with updateagent (read it first with getagent, and keep its existing prompt). Step 2B: builder Check for a mention conflict first, before creating anything. Call listagents, then listrepositories for each native agent you can see, to find one linked to the repository with the mention trigger (only one agent per repository may handle mentions). If one exists, reuse it as the router only if the user owns it and agrees; then attach the builder to it and skip creating a router. Never unlink or relink another agent. Ask the user to confirm the GitHub App subscribes to Issue comment, Pull request review comment, and Issues events. Call createagent for the builder: name: \"<repo-builder\", kind: \"coding\", a model the chosen provider supports, budgetUsd such as 5, systemPrompt the prompt from gethelparticle with id: \"builder-agent\" (section \"Builder prompt\"), and a codingProfile with provider, repository, baseRef, and timeoutSec (for example 1800), plus the stack settings: Node/TypeScript: toolchain: \"node\", with packageAllowlist such as { \"npm\": [\"react@^19\", \"vitest\"] }. Python: toolchain: \"node-python\", toolchainVersion: \"3.12\", with packageAllowlist such as { \"pypi\": [\"flask=3\"] } (wheels only; list a wheel package's own name, not an extra). Add services: [\"postgres\"] if tests need a database: the repository must commit .wardby/services.yaml declaring it, and the name must be in the catalog (listservices), or createagent returns 400. Other: toolchain: \"node\" plus a digest-pinned workerImageRef. Ask the user for the image reference; never invent one. It needs the agents:admin scope; if the user lacks it, stop and say so. A packageAllowlist needs packages:approve or agents:admin. If you are not reusing a router, call createagent with name: \"<repo-router\", kind: \"native\", a small fast model, a budgetUsd of the builder's budget plus a little, and the router prompt from gethelparticle with id: \"builder-agent\" (section \"Router prompt\"). Call attachsubagent with parentAgentId the router, childAgentId the builder, and boundName: \"builder\". Call linkrepository with agentId the router, repository, access: \"write\", and triggers: [\"mention\"]. If it returns the 409 \"Another agent already handles @-mentions\", stop and tell the user, and list the agents you created. Never unlink or relink another agent. If linking fails for any reason after you created agents, tell the user what was created. Ask the user to try one @<app-slug request on an issue, where <app-slug is the GitHub App's name. A test run is billed up to the builder's budget; say so first. Step 2C (optional): a lead that fans out A router delegates once per run by default. For one native agent that splits a request across several repositories, attach one builder per repository and set the lead's maxDelegationsPerRun (1 to 20) with createagent or updateagent. A run delegates to each sub-agent and repository at most once; the calls run one after another unless you also set parallelDelegations: true, which starts only the consecutive delegateto calls of one turn together — a non-delegation call between two delegations splits them, nothing is reordered, and results return to the lead in call order (tell the lead to make its independent delegations consecutively, in one turn; coding builders beyond CODINGMAXCONCURRENT queue); the run tree shares the lead's budget, so size budgetUsd for every builder it may start. Builders started together each reserve their budget up front, so size the lead's budgetUsd for all of them, with headroom since the lead's own unspent budget isn't reserved against them; a builder refused for budget while a sibling still runs waits for it and retries (otherwise the refusal is immediate). Cancelling the lead stops a running coding sub-agent but not a running native one. Put the full cross-repository contract in each builder's task, since each builder sees only its own repository. Each builder's result includes pullRequest (outcome, repository, number, url) from Wardby's own record when it opened or pushed to one, so the lead can report the links. When the builders' changes must land in a particular order, pass mergeOrder (1 to 99, 1 first) in each delegateto<name call — give a dependency a lower number than what calls it, and give two changes the same number when there is no order between them: { \"task\": \"Add the /quotes endpoint the client will call.\", \"mergeOrder\": 1 } { \"task\": \"Add the quotes page that calls /quotes.\", \"mergeOrder\": 2 } Leave mergeOrder out and the pull requests' Related pull requests section lists them in delegation order instead, labelled as a suggestion rather than a set order. It applies only to coding sub-agents; a native sub-agent ignores it. A follow-up that continues one of these pull requests with continuePriorRun and no mergeOrder of its own keeps the pull request's current value (the one most recently set for it, by the run that opened it or a later continuation); one that passes mergeOrder replaces it. With Wardby 0.6.0 or later, once a set has more than one mergeOrder, each pull request in it also gets a wardby merge order check run showing whether its earlier steps have merged yet; search help for \"merge order check\" for its states and for requiring it in branch protection. One coding agent across several repositories. Instead of one builder per repository, give one coding builder a list: its default in codingProfile.repository, and each other repository with linkrepository (access: \"write\", no triggers). The lead then names the repository on each call, and may delegate to the same builder once per repository: { \"task\": \"Add the /quotes endpoint the client will call.\", \"repository\": \"your-org/api\", \"mergeOrder\": 1 } { \"task\": \"Add the quotes page that calls /quotes.\", \"repository\": \"your-org/web\", \"mergeOrder\": 2 } Set maxDelegationsPerRun (up to 20) for the number of calls, and use mergeOrder where the pull requests must land in order. A call without repository is refused with repositoryrequired (unless it continues a prior run with continuePriorRun), and a repository not on the list with repositorynotlisted. A native sub-agent refuses repository with repositoryrequirescodingagent. The lead sees the list in the tool definition only when it has the same owner as the builder, or another owner with execute access to a builder that sets allowWebhookTaskOverride. All repositories share the builder's toolchain, budget and prompt. Being on the list lets a run work in a repository; it starts nothing there. Link the lead and the reviewer on each listed GitHub repository with the triggers they need, or a pull request opened there gets no review, mention follow-up, fix round or mark-ready. Search help for repositoryrequired or repositorynotlisted for what to do about those refusals. Step 3: confirm Summarize what you created: each agent's name and id, the sub-agent bindings, the repository links and their triggers, and the schedule. Then state the next manual step for the user: merge the first knowledge pull request, tick any App events still missing, or try the first @ mention. Remind them that Wardby never merges pull requests for them. Related: Builder and router prompts, Set up an architecture agent, Architecture knowledge bundles, Choose a native or coding agent, Connect GitHub repositories, Run GitHub code-review agents, Approve packages for coding agents, and Services for coding runs.",
|
|
63
63
|
"headings": [
|
|
64
64
|
{
|
|
65
65
|
"level": 1,
|
|
@@ -246,8 +246,8 @@
|
|
|
246
246
|
],
|
|
247
247
|
"appliesTo": ">=0.6.0",
|
|
248
248
|
"sourcePath": "brokered-secrets.md",
|
|
249
|
-
"markdown": "\n# Brokered secrets and the secret broker\n\nA readable secret hands its value to any tool that is granted it, so a tool with\nuntrusted code, or a prompt-injected agent, can send the value anywhere the tool\nmay fetch. A **brokered** secret never reaches tool code: you fix the hosts it\nmay be sent to and how it is placed, and the Wardby host adds it to the request.\n\n## When to use it\n\nBroker any secret that a tool only needs to send to an API, such as a bearer\ntoken, an API key, or AWS credentials. Keep a secret readable only when the tool\nmust compute with the value itself.\n\n## Set it up\n\n1. Create the secret with a broker config, in one call or in the browser form's\n \"Brokered\" checkbox: `create_secret { name, broker }`. For an existing secret\n use `set_secret_broker { name, broker }`.\n2. Attach it to the agent (`attach_secret`) and list its name in the tool\n attachment's `allowedSecrets` (`attach_tool`).\n3. Include the host in the attachment's `allowedHosts` too. The normal fetch\n policy still applies on top of the broker.\n\nThe config is `{ hosts, pathPrefixes?, placement }`. Hosts are exact hostnames\nsuch as `api.example.com`, and the request must use https on the default port.\n\n## The four placements\n\n- **header**: `{ \"kind\": \"header\", \"name\": \"Authorization\", \"format\": \"Bearer {value}\" }`\n- **query**: `{ \"kind\": \"query\", \"name\": \"api_key\" }`\n- **body**: `{ \"kind\": \"body\", \"field\": \"token\" }`, for a JSON-object or form body\n- **aws-sigv4**: `{ \"kind\": \"aws-sigv4\", \"region\": \"us-east-1\", \"service\": \"s3\" }`,\n where the value is JSON `{ \"accessKeyId\", \"secretAccessKey\", \"sessionToken?\" }`\n\n## Use it in a tool\n\n```js\nconst response = await fetch(\"https://api.example.com/v1/items\", {\n secrets: [\"EXAMPLE_API_KEY\"],\n});\n```\n\n`secrets.get(\"EXAMPLE_API_KEY\")` on a brokered secret throws\n[`secret_brokered`](errors/secret-brokered.md). Redirects are not followed, and\nthe value is scrubbed from responses and console output.\n\n## Change or remove brokering\n\nChanging the config (hosts, path prefixes, or placement) with\n`set_secret_broker` or `create_secret` takes effect immediately and is not\nconfirmed in a browser. Anyone who can act as the owner over MCP can send the\nvalue to another host they also grant through `attach_tool` `allowedHosts`; the\noperator's fetch policy still applies.\n\nOnly removal is confirmed: `set_secret_broker { name, broker: null }` returns a\nbrowser link, and a person confirms by typing the secret's name. The MCP call\nalone never removes it. Every change is audited.\n\n## Related\n\n- Full guide: [`docs/tool-secrets.md`](../docs/tool-secrets.md)\n- [Use native agents, tools, and data](native-capabilities.md)\n- Errors: [`secret_brokered`](errors/secret-brokered.md),\n [`secret_not_brokered`](errors/secret-not-brokered.md),\n [`secret_broker_destination_denied`](errors/secret-broker-destination-denied.md),\n [`secret_broker_conflict`](errors/secret-broker-conflict.md),\n [`secret_broker_body_invalid`](errors/secret-broker-body-invalid.md),\n [`secret_broker_value_invalid`](errors/secret-broker-value-invalid.md),\n [`secret_broker_changed`](errors/secret-broker-changed.md),\n [`secret_broker_config_invalid`](errors/secret-broker-config-invalid.md)\n",
|
|
250
|
-
"plainText": "Brokered secrets and the secret broker A readable secret hands its value to any tool that is granted it, so a tool with untrusted code, or a prompt-injected agent, can send the value anywhere the tool may fetch. A brokered secret never reaches tool code: you fix the hosts it may be sent to and how it is placed, and the Wardby host adds it to the request. When to use it Broker any secret that a tool only needs to send to an API, such as a bearer token, an API key, or AWS credentials. Keep a secret readable only when the tool must compute with the value itself. Set it up Create the secret with a broker config, in one call or in the browser form's \"Brokered\" checkbox: createsecret { name, broker }. For an existing secret use setsecretbroker { name, broker }. Attach it to the agent (attachsecret) and list its name in the tool attachment's allowedSecrets (attachtool). Include the host in the attachment's allowedHosts too. The normal fetch policy still applies on top of the broker. The config is { hosts, pathPrefixes?, placement }. Hosts are exact hostnames such as api.example.com, and the request must use https on the default port. The four placements header: { \"kind\": \"header\", \"name\": \"Authorization\", \"format\": \"Bearer {value}\" } query: { \"kind\": \"query\", \"name\": \"apikey\" } body: { \"kind\": \"body\", \"field\": \"token\" }, for a JSON-object or form body aws-sigv4: { \"kind\": \"aws-sigv4\", \"region\": \"us-east-1\", \"service\": \"s3\" }, where the value is JSON { \"accessKeyId\", \"secretAccessKey\", \"sessionToken?\" } Use it in a tool const response = await fetch(\"https://api.example.com/v1/items\", { secrets: [\"EXAMPLEAPIKEY\"], }); secrets.get(\"EXAMPLEAPIKEY\") on a brokered secret throws secretbrokered. Redirects are not followed, and the value is scrubbed from responses and console output. Change or remove brokering Changing the config (hosts, path prefixes, or placement) with setsecretbroker or createsecret takes effect immediately and is not confirmed in a browser. Anyone who can act as the owner over MCP can send the value to another host they also grant through attachtool allowedHosts; the operator's fetch policy still applies. Only removal is confirmed: setsecretbroker { name, broker: null } returns a browser link, and a person confirms by typing the secret's name. The MCP call alone never removes it. Every change is audited. Related Full guide: docs/tool-secrets.md Use native agents, tools, and data Errors: secretbrokered, secretnotbrokered, secretbrokerdestinationdenied, secretbrokerconflict, secretbrokerbodyinvalid, secretbrokervalueinvalid, secretbrokerchanged, secretbrokerconfiginvalid",
|
|
249
|
+
"markdown": "\n# Brokered secrets and the secret broker\n\nA readable secret hands its value to any tool that is granted it, so a tool with\nuntrusted code, or a prompt-injected agent, can send the value anywhere the tool\nmay fetch. A **brokered** secret never reaches tool code: you fix the hosts it\nmay be sent to and how it is placed, and the Wardby host adds it to the request.\n\n## When to use it\n\nBroker any secret that a tool only needs to send to an API, such as a bearer\ntoken, an API key, or AWS credentials. Keep a secret readable only when the tool\nmust compute with the value itself.\n\n## Set it up\n\n1. Create the secret with a broker config, in one call or in the browser form's\n \"Brokered\" checkbox: `create_secret { name, broker }`. For an existing secret\n use `set_secret_broker { name, broker }`.\n2. Attach it to the agent (`attach_secret`) and list its name in the tool\n attachment's `allowedSecrets` (`attach_tool`).\n3. Include the host in the attachment's `allowedHosts` too. The normal fetch\n policy still applies on top of the broker.\n\nThe config is `{ hosts, pathPrefixes?, placement }`. Hosts are exact hostnames\nsuch as `api.example.com`, and the request must use https on the default port.\n\n## The four placements\n\n- **header**: `{ \"kind\": \"header\", \"name\": \"Authorization\", \"format\": \"Bearer {value}\" }`\n- **query**: `{ \"kind\": \"query\", \"name\": \"api_key\" }`\n- **body**: `{ \"kind\": \"body\", \"field\": \"token\" }`, for a JSON-object or form body\n- **aws-sigv4**: `{ \"kind\": \"aws-sigv4\", \"region\": \"us-east-1\", \"service\": \"s3\" }`,\n where the value is JSON `{ \"accessKeyId\", \"secretAccessKey\", \"sessionToken?\" }`\n\n## Use it in a tool\n\n```js\nconst response = await fetch(\"https://api.example.com/v1/items\", {\n secrets: [\"EXAMPLE_API_KEY\"],\n});\n```\n\n`secrets.get(\"EXAMPLE_API_KEY\")` on a brokered secret throws\n[`secret_brokered`](errors/secret-brokered.md). Redirects are not followed, and\nthe value is scrubbed from responses and console output.\n\n## Change or remove brokering\n\nChanging the config (hosts, path prefixes, or placement) with\n`set_secret_broker` or `create_secret` takes effect immediately and is not\nconfirmed in a browser. Anyone who can act as the owner over MCP can send the\nvalue to another host they also grant through `attach_tool` `allowedHosts`; the\noperator's fetch policy still applies.\n\nOnly removal is confirmed: `set_secret_broker { name, broker: null }` returns a\nbrowser link, and a person confirms by typing the secret's name. The MCP call\nalone never removes it. Every change is audited.\n\n## Related\n\n- [Host providers](../docs/host-providers.md): a provider's credentials must be brokered\n secrets\n- [Remote MCP servers](../docs/mcp-servers.md) (0.8.0+): a server's credentials are brokered secrets\n- Full guide: [`docs/tool-secrets.md`](../docs/tool-secrets.md)\n- [Use native agents, tools, and data](native-capabilities.md)\n- Errors: [`secret_brokered`](errors/secret-brokered.md),\n [`secret_not_brokered`](errors/secret-not-brokered.md),\n [`secret_broker_destination_denied`](errors/secret-broker-destination-denied.md),\n [`secret_broker_conflict`](errors/secret-broker-conflict.md),\n [`secret_broker_body_invalid`](errors/secret-broker-body-invalid.md),\n [`secret_broker_value_invalid`](errors/secret-broker-value-invalid.md),\n [`secret_broker_changed`](errors/secret-broker-changed.md),\n [`secret_broker_config_invalid`](errors/secret-broker-config-invalid.md)\n",
|
|
250
|
+
"plainText": "Brokered secrets and the secret broker A readable secret hands its value to any tool that is granted it, so a tool with untrusted code, or a prompt-injected agent, can send the value anywhere the tool may fetch. A brokered secret never reaches tool code: you fix the hosts it may be sent to and how it is placed, and the Wardby host adds it to the request. When to use it Broker any secret that a tool only needs to send to an API, such as a bearer token, an API key, or AWS credentials. Keep a secret readable only when the tool must compute with the value itself. Set it up Create the secret with a broker config, in one call or in the browser form's \"Brokered\" checkbox: createsecret { name, broker }. For an existing secret use setsecretbroker { name, broker }. Attach it to the agent (attachsecret) and list its name in the tool attachment's allowedSecrets (attachtool). Include the host in the attachment's allowedHosts too. The normal fetch policy still applies on top of the broker. The config is { hosts, pathPrefixes?, placement }. Hosts are exact hostnames such as api.example.com, and the request must use https on the default port. The four placements header: { \"kind\": \"header\", \"name\": \"Authorization\", \"format\": \"Bearer {value}\" } query: { \"kind\": \"query\", \"name\": \"apikey\" } body: { \"kind\": \"body\", \"field\": \"token\" }, for a JSON-object or form body aws-sigv4: { \"kind\": \"aws-sigv4\", \"region\": \"us-east-1\", \"service\": \"s3\" }, where the value is JSON { \"accessKeyId\", \"secretAccessKey\", \"sessionToken?\" } Use it in a tool const response = await fetch(\"https://api.example.com/v1/items\", { secrets: [\"EXAMPLEAPIKEY\"], }); secrets.get(\"EXAMPLEAPIKEY\") on a brokered secret throws secretbrokered. Redirects are not followed, and the value is scrubbed from responses and console output. Change or remove brokering Changing the config (hosts, path prefixes, or placement) with setsecretbroker or createsecret takes effect immediately and is not confirmed in a browser. Anyone who can act as the owner over MCP can send the value to another host they also grant through attachtool allowedHosts; the operator's fetch policy still applies. Only removal is confirmed: setsecretbroker { name, broker: null } returns a browser link, and a person confirms by typing the secret's name. The MCP call alone never removes it. Every change is audited. Related Host providers: a provider's credentials must be brokered secrets Remote MCP servers (0.8.0+): a server's credentials are brokered secrets Full guide: docs/tool-secrets.md Use native agents, tools, and data Errors: secretbrokered, secretnotbrokered, secretbrokerdestinationdenied, secretbrokerconflict, secretbrokerbodyinvalid, secretbrokervalueinvalid, secretbrokerchanged, secretbrokerconfiginvalid",
|
|
251
251
|
"headings": [
|
|
252
252
|
{
|
|
253
253
|
"level": 1,
|
|
@@ -301,7 +301,7 @@
|
|
|
301
301
|
"ruby",
|
|
302
302
|
"toolchain"
|
|
303
303
|
],
|
|
304
|
-
"appliesTo": ">=0.
|
|
304
|
+
"appliesTo": ">=0.6.0",
|
|
305
305
|
"sourcePath": "build-claude-code-image.md",
|
|
306
306
|
"markdown": "\n# Build a tool runner image for a Claude Code agent\n\nA Claude Code agent uses two containers. One runs Claude Code and holds its API\nkey; it always uses Wardby's standard image. The other, the **tool runner**,\nruns the agent's commands and has the repository. `codingProfile.workerImageRef`\nreplaces the tool runner. The long-form guide is\n[`docs/coding-worker-byo-images.md`](../docs/coding-worker-byo-images.md).\n\nFor a Codex agent, follow [Build a custom worker image](build-worker-image.md)\ninstead.\n\nIf you are an assistant connected to Wardby over MCP, follow these steps. Do\nthem in order, ask the user instead of guessing, and stop at the first failed\nprerequisite. Never write into the user's repository; ask where to keep the\nDockerfile (for example a folder outside the repository).\n\n## Step 1: find the toolchain\n\nRead the project's manifests and how it runs its tests, as in \"Step 1: find the\ntoolchain\" of [Build a custom worker image](build-worker-image.md). Ask the user\nwhen the language or version is unclear.\n\n## Step 2: find the base image\n\nAsk the user for the value of `CODING_CLAUDE_TOOL_RUNNER_IMAGE` in the Wardby\nserver's settings (on a quickstart install, `.wardby/.env` in the Wardby project\ndirectory). Use `CODING_CLAUDE_TOOL_RUNNER_IMAGE_NODE_PYTHON_3_12` instead when\nthe project also needs Python. This image comes from the same Wardby release as\nthe server, which the custom image must match.\n\nIf the value is a bare local ID (`sha256:...`), tag it first, because Docker\ncannot build `FROM` an ID:\n\n```sh\ndocker tag sha256:<id> wardby-tool-runner-base:local\n```\n\n## Step 3: write the Dockerfile\n\nStart from the base image, install as `root`, and end as the tool runner's user:\n\n```dockerfile\nFROM <base image from step 2>\nUSER root\nRUN apt-get update \\\n && apt-get install -y --no-install-recommends <packages> \\\n && rm -rf /var/lib/apt/lists/*\nUSER 10001:10001\n```\n\nRules:\n\n- **Keep the entrypoint.** Do not set `ENTRYPOINT` or `CMD`, and keep\n `USER 10001:10001` as the last `USER` line.\n- **Install everything at build time.** A run can download only npm and PyPI\n packages, so every other package must be in the image.\n- **Compile in an earlier stage.** The tool runner is Debian 12 (bookworm).\n Compile native code in an earlier build stage that uses a bookworm image,\n and copy only the results. The long-form guide has a Ruby example.\n- **Settings go in `/etc/profile.d/`.** Commands run as `sh -lc` with a fixed\n environment, so `ENV` lines do not reach them. Put settings in a file under\n `/etc/profile.d/`, and put programs in `/usr/local/bin`.\n- **Mind the run's filesystem.** The root filesystem is read-only. `/tmp` and\n `/home/wardby` are empty scratch space; anything the image put there is\n hidden. `/workspace` is the checkout; files you want to keep go there. Put\n caches and temporary files under `/workspace/.cache/`.\n- **No root at run time.** Commands always run as user 10001 with\n `no-new-privileges`, so setuid programs do not help.\n- Release images are `linux/amd64`. On an ARM machine, pass\n `--platform linux/amd64` to `docker build` and `docker run`.\n\n## Step 4: build it and run the tests the way a run would\n\n```sh\ndocker build --tag wardby-tool-runner-<language>:local <dockerfile folder>\n```\n\nThen run the project's test command against a **throwaway clone**, never the\nuser's checkout. This command uses a run's restrictions and the same fixed\nenvironment a run gives commands, so `ENV` lines in the image do not apply:\n\n```sh\ngit clone <repository> /tmp/wardby-image-check\ndocker 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 /tmp/wardby-image-check:/workspace -w /workspace --entrypoint env wardby-tool-runner-<language>:local -i HOME=/home/wardby LANG=C.UTF-8 PATH=/opt/wardby/bin:/usr/local/bin:/usr/bin:/bin sh -lc '<test command, e.g. bundle exec rake test>'\n```\n\nOn Linux, make the clone writable for user 10001 first (it is a throwaway copy:\n`chmod -R a+rwX /tmp/wardby-image-check`). Fix the Dockerfile until the tests\nrun. A \"command not found\" means a missing program or a missing\n`/etc/profile.d/` setting. Delete the clone afterwards.\n\n## Step 5: choose the image reference\n\n`workerImageRef` must be immutable; a tag is refused.\n\n- **Local quickstart** (Wardby runs coding jobs with Docker on this machine):\n use the local image ID,\n `docker image inspect --format '{{.Id}}' wardby-tool-runner-<language>:local`.\n Wardby never pulls these images, so build on the same machine.\n- **Kubernetes**: push the image to a registry the cluster can pull from,\n and use `<registry>/<name>@sha256:<digest>`.\n\n## Step 6: update the builder and try it\n\n1. Call `update_agent` with the coding agent's id and\n `codingProfile: {workerImageRef: \"<reference from step 5>\"}`. This needs the\n `agents:admin` scope and the admin role. On a hosted server, ask an\n administrator if it is refused.\n2. Start a small run that exercises the toolchain:\n `trigger_agent {agentId, task: \"Run the project's tests and report the results. Change nothing.\"}`.\n3. Read the result with `get_run` and report to the user what ran, what passed\n and what failed.\n\nIf a run fails with `worker_tool_runner_unreachable`, the image was usually not\nbuilt `FROM` this release's tool runner, or its `USER` or `ENTRYPOINT` was\nchanged. Rebuild the image whenever Wardby is upgraded.\n\nTo undo it, call `update_agent` with `codingProfile: {workerImageRef: null}`.\n\nRelated: [Build a custom worker image](build-worker-image.md),\n[Approve packages for coding agents](coding-packages.md) and\n[Troubleshoot coding workers](troubleshooting/coding-workers.md).\n",
|
|
307
307
|
"plainText": "Build a tool runner image for a Claude Code agent A Claude Code agent uses two containers. One runs Claude Code and holds its API key; it always uses Wardby's standard image. The other, the tool runner, runs the agent's commands and has the repository. codingProfile.workerImageRef replaces the tool runner. The long-form guide is docs/coding-worker-byo-images.md. For a Codex agent, follow Build a custom worker image instead. If you are an assistant connected to Wardby over MCP, follow these steps. Do them in order, ask the user instead of guessing, and stop at the first failed prerequisite. Never write into the user's repository; ask where to keep the Dockerfile (for example a folder outside the repository). Step 1: find the toolchain Read the project's manifests and how it runs its tests, as in \"Step 1: find the toolchain\" of Build a custom worker image. Ask the user when the language or version is unclear. Step 2: find the base image Ask the user for the value of CODINGCLAUDETOOLRUNNERIMAGE in the Wardby server's settings (on a quickstart install, .wardby/.env in the Wardby project directory). Use CODINGCLAUDETOOLRUNNERIMAGENODEPYTHON312 instead when the project also needs Python. This image comes from the same Wardby release as the server, which the custom image must match. If the value is a bare local ID (sha256:...), tag it first, because Docker cannot build FROM an ID: docker tag sha256:<id wardby-tool-runner-base:local Step 3: write the Dockerfile Start from the base image, install as root, and end as the tool runner's user: FROM <base image from step 2 USER root RUN apt-get update \\ && apt-get install -y --no-install-recommends <packages \\ && rm -rf /var/lib/apt/lists/ USER 10001:10001 Rules: Keep the entrypoint. Do not set ENTRYPOINT or CMD, and keep USER 10001:10001 as the last USER line. Install everything at build time. A run can download only npm and PyPI packages, so every other package must be in the image. Compile in an earlier stage. The tool runner is Debian 12 (bookworm). Compile native code in an earlier build stage that uses a bookworm image, and copy only the results. The long-form guide has a Ruby example. Settings go in /etc/profile.d/. Commands run as sh -lc with a fixed environment, so ENV lines do not reach them. Put settings in a file under /etc/profile.d/, and put programs in /usr/local/bin. Mind the run's filesystem. The root filesystem is read-only. /tmp and /home/wardby are empty scratch space; anything the image put there is hidden. /workspace is the checkout; files you want to keep go there. Put caches and temporary files under /workspace/.cache/. No root at run time. Commands always run as user 10001 with no-new-privileges, so setuid programs do not help. Release images are linux/amd64. On an ARM machine, pass --platform linux/amd64 to docker build and docker run. Step 4: build it and run the tests the way a run would docker build --tag wardby-tool-runner-<language:local <dockerfile folder Then run the project's test command against a throwaway clone, never the user's checkout. This command uses a run's restrictions and the same fixed environment a run gives commands, so ENV lines in the image do not apply: git clone <repository /tmp/wardby-image-check 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 /tmp/wardby-image-check:/workspace -w /workspace --entrypoint env wardby-tool-runner-<language:local -i HOME=/home/wardby LANG=C.UTF-8 PATH=/opt/wardby/bin:/usr/local/bin:/usr/bin:/bin sh -lc '<test command, e.g. bundle exec rake test' On Linux, make the clone writable for user 10001 first (it is a throwaway copy: chmod -R a+rwX /tmp/wardby-image-check). Fix the Dockerfile until the tests run. A \"command not found\" means a missing program or a missing /etc/profile.d/ setting. Delete the clone afterwards. Step 5: choose the image reference workerImageRef must be immutable; a tag is refused. Local quickstart (Wardby runs coding jobs with Docker on this machine): use the local image ID, docker image inspect --format '{{.Id}}' wardby-tool-runner-<language:local. Wardby never pulls these images, so build on the same machine. Kubernetes: push the image to a registry the cluster can pull from, and use <registry/<name@sha256:<digest. Step 6: update the builder and try it Call updateagent with the coding agent's id and codingProfile: {workerImageRef: \"<reference from step 5\"}. This needs the agents:admin scope and the admin role. On a hosted server, ask an administrator if it is refused. Start a small run that exercises the toolchain: triggeragent {agentId, task: \"Run the project's tests and report the results. Change nothing.\"}. Read the result with getrun and report to the user what ran, what passed and what failed. If a run fails with workertoolrunnerunreachable, the image was usually not built FROM this release's tool runner, or its USER or ENTRYPOINT was changed. Rebuild the image whenever Wardby is upgraded. To undo it, call updateagent with codingProfile: {workerImageRef: null}. Related: Build a custom worker image, Approve packages for coding agents and Troubleshoot coding workers.",
|
|
@@ -463,6 +463,35 @@
|
|
|
463
463
|
}
|
|
464
464
|
]
|
|
465
465
|
},
|
|
466
|
+
{
|
|
467
|
+
"id": "claude-code-run-pane",
|
|
468
|
+
"title": "See your runs in Claude Code (the wardby-runs plugin)",
|
|
469
|
+
"summary": "Install the wardby-runs Claude Code plugin to see your runs beside the chat, grouped by pull request, with run details and Continue locally.",
|
|
470
|
+
"audience": "operator",
|
|
471
|
+
"tags": [
|
|
472
|
+
"run steps",
|
|
473
|
+
"get_run_steps",
|
|
474
|
+
"claude code",
|
|
475
|
+
"plugin",
|
|
476
|
+
"wardby-runs",
|
|
477
|
+
"pane",
|
|
478
|
+
"claude-plugin",
|
|
479
|
+
"runs",
|
|
480
|
+
"auto mode",
|
|
481
|
+
"permissions"
|
|
482
|
+
],
|
|
483
|
+
"appliesTo": ">=0.8.0",
|
|
484
|
+
"sourcePath": "claude-code-run-pane.md",
|
|
485
|
+
"markdown": "\n# See your runs in Claude Code\n\nThe `wardby-runs` plugin opens a pane in Claude Code that lists your wardby\nruns, grouped by pull request, and shows each run's details. It uses the\n`wardby` MCP server your session already has and only reads.\n\nInstall it, and allow its read-only tools for auto mode, with:\n\n```sh\nnpx @wardby/cli@latest claude-plugin install\n```\n\nAdd `--server-url https://<your wardby host>/mcp` if Claude Code has no MCP\nserver named `wardby` yet. Or install it yourself with\n`/plugin install wardby-runs --marketplace wardby/wardby`. Then run\n`/wardby-runs`.\n\nIf the pane says auto mode refused a call, allow `mcp__wardby__list_runs`,\n`mcp__wardby__list_agents`, `mcp__wardby__get_run`,\n`mcp__wardby__get_run_transcript` and `mcp__wardby__get_run_steps` in\n`/permissions`. Run `wardby claude-plugin install` again to add a rule a newer\npane needs.\n\nIn the terminal, the pane takes clicks and sits beside the chat only in Claude\nCode's fullscreen view (`\"tui\": \"fullscreen\"`); otherwise use ctrl+x tab and the\nkeys it shows. The desktop app needs no setting.\n\n`wardby quickstart` offers the pane when it connects Claude Code, and\n`wardby doctor` and `wardby claude-plugin status` check the setup; `wardby claude-plugin\nuninstall` removes the plugin and the rules install added. To continue a run\nfrom the pane, see `resume-runs-locally`.\n\nA running run's detail shows its **Recent steps** (the last 8 tool calls and\nmessages: a ✓ or the exit code of a failed command, then the tool and its\ncommand; what the model said wraps to about two lines); a finished run's shows all its\n**Steps**, 200 at a time. In the list, a running or failed run shows its newest\nstep under its name. Against a server without `get_run_steps` the pane shows no\nsteps and checks again every few refreshes; with run steps off it says \"Steps\nare off on this server.\" See `run-steps`. Steps need Wardby 0.9.0 or later\non the server. From 0.9.0, a step with detail, or a longer message, has a ▸ at\nits right that opens it; in the terminal, `j`/`k` also move between such steps\nand `e` shows or hides one. An open command shows \"$ command\", its exit status\nand its output, without Codex's framing lines. Detail appears only for the\nagent's owner and the run's starter (and the stdio operator), on a server at\nthe detail level. An open detail shows its last 40 lines, with a count of the\nlines above them.\n\nEach section of a run's detail is a card, coloured by its kind (a bar on the\ndesktop, the border in the terminal). On the desktop each card, an error and an\nopen step's detail have a **Copy** button that copies the full text as the\nserver sent it, an open step's detail included in full; in the terminal, **Copy section** (`y`) copies the open\nstep's detail.\n\nThe full guide is [Claude Code plugin](../docs/claude-code-plugin.md).\n",
|
|
486
|
+
"plainText": "See your runs in Claude Code The wardby-runs plugin opens a pane in Claude Code that lists your wardby runs, grouped by pull request, and shows each run's details. It uses the wardby MCP server your session already has and only reads. Install it, and allow its read-only tools for auto mode, with: npx @wardby/cli@latest claude-plugin install Add --server-url https://<your wardby host/mcp if Claude Code has no MCP server named wardby yet. Or install it yourself with /plugin install wardby-runs --marketplace wardby/wardby. Then run /wardby-runs. If the pane says auto mode refused a call, allow mcpwardbylistruns, mcpwardbylistagents, mcpwardbygetrun, mcpwardbygetruntranscript and mcpwardbygetrunsteps in /permissions. Run wardby claude-plugin install again to add a rule a newer pane needs. In the terminal, the pane takes clicks and sits beside the chat only in Claude Code's fullscreen view (\"tui\": \"fullscreen\"); otherwise use ctrl+x tab and the keys it shows. The desktop app needs no setting. wardby quickstart offers the pane when it connects Claude Code, and wardby doctor and wardby claude-plugin status check the setup; wardby claude-plugin uninstall removes the plugin and the rules install added. To continue a run from the pane, see resume-runs-locally. A running run's detail shows its Recent steps (the last 8 tool calls and messages: a ✓ or the exit code of a failed command, then the tool and its command; what the model said wraps to about two lines); a finished run's shows all its Steps, 200 at a time. In the list, a running or failed run shows its newest step under its name. Against a server without getrunsteps the pane shows no steps and checks again every few refreshes; with run steps off it says \"Steps are off on this server.\" See run-steps. Steps need Wardby 0.9.0 or later on the server. From 0.9.0, a step with detail, or a longer message, has a ▸ at its right that opens it; in the terminal, j/k also move between such steps and e shows or hides one. An open command shows \"$ command\", its exit status and its output, without Codex's framing lines. Detail appears only for the agent's owner and the run's starter (and the stdio operator), on a server at the detail level. An open detail shows its last 40 lines, with a count of the lines above them. Each section of a run's detail is a card, coloured by its kind (a bar on the desktop, the border in the terminal). On the desktop each card, an error and an open step's detail have a Copy button that copies the full text as the server sent it, an open step's detail included in full; in the terminal, Copy section (y) copies the open step's detail. The full guide is Claude Code plugin.",
|
|
487
|
+
"headings": [
|
|
488
|
+
{
|
|
489
|
+
"level": 1,
|
|
490
|
+
"text": "See your runs in Claude Code",
|
|
491
|
+
"slug": "see-your-runs-in-claude-code"
|
|
492
|
+
}
|
|
493
|
+
]
|
|
494
|
+
},
|
|
466
495
|
{
|
|
467
496
|
"id": "code-review-agents",
|
|
468
497
|
"title": "Run GitHub code-review agents",
|
|
@@ -833,8 +862,8 @@
|
|
|
833
862
|
],
|
|
834
863
|
"appliesTo": ">=0.2.1",
|
|
835
864
|
"sourcePath": "deploy-gke.md",
|
|
836
|
-
"markdown": "\n# Deploy Wardby on GKE Autopilot\n\nThe supported Google Cloud deployment creates a GKE Autopilot cluster, private\nCloud SQL for PostgreSQL, Artifact Registry, HTTPS Gateway, Google Secret\nManager synchronization, and isolated gVisor-backed coding-worker pods for\nCodex and Claude Code. It also applies namespace RBAC and default-deny network\npolicies.\n\nUse a dedicated billed project, a hostname you control, remote Terraform state,\nand a GitHub App installed only on repositories that agents need. Review\nTerraform's plan and set cloud budgets before applying it: the deployment\ncreates billable resources.\n\nThe deployment process is:\n\n1. Install `gcloud`, Terraform, Docker with `linux/amd64` support, `kubectl`,\n Helm, Node.js 24, and authenticate to the target project.\n2. Configure `deploy/gke/terraform.tfvars`, apply Terraform, and prepare the\n Gateway's address, certificate map, Cloud Armor policy, and DNS record. On\n a brand-new project, run `deploy/gke/bootstrap-database-iam.sh` once after\n `terraform apply`, so the migrator has its database grants before the\n first migration.\n3. Put first-time values in an untracked `.env.local`; `deploy/gke/up.sh`\n seeds Secret Manager without overwriting existing production values.\n Jira settings are optional there, all or none; see [Jira](jira.md).\n4. Run `WARDBY_HOSTNAME=wardby.example.com deploy/gke/up.sh`, then verify DNS,\n certificate issuance, and service health.\n Use `WARDBY_HOSTNAME`, not `HOSTNAME` (shells set that to the machine name);\n the script refuses local names such as `*.lan` or `*.local`, and asks you\n to confirm (or set `WARDBY_HOSTNAME_CHANGE=<new hostname>`) before moving\n a deployment to a different hostname.\n\nTo upgrade, re-run `deploy/gke/up.sh` from the new release. It applies the\nmigrations, then the database grants (`deploy/gke/database-grants.sql`), and\nonly then rolls out the new pods, so a release that adds tables or columns the\ncoding proxy uses (such as per-model usage for\n[cost attribution](cost-attribution.md)) needs no manual grants step. If the\ngrants fail, `up.sh` stops before the rollout with a non-zero exit;\n`deploy/gke/bootstrap-database-iam.sh --check` shows the refused statement\nwithout changing anything. See\n[Upgrading an existing deployment](../docs/getting-started-gke.md#upgrading-an-existing-deployment).\n\nThe Kubernetes launcher runs Codex and Claude Code coding workers; a Claude\nCode pod adds a tool-runner sidecar with its own image. Configure an identity\nprovider and GitHub App before allowing people to use the public endpoint.\n\nTo lower the idle cost of a lightly used deployment, see\n[Low-power mode](../docs/getting-started-gke.md#low-power-mode) (Wardby 0.6.0 and later).\n\n## Plan it with your assistant\n\nIf you are an assistant connected to Wardby over MCP and the user asked to plan\na GKE deployment, produce a written plan; do not create cloud resources. Read\n[Choose a deployment target](deployment-targets.md) first and confirm GKE is\nthe right target. Then ask for, one at a time, and record:\n\n1. The Google Cloud project (dedicated, with billing) and region, and who\n holds the IAM roles to apply Terraform.\n2. The public hostname and who controls its DNS.\n3. The identity provider for people signing in (see\n [Configure identity and privileged access](identity-and-access.md)).\n4. The GitHub App: which repositories it is installed on (see\n [Connect GitHub repositories](github.md)).\n5. Which coding providers the agents use (Codex, Claude Code or both), and\n which provider keys and worker images that needs.\n6. Where Terraform state lives, and the monthly cloud budget and alerts.\n7. Optional: Jira.\n\nThe plan lists those answers, the ordered steps above with the values filled\nin, the commands the user will run themselves, and the open questions. Point\nthe user to the full guide below for every step.\n\nFollow the complete, ordered guide at\n[`docs/getting-started-gke.md`](../docs/getting-started-gke.md). It includes\nthe precise IAM, DNS, bootstrap, upgrades, and teardown steps.\n",
|
|
837
|
-
"plainText": "Deploy Wardby on GKE Autopilot The supported Google Cloud deployment creates a GKE Autopilot cluster, private Cloud SQL for PostgreSQL, Artifact Registry, HTTPS Gateway, Google Secret Manager synchronization, and isolated gVisor-backed coding-worker pods for Codex and Claude Code. It also applies namespace RBAC and default-deny network policies. Use a dedicated billed project, a hostname you control, remote Terraform state, and a GitHub App installed only on repositories that agents need. Review Terraform's plan and set cloud budgets before applying it: the deployment creates billable resources. The deployment process is: Install gcloud, Terraform, Docker with linux/amd64 support, kubectl, Helm, Node.js 24, and authenticate to the target project. Configure deploy/gke/terraform.tfvars, apply Terraform, and prepare the Gateway's address, certificate map, Cloud Armor policy, and DNS record. On a brand-new project, run deploy/gke/bootstrap-database-iam.sh once after terraform apply, so the migrator has its database grants before the first migration. Put first-time values in an untracked .env.local; deploy/gke/up.sh seeds Secret Manager without overwriting existing production values. Jira settings are optional there, all or none; see Jira. Run WARDBYHOSTNAME=wardby.example.com deploy/gke/up.sh, then verify DNS, certificate issuance, and service health. Use WARDBYHOSTNAME, not HOSTNAME (shells set that to the machine name); the script refuses local names such as .lan or .local, and asks you to confirm (or set WARDBYHOSTNAMECHANGE=<new hostname) before moving a deployment to a different hostname. To upgrade, re-run deploy/gke/up.sh from the new release. It applies the migrations, then the database grants (deploy/gke/database-grants.sql), and only then rolls out the new pods, so a release that adds tables or columns the coding proxy uses (such as per-model usage for cost attribution) needs no manual grants step. If the grants fail, up.sh stops before the rollout with a non-zero exit; deploy/gke/bootstrap-database-iam.sh --check shows the refused statement without changing anything. See Upgrading an existing deployment. The Kubernetes launcher runs Codex and Claude Code coding workers; a Claude Code pod adds a tool-runner sidecar with its own image. Configure an identity provider and GitHub App before allowing people to use the public endpoint. To lower the idle cost of a lightly used deployment, see Low-power mode (Wardby 0.6.0 and later). Plan it with your assistant If you are an assistant connected to Wardby over MCP and the user asked to plan a GKE deployment, produce a written plan; do not create cloud resources. Read Choose a deployment target first and confirm GKE is the right target. Then ask for, one at a time, and record: The Google Cloud project (dedicated, with billing) and region, and who holds the IAM roles to apply Terraform. The public hostname and who controls its DNS. The identity provider for people signing in (see Configure identity and privileged access). The GitHub App: which repositories it is installed on (see Connect GitHub repositories). Which coding providers the agents use (Codex, Claude Code or both), and which provider keys and worker images that needs. Where Terraform state lives, and the monthly cloud budget and alerts. Optional: Jira. The plan lists those answers, the ordered steps above with the values filled in, the commands the user will run themselves, and the open questions. Point the user to the full guide below for every step. Follow the complete, ordered guide at docs/getting-started-gke.md. It includes the precise IAM, DNS, bootstrap, upgrades, and teardown steps.",
|
|
865
|
+
"markdown": "\n# Deploy Wardby on GKE Autopilot\n\nThe supported Google Cloud deployment creates a GKE Autopilot cluster, private\nCloud SQL for PostgreSQL, Artifact Registry, HTTPS Gateway, Google Secret\nManager synchronization, and isolated gVisor-backed coding-worker pods for\nCodex and Claude Code. It also applies namespace RBAC and default-deny network\npolicies.\n\nUse a dedicated billed project, a hostname you control, remote Terraform state,\nand a GitHub App installed only on repositories that agents need. Review\nTerraform's plan and set cloud budgets before applying it: the deployment\ncreates billable resources.\n\nThe deployment process is:\n\n1. Install `gcloud`, Terraform, Docker with `linux/amd64` support, `kubectl`,\n Helm, Node.js 24, and authenticate to the target project.\n2. Configure `deploy/gke/terraform.tfvars`, apply Terraform, and prepare the\n Gateway's address, certificate map, Cloud Armor policy, and DNS record. On\n a brand-new project, run `deploy/gke/bootstrap-database-iam.sh` once after\n `terraform apply`, so the migrator has its database grants before the\n first migration.\n3. Put first-time values in an untracked `.env.local`; `deploy/gke/up.sh`\n seeds Secret Manager without overwriting existing production values.\n Jira settings are optional there, all or none; see [Jira](jira.md).\n4. Run `WARDBY_HOSTNAME=wardby.example.com deploy/gke/up.sh`, then verify DNS,\n certificate issuance, and service health.\n Use `WARDBY_HOSTNAME`, not `HOSTNAME` (shells set that to the machine name);\n the script refuses local names such as `*.lan` or `*.local`, and asks you\n to confirm (or set `WARDBY_HOSTNAME_CHANGE=<new hostname>`) before moving\n a deployment to a different hostname.\n\nTo upgrade, re-run `deploy/gke/up.sh` from the new release. It applies the\nmigrations, then the database grants (`deploy/gke/database-grants.sql`), and\nonly then rolls out the new pods, so a release that adds tables or columns the\ncoding proxy uses (such as per-model usage for\n[cost attribution](cost-attribution.md)) needs no manual grants step. If the\ngrants fail, `up.sh` stops before the rollout with a non-zero exit;\n`deploy/gke/bootstrap-database-iam.sh --check` shows the refused statement\nwithout changing anything. See\n[Upgrading an existing deployment](../docs/getting-started-gke.md#upgrading-an-existing-deployment).\n\n`up.sh` works from its own one-cluster copy of the cluster's\nkubeconfig context, so switching contexts in another terminal mid-deploy can't\nsend a step to another cluster. Run one deploy of a cluster at a time: a second\nstops with `another operation (install/upgrade/rollback) is in progress`.\n\nThe Kubernetes launcher runs Codex and Claude Code coding workers; a Claude\nCode pod adds a tool-runner sidecar with its own image. Configure an identity\nprovider and GitHub App before allowing people to use the public endpoint.\n\nTo lower the idle cost of a lightly used deployment, see\n[Low-power mode](../docs/getting-started-gke.md#low-power-mode) (Wardby 0.6.0 and later).\n\n## Plan it with your assistant\n\nIf you are an assistant connected to Wardby over MCP and the user asked to plan\na GKE deployment, produce a written plan; do not create cloud resources. Read\n[Choose a deployment target](deployment-targets.md) first and confirm GKE is\nthe right target. Then ask for, one at a time, and record:\n\n1. The Google Cloud project (dedicated, with billing) and region, and who\n holds the IAM roles to apply Terraform.\n2. The public hostname and who controls its DNS.\n3. The identity provider for people signing in (see\n [Configure identity and privileged access](identity-and-access.md)).\n4. The GitHub App: which repositories it is installed on (see\n [Connect GitHub repositories](github.md)).\n5. Which coding providers the agents use (Codex, Claude Code or both), and\n which provider keys and worker images that needs.\n6. Where Terraform state lives, and the monthly cloud budget and alerts.\n7. Optional: Jira.\n\nThe plan lists those answers, the ordered steps above with the values filled\nin, the commands the user will run themselves, and the open questions. Point\nthe user to the full guide below for every step.\n\nFollow the complete, ordered guide at\n[`docs/getting-started-gke.md`](../docs/getting-started-gke.md). It includes\nthe precise IAM, DNS, bootstrap, upgrades, and teardown steps.\n",
|
|
866
|
+
"plainText": "Deploy Wardby on GKE Autopilot The supported Google Cloud deployment creates a GKE Autopilot cluster, private Cloud SQL for PostgreSQL, Artifact Registry, HTTPS Gateway, Google Secret Manager synchronization, and isolated gVisor-backed coding-worker pods for Codex and Claude Code. It also applies namespace RBAC and default-deny network policies. Use a dedicated billed project, a hostname you control, remote Terraform state, and a GitHub App installed only on repositories that agents need. Review Terraform's plan and set cloud budgets before applying it: the deployment creates billable resources. The deployment process is: Install gcloud, Terraform, Docker with linux/amd64 support, kubectl, Helm, Node.js 24, and authenticate to the target project. Configure deploy/gke/terraform.tfvars, apply Terraform, and prepare the Gateway's address, certificate map, Cloud Armor policy, and DNS record. On a brand-new project, run deploy/gke/bootstrap-database-iam.sh once after terraform apply, so the migrator has its database grants before the first migration. Put first-time values in an untracked .env.local; deploy/gke/up.sh seeds Secret Manager without overwriting existing production values. Jira settings are optional there, all or none; see Jira. Run WARDBYHOSTNAME=wardby.example.com deploy/gke/up.sh, then verify DNS, certificate issuance, and service health. Use WARDBYHOSTNAME, not HOSTNAME (shells set that to the machine name); the script refuses local names such as .lan or .local, and asks you to confirm (or set WARDBYHOSTNAMECHANGE=<new hostname) before moving a deployment to a different hostname. To upgrade, re-run deploy/gke/up.sh from the new release. It applies the migrations, then the database grants (deploy/gke/database-grants.sql), and only then rolls out the new pods, so a release that adds tables or columns the coding proxy uses (such as per-model usage for cost attribution) needs no manual grants step. If the grants fail, up.sh stops before the rollout with a non-zero exit; deploy/gke/bootstrap-database-iam.sh --check shows the refused statement without changing anything. See Upgrading an existing deployment. up.sh works from its own one-cluster copy of the cluster's kubeconfig context, so switching contexts in another terminal mid-deploy can't send a step to another cluster. Run one deploy of a cluster at a time: a second stops with another operation (install/upgrade/rollback) is in progress. The Kubernetes launcher runs Codex and Claude Code coding workers; a Claude Code pod adds a tool-runner sidecar with its own image. Configure an identity provider and GitHub App before allowing people to use the public endpoint. To lower the idle cost of a lightly used deployment, see Low-power mode (Wardby 0.6.0 and later). Plan it with your assistant If you are an assistant connected to Wardby over MCP and the user asked to plan a GKE deployment, produce a written plan; do not create cloud resources. Read Choose a deployment target first and confirm GKE is the right target. Then ask for, one at a time, and record: The Google Cloud project (dedicated, with billing) and region, and who holds the IAM roles to apply Terraform. The public hostname and who controls its DNS. The identity provider for people signing in (see Configure identity and privileged access). The GitHub App: which repositories it is installed on (see Connect GitHub repositories). Which coding providers the agents use (Codex, Claude Code or both), and which provider keys and worker images that needs. Where Terraform state lives, and the monthly cloud budget and alerts. Optional: Jira. The plan lists those answers, the ordered steps above with the values filled in, the commands the user will run themselves, and the open questions. Point the user to the full guide below for every step. Follow the complete, ordered guide at docs/getting-started-gke.md. It includes the precise IAM, DNS, bootstrap, upgrades, and teardown steps.",
|
|
838
867
|
"headings": [
|
|
839
868
|
{
|
|
840
869
|
"level": 1,
|
|
@@ -965,6 +994,75 @@
|
|
|
965
994
|
}
|
|
966
995
|
]
|
|
967
996
|
},
|
|
997
|
+
{
|
|
998
|
+
"id": "errors/coding-mcp-gateway-unavailable",
|
|
999
|
+
"title": "A coding run failed before launch because the native gateway did not wake",
|
|
1000
|
+
"summary": "In low-power mode, the run failed with coding_failure_mcp_gateway_unavailable because the native gateway that serves its MCP tools did not wake in time.",
|
|
1001
|
+
"audience": "operator",
|
|
1002
|
+
"tags": [
|
|
1003
|
+
"error",
|
|
1004
|
+
"mcp",
|
|
1005
|
+
"coding-agents",
|
|
1006
|
+
"low-power",
|
|
1007
|
+
"coding_failure_mcp_gateway_unavailable",
|
|
1008
|
+
"coding_mcp_gateway_unavailable"
|
|
1009
|
+
],
|
|
1010
|
+
"appliesTo": ">=0.8.0",
|
|
1011
|
+
"sourcePath": "errors/coding-mcp-gateway-unavailable.md",
|
|
1012
|
+
"markdown": "\n# A coding run failed before launch because the native gateway did not wake\n\n## What happened\n\nThe run's error starts with `coding_failure_mcp_gateway_unavailable`, followed\nby a diagnostic id. It happens only in [low-power mode](../low-power-mode.md).\n\nA coding run with MCP tools sends every MCP call through the coding proxy to\nthe native gateway (`wardby-native-gateway`). In low-power mode the gateway\nmay be scaled to zero, so before such a run launches, wardby wakes the gateway\ntogether with the proxy and waits for a ready endpoint. The gateway did not\nbecome ready in time, so wardby failed the run rather than start it without\nits MCP tools. Nothing was launched, so the run made no changes.\n\nThe run's error contains only the code and the diagnostic id. The control\nplane log has the cause at `warn`, under the same diagnostic id, with the\ninternal code `coding_mcp_gateway_unavailable` and the underlying wake error,\nusually [`low_power_wake_timeout`](low-power-wake-timeout.md) or\n[`low_power_scale_forbidden`](low-power-scale-forbidden.md).\n\n## What to do\n\n1. Search the control plane log for the diagnostic id and read the wake error.\n2. For `low_power_wake_timeout`, check why the gateway pod did not become\n ready: `kubectl -n <namespace> describe deployment wardby-native-gateway`\n and the events of its pod. A cold Autopilot node can take a few minutes.\n The wait is at least 5 minutes; for coding runs a\n `KUBERNETES_READY_TIMEOUT_MS` above that, set on the control-plane\n Deployment, raises it.\n3. For `low_power_scale_forbidden`, re-run `up.sh` with `WARDBY_LOW_POWER=1` to\n apply the `wardby-power` Role.\n4. Trigger the agent again once the gateway is ready.\n\nRuns without MCP tools do not wake the gateway and never fail this way.\n\nSee [Remote MCP servers for coding agents](../../docs/mcp-servers.md#coding-agents)\nand [Low-power mode](../low-power-mode.md).\n",
|
|
1013
|
+
"plainText": "A coding run failed before launch because the native gateway did not wake What happened The run's error starts with codingfailuremcpgatewayunavailable, followed by a diagnostic id. It happens only in low-power mode. A coding run with MCP tools sends every MCP call through the coding proxy to the native gateway (wardby-native-gateway). In low-power mode the gateway may be scaled to zero, so before such a run launches, wardby wakes the gateway together with the proxy and waits for a ready endpoint. The gateway did not become ready in time, so wardby failed the run rather than start it without its MCP tools. Nothing was launched, so the run made no changes. The run's error contains only the code and the diagnostic id. The control plane log has the cause at warn, under the same diagnostic id, with the internal code codingmcpgatewayunavailable and the underlying wake error, usually lowpowerwaketimeout or lowpowerscaleforbidden. What to do Search the control plane log for the diagnostic id and read the wake error. For lowpowerwaketimeout, check why the gateway pod did not become ready: kubectl -n <namespace describe deployment wardby-native-gateway and the events of its pod. A cold Autopilot node can take a few minutes. The wait is at least 5 minutes; for coding runs a KUBERNETESREADYTIMEOUTMS above that, set on the control-plane Deployment, raises it. For lowpowerscaleforbidden, re-run up.sh with WARDBYLOWPOWER=1 to apply the wardby-power Role. Trigger the agent again once the gateway is ready. Runs without MCP tools do not wake the gateway and never fail this way. See Remote MCP servers for coding agents and Low-power mode.",
|
|
1014
|
+
"headings": [
|
|
1015
|
+
{
|
|
1016
|
+
"level": 1,
|
|
1017
|
+
"text": "A coding run failed before launch because the native gateway did not wake",
|
|
1018
|
+
"slug": "a-coding-run-failed-before-launch-because-the-native-gateway-did-not-wake"
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
"level": 2,
|
|
1022
|
+
"text": "What happened",
|
|
1023
|
+
"slug": "what-happened"
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
"level": 2,
|
|
1027
|
+
"text": "What to do",
|
|
1028
|
+
"slug": "what-to-do"
|
|
1029
|
+
}
|
|
1030
|
+
]
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
"id": "errors/coding-mcp-pins-unavailable",
|
|
1034
|
+
"title": "A coding run failed before launch because its MCP tools could not be read",
|
|
1035
|
+
"summary": "The run failed with coding_failure_mcp_pins_unavailable because wardby could not read the agent's MCP server attachments when it launched the run.",
|
|
1036
|
+
"audience": "operator",
|
|
1037
|
+
"tags": [
|
|
1038
|
+
"error",
|
|
1039
|
+
"mcp",
|
|
1040
|
+
"coding-agents",
|
|
1041
|
+
"coding_failure_mcp_pins_unavailable",
|
|
1042
|
+
"coding_mcp_pins_unavailable"
|
|
1043
|
+
],
|
|
1044
|
+
"appliesTo": ">=0.8.0",
|
|
1045
|
+
"sourcePath": "errors/coding-mcp-pins-unavailable.md",
|
|
1046
|
+
"markdown": "\n# A coding run failed before launch because its MCP tools could not be read\n\n## What happened\n\nThe run's error starts with `coding_failure_mcp_pins_unavailable`, followed by\na diagnostic id. When wardby launches a coding run, it reads the MCP server\ntools attached to the agent and fixes them for that run. That read failed, so\nwardby failed the run rather than launch it without the tools it expected.\nNothing was launched, so the run made no changes.\n\nThe run's error contains only the code and the diagnostic id. The control\nplane log has the real cause at `warn`, under the same diagnostic id, with\nthe internal code `coding_mcp_pins_unavailable`.\n\n## What to do\n\n1. Search the control plane log for the diagnostic id. The cause is usually\n the database: a lost connection, a timeout, or a migration that has not\n been applied.\n2. Fix the database problem, then trigger the agent again. A run that hit a\n brief database outage usually works the next time.\n3. If it keeps happening and you don't need MCP tools on this agent, detach\n its MCP servers with `detach_mcp_server`, or turn MCP servers off with\n `WARDBY_MCP_SERVERS=off`. Either way, the run no longer reads them.\n\nSee [Remote MCP servers for coding agents](../../docs/mcp-servers.md#coding-agents).\n",
|
|
1047
|
+
"plainText": "A coding run failed before launch because its MCP tools could not be read What happened The run's error starts with codingfailuremcppinsunavailable, followed by a diagnostic id. When wardby launches a coding run, it reads the MCP server tools attached to the agent and fixes them for that run. That read failed, so wardby failed the run rather than launch it without the tools it expected. Nothing was launched, so the run made no changes. The run's error contains only the code and the diagnostic id. The control plane log has the real cause at warn, under the same diagnostic id, with the internal code codingmcppinsunavailable. What to do Search the control plane log for the diagnostic id. The cause is usually the database: a lost connection, a timeout, or a migration that has not been applied. Fix the database problem, then trigger the agent again. A run that hit a brief database outage usually works the next time. If it keeps happening and you don't need MCP tools on this agent, detach its MCP servers with detachmcpserver, or turn MCP servers off with WARDBYMCPSERVERS=off. Either way, the run no longer reads them. See Remote MCP servers for coding agents.",
|
|
1048
|
+
"headings": [
|
|
1049
|
+
{
|
|
1050
|
+
"level": 1,
|
|
1051
|
+
"text": "A coding run failed before launch because its MCP tools could not be read",
|
|
1052
|
+
"slug": "a-coding-run-failed-before-launch-because-its-mcp-tools-could-not-be-read"
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
"level": 2,
|
|
1056
|
+
"text": "What happened",
|
|
1057
|
+
"slug": "what-happened"
|
|
1058
|
+
},
|
|
1059
|
+
{
|
|
1060
|
+
"level": 2,
|
|
1061
|
+
"text": "What to do",
|
|
1062
|
+
"slug": "what-to-do"
|
|
1063
|
+
}
|
|
1064
|
+
]
|
|
1065
|
+
},
|
|
968
1066
|
{
|
|
969
1067
|
"id": "errors/coding-provider-not-configured",
|
|
970
1068
|
"title": "Coding provider not configured",
|
|
@@ -1121,7 +1219,7 @@
|
|
|
1121
1219
|
"database_auth_invalid",
|
|
1122
1220
|
"rds-iam"
|
|
1123
1221
|
],
|
|
1124
|
-
"appliesTo": ">=0.
|
|
1222
|
+
"appliesTo": ">=0.6.0",
|
|
1125
1223
|
"sourcePath": "errors/database-auth-invalid.md",
|
|
1126
1224
|
"markdown": "\n# Database authentication is misconfigured\n\n`database_auth_invalid` means `DATABASE_AUTH` is not valid, or `DATABASE_AUTH=rds-iam` is set and `DATABASE_URL` (or `DBOS_SYSTEM_DATABASE_URL`) does not meet its rules. Wardby checks this when the process starts, so every `wardby` command fails with it, not only the server. The message names the problem; it never includes the URL, credentials, or parameter values.\n\n`DATABASE_AUTH` is `password` (the default; the password is in `DATABASE_URL`) or `rds-iam` (Amazon RDS IAM database authentication, where the password is a short-lived token signed with the workload's AWS credentials). Any other value is refused.\n\nUnder `rds-iam` check each of these:\n\n1. `DATABASE_URL` starts with `postgresql://` or `postgres://`, has a user, and has no password.\n2. `AWS_REGION` or `DATABASE_AWS_REGION` is set (`DATABASE_AWS_REGION` wins).\n3. The URL has `sslmode=verify-full` and `sslrootcert=<path to the RDS CA bundle>`, and that file exists and is readable in the container. An unreadable file is reported with its error code, such as `ENOENT` for a missing file or `EACCES` for one the process cannot read.\n4. Only supported parameters are present: `sslmode`, `sslrootcert`, `application_name`, `fallback_application_name`, `options`, `client_encoding`, `statement_timeout`, `lock_timeout`, `idle_in_transaction_session_timeout`, `query_timeout`, `connection_limit`, `pool_timeout`, `connect_timeout`, `schema`. Anything else (`sslcert`, `sslkey`, `ssl`, `host`, `pgbouncer`, ...) is refused by name; remove it.\n5. User and database names in the URL are correctly percent-encoded.\n\nIf the code is not raised but connections are rejected, the configuration is valid and the problem is on the AWS side: the workload's IAM role needs `rds-db:connect` for the database user, and that user needs the `rds_iam` role in the database.\n\n`prisma migrate deploy` and `dbos schema` take a URL and do not follow `DATABASE_AUTH`. Mint a short-lived URL with the migration image's helper: `DATABASE_URL=\"$(node scripts/rds-iam-url.mjs)\" && export DATABASE_URL && npm run prisma:migrate && npm run dbos:migrate`. It reports the same `database_auth_invalid` errors for the checks it shares. `wardby quickstart` does not support `rds-iam`.\n\nSee [Database authentication](../../docs/security-deployment.md#database-authentication).\n",
|
|
1127
1225
|
"plainText": "Database authentication is misconfigured databaseauthinvalid means DATABASEAUTH is not valid, or DATABASEAUTH=rds-iam is set and DATABASEURL (or DBOSSYSTEMDATABASEURL) does not meet its rules. Wardby checks this when the process starts, so every wardby command fails with it, not only the server. The message names the problem; it never includes the URL, credentials, or parameter values. DATABASEAUTH is password (the default; the password is in DATABASEURL) or rds-iam (Amazon RDS IAM database authentication, where the password is a short-lived token signed with the workload's AWS credentials). Any other value is refused. Under rds-iam check each of these: DATABASEURL starts with postgresql:// or postgres://, has a user, and has no password. AWSREGION or DATABASEAWSREGION is set (DATABASEAWSREGION wins). The URL has sslmode=verify-full and sslrootcert=<path to the RDS CA bundle, and that file exists and is readable in the container. An unreadable file is reported with its error code, such as ENOENT for a missing file or EACCES for one the process cannot read. Only supported parameters are present: sslmode, sslrootcert, applicationname, fallbackapplicationname, options, clientencoding, statementtimeout, locktimeout, idleintransactionsessiontimeout, querytimeout, connectionlimit, pooltimeout, connecttimeout, schema. Anything else (sslcert, sslkey, ssl, host, pgbouncer, ...) is refused by name; remove it. User and database names in the URL are correctly percent-encoded. If the code is not raised but connections are rejected, the configuration is valid and the problem is on the AWS side: the workload's IAM role needs rds-db:connect for the database user, and that user needs the rdsiam role in the database. prisma migrate deploy and dbos schema take a URL and do not follow DATABASEAUTH. Mint a short-lived URL with the migration image's helper: DATABASEURL=\"$(node scripts/rds-iam-url.mjs)\" && export DATABASEURL && npm run prisma:migrate && npm run dbos:migrate. It reports the same databaseauthinvalid errors for the checks it shares. wardby quickstart does not support rds-iam. See Database authentication.",
|
|
@@ -1376,6 +1474,79 @@
|
|
|
1376
1474
|
}
|
|
1377
1475
|
]
|
|
1378
1476
|
},
|
|
1477
|
+
{
|
|
1478
|
+
"id": "errors/host-provider-error",
|
|
1479
|
+
"title": "Host provider refused (host_provider_*)",
|
|
1480
|
+
"summary": "Registering a host provider, approving its tools or rotating its secrets was refused with a host_provider_ code. Each code has one cause and one fix.",
|
|
1481
|
+
"audience": "operator",
|
|
1482
|
+
"tags": [
|
|
1483
|
+
"host_provider_not_found",
|
|
1484
|
+
"host_provider_in_use",
|
|
1485
|
+
"host_provider_webhook_secret_short",
|
|
1486
|
+
"host provider",
|
|
1487
|
+
"error"
|
|
1488
|
+
],
|
|
1489
|
+
"appliesTo": ">=0.8.0",
|
|
1490
|
+
"sourcePath": "errors/host-provider-error.md",
|
|
1491
|
+
"markdown": "\n# Host provider refused\n\nNothing was changed. The message holds a code and secret or tool names, never a value.\n\n## Registering or approving\n\n- `host_provider_not_found`: no provider has that name. Check it, or register it.\n- `host_provider_missing_operation`: a required operation has no tool. Bind it in `tools`.\n- `host_provider_operation_not_bound`: that isn't a known operation, or this provider doesn't bind it. Check the name.\n- `host_provider_tool_not_found`: you own no tool with that name. Create it, or fix the name.\n- `host_provider_tool_deleted`: the tool behind this operation was deleted, so there's nothing to approve. Bind a new one by registering again.\n- `host_provider_secret_not_found`: you own no secret with that name. Create it, or fix the name.\n- `host_provider_secret_not_brokered`: a credential isn't brokered. Broker it with `set_secret_broker`.\n- `host_provider_secret_hosts`: its broker config misses a host. Allow every API host, and the git host for a repository credential.\n- `host_provider_secret_placement`: it isn't placed in a header or query parameter. Change its placement.\n- `host_provider_permission_secret_shared`: the permission secret is also a credential, or is used by another provider. Give it its own secret.\n- `host_provider_webhook_secret_shared`: the webhook secret is also a credential or permission secret, or is attached to an agent. Give it its own secret, and detach it.\n- `host_provider_webhook_secret_short`: the webhook secret is under 16 characters. Store a longer one.\n- `host_provider_username_is_secret`: `gitUsername` equals a credential's value. Use the host's token username.\n\n## Using a provider's secrets\n\n- `host_provider_webhook_secret_attached`: `attach_secret` or `wardby import` tried to attach a webhook secret to an agent. Don't: no tool may read it.\n- `host_provider_secret_link_stale`: the browser link was requested before a provider used this secret. Request a new one with `hosts:admin`.\n- `host_provider_webhook_secret_short` also refuses a rotation to a value under 16 characters. Enter a longer one; the same link still works.\n\n## Deleting\n\n- `host_provider_in_use`: an agent links to one of its repositories. Remove those links first.\n\nSee [Host providers](../host-providers.md).\n",
|
|
1492
|
+
"plainText": "Host provider refused Nothing was changed. The message holds a code and secret or tool names, never a value. Registering or approving hostprovidernotfound: no provider has that name. Check it, or register it. hostprovidermissingoperation: a required operation has no tool. Bind it in tools. hostprovideroperationnotbound: that isn't a known operation, or this provider doesn't bind it. Check the name. hostprovidertoolnotfound: you own no tool with that name. Create it, or fix the name. hostprovidertooldeleted: the tool behind this operation was deleted, so there's nothing to approve. Bind a new one by registering again. hostprovidersecretnotfound: you own no secret with that name. Create it, or fix the name. hostprovidersecretnotbrokered: a credential isn't brokered. Broker it with setsecretbroker. hostprovidersecrethosts: its broker config misses a host. Allow every API host, and the git host for a repository credential. hostprovidersecretplacement: it isn't placed in a header or query parameter. Change its placement. hostproviderpermissionsecretshared: the permission secret is also a credential, or is used by another provider. Give it its own secret. hostproviderwebhooksecretshared: the webhook secret is also a credential or permission secret, or is attached to an agent. Give it its own secret, and detach it. hostproviderwebhooksecretshort: the webhook secret is under 16 characters. Store a longer one. hostproviderusernameissecret: gitUsername equals a credential's value. Use the host's token username. Using a provider's secrets hostproviderwebhooksecretattached: attachsecret or wardby import tried to attach a webhook secret to an agent. Don't: no tool may read it. hostprovidersecretlinkstale: the browser link was requested before a provider used this secret. Request a new one with hosts:admin. hostproviderwebhooksecretshort also refuses a rotation to a value under 16 characters. Enter a longer one; the same link still works. Deleting hostproviderinuse: an agent links to one of its repositories. Remove those links first. See Host providers.",
|
|
1493
|
+
"headings": [
|
|
1494
|
+
{
|
|
1495
|
+
"level": 1,
|
|
1496
|
+
"text": "Host provider refused",
|
|
1497
|
+
"slug": "host-provider-refused"
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
"level": 2,
|
|
1501
|
+
"text": "Registering or approving",
|
|
1502
|
+
"slug": "registering-or-approving"
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
"level": 2,
|
|
1506
|
+
"text": "Using a provider's secrets",
|
|
1507
|
+
"slug": "using-a-provider-s-secrets"
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
"level": 2,
|
|
1511
|
+
"text": "Deleting",
|
|
1512
|
+
"slug": "deleting"
|
|
1513
|
+
}
|
|
1514
|
+
]
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
"id": "errors/host-tool-failed",
|
|
1518
|
+
"title": "A host provider tool failed (host_tool_*, host_*)",
|
|
1519
|
+
"summary": "test_host_provider reports a fixed code for each failed operation; a tool's own message is dropped on purpose, so test the tool with dry_run_tool.",
|
|
1520
|
+
"audience": "operator",
|
|
1521
|
+
"tags": [
|
|
1522
|
+
"host_tool_failed",
|
|
1523
|
+
"host_tool_timeout",
|
|
1524
|
+
"host_tool_request_denied",
|
|
1525
|
+
"host_tool_no_credential",
|
|
1526
|
+
"host_forbidden"
|
|
1527
|
+
],
|
|
1528
|
+
"appliesTo": ">=0.8.0",
|
|
1529
|
+
"sourcePath": "errors/host-tool-failed.md",
|
|
1530
|
+
"markdown": "\n# A host provider tool failed\n\n## What happened\n\nA tool's own text never reaches a report, a model or a comment, in case it holds something\nprivate. So `test_host_provider` gives a fixed code for each operation.\n\n## What to do\n\n- `host_unauthorized` or `host_forbidden`: the host refused the credential. Check the token and\n its scopes. On the permission lookup, a repository token is often not enough.\n- `host_not_found`, `host_conflict`, `host_rate_limited` or `host_unavailable`: the host answered\n with that state. Check the repository, pull request or ref you named, or try again later.\n- `host_tool_no_credential`: no `credentials` entry covers this repository, the secret can't be\n decrypted, or the secret is no longer brokered or no longer allows every API host.\n- `host_tool_request_denied`: the tool left its API hosts or repository path, used the wrong\n method, set a header other than `accept`, `content-type`, `if-match` or `if-none-match`, sent a\n `_method` or `x-http-method*` query key, sent a path a server could read as something else (dot-only segments, encoded separators), or made\n more than three requests. No request follows a redirect: fetch the `Location` yourself.\n- `host_tool_invalid_result` or `host_tool_invalid_params`: the tool doesn't match its\n operation's shape.\n- `host_tool_failed`: the tool threw an error. `dry_run_tool` shows errors that don't involve the request, for example with a stubbed response. It has no `host` credential, so a tool using `secrets: [\"host\"]` fails there for another reason.\n- `host_tool_timeout`: it ran out of time or instructions.\n\nTo fix a tool, call `update_tool`, then `approve_host_provider_tools`.\n\nSee [Host providers](../host-providers.md).\n",
|
|
1531
|
+
"plainText": "A host provider tool failed What happened A tool's own text never reaches a report, a model or a comment, in case it holds something private. So testhostprovider gives a fixed code for each operation. What to do hostunauthorized or hostforbidden: the host refused the credential. Check the token and its scopes. On the permission lookup, a repository token is often not enough. hostnotfound, hostconflict, hostratelimited or hostunavailable: the host answered with that state. Check the repository, pull request or ref you named, or try again later. hosttoolnocredential: no credentials entry covers this repository, the secret can't be decrypted, or the secret is no longer brokered or no longer allows every API host. hosttoolrequestdenied: the tool left its API hosts or repository path, used the wrong method, set a header other than accept, content-type, if-match or if-none-match, sent a method or x-http-method query key, sent a path a server could read as something else (dot-only segments, encoded separators), or made more than three requests. No request follows a redirect: fetch the Location yourself. hosttoolinvalidresult or hosttoolinvalidparams: the tool doesn't match its operation's shape. hosttoolfailed: the tool threw an error. dryruntool shows errors that don't involve the request, for example with a stubbed response. It has no host credential, so a tool using secrets: [\"host\"] fails there for another reason. hosttooltimeout: it ran out of time or instructions. To fix a tool, call updatetool, then approvehostprovidertools. See Host providers.",
|
|
1532
|
+
"headings": [
|
|
1533
|
+
{
|
|
1534
|
+
"level": 1,
|
|
1535
|
+
"text": "A host provider tool failed",
|
|
1536
|
+
"slug": "a-host-provider-tool-failed"
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
"level": 2,
|
|
1540
|
+
"text": "What happened",
|
|
1541
|
+
"slug": "what-happened"
|
|
1542
|
+
},
|
|
1543
|
+
{
|
|
1544
|
+
"level": 2,
|
|
1545
|
+
"text": "What to do",
|
|
1546
|
+
"slug": "what-to-do"
|
|
1547
|
+
}
|
|
1548
|
+
]
|
|
1549
|
+
},
|
|
1379
1550
|
{
|
|
1380
1551
|
"id": "errors/local-branch-conflict",
|
|
1381
1552
|
"title": "Run's branch was modified or is checked out",
|
|
@@ -1617,6 +1788,352 @@
|
|
|
1617
1788
|
}
|
|
1618
1789
|
]
|
|
1619
1790
|
},
|
|
1791
|
+
{
|
|
1792
|
+
"id": "errors/mcp-call-limit",
|
|
1793
|
+
"title": "A coding run used up its remote tool calls (mcp_call_limit)",
|
|
1794
|
+
"summary": "A Claude Code or Codex run made more remote MCP tool calls than WARDBY_MCP_MAX_CALLS_PER_RUN allows, so further calls are refused.",
|
|
1795
|
+
"audience": "operator",
|
|
1796
|
+
"tags": [
|
|
1797
|
+
"mcp",
|
|
1798
|
+
"mcp_call_limit",
|
|
1799
|
+
"WARDBY_MCP_MAX_CALLS_PER_RUN",
|
|
1800
|
+
"coding agent",
|
|
1801
|
+
"claude code",
|
|
1802
|
+
"codex",
|
|
1803
|
+
"call limit"
|
|
1804
|
+
],
|
|
1805
|
+
"appliesTo": ">=0.8.0",
|
|
1806
|
+
"sourcePath": "errors/mcp-call-limit.md",
|
|
1807
|
+
"markdown": "\n# A coding run used up its remote tool calls\n\n## What happened\n\nA call to a remote MCP tool returned `mcp_call_limit`. Each coding run (Claude Code or Codex) may make a fixed number of remote MCP tool calls, `100` by default. Every call counts, including calls that failed or timed out. Once the run reaches the limit, further calls are refused; the agent sees the refusal as the tool's result and the run goes on.\n\n## What to do\n\n1. Check whether the agent is looping on a tool, for example retrying a call that keeps failing. Fix the cause, or tighten the agent's instructions.\n2. If the run really needs more calls, ask the operator to raise `WARDBY_MCP_MAX_CALLS_PER_RUN` on the native gateway, which counts the calls, and on the server so both agree (a positive whole number; any other value stops start-up). Restart them to apply it.\n3. Native agents are not limited by this setting.\n\nSee [Remote MCP servers](../mcp-servers.md) and [Remote MCP servers for coding agents](../../docs/mcp-servers.md#coding-agents).\n",
|
|
1808
|
+
"plainText": "A coding run used up its remote tool calls What happened A call to a remote MCP tool returned mcpcalllimit. Each coding run (Claude Code or Codex) may make a fixed number of remote MCP tool calls, 100 by default. Every call counts, including calls that failed or timed out. Once the run reaches the limit, further calls are refused; the agent sees the refusal as the tool's result and the run goes on. What to do Check whether the agent is looping on a tool, for example retrying a call that keeps failing. Fix the cause, or tighten the agent's instructions. If the run really needs more calls, ask the operator to raise WARDBYMCPMAXCALLSPERRUN on the native gateway, which counts the calls, and on the server so both agree (a positive whole number; any other value stops start-up). Restart them to apply it. Native agents are not limited by this setting. See Remote MCP servers and Remote MCP servers for coding agents.",
|
|
1809
|
+
"headings": [
|
|
1810
|
+
{
|
|
1811
|
+
"level": 1,
|
|
1812
|
+
"text": "A coding run used up its remote tool calls",
|
|
1813
|
+
"slug": "a-coding-run-used-up-its-remote-tool-calls"
|
|
1814
|
+
},
|
|
1815
|
+
{
|
|
1816
|
+
"level": 2,
|
|
1817
|
+
"text": "What happened",
|
|
1818
|
+
"slug": "what-happened"
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
"level": 2,
|
|
1822
|
+
"text": "What to do",
|
|
1823
|
+
"slug": "what-to-do"
|
|
1824
|
+
}
|
|
1825
|
+
]
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
"id": "errors/mcp-call-timeout",
|
|
1829
|
+
"title": "A remote tool call ran out of time (mcp_call_timeout)",
|
|
1830
|
+
"summary": "A remote tool call hit its callTimeoutMs or the run's deadline, or was stopped.",
|
|
1831
|
+
"audience": "operator",
|
|
1832
|
+
"tags": [
|
|
1833
|
+
"mcp",
|
|
1834
|
+
"mcp_call_timeout",
|
|
1835
|
+
"callTimeoutMs",
|
|
1836
|
+
"timeout",
|
|
1837
|
+
"stop_run",
|
|
1838
|
+
"WARDBY_TOOL_MAX_TIMEOUT_MS"
|
|
1839
|
+
],
|
|
1840
|
+
"appliesTo": ">=0.8.0",
|
|
1841
|
+
"sourcePath": "errors/mcp-call-timeout.md",
|
|
1842
|
+
"markdown": "\n# A remote tool call ran out of time\n\n## What happened\n\nA call returned `mcp_call_timeout`: the server did not answer within the call's limit, the run's own time limit was reached, or `stop_run` stopped the call. Only this call failed.\n\n## What to do\n\n1. If the server is slow, raise `callTimeoutMs` with `attach_mcp_server` (default `30000`).\n2. The limit can't exceed `WARDBY_TOOL_MAX_TIMEOUT_MS`; ask the operator to raise that if needed.\n3. A call is also cut to the run's deadline; give the agent a longer run time if needed.\n\nSee [Remote MCP servers](../mcp-servers.md).\n",
|
|
1843
|
+
"plainText": "A remote tool call ran out of time What happened A call returned mcpcalltimeout: the server did not answer within the call's limit, the run's own time limit was reached, or stoprun stopped the call. Only this call failed. What to do If the server is slow, raise callTimeoutMs with attachmcpserver (default 30000). The limit can't exceed WARDBYTOOLMAXTIMEOUTMS; ask the operator to raise that if needed. A call is also cut to the run's deadline; give the agent a longer run time if needed. See Remote MCP servers.",
|
|
1844
|
+
"headings": [
|
|
1845
|
+
{
|
|
1846
|
+
"level": 1,
|
|
1847
|
+
"text": "A remote tool call ran out of time",
|
|
1848
|
+
"slug": "a-remote-tool-call-ran-out-of-time"
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
"level": 2,
|
|
1852
|
+
"text": "What happened",
|
|
1853
|
+
"slug": "what-happened"
|
|
1854
|
+
},
|
|
1855
|
+
{
|
|
1856
|
+
"level": 2,
|
|
1857
|
+
"text": "What to do",
|
|
1858
|
+
"slug": "what-to-do"
|
|
1859
|
+
}
|
|
1860
|
+
]
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
"id": "errors/mcp-server-auth-failed",
|
|
1864
|
+
"title": "A remote tool server refused the credentials (mcp_server_auth_failed)",
|
|
1865
|
+
"summary": "The MCP server answered 401 or 403; fix the brokered secret or its placement.",
|
|
1866
|
+
"audience": "operator",
|
|
1867
|
+
"tags": [
|
|
1868
|
+
"mcp",
|
|
1869
|
+
"mcp_server_auth_failed",
|
|
1870
|
+
"401",
|
|
1871
|
+
"403",
|
|
1872
|
+
"brokered",
|
|
1873
|
+
"set_secret_broker"
|
|
1874
|
+
],
|
|
1875
|
+
"appliesTo": ">=0.8.0",
|
|
1876
|
+
"sourcePath": "errors/mcp-server-auth-failed.md",
|
|
1877
|
+
"markdown": "\n# A remote tool server refused the credentials\n\n## What happened\n\nA call, or a register or refresh, failed with `mcp_server_auth_failed`: the server answered HTTP 401 or 403 to the credentials Wardby sent.\n\n## What to do\n\n1. Check that the token behind the server's `secretNames` is current and has access to the tool.\n2. Check the secret's placement with `set_secret_broker`, for example header `Authorization` with format `Bearer {value}`.\n3. Update the secret, then `refresh_mcp_server` to confirm. Secret values are never shown in the error.\n\nSee [Remote MCP servers](../mcp-servers.md).\n",
|
|
1878
|
+
"plainText": "A remote tool server refused the credentials What happened A call, or a register or refresh, failed with mcpserverauthfailed: the server answered HTTP 401 or 403 to the credentials Wardby sent. What to do Check that the token behind the server's secretNames is current and has access to the tool. Check the secret's placement with setsecretbroker, for example header Authorization with format Bearer {value}. Update the secret, then refreshmcpserver to confirm. Secret values are never shown in the error. See Remote MCP servers.",
|
|
1879
|
+
"headings": [
|
|
1880
|
+
{
|
|
1881
|
+
"level": 1,
|
|
1882
|
+
"text": "A remote tool server refused the credentials",
|
|
1883
|
+
"slug": "a-remote-tool-server-refused-the-credentials"
|
|
1884
|
+
},
|
|
1885
|
+
{
|
|
1886
|
+
"level": 2,
|
|
1887
|
+
"text": "What happened",
|
|
1888
|
+
"slug": "what-happened"
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
"level": 2,
|
|
1892
|
+
"text": "What to do",
|
|
1893
|
+
"slug": "what-to-do"
|
|
1894
|
+
}
|
|
1895
|
+
]
|
|
1896
|
+
},
|
|
1897
|
+
{
|
|
1898
|
+
"id": "errors/mcp-server-credentials-unavailable",
|
|
1899
|
+
"title": "A remote tool server's credentials can't be decrypted (mcp_server_credentials_unavailable)",
|
|
1900
|
+
"summary": "A brokered secret of an MCP server exists but this Wardby server can't decrypt it; check SECRET_APP_KEY.",
|
|
1901
|
+
"audience": "operator",
|
|
1902
|
+
"tags": [
|
|
1903
|
+
"mcp",
|
|
1904
|
+
"mcp_server_credentials_unavailable",
|
|
1905
|
+
"credentials",
|
|
1906
|
+
"decrypt",
|
|
1907
|
+
"SECRET_APP_KEY",
|
|
1908
|
+
"register_mcp_server"
|
|
1909
|
+
],
|
|
1910
|
+
"appliesTo": ">=0.8.0",
|
|
1911
|
+
"sourcePath": "errors/mcp-server-credentials-unavailable.md",
|
|
1912
|
+
"markdown": "\n# A remote tool server's credentials can't be decrypted\n\n## What happened\n\nAn agent's MCP tool call returned `mcp_server_credentials_unavailable`, or `register_mcp_server`,\n`update_mcp_server` or `refresh_mcp_server` failed with it (as an HTTP 500 error). The server's\nbrokered secret exists, but the Wardby process that made the call could not decrypt its stored value.\nWardby did not contact the MCP server. The same cause has knock-on effects elsewhere in the run:\nposting and `delegate_to_*` tools return `secret_check_unavailable`, the run's final text and error\nare withheld, and `get_run` withholds the request (see [Secrets and tools](../../docs/tool-secrets.md)).\n\nThe usual causes:\n\n- The Wardby processes don't share one `SECRET_APP_KEY`. The control plane, the scheduler and the\n native gateway each decrypt secrets, so a process started with another key can't read a secret\n the others saved.\n- `SECRET_APP_KEY` was changed after the secret was saved.\n- The stored value is damaged.\n\nAn agent that uses another owner's server through a grant sees the same code with a generic\nmessage: \"The MCP server's credentials can't be used; ask its owner to check it.\"\n\n## What to do\n\n1. Check that every Wardby process (control plane, scheduler, native gateway) gets the same\n `SECRET_APP_KEY`. Fix the one that differs and restart it.\n2. If the key really changed, set the secret again with its new value (`create_secret` with the same\n name), then run `refresh_mcp_server`.\n3. Operator logs carry one `warn` line per failure with `reason: \"mcp_secret_decrypt_failed\"`, the\n server and the secret name (never the value or the cipher's error).\n\nA secret that is missing, not brokered, or not brokered to the server's host is an input problem\ninstead and returns [`mcp_server_error`](mcp-server-error.md) or a 400 error from the register,\nupdate and refresh tools.\n\nSee [Remote MCP servers](../mcp-servers.md) and [Secrets and tools](../../docs/tool-secrets.md).\n",
|
|
1913
|
+
"plainText": "A remote tool server's credentials can't be decrypted What happened An agent's MCP tool call returned mcpservercredentialsunavailable, or registermcpserver, updatemcpserver or refreshmcpserver failed with it (as an HTTP 500 error). The server's brokered secret exists, but the Wardby process that made the call could not decrypt its stored value. Wardby did not contact the MCP server. The same cause has knock-on effects elsewhere in the run: posting and delegateto tools return secretcheckunavailable, the run's final text and error are withheld, and getrun withholds the request (see Secrets and tools). The usual causes: The Wardby processes don't share one SECRETAPPKEY. The control plane, the scheduler and the native gateway each decrypt secrets, so a process started with another key can't read a secret the others saved. SECRETAPPKEY was changed after the secret was saved. The stored value is damaged. An agent that uses another owner's server through a grant sees the same code with a generic message: \"The MCP server's credentials can't be used; ask its owner to check it.\" What to do Check that every Wardby process (control plane, scheduler, native gateway) gets the same SECRETAPPKEY. Fix the one that differs and restart it. If the key really changed, set the secret again with its new value (createsecret with the same name), then run refreshmcpserver. Operator logs carry one warn line per failure with reason: \"mcpsecretdecryptfailed\", the server and the secret name (never the value or the cipher's error). A secret that is missing, not brokered, or not brokered to the server's host is an input problem instead and returns mcpservererror or a 400 error from the register, update and refresh tools. See Remote MCP servers and Secrets and tools.",
|
|
1914
|
+
"headings": [
|
|
1915
|
+
{
|
|
1916
|
+
"level": 1,
|
|
1917
|
+
"text": "A remote tool server's credentials can't be decrypted",
|
|
1918
|
+
"slug": "a-remote-tool-server-s-credentials-can-t-be-decrypted"
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
"level": 2,
|
|
1922
|
+
"text": "What happened",
|
|
1923
|
+
"slug": "what-happened"
|
|
1924
|
+
},
|
|
1925
|
+
{
|
|
1926
|
+
"level": 2,
|
|
1927
|
+
"text": "What to do",
|
|
1928
|
+
"slug": "what-to-do"
|
|
1929
|
+
}
|
|
1930
|
+
]
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
"id": "errors/mcp-server-error",
|
|
1934
|
+
"title": "A remote tool server returned an error (mcp_server_error)",
|
|
1935
|
+
"summary": "The MCP server answered with an HTTP error or a bad reply, asked for something Wardby doesn't support, or the tool reported an error.",
|
|
1936
|
+
"audience": "operator",
|
|
1937
|
+
"tags": [
|
|
1938
|
+
"mcp",
|
|
1939
|
+
"mcp_server_error",
|
|
1940
|
+
"isError",
|
|
1941
|
+
"tools/call",
|
|
1942
|
+
"credentials"
|
|
1943
|
+
],
|
|
1944
|
+
"appliesTo": ">=0.8.0",
|
|
1945
|
+
"sourcePath": "errors/mcp-server-error.md",
|
|
1946
|
+
"markdown": "\n# A remote tool server returned an error\n\n## What happened\n\nA call returned `mcp_server_error`. One of these happened:\n\n- the server answered with an HTTP status other than 2xx (not 401 or 403), or sent a reply Wardby could not read;\n- the server's reply carried only a request of its own (sampling, elicitation or roots) and no answer: Wardby supports none of them, so the call fails;\n- the tool ran and reported an error; the server's message is passed on with secret values removed;\n- the server's secrets could not be loaded (missing, not brokered, or not brokered to the server's host). The server's owner sees which secret; an agent using a server shared with its owner sees only \"The MCP server's credentials can't be used; ask its owner to check it.\"\n\n## What to do\n\n1. Read the message: a tool-reported error usually says what was wrong with the arguments.\n2. If the HTTP status is a 5xx, retry later or ask the server's operator.\n3. If the tool's input changed, `refresh_mcp_server` and review `get_mcp_server`.\n4. For a credentials message on a shared server, ask the server's owner to check its secrets with `get_mcp_server` and `list_secrets`.\n\nSee [Remote MCP servers](../mcp-servers.md).\n",
|
|
1947
|
+
"plainText": "A remote tool server returned an error What happened A call returned mcpservererror. One of these happened: the server answered with an HTTP status other than 2xx (not 401 or 403), or sent a reply Wardby could not read; the server's reply carried only a request of its own (sampling, elicitation or roots) and no answer: Wardby supports none of them, so the call fails; the tool ran and reported an error; the server's message is passed on with secret values removed; the server's secrets could not be loaded (missing, not brokered, or not brokered to the server's host). The server's owner sees which secret; an agent using a server shared with its owner sees only \"The MCP server's credentials can't be used; ask its owner to check it.\" What to do Read the message: a tool-reported error usually says what was wrong with the arguments. If the HTTP status is a 5xx, retry later or ask the server's operator. If the tool's input changed, refreshmcpserver and review getmcpserver. For a credentials message on a shared server, ask the server's owner to check its secrets with getmcpserver and listsecrets. See Remote MCP servers.",
|
|
1948
|
+
"headings": [
|
|
1949
|
+
{
|
|
1950
|
+
"level": 1,
|
|
1951
|
+
"text": "A remote tool server returned an error",
|
|
1952
|
+
"slug": "a-remote-tool-server-returned-an-error"
|
|
1953
|
+
},
|
|
1954
|
+
{
|
|
1955
|
+
"level": 2,
|
|
1956
|
+
"text": "What happened",
|
|
1957
|
+
"slug": "what-happened"
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
"level": 2,
|
|
1961
|
+
"text": "What to do",
|
|
1962
|
+
"slug": "what-to-do"
|
|
1963
|
+
}
|
|
1964
|
+
]
|
|
1965
|
+
},
|
|
1966
|
+
{
|
|
1967
|
+
"id": "errors/mcp-server-unreachable",
|
|
1968
|
+
"title": "A remote tool server could not be reached (mcp_server_unreachable)",
|
|
1969
|
+
"summary": "Wardby could not connect to a remote MCP server; check the URL, the server and its network path.",
|
|
1970
|
+
"audience": "operator",
|
|
1971
|
+
"tags": [
|
|
1972
|
+
"mcp",
|
|
1973
|
+
"mcp_server_unreachable",
|
|
1974
|
+
"unreachable",
|
|
1975
|
+
"register_mcp_server",
|
|
1976
|
+
"update_mcp_server"
|
|
1977
|
+
],
|
|
1978
|
+
"appliesTo": ">=0.8.0",
|
|
1979
|
+
"sourcePath": "errors/mcp-server-unreachable.md",
|
|
1980
|
+
"markdown": "\n# A remote tool server could not be reached\n\n## What happened\n\nAn agent's MCP tool call returned `mcp_server_unreachable`, or `register_mcp_server` / `refresh_mcp_server` failed with it. Wardby could not open a connection to the server's URL (DNS, TLS, refused or reset connection). Only this call failed.\n\n## What to do\n\n1. Check the URL with `get_mcp_server` (the owner sees it) and that the server is up.\n2. Check that Wardby's network can reach the host over HTTPS on the default port.\n3. Fix the URL with `update_mcp_server`, then `refresh_mcp_server`.\n\nSee [Remote MCP servers](../mcp-servers.md).\n",
|
|
1981
|
+
"plainText": "A remote tool server could not be reached What happened An agent's MCP tool call returned mcpserverunreachable, or registermcpserver / refreshmcpserver failed with it. Wardby could not open a connection to the server's URL (DNS, TLS, refused or reset connection). Only this call failed. What to do Check the URL with getmcpserver (the owner sees it) and that the server is up. Check that Wardby's network can reach the host over HTTPS on the default port. Fix the URL with updatemcpserver, then refreshmcpserver. See Remote MCP servers.",
|
|
1982
|
+
"headings": [
|
|
1983
|
+
{
|
|
1984
|
+
"level": 1,
|
|
1985
|
+
"text": "A remote tool server could not be reached",
|
|
1986
|
+
"slug": "a-remote-tool-server-could-not-be-reached"
|
|
1987
|
+
},
|
|
1988
|
+
{
|
|
1989
|
+
"level": 2,
|
|
1990
|
+
"text": "What happened",
|
|
1991
|
+
"slug": "what-happened"
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
"level": 2,
|
|
1995
|
+
"text": "What to do",
|
|
1996
|
+
"slug": "what-to-do"
|
|
1997
|
+
}
|
|
1998
|
+
]
|
|
1999
|
+
},
|
|
2000
|
+
{
|
|
2001
|
+
"id": "errors/mcp-servers-off",
|
|
2002
|
+
"title": "Remote tool servers are turned off (mcp_servers_off)",
|
|
2003
|
+
"summary": "WARDBY_MCP_SERVERS=off: MCP server tools are refused and attached servers are left out of runs.",
|
|
2004
|
+
"audience": "operator",
|
|
2005
|
+
"tags": [
|
|
2006
|
+
"mcp",
|
|
2007
|
+
"mcp_servers_off",
|
|
2008
|
+
"WARDBY_MCP_SERVERS",
|
|
2009
|
+
"off",
|
|
2010
|
+
"admins"
|
|
2011
|
+
],
|
|
2012
|
+
"appliesTo": ">=0.8.0",
|
|
2013
|
+
"sourcePath": "errors/mcp-servers-off.md",
|
|
2014
|
+
"markdown": "\n# Remote tool servers are turned off\n\n## What happened\n\nThe Wardby MCP-server tools answered `mcp_servers_off` (403), or a run's MCP call did. The server has `WARDBY_MCP_SERVERS=off`. Attached servers' tools are left out of new runs. `detach_mcp_server` and `delete_mcp_server` still work, so you can clean up while the feature is off.\n\n## What to do\n\n1. Ask the operator to set `WARDBY_MCP_SERVERS` to `owners` or `admins` and restart.\n2. With `admins`, registering, updating and refreshing need `hosts:admin`.\n\nSee [Remote MCP servers](../mcp-servers.md).\n",
|
|
2015
|
+
"plainText": "Remote tool servers are turned off What happened The Wardby MCP-server tools answered mcpserversoff (403), or a run's MCP call did. The server has WARDBYMCPSERVERS=off. Attached servers' tools are left out of new runs. detachmcpserver and deletemcpserver still work, so you can clean up while the feature is off. What to do Ask the operator to set WARDBYMCPSERVERS to owners or admins and restart. With admins, registering, updating and refreshing need hosts:admin. See Remote MCP servers.",
|
|
2016
|
+
"headings": [
|
|
2017
|
+
{
|
|
2018
|
+
"level": 1,
|
|
2019
|
+
"text": "Remote tool servers are turned off",
|
|
2020
|
+
"slug": "remote-tool-servers-are-turned-off"
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
"level": 2,
|
|
2024
|
+
"text": "What happened",
|
|
2025
|
+
"slug": "what-happened"
|
|
2026
|
+
},
|
|
2027
|
+
{
|
|
2028
|
+
"level": 2,
|
|
2029
|
+
"text": "What to do",
|
|
2030
|
+
"slug": "what-to-do"
|
|
2031
|
+
}
|
|
2032
|
+
]
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
"id": "errors/mcp-tool-not-allowed",
|
|
2036
|
+
"title": "A remote tool is no longer allowed (mcp_tool_not_allowed)",
|
|
2037
|
+
"summary": "The agent's MCP server was detached, the tool left its allowlist, or the agent's owner lost use access to a shared server.",
|
|
2038
|
+
"audience": "operator",
|
|
2039
|
+
"tags": [
|
|
2040
|
+
"mcp",
|
|
2041
|
+
"mcp_tool_not_allowed",
|
|
2042
|
+
"attach_mcp_server",
|
|
2043
|
+
"detach_mcp_server",
|
|
2044
|
+
"allowedTools",
|
|
2045
|
+
"revoke_access"
|
|
2046
|
+
],
|
|
2047
|
+
"appliesTo": ">=0.8.0",
|
|
2048
|
+
"sourcePath": "errors/mcp-tool-not-allowed.md",
|
|
2049
|
+
"markdown": "\n# A remote tool is no longer allowed\n\n## What happened\n\nA call returned `mcp_tool_not_allowed`. Wardby checks the agent's attachment on every call, and since the run began one of these happened:\n\n- the server was detached, or the tool left `allowedTools`;\n- the server's owner deleted the server;\n- the server is shared with the agent's owner, and its owner revoked that grant or lowered it to `read`. The agent's owner must own the server or hold `use` on it; when that ends, Wardby detaches the server from the agent too.\n\n## What to do\n\n1. Check `get_agent` for `mcpServers`.\n2. Re-attach with `attach_mcp_server` and include the tool in `allowedTools`. For a shared server, ask its owner for `use` again first.\n3. A run that started before the change still lists the tool, but every call re-checks the attachment, so the call is refused with this error.\n\nSee [Remote MCP servers](../mcp-servers.md).\n",
|
|
2050
|
+
"plainText": "A remote tool is no longer allowed What happened A call returned mcptoolnotallowed. Wardby checks the agent's attachment on every call, and since the run began one of these happened: the server was detached, or the tool left allowedTools; the server's owner deleted the server; the server is shared with the agent's owner, and its owner revoked that grant or lowered it to read. The agent's owner must own the server or hold use on it; when that ends, Wardby detaches the server from the agent too. What to do Check getagent for mcpServers. Re-attach with attachmcpserver and include the tool in allowedTools. For a shared server, ask its owner for use again first. A run that started before the change still lists the tool, but every call re-checks the attachment, so the call is refused with this error. See Remote MCP servers.",
|
|
2051
|
+
"headings": [
|
|
2052
|
+
{
|
|
2053
|
+
"level": 1,
|
|
2054
|
+
"text": "A remote tool is no longer allowed",
|
|
2055
|
+
"slug": "a-remote-tool-is-no-longer-allowed"
|
|
2056
|
+
},
|
|
2057
|
+
{
|
|
2058
|
+
"level": 2,
|
|
2059
|
+
"text": "What happened",
|
|
2060
|
+
"slug": "what-happened"
|
|
2061
|
+
},
|
|
2062
|
+
{
|
|
2063
|
+
"level": 2,
|
|
2064
|
+
"text": "What to do",
|
|
2065
|
+
"slug": "what-to-do"
|
|
2066
|
+
}
|
|
2067
|
+
]
|
|
2068
|
+
},
|
|
2069
|
+
{
|
|
2070
|
+
"id": "errors/mcp-tool-removed",
|
|
2071
|
+
"title": "A remote tool is no longer on the server (mcp_tool_removed)",
|
|
2072
|
+
"summary": "The server's saved tool list no longer has the tool; check missingTools in get_agent.",
|
|
2073
|
+
"audience": "operator",
|
|
2074
|
+
"tags": [
|
|
2075
|
+
"mcp",
|
|
2076
|
+
"mcp_tool_removed",
|
|
2077
|
+
"missingTools",
|
|
2078
|
+
"refresh_mcp_server"
|
|
2079
|
+
],
|
|
2080
|
+
"appliesTo": ">=0.8.0",
|
|
2081
|
+
"sourcePath": "errors/mcp-tool-removed.md",
|
|
2082
|
+
"markdown": "\n# A remote tool is no longer on the server\n\n## What happened\n\nA call returned `mcp_tool_removed`. After a `refresh_mcp_server`, the server's saved list no longer includes a tool the agent allows, so calls to it are refused. `get_agent` lists it under `missingTools`.\n\n## What to do\n\n1. Check `get_mcp_server` for the tool's current name; servers sometimes rename tools.\n2. Re-attach with `attach_mcp_server` using the new name.\n3. If the tool is back on the server, `refresh_mcp_server` makes it callable again.\n\nSee [Remote MCP servers](../mcp-servers.md).\n",
|
|
2083
|
+
"plainText": "A remote tool is no longer on the server What happened A call returned mcptoolremoved. After a refreshmcpserver, the server's saved list no longer includes a tool the agent allows, so calls to it are refused. getagent lists it under missingTools. What to do Check getmcpserver for the tool's current name; servers sometimes rename tools. Re-attach with attachmcpserver using the new name. If the tool is back on the server, refreshmcpserver makes it callable again. See Remote MCP servers.",
|
|
2084
|
+
"headings": [
|
|
2085
|
+
{
|
|
2086
|
+
"level": 1,
|
|
2087
|
+
"text": "A remote tool is no longer on the server",
|
|
2088
|
+
"slug": "a-remote-tool-is-no-longer-on-the-server"
|
|
2089
|
+
},
|
|
2090
|
+
{
|
|
2091
|
+
"level": 2,
|
|
2092
|
+
"text": "What happened",
|
|
2093
|
+
"slug": "what-happened"
|
|
2094
|
+
},
|
|
2095
|
+
{
|
|
2096
|
+
"level": 2,
|
|
2097
|
+
"text": "What to do",
|
|
2098
|
+
"slug": "what-to-do"
|
|
2099
|
+
}
|
|
2100
|
+
]
|
|
2101
|
+
},
|
|
2102
|
+
{
|
|
2103
|
+
"id": "errors/mcp-unavailable",
|
|
2104
|
+
"title": "Remote MCP tools are unavailable to a coding run (mcp_unavailable)",
|
|
2105
|
+
"summary": "The coding proxy's MCP route has no native gateway to forward to, or could not reach it, so coding agents get no remote MCP tools.",
|
|
2106
|
+
"audience": "operator",
|
|
2107
|
+
"tags": [
|
|
2108
|
+
"mcp",
|
|
2109
|
+
"mcp_unavailable",
|
|
2110
|
+
"WARDBY_MCP_GATEWAY_URL",
|
|
2111
|
+
"coding proxy",
|
|
2112
|
+
"native gateway",
|
|
2113
|
+
"coding agent"
|
|
2114
|
+
],
|
|
2115
|
+
"appliesTo": ">=0.8.0",
|
|
2116
|
+
"sourcePath": "errors/mcp-unavailable.md",
|
|
2117
|
+
"markdown": "\n# Remote MCP tools are unavailable to a coding run\n\n## What happened\n\nThe coding proxy's `/mcp` route answered `503` or `502` with `mcp_unavailable`. A coding worker reaches its MCP tools only through that route, which forwards to the native gateway. It fails in one of two ways:\n\n- `WARDBY_MCP_GATEWAY_URL` is not set on the proxy (`503`). The coding agent then runs without MCP tools; the run does not fail.\n- The gateway could not be reached, timed out or answered too much (`502`). Only that request fails.\n\n## What to do\n\n1. Set `WARDBY_MCP_GATEWAY_URL` on the coding proxy to the native gateway's base URL, for example `http://<gateway host>:<port>`. The kind and GKE manifests set it to the in-cluster gateway.\n2. Check that the native gateway is running and that the proxy's network policy allows it to reach the gateway's HTTP port.\n3. Restart the proxy after changing the variable. An invalid value stops start-up.\n\nSee [Remote MCP servers for coding agents](../../docs/mcp-servers.md#coding-agents).\n",
|
|
2118
|
+
"plainText": "Remote MCP tools are unavailable to a coding run What happened The coding proxy's /mcp route answered 503 or 502 with mcpunavailable. A coding worker reaches its MCP tools only through that route, which forwards to the native gateway. It fails in one of two ways: WARDBYMCPGATEWAYURL is not set on the proxy (503). The coding agent then runs without MCP tools; the run does not fail. The gateway could not be reached, timed out or answered too much (502). Only that request fails. What to do Set WARDBYMCPGATEWAYURL on the coding proxy to the native gateway's base URL, for example http://<gateway host:<port. The kind and GKE manifests set it to the in-cluster gateway. Check that the native gateway is running and that the proxy's network policy allows it to reach the gateway's HTTP port. Restart the proxy after changing the variable. An invalid value stops start-up. See Remote MCP servers for coding agents.",
|
|
2119
|
+
"headings": [
|
|
2120
|
+
{
|
|
2121
|
+
"level": 1,
|
|
2122
|
+
"text": "Remote MCP tools are unavailable to a coding run",
|
|
2123
|
+
"slug": "remote-mcp-tools-are-unavailable-to-a-coding-run"
|
|
2124
|
+
},
|
|
2125
|
+
{
|
|
2126
|
+
"level": 2,
|
|
2127
|
+
"text": "What happened",
|
|
2128
|
+
"slug": "what-happened"
|
|
2129
|
+
},
|
|
2130
|
+
{
|
|
2131
|
+
"level": 2,
|
|
2132
|
+
"text": "What to do",
|
|
2133
|
+
"slug": "what-to-do"
|
|
2134
|
+
}
|
|
2135
|
+
]
|
|
2136
|
+
},
|
|
1620
2137
|
{
|
|
1621
2138
|
"id": "errors/merge-conflict",
|
|
1622
2139
|
"title": "Conflict markers remain",
|
|
@@ -1714,7 +2231,7 @@
|
|
|
1714
2231
|
"quota",
|
|
1715
2232
|
"native_sandbox_capacity"
|
|
1716
2233
|
],
|
|
1717
|
-
"appliesTo": ">=0.
|
|
2234
|
+
"appliesTo": ">=0.6.0",
|
|
1718
2235
|
"sourcePath": "errors/native-sandbox-capacity.md",
|
|
1719
2236
|
"markdown": "\n# Native sandbox is at capacity\n\n`native_sandbox_capacity` means a sandbox-mode run could not start because there was no room for it. The run failed at start; it is not queued. The message gives one of two reasons:\n\n- **\"N sandbox runs are already active (NATIVE_SANDBOX_MAX_CONCURRENT)\"**: the cap on concurrent sandbox runs, counted across all server replicas as active gateway sessions, has been reached.\n- **\"the namespace's ResourceQuota has no room for another native worker pod\"**: with `NATIVE_SANDBOX_LAUNCHER=kubernetes`, the run namespace's quota on pods, CPU, or memory is full.\n\n1. Wait for running sandbox runs to finish, then trigger the run again.\n2. To allow more at once, raise `NATIVE_SANDBOX_MAX_CONCURRENT` (unset means no cap) and raise the namespace ResourceQuota with it. Each worker pod needs its CPU and memory limits (`NATIVE_SANDBOX_CPUS`, `NATIVE_SANDBOX_MEMORY_MB`) from the quota, which coding runs and the gateway share. Idle warm-pool workers (`NATIVE_SANDBOX_WARM_POOL_SIZE`) take quota too, so leave room for `NATIVE_SANDBOX_MAX_CONCURRENT` plus the pool size.\n3. Check current usage with `kubectl describe resourcequota -n <namespace>` and `kubectl get pods -n <namespace> -l wardby.io/component=native-run`.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1720
2237
|
"plainText": "Native sandbox is at capacity nativesandboxcapacity means a sandbox-mode run could not start because there was no room for it. The run failed at start; it is not queued. The message gives one of two reasons: \"N sandbox runs are already active (NATIVESANDBOXMAXCONCURRENT)\": the cap on concurrent sandbox runs, counted across all server replicas as active gateway sessions, has been reached. \"the namespace's ResourceQuota has no room for another native worker pod\": with NATIVESANDBOXLAUNCHER=kubernetes, the run namespace's quota on pods, CPU, or memory is full. Wait for running sandbox runs to finish, then trigger the run again. To allow more at once, raise NATIVESANDBOXMAXCONCURRENT (unset means no cap) and raise the namespace ResourceQuota with it. Each worker pod needs its CPU and memory limits (NATIVESANDBOXCPUS, NATIVESANDBOXMEMORYMB) from the quota, which coding runs and the gateway share. Idle warm-pool workers (NATIVESANDBOXWARMPOOLSIZE) take quota too, so leave room for NATIVESANDBOXMAXCONCURRENT plus the pool size. Check current usage with kubectl describe resourcequota -n <namespace and kubectl get pods -n <namespace -l wardby.io/component=native-run. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1737,7 +2254,7 @@
|
|
|
1737
2254
|
"sandbox",
|
|
1738
2255
|
"native_sandbox_deadline_exceeded"
|
|
1739
2256
|
],
|
|
1740
|
-
"appliesTo": ">=0.
|
|
2257
|
+
"appliesTo": ">=0.6.0",
|
|
1741
2258
|
"sourcePath": "errors/native-sandbox-deadline-exceeded.md",
|
|
1742
2259
|
"markdown": "\n# Native run deadline exceeded\n\n`native_sandbox_deadline_exceeded` means the run was still going when it reached the sandbox's maximum lifetime of 60 minutes, so the worker was stopped and the run failed. The limit protects against stuck runs and is not configurable.\n\n1. Look for a tool that waits forever or a loop that does not converge.\n2. Split long work into smaller runs, or delegate parts to sub-agents (each is its own run).\n3. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1743
2260
|
"plainText": "Native run deadline exceeded nativesandboxdeadlineexceeded means the run was still going when it reached the sandbox's maximum lifetime of 60 minutes, so the worker was stopped and the run failed. The limit protects against stuck runs and is not configurable. Look for a tool that waits forever or a loop that does not converge. Split long work into smaller runs, or delegate parts to sub-agents (each is its own run). Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1760,7 +2277,7 @@
|
|
|
1760
2277
|
"sandbox",
|
|
1761
2278
|
"native_sandbox_docker_failed"
|
|
1762
2279
|
],
|
|
1763
|
-
"appliesTo": ">=0.
|
|
2280
|
+
"appliesTo": ">=0.6.0",
|
|
1764
2281
|
"sourcePath": "errors/native-sandbox-docker-failed.md",
|
|
1765
2282
|
"markdown": "\n# Native worker Docker command failed\n\n`native_sandbox_docker_failed` means a Docker command needed to launch a worker (pull the image, create the run network, join the gateway to it, or start the container) failed. The message names the step and includes Docker's error output.\n\n1. Confirm the server can reach the Docker daemon (`docker info` as the server's user).\n2. For an image step, confirm the image exists on the host (a local id must already be present; a digest must be pullable without registry credentials, or pull it beforehand).\n3. For a network step, confirm `NATIVE_GATEWAY_CONTAINER` names a running gateway container on this Docker host.\n4. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1766
2283
|
"plainText": "Native worker Docker command failed nativesandboxdockerfailed means a Docker command needed to launch a worker (pull the image, create the run network, join the gateway to it, or start the container) failed. The message names the step and includes Docker's error output. Confirm the server can reach the Docker daemon (docker info as the server's user). For an image step, confirm the image exists on the host (a local id must already be present; a digest must be pullable without registry credentials, or pull it beforehand). For a network step, confirm NATIVEGATEWAYCONTAINER names a running gateway container on this Docker host. Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1783,7 +2300,7 @@
|
|
|
1783
2300
|
"sandbox",
|
|
1784
2301
|
"native_sandbox_gateway_error"
|
|
1785
2302
|
],
|
|
1786
|
-
"appliesTo": ">=0.
|
|
2303
|
+
"appliesTo": ">=0.6.0",
|
|
1787
2304
|
"sourcePath": "errors/native-sandbox-gateway-error.md",
|
|
1788
2305
|
"markdown": "\n# Native worker's gateway call failed\n\n`native_sandbox_gateway_error: <code>: <message>` means the sandbox worker called the gateway (a model turn, a tool, or a delegation) and got an error the run could not continue from. The worker reports the run failed with this error instead of exiting, so it is not `native_sandbox_worker_exited`.\n\n1. Read the code and message in the run's error (`get_run`).\n2. For the gateway's `internal` code the message is never recorded. When the gateway's error named one of wardby's own declared codes, that code follows (any other leading word, and any code that matches a secret value the run can read, never leaves the gateway), for example `native_sandbox_gateway_error: internal: coding_execution_not_configured` (the gateway that served the call cannot start coding runs); otherwise the error is `native_sandbox_gateway_error: internal`. Read the gateway's logs (`native gateway request failed`) for the details: the line carries the error's message and stack with the run's secret values replaced by `[REDACTED]`; when the gateway could not read the run's secret values, or the failure was not an error object, it carries only the error's name (`errName`) and declared code (`causeCode`).\n3. Fix the cause the message names, or check that the gateway can reach the database and the LLM provider.\n4. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1789
2306
|
"plainText": "Native worker's gateway call failed nativesandboxgatewayerror: <code: <message means the sandbox worker called the gateway (a model turn, a tool, or a delegation) and got an error the run could not continue from. The worker reports the run failed with this error instead of exiting, so it is not nativesandboxworkerexited. Read the code and message in the run's error (getrun). For the gateway's internal code the message is never recorded. When the gateway's error named one of wardby's own declared codes, that code follows (any other leading word, and any code that matches a secret value the run can read, never leaves the gateway), for example nativesandboxgatewayerror: internal: codingexecutionnotconfigured (the gateway that served the call cannot start coding runs); otherwise the error is nativesandboxgatewayerror: internal. Read the gateway's logs (native gateway request failed) for the details: the line carries the error's message and stack with the run's secret values replaced by [REDACTED]; when the gateway could not read the run's secret values, or the failure was not an error object, it carries only the error's name (errName) and declared code (causeCode). Fix the cause the message names, or check that the gateway can reach the database and the LLM provider. Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1807,7 +2324,7 @@
|
|
|
1807
2324
|
"kubernetes",
|
|
1808
2325
|
"native_sandbox_gateway_unavailable"
|
|
1809
2326
|
],
|
|
1810
|
-
"appliesTo": ">=0.
|
|
2327
|
+
"appliesTo": ">=0.6.0",
|
|
1811
2328
|
"sourcePath": "errors/native-sandbox-gateway-unavailable.md",
|
|
1812
2329
|
"markdown": "\n# Native gateway Service unavailable\n\n`native_sandbox_gateway_unavailable` means that with `NATIVE_SANDBOX_LAUNCHER=kubernetes`, the Service named by `NATIVE_GATEWAY_SERVICE` (default `wardby-native-gateway`) does not exist in the sandbox namespace or has no ClusterIP. Workers dial the Service's ClusterIP, so Wardby needs one.\n\n1. Confirm the namespace: `NATIVE_SANDBOX_NAMESPACE`, else `KUBERNETES_NAMESPACE`, else `wardby-coding`.\n2. Create the Service there as a regular ClusterIP Service (not headless) that selects the gateway pods (`app.kubernetes.io/name: wardby-native-gateway`) and exposes both 8790 and the deny port 8791.\n3. Confirm the server's Role allows `get` on `services` in that namespace.\n4. Alternatively set `NATIVE_GATEWAY_URL` to an address workers can dial, and keep the gateway's NetworkPolicy and the workers' egress consistent with it.\n5. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1813
2330
|
"plainText": "Native gateway Service unavailable nativesandboxgatewayunavailable means that with NATIVESANDBOXLAUNCHER=kubernetes, the Service named by NATIVEGATEWAYSERVICE (default wardby-native-gateway) does not exist in the sandbox namespace or has no ClusterIP. Workers dial the Service's ClusterIP, so Wardby needs one. Confirm the namespace: NATIVESANDBOXNAMESPACE, else KUBERNETESNAMESPACE, else wardby-coding. Create the Service there as a regular ClusterIP Service (not headless) that selects the gateway pods (app.kubernetes.io/name: wardby-native-gateway) and exposes both 8790 and the deny port 8791. Confirm the server's Role allows get on services in that namespace. Alternatively set NATIVEGATEWAYURL to an address workers can dial, and keep the gateway's NetworkPolicy and the workers' egress consistent with it. Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1830,7 +2347,7 @@
|
|
|
1830
2347
|
"sandbox",
|
|
1831
2348
|
"native_sandbox_image_not_pinned"
|
|
1832
2349
|
],
|
|
1833
|
-
"appliesTo": ">=0.
|
|
2350
|
+
"appliesTo": ">=0.6.0",
|
|
1834
2351
|
"sourcePath": "errors/native-sandbox-image-not-pinned.md",
|
|
1835
2352
|
"markdown": "\n# Native worker image not pinned\n\n`native_sandbox_image_not_pinned` means `NATIVE_SANDBOX_WORKER_IMAGE` is not immutable. Wardby only launches a worker from a digest (`repo@sha256:...`) or a local image id, so the code it isolates cannot change underneath it.\n\n1. Use the digest-pinned reference listed as `nativeWorker` in `dist/quickstart-images.json` for your version, or build locally with `npm run native-worker:image:local` and use the image id from `docker image inspect --format '{{.Id}}' wardby-native-worker:local`.\n2. On Kubernetes (`NATIVE_SANDBOX_LAUNCHER=kubernetes`) a local image id is not accepted: the image must be a registry digest, `repo@sha256:...`, that the cluster can pull. Push your build to a registry and use its digest.\n3. Set it as `NATIVE_SANDBOX_WORKER_IMAGE`, restart the server, and trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1836
2353
|
"plainText": "Native worker image not pinned nativesandboximagenotpinned means NATIVESANDBOXWORKERIMAGE is not immutable. Wardby only launches a worker from a digest (repo@sha256:...) or a local image id, so the code it isolates cannot change underneath it. Use the digest-pinned reference listed as nativeWorker in dist/quickstart-images.json for your version, or build locally with npm run native-worker:image:local and use the image id from docker image inspect --format '{{.Id}}' wardby-native-worker:local. On Kubernetes (NATIVESANDBOXLAUNCHER=kubernetes) a local image id is not accepted: the image must be a registry digest, repo@sha256:..., that the cluster can pull. Push your build to a registry and use its digest. Set it as NATIVESANDBOXWORKERIMAGE, restart the server, and trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1854,7 +2371,7 @@
|
|
|
1854
2371
|
"kubernetes",
|
|
1855
2372
|
"native_sandbox_isolation_mismatch"
|
|
1856
2373
|
],
|
|
1857
|
-
"appliesTo": ">=0.
|
|
2374
|
+
"appliesTo": ">=0.6.0",
|
|
1858
2375
|
"sourcePath": "errors/native-sandbox-isolation-mismatch.md",
|
|
1859
2376
|
"markdown": "\n# Native worker pod differs from what Wardby built\n\n`native_sandbox_isolation_mismatch` means that with `NATIVE_SANDBOX_LAUNCHER=kubernetes`, Wardby read back the worker pod and NetworkPolicy it had just created and found a security-relevant difference: a service-account token, host networking, a different runtime class, priority class, image, container resources, or container security context or environment, an extra init container, or a changed NetworkPolicy. Something in the cluster modified the objects after creation, typically a mutating admission webhook, policy engine, or service mesh injector. The run is failed and the pod removed.\n\n1. Inspect an equivalent pod while a run is starting: `kubectl get pods -n <namespace> -l wardby.io/component=native-run -o yaml`.\n2. Find the admission controller that changes it (`kubectl get mutatingwebhookconfigurations`) and exempt pods labeled `wardby.io/component: native-run` and the run namespace's NetworkPolicies, for example by namespace or label selector. Do not disable sidecar-style injection by editing the pod after the fact.\n3. If `NATIVE_SANDBOX_RUNTIME_CLASS` or `NATIVE_SANDBOX_PRIORITY_CLASS` is set, confirm no policy overrides it. On GKE Autopilot set `KUBERNETES_PLATFORM=gke-autopilot` so pod resources are already in the form Autopilot admits and are not rewritten.\n4. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1860
2377
|
"plainText": "Native worker pod differs from what Wardby built nativesandboxisolationmismatch means that with NATIVESANDBOXLAUNCHER=kubernetes, Wardby read back the worker pod and NetworkPolicy it had just created and found a security-relevant difference: a service-account token, host networking, a different runtime class, priority class, image, container resources, or container security context or environment, an extra init container, or a changed NetworkPolicy. Something in the cluster modified the objects after creation, typically a mutating admission webhook, policy engine, or service mesh injector. The run is failed and the pod removed. Inspect an equivalent pod while a run is starting: kubectl get pods -n <namespace -l wardby.io/component=native-run -o yaml. Find the admission controller that changes it (kubectl get mutatingwebhookconfigurations) and exempt pods labeled wardby.io/component: native-run and the run namespace's NetworkPolicies, for example by namespace or label selector. Do not disable sidecar-style injection by editing the pod after the fact. If NATIVESANDBOXRUNTIMECLASS or NATIVESANDBOXPRIORITYCLASS is set, confirm no policy overrides it. On GKE Autopilot set KUBERNETESPLATFORM=gke-autopilot so pod resources are already in the form Autopilot admits and are not rewritten. Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1903,7 +2420,7 @@
|
|
|
1903
2420
|
"kubernetes",
|
|
1904
2421
|
"native_sandbox_network_unenforced"
|
|
1905
2422
|
],
|
|
1906
|
-
"appliesTo": ">=0.
|
|
2423
|
+
"appliesTo": ">=0.6.0",
|
|
1907
2424
|
"sourcePath": "errors/native-sandbox-network-unenforced.md",
|
|
1908
2425
|
"markdown": "\n# Native worker network isolation not proven\n\n`native_sandbox_network_unenforced` means that with `NATIVE_SANDBOX_LAUNCHER=kubernetes`, Wardby ran a check inside the worker pod and it did not pass before the time limit. The check requires the gateway to be reachable on port 8790 while the gateway's deny port (8791 by default), an outside address, and the cloud metadata endpoints (`169.254.169.254:80`, the EKS Pod Identity agent `169.254.170.23:80` and `[fd00:ec2::23]:80`, and EC2's IPv6 metadata address `[fd00:ec2::254]:80`) are not. The message says which part failed. The pod is removed and the run never started.\n\n- **\"the gateway was unreachable\"**: confirm the gateway Deployment has ready pods, the `wardby-native-gateway` Service (or `NATIVE_GATEWAY_SERVICE`) exposes 8790 and 8791, and the gateway's own NetworkPolicy admits `wardby.io/component: native-run` pods on port 8790.\n- **\"the gateway's deny port was reachable\"** or **\"an outside address was reachable\"** (or a metadata endpoint): the cluster is not enforcing the per-run NetworkPolicy. Confirm your CNI enforces `NetworkPolicy` (some local clusters need a policy-capable CNI such as Calico), and that no other policy or mesh adds egress for these pods.\n- If the Service lacks port 8791, or the gateway's policy does not admit 8791, unprogrammed pods would look isolated. Keep both in place; the check depends on them.\n- On a slow node the policy can take longer to program. Retrigger the run once, or raise `NATIVE_SANDBOX_ENFORCEMENT_TIMEOUT_MS` (default 30000), before changing anything.\n\nA cluster that does not enforce NetworkPolicy fails every sandbox run this way, by design. Switch the agent back to `control-plane` if you cannot enable enforcement.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1909
2426
|
"plainText": "Native worker network isolation not proven nativesandboxnetworkunenforced means that with NATIVESANDBOXLAUNCHER=kubernetes, Wardby ran a check inside the worker pod and it did not pass before the time limit. The check requires the gateway to be reachable on port 8790 while the gateway's deny port (8791 by default), an outside address, and the cloud metadata endpoints (169.254.169.254:80, the EKS Pod Identity agent 169.254.170.23:80 and [fd00:ec2::23]:80, and EC2's IPv6 metadata address [fd00:ec2::254]:80) are not. The message says which part failed. The pod is removed and the run never started. \"the gateway was unreachable\": confirm the gateway Deployment has ready pods, the wardby-native-gateway Service (or NATIVEGATEWAYSERVICE) exposes 8790 and 8791, and the gateway's own NetworkPolicy admits wardby.io/component: native-run pods on port 8790. \"the gateway's deny port was reachable\" or \"an outside address was reachable\" (or a metadata endpoint): the cluster is not enforcing the per-run NetworkPolicy. Confirm your CNI enforces NetworkPolicy (some local clusters need a policy-capable CNI such as Calico), and that no other policy or mesh adds egress for these pods. If the Service lacks port 8791, or the gateway's policy does not admit 8791, unprogrammed pods would look isolated. Keep both in place; the check depends on them. On a slow node the policy can take longer to program. Retrigger the run once, or raise NATIVESANDBOXENFORCEMENTTIMEOUTMS (default 30000), before changing anything. A cluster that does not enforce NetworkPolicy fails every sandbox run this way, by design. Switch the agent back to control-plane if you cannot enable enforcement. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1927,7 +2444,7 @@
|
|
|
1927
2444
|
"model-catalog",
|
|
1928
2445
|
"native_sandbox_requires_catalog"
|
|
1929
2446
|
],
|
|
1930
|
-
"appliesTo": ">=0.
|
|
2447
|
+
"appliesTo": ">=0.6.0",
|
|
1931
2448
|
"sourcePath": "errors/native-sandbox-requires-catalog.md",
|
|
1932
2449
|
"markdown": "\n# Sandbox run has no model catalog entry\n\n`native_sandbox_requires_catalog` means a sandbox-mode run reached its worker\nlaunch without a model catalog entry. The worker prices every model call and\nenforces the run's budget from that entry, so Wardby fails the run before\nstarting a worker or spending anything.\n\nEvery run records its model's catalog entry when it first starts. A model\nthat is unknown, disabled, or has no configured provider fails earlier with\nits own model error, not this one. This error only appears when the process\nexecuting the run does not use Wardby's catalog-backed model router, for\nexample a modified build or an embedding that supplies its own LLM provider.\n\n1. Run sandbox-mode agents on a standard `wardby serve` (or `wardby\nscheduler` / `wardby mcp`) process, which always uses the catalog.\n2. If you supply your own LLM provider, route it through the model catalog,\n or keep the agent on `control-plane` with `update_agent` or\n `wardby agent mode <name> control-plane`.\n3. Trigger the run again. A failed run is not retried on its own.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and\n[Models and the model catalog](../models.md).\n",
|
|
1933
2450
|
"plainText": "Sandbox run has no model catalog entry nativesandboxrequirescatalog means a sandbox-mode run reached its worker launch without a model catalog entry. The worker prices every model call and enforces the run's budget from that entry, so Wardby fails the run before starting a worker or spending anything. Every run records its model's catalog entry when it first starts. A model that is unknown, disabled, or has no configured provider fails earlier with its own model error, not this one. This error only appears when the process executing the run does not use Wardby's catalog-backed model router, for example a modified build or an embedding that supplies its own LLM provider. Run sandbox-mode agents on a standard wardby serve (or wardby scheduler / wardby mcp) process, which always uses the catalog. If you supply your own LLM provider, route it through the model catalog, or keep the agent on control-plane with updateagent or wardby agent mode <name control-plane. Trigger the run again. A failed run is not retried on its own. See Run native agents in a sandbox and Models and the model catalog.",
|
|
@@ -1950,7 +2467,7 @@
|
|
|
1950
2467
|
"sandbox",
|
|
1951
2468
|
"native_sandbox_unavailable"
|
|
1952
2469
|
],
|
|
1953
|
-
"appliesTo": ">=0.
|
|
2470
|
+
"appliesTo": ">=0.6.0",
|
|
1954
2471
|
"sourcePath": "errors/native-sandbox-unavailable.md",
|
|
1955
2472
|
"markdown": "\n# Native execution mode unavailable\n\n`native_sandbox_unavailable` means the agent's `nativeExecutionMode` is `sandbox` but this deployment has no native sandbox configured. Wardby fails the run before any spend rather than running it unisolated.\n\n1. To use the sandbox, set `NATIVE_SANDBOX_LAUNCHER=docker`, `NATIVE_SANDBOX_WORKER_IMAGE`, and `NATIVE_GATEWAY_CONTAINER` on the server that executes runs (`wardby serve` or `wardby scheduler`), start the native gateway, and restart the server.\n2. Otherwise set the agent back to `control-plane` with `update_agent`.\n3. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
1956
2473
|
"plainText": "Native execution mode unavailable nativesandboxunavailable means the agent's nativeExecutionMode is sandbox but this deployment has no native sandbox configured. Wardby fails the run before any spend rather than running it unisolated. To use the sandbox, set NATIVESANDBOXLAUNCHER=docker, NATIVESANDBOXWORKERIMAGE, and NATIVEGATEWAYCONTAINER on the server that executes runs (wardby serve or wardby scheduler), start the native gateway, and restart the server. Otherwise set the agent back to control-plane with updateagent. Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -1976,7 +2493,7 @@
|
|
|
1976
2493
|
"docker",
|
|
1977
2494
|
"native_sandbox_warm_delivery_failed"
|
|
1978
2495
|
],
|
|
1979
|
-
"appliesTo": ">=0.
|
|
2496
|
+
"appliesTo": ">=0.6.0",
|
|
1980
2497
|
"sourcePath": "errors/native-sandbox-warm-delivery-failed.md",
|
|
1981
2498
|
"markdown": "\n# Native sandbox warm worker could not take the run\n\n`native_sandbox_warm_delivery_failed` means a sandbox run claimed an idle worker from the warm pool (`NATIVE_SANDBOX_WARM_POOL_SIZE`), but writing the run's input into that worker failed. The worker may already hold the run's one-time gateway capability, so Wardby removes it and waits up to 30 seconds for it to be confirmed gone before starting a cold worker. This error means it could not be confirmed gone in that time, so the run failed rather than risk two workers holding the same capability. If the worker is confirmed gone, the run cold-launches and you see no error (the log has a `fallback` event).\n\n1. Trigger the run again. Most failures are transient.\n2. Check that the worker is gone: `kubectl get pods -n <namespace> -l wardby.io/pool=warm` (Kubernetes) or `docker ps --all --filter label=io.wardby.pool=warm` (Docker). Pool upkeep removes leftovers, but a stuck pod usually means the node or Docker host is unhealthy.\n3. Look for `native-warm-pool` log entries with `event` `fallback`, and check that the server may exec into pods in the run namespace.\n4. To bypass the pool while you investigate, set `NATIVE_SANDBOX_WARM_POOL_SIZE=0`; every run then cold-starts.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md#warm-pool). A related error is\n[native_sandbox_capacity](native-sandbox-capacity.md).\n",
|
|
1982
2499
|
"plainText": "Native sandbox warm worker could not take the run nativesandboxwarmdeliveryfailed means a sandbox run claimed an idle worker from the warm pool (NATIVESANDBOXWARMPOOLSIZE), but writing the run's input into that worker failed. The worker may already hold the run's one-time gateway capability, so Wardby removes it and waits up to 30 seconds for it to be confirmed gone before starting a cold worker. This error means it could not be confirmed gone in that time, so the run failed rather than risk two workers holding the same capability. If the worker is confirmed gone, the run cold-launches and you see no error (the log has a fallback event). Trigger the run again. Most failures are transient. Check that the worker is gone: kubectl get pods -n <namespace -l wardby.io/pool=warm (Kubernetes) or docker ps --all --filter label=io.wardby.pool=warm (Docker). Pool upkeep removes leftovers, but a stuck pod usually means the node or Docker host is unhealthy. Look for native-warm-pool log entries with event fallback, and check that the server may exec into pods in the run namespace. To bypass the pool while you investigate, set NATIVESANDBOXWARMPOOLSIZE=0; every run then cold-starts. See Run native agents in a sandbox and the native sandbox guide. A related error is nativesandboxcapacity.",
|
|
@@ -1999,7 +2516,7 @@
|
|
|
1999
2516
|
"sandbox",
|
|
2000
2517
|
"native_sandbox_worker_exited"
|
|
2001
2518
|
],
|
|
2002
|
-
"appliesTo": ">=0.
|
|
2519
|
+
"appliesTo": ">=0.6.0",
|
|
2003
2520
|
"sourcePath": "errors/native-sandbox-worker-exited.md",
|
|
2004
2521
|
"markdown": "\n# Native worker exited without a result\n\n`native_sandbox_worker_exited` means the worker container stopped without reporting a result; the message includes its exit code. Common causes are a tool that exhausted the worker's memory or process limit, or a crash in tool code.\n\n1. Read the exit code in the run's error (`get_run`). Code 137 usually means the memory limit was hit.\n2. If limits are the cause, raise `NATIVE_SANDBOX_MEMORY_MB`, `NATIVE_SANDBOX_PIDS`, or `NATIVE_SANDBOX_CPUS` on the server and restart it.\n3. Read the server log line `native worker exited non-zero` (Docker and Kubernetes): its `stderrTail` is the end of the worker's output. The server masks the run's gateway capability and every secret value the agent's tools can read (six characters or longer, as in tool console output) as `[REDACTED]`. If the line has `stderrTailOmitted` instead, there is no tail: `secrets_unavailable` means the server could not read one of those secrets (check the secret store and the tools' attached secrets); `log_read_failed` means it could not read the worker pod's log on Kubernetes (check that the server's Role allows `get` on `pods/log`).\n4. Otherwise test the agent's tools with `dry_run_tool` and fix the failing code.\n5. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
2005
2522
|
"plainText": "Native worker exited without a result nativesandboxworkerexited means the worker container stopped without reporting a result; the message includes its exit code. Common causes are a tool that exhausted the worker's memory or process limit, or a crash in tool code. Read the exit code in the run's error (getrun). Code 137 usually means the memory limit was hit. If limits are the cause, raise NATIVESANDBOXMEMORYMB, NATIVESANDBOXPIDS, or NATIVESANDBOXCPUS on the server and restart it. Read the server log line native worker exited non-zero (Docker and Kubernetes): its stderrTail is the end of the worker's output. The server masks the run's gateway capability and every secret value the agent's tools can read (six characters or longer, as in tool console output) as [REDACTED]. If the line has stderrTailOmitted instead, there is no tail: secretsunavailable means the server could not read one of those secrets (check the secret store and the tools' attached secrets); logreadfailed means it could not read the worker pod's log on Kubernetes (check that the server's Role allows get on pods/log). Otherwise test the agent's tools with dryruntool and fix the failing code. Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -2022,7 +2539,7 @@
|
|
|
2022
2539
|
"sandbox",
|
|
2023
2540
|
"native_sandbox_worker_lost"
|
|
2024
2541
|
],
|
|
2025
|
-
"appliesTo": ">=0.
|
|
2542
|
+
"appliesTo": ">=0.6.0",
|
|
2026
2543
|
"sourcePath": "errors/native-sandbox-worker-lost.md",
|
|
2027
2544
|
"markdown": "\n# Native worker lost\n\n`native_sandbox_worker_lost` means the run's worker container (or Kubernetes pod) is gone and left no result, for example because the Docker host restarted or an operator removed the container. Wardby never relaunches a worker, because a relaunch could repeat tool side effects.\n\n1. Check whether the Docker host or daemon restarted around the run's time.\n2. List workers with `docker ps --all --filter label=io.wardby.component=native-worker`; do not remove workers of running runs by hand.\n3. On Kubernetes, check whether the node was drained or preempted, and list pods with `kubectl get pods -n <namespace> -l wardby.io/component=native-run`.\n4. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
2028
2545
|
"plainText": "Native worker lost nativesandboxworkerlost means the run's worker container (or Kubernetes pod) is gone and left no result, for example because the Docker host restarted or an operator removed the container. Wardby never relaunches a worker, because a relaunch could repeat tool side effects. Check whether the Docker host or daemon restarted around the run's time. List workers with docker ps --all --filter label=io.wardby.component=native-worker; do not remove workers of running runs by hand. On Kubernetes, check whether the node was drained or preempted, and list pods with kubectl get pods -n <namespace -l wardby.io/component=native-run. Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -2046,7 +2563,7 @@
|
|
|
2046
2563
|
"kubernetes",
|
|
2047
2564
|
"native_sandbox_worker_unready"
|
|
2048
2565
|
],
|
|
2049
|
-
"appliesTo": ">=0.
|
|
2566
|
+
"appliesTo": ">=0.6.0",
|
|
2050
2567
|
"sourcePath": "errors/native-sandbox-worker-unready.md",
|
|
2051
2568
|
"markdown": "\n# Native worker pod did not start\n\n`native_sandbox_worker_unready` means that with `NATIVE_SANDBOX_LAUNCHER=kubernetes`, the worker pod stayed pending past the start-up limit (`NATIVE_SANDBOX_READY_TIMEOUT_MS`, default two minutes). Nothing ran.\n\n1. Describe the pod while it waits: `kubectl describe pod -n <namespace> -l wardby.io/component=native-run`. Look at the events for image pull errors, unschedulable reasons, or an unknown runtime class.\n2. Image pull: the cluster must be able to pull `NATIVE_SANDBOX_WORKER_IMAGE` (a registry digest) without interactive credentials; add a pull secret to the namespace's default service account if the registry is private.\n3. Scheduling: raise node capacity or lower `NATIVE_SANDBOX_CPUS` and `NATIVE_SANDBOX_MEMORY_MB`, and check namespace ResourceQuotas.\n4. Runtime class: confirm `NATIVE_SANDBOX_RUNTIME_CLASS` (or `KUBERNETES_RUNTIME_CLASS`) exists on the cluster. On Amazon EKS (`KUBERNETES_PLATFORM=eks`) the `gvisor` RuntimeClass must use handler `runsc` and its scheduling block must match your sandbox nodes (label `wardby.dev/sandbox=gvisor`, taint `sandbox=gvisor:NoSchedule`); a mismatch leaves the pod pending.\n5. On a cold node, such as a first gVisor pod on GKE Autopilot (about two minutes), raise `NATIVE_SANDBOX_READY_TIMEOUT_MS` (1000 to 1800000; about 600000 on Autopilot).\n6. Trigger the run again.\n\nSee [Run native agents in a sandbox](../native-sandbox.md) and the\n[native sandbox guide](../../docs/native-sandbox.md).\n",
|
|
2052
2569
|
"plainText": "Native worker pod did not start nativesandboxworkerunready means that with NATIVESANDBOXLAUNCHER=kubernetes, the worker pod stayed pending past the start-up limit (NATIVESANDBOXREADYTIMEOUTMS, default two minutes). Nothing ran. Describe the pod while it waits: kubectl describe pod -n <namespace -l wardby.io/component=native-run. Look at the events for image pull errors, unschedulable reasons, or an unknown runtime class. Image pull: the cluster must be able to pull NATIVESANDBOXWORKERIMAGE (a registry digest) without interactive credentials; add a pull secret to the namespace's default service account if the registry is private. Scheduling: raise node capacity or lower NATIVESANDBOXCPUS and NATIVESANDBOXMEMORYMB, and check namespace ResourceQuotas. Runtime class: confirm NATIVESANDBOXRUNTIMECLASS (or KUBERNETESRUNTIMECLASS) exists on the cluster. On Amazon EKS (KUBERNETESPLATFORM=eks) the gvisor RuntimeClass must use handler runsc and its scheduling block must match your sandbox nodes (label wardby.dev/sandbox=gvisor, taint sandbox=gvisor:NoSchedule); a mismatch leaves the pod pending. On a cold node, such as a first gVisor pod on GKE Autopilot (about two minutes), raise NATIVESANDBOXREADYTIMEOUTMS (1000 to 1800000; about 600000 on Autopilot). Trigger the run again. See Run native agents in a sandbox and the native sandbox guide.",
|
|
@@ -2244,6 +2761,65 @@
|
|
|
2244
2761
|
}
|
|
2245
2762
|
]
|
|
2246
2763
|
},
|
|
2764
|
+
{
|
|
2765
|
+
"id": "errors/repository-not-listed",
|
|
2766
|
+
"title": "Repository not on the agent's list (repository_not_listed)",
|
|
2767
|
+
"summary": "The repository named for a coding run is not the agent's default or one of its write links; name a listed one, or add it with link_repository.",
|
|
2768
|
+
"audience": "operator",
|
|
2769
|
+
"tags": [
|
|
2770
|
+
"error",
|
|
2771
|
+
"coding-agents",
|
|
2772
|
+
"repository_not_listed",
|
|
2773
|
+
"invalid_repository",
|
|
2774
|
+
"link_repository"
|
|
2775
|
+
],
|
|
2776
|
+
"appliesTo": ">=0.8.0",
|
|
2777
|
+
"sourcePath": "errors/repository-not-listed.md",
|
|
2778
|
+
"markdown": "\n# Repository not on the agent's list\n\n`repository_not_listed` means the `repository` given to `trigger_agent` or to a\n`delegate_to_<name>` call is neither the coding agent's default\n(`codingProfile.repository`) nor one of its repository links (write access, no\ntriggers). No run was started. The message lists the repositories that are\nallowed and never repeats the value that was sent.\n\nA webhook that sends `wardbyRepository` gets the same refusal as a 400\n`{ \"error\": \"invalid_repository\" }` when\n`codingProfile.allowWebhookTaskOverride` is on. A malformed value (not a string,\nempty, or over 300 characters) is that same 400 with the flag on or off. With\nthe flag off, a well-formed value is refused with 403 `{ \"error\": \"disabled\" }`\nbefore it is compared with the list, whoever created the webhook.\n\n## What to do\n\n- Name one of the listed repositories, spelled as `your-org/your-repo`.\n- To add a repository, the agent's owner calls `link_repository` with\n `access: \"write\"`, no triggers and, optionally, a `baseRef`. The owner needs\n write access to it on the host, or an admin approves it.\n- If a native (non-coding) sub-agent is the target, `repository` is refused\n with `repository_requires_coding_agent`: drop the argument.\n\nSee [Repository required](repository-required.md),\n[Agent recipes](../agent-recipes.md) and the operator guide\n`docs/coding-agent-setup.md`, section \"A coding agent's repositories\".\n",
|
|
2779
|
+
"plainText": "Repository not on the agent's list repositorynotlisted means the repository given to triggeragent or to a delegateto<name call is neither the coding agent's default (codingProfile.repository) nor one of its repository links (write access, no triggers). No run was started. The message lists the repositories that are allowed and never repeats the value that was sent. A webhook that sends wardbyRepository gets the same refusal as a 400 { \"error\": \"invalidrepository\" } when codingProfile.allowWebhookTaskOverride is on. A malformed value (not a string, empty, or over 300 characters) is that same 400 with the flag on or off. With the flag off, a well-formed value is refused with 403 { \"error\": \"disabled\" } before it is compared with the list, whoever created the webhook. What to do Name one of the listed repositories, spelled as your-org/your-repo. To add a repository, the agent's owner calls linkrepository with access: \"write\", no triggers and, optionally, a baseRef. The owner needs write access to it on the host, or an admin approves it. If a native (non-coding) sub-agent is the target, repository is refused with repositoryrequirescodingagent: drop the argument. See Repository required, Agent recipes and the operator guide docs/coding-agent-setup.md, section \"A coding agent's repositories\".",
|
|
2780
|
+
"headings": [
|
|
2781
|
+
{
|
|
2782
|
+
"level": 1,
|
|
2783
|
+
"text": "Repository not on the agent's list",
|
|
2784
|
+
"slug": "repository-not-on-the-agent-s-list"
|
|
2785
|
+
},
|
|
2786
|
+
{
|
|
2787
|
+
"level": 2,
|
|
2788
|
+
"text": "What to do",
|
|
2789
|
+
"slug": "what-to-do"
|
|
2790
|
+
}
|
|
2791
|
+
]
|
|
2792
|
+
},
|
|
2793
|
+
{
|
|
2794
|
+
"id": "errors/repository-required",
|
|
2795
|
+
"title": "Repository required (repository_required)",
|
|
2796
|
+
"summary": "A coding agent with several repositories was asked to work without being told which one; pass repository, or use continuePriorRun.",
|
|
2797
|
+
"audience": "operator",
|
|
2798
|
+
"tags": [
|
|
2799
|
+
"error",
|
|
2800
|
+
"coding-agents",
|
|
2801
|
+
"repository_required",
|
|
2802
|
+
"repository",
|
|
2803
|
+
"link_repository",
|
|
2804
|
+
"delegation"
|
|
2805
|
+
],
|
|
2806
|
+
"appliesTo": ">=0.8.0",
|
|
2807
|
+
"sourcePath": "errors/repository-required.md",
|
|
2808
|
+
"markdown": "\n# Repository required\n\n`repository_required` means a coding agent has more than its default repository\n(it has write links without triggers added with `link_repository`), and the\nrequest did not say which one to work in. Nothing was started.\n\nA `delegate_to_<name>` call to such a sub-agent must name a repository. The\nexception is a follow-up: with `continuePriorRun`, the run works in the\nrepository of the run it continues. The message lists the repositories on the\nagent's list.\n\n## What to do\n\n- Pass `repository` on the call, using one of the listed repositories, for\n example `your-org/your-repo`.\n- Tell the lead agent in its system prompt which repository each kind of\n change belongs to.\n- If the agent should only work in one repository, remove the extra ones with\n `unlink_repository`.\n\nOn `trigger_agent` and webhooks, leaving `repository` out uses the default\nrepository (`codingProfile.repository`) and is not an error. Webhooks use the\nbody field `wardbyRepository`.\n\nSee [Repository not on the agent's list](repository-not-listed.md),\n[Agent recipes](../agent-recipes.md) and the operator guide\n`docs/coding-agent-setup.md`, section \"A coding agent's repositories\".\n",
|
|
2809
|
+
"plainText": "Repository required repositoryrequired means a coding agent has more than its default repository (it has write links without triggers added with linkrepository), and the request did not say which one to work in. Nothing was started. A delegateto<name call to such a sub-agent must name a repository. The exception is a follow-up: with continuePriorRun, the run works in the repository of the run it continues. The message lists the repositories on the agent's list. What to do Pass repository on the call, using one of the listed repositories, for example your-org/your-repo. Tell the lead agent in its system prompt which repository each kind of change belongs to. If the agent should only work in one repository, remove the extra ones with unlinkrepository. On triggeragent and webhooks, leaving repository out uses the default repository (codingProfile.repository) and is not an error. Webhooks use the body field wardbyRepository. See Repository not on the agent's list, Agent recipes and the operator guide docs/coding-agent-setup.md, section \"A coding agent's repositories\".",
|
|
2810
|
+
"headings": [
|
|
2811
|
+
{
|
|
2812
|
+
"level": 1,
|
|
2813
|
+
"text": "Repository required",
|
|
2814
|
+
"slug": "repository-required"
|
|
2815
|
+
},
|
|
2816
|
+
{
|
|
2817
|
+
"level": 2,
|
|
2818
|
+
"text": "What to do",
|
|
2819
|
+
"slug": "what-to-do"
|
|
2820
|
+
}
|
|
2821
|
+
]
|
|
2822
|
+
},
|
|
2247
2823
|
{
|
|
2248
2824
|
"id": "errors/run-lost",
|
|
2249
2825
|
"title": "Run lost",
|
|
@@ -2809,6 +3385,41 @@
|
|
|
2809
3385
|
}
|
|
2810
3386
|
]
|
|
2811
3387
|
},
|
|
3388
|
+
{
|
|
3389
|
+
"id": "errors/tool-timeout",
|
|
3390
|
+
"title": "A tool call ran out of time (timeout, fetch_cancelled_or_timeout)",
|
|
3391
|
+
"summary": "A sandboxed tool call hit its time limit; raise the tool's timeoutMs, up to the server's WARDBY_TOOL_MAX_TIMEOUT_MS.",
|
|
3392
|
+
"audience": "developer",
|
|
3393
|
+
"tags": [
|
|
3394
|
+
"timeout",
|
|
3395
|
+
"timeoutMs",
|
|
3396
|
+
"wall-time",
|
|
3397
|
+
"fetch_cancelled_or_timeout",
|
|
3398
|
+
"sleep_limit",
|
|
3399
|
+
"WARDBY_TOOL_MAX_TIMEOUT_MS"
|
|
3400
|
+
],
|
|
3401
|
+
"appliesTo": ">=0.8.0",
|
|
3402
|
+
"sourcePath": "errors/tool-timeout.md",
|
|
3403
|
+
"markdown": "\n# A tool call ran out of time\n\n## What happened\n\nA tool's result was `{\"error\":\"timeout\",\"message\":\"Exceeded the 10000ms wall-time limit. ...\"}`.\nThe call ran longer than the tool's time limit, so it was stopped. The run goes on: only this call\nfailed. The message names the limit. Without `timeoutMs` a tool has 10 seconds.\n\nRelated results:\n\n- `fetch_cancelled_or_timeout` from inside the tool: a `fetch` was aborted because the call ran\n out of time or the run stopped.\n- `sleep_limit`: the tool asked to wait longer than its own limit.\n- `{\"error\":\"cancelled\"}`: the run was stopped while the call was running.\n\n## What to do\n\n1. Check how long the API the tool calls really takes.\n2. Give the tool a longer limit with `update_tool` (`timeoutMs`, in milliseconds), or\n `wardby tool update <tool> --timeout-ms <ms>`.\n3. Test it with `dry_run_tool` and the same `timeoutMs`.\n\n`timeoutMs` can't exceed the server's `WARDBY_TOOL_MAX_TIMEOUT_MS` (default `300000`); a larger\nvalue is refused with an error naming the ceiling. If you need more, ask the operator to raise it.\nIf the operator lowers the ceiling, a tool with a larger `timeoutMs` runs with the ceiling.\n\nRuns that started before the change keep the limit they loaded; the next run uses the new one.\n\nSee [Use native agents, tools, and data](../native-capabilities.md#tool-time-limits).\n",
|
|
3404
|
+
"plainText": "A tool call ran out of time What happened A tool's result was {\"error\":\"timeout\",\"message\":\"Exceeded the 10000ms wall-time limit. ...\"}. The call ran longer than the tool's time limit, so it was stopped. The run goes on: only this call failed. The message names the limit. Without timeoutMs a tool has 10 seconds. Related results: fetchcancelledortimeout from inside the tool: a fetch was aborted because the call ran out of time or the run stopped. sleeplimit: the tool asked to wait longer than its own limit. {\"error\":\"cancelled\"}: the run was stopped while the call was running. What to do Check how long the API the tool calls really takes. Give the tool a longer limit with updatetool (timeoutMs, in milliseconds), or wardby tool update <tool --timeout-ms <ms. Test it with dryruntool and the same timeoutMs. timeoutMs can't exceed the server's WARDBYTOOLMAXTIMEOUTMS (default 300000); a larger value is refused with an error naming the ceiling. If you need more, ask the operator to raise it. If the operator lowers the ceiling, a tool with a larger timeoutMs runs with the ceiling. Runs that started before the change keep the limit they loaded; the next run uses the new one. See Use native agents, tools, and data.",
|
|
3405
|
+
"headings": [
|
|
3406
|
+
{
|
|
3407
|
+
"level": 1,
|
|
3408
|
+
"text": "A tool call ran out of time",
|
|
3409
|
+
"slug": "a-tool-call-ran-out-of-time"
|
|
3410
|
+
},
|
|
3411
|
+
{
|
|
3412
|
+
"level": 2,
|
|
3413
|
+
"text": "What happened",
|
|
3414
|
+
"slug": "what-happened"
|
|
3415
|
+
},
|
|
3416
|
+
{
|
|
3417
|
+
"level": 2,
|
|
3418
|
+
"text": "What to do",
|
|
3419
|
+
"slug": "what-to-do"
|
|
3420
|
+
}
|
|
3421
|
+
]
|
|
3422
|
+
},
|
|
2812
3423
|
{
|
|
2813
3424
|
"id": "errors/vcs-github-not-configured",
|
|
2814
3425
|
"title": "GitHub is not configured for coding agents",
|
|
@@ -3009,6 +3620,30 @@
|
|
|
3009
3620
|
}
|
|
3010
3621
|
]
|
|
3011
3622
|
},
|
|
3623
|
+
{
|
|
3624
|
+
"id": "host-providers",
|
|
3625
|
+
"title": "Add a code host with your own tools (host providers)",
|
|
3626
|
+
"summary": "Register a code host implemented by custom tools, approve changes to them, and test them with read-only calls. Agents can't use a provider yet.",
|
|
3627
|
+
"audience": "operator",
|
|
3628
|
+
"tags": [
|
|
3629
|
+
"host provider",
|
|
3630
|
+
"register_host_provider",
|
|
3631
|
+
"approve_host_provider_tools",
|
|
3632
|
+
"hosts:admin",
|
|
3633
|
+
"host-manager"
|
|
3634
|
+
],
|
|
3635
|
+
"appliesTo": ">=0.8.0",
|
|
3636
|
+
"sourcePath": "host-providers.md",
|
|
3637
|
+
"markdown": "\n# Host providers\n\nA host provider adds a code host using your own custom tools. This release lets you register\na provider, approve its tools and test them. Agents can't use a registered provider yet.\n\nYou need the `hosts:admin` scope and a role that grants it (`admin` or `host-manager`). See\n[Identity and access](identity-and-access.md).\n\n1. Write one tool per operation with `create_tool`.\n2. Broker each credential with `set_secret_broker`, allowing the API hosts and the git host. The\n permission credential needs only the API hosts ([Brokered secrets](brokered-secrets.md)).\n3. Call `register_host_provider`. No restart is needed today, because agents can't use a provider\n yet; a new provider will need one once they can. A refusal has a\n [`host_provider_*` code](errors/host-provider-error.md).\n4. Call `test_host_provider` to check each read-only tool. Failures have\n [fixed codes](errors/host-tool-failed.md).\n\n`update_tool` changes nothing until you call `approve_host_provider_tools`, a new `timeoutMs`\nincluded. See which tools have changes with `get_host_provider`.\n\nA bound tool reaches only the provider's API hosts, inside one repository's path, and Wardby\nfollows no redirects; the tool must fetch the `Location` itself. Any host manager can read and re-register any\nprovider.\n\nReplacing a secret a provider uses, or changing its broker config, needs `hosts:admin` as well as\n`secrets:write`. A webhook secret stays at 16 characters or more.\n\nKeep provider credentials unattached: an agent's own tools can use an attached one without the\nprovider's path guard.\n\nSee [docs/host-providers.md](../docs/host-providers.md) for the full guide.\n",
|
|
3638
|
+
"plainText": "Host providers A host provider adds a code host using your own custom tools. This release lets you register a provider, approve its tools and test them. Agents can't use a registered provider yet. You need the hosts:admin scope and a role that grants it (admin or host-manager). See Identity and access. Write one tool per operation with createtool. Broker each credential with setsecretbroker, allowing the API hosts and the git host. The permission credential needs only the API hosts (Brokered secrets). Call registerhostprovider. No restart is needed today, because agents can't use a provider yet; a new provider will need one once they can. A refusal has a hostprovider code. Call testhostprovider to check each read-only tool. Failures have fixed codes. updatetool changes nothing until you call approvehostprovidertools, a new timeoutMs included. See which tools have changes with gethostprovider. A bound tool reaches only the provider's API hosts, inside one repository's path, and Wardby follows no redirects; the tool must fetch the Location itself. Any host manager can read and re-register any provider. Replacing a secret a provider uses, or changing its broker config, needs hosts:admin as well as secrets:write. A webhook secret stays at 16 characters or more. Keep provider credentials unattached: an agent's own tools can use an attached one without the provider's path guard. See docs/host-providers.md for the full guide.",
|
|
3639
|
+
"headings": [
|
|
3640
|
+
{
|
|
3641
|
+
"level": 1,
|
|
3642
|
+
"text": "Host providers",
|
|
3643
|
+
"slug": "host-providers"
|
|
3644
|
+
}
|
|
3645
|
+
]
|
|
3646
|
+
},
|
|
3012
3647
|
{
|
|
3013
3648
|
"id": "identity-and-access",
|
|
3014
3649
|
"title": "Configure identity and privileged access",
|
|
@@ -3023,8 +3658,8 @@
|
|
|
3023
3658
|
],
|
|
3024
3659
|
"appliesTo": ">=0.2.1",
|
|
3025
3660
|
"sourcePath": "identity-and-access.md",
|
|
3026
|
-
"markdown": "\n# Configure identity and privileged access\n\nLocal stdio MCP created by `wardby quickstart` trusts the local operator. A\nshared HTTPS deployment needs an OAuth/OIDC identity provider. In delegating\nmode, that provider authenticates the caller and issues a signed JWT access\ntoken; Wardby verifies the token and enforces its scopes without administering\nthe provider's users or exchanging authorization codes.\n\nSet the provider's resource audience, `MCP_CANONICAL_URI`, and `AUTH_AUDIENCE`\nto the exact same public MCP URL. Tokens need a stable subject, expiry, issuer,\naudience, and the granted Wardby scopes in `scope` or `scp`.\n\nScopes authorize normal operations such as managing agents, runs, tools,\ndatastores, secrets, webhooks, budgets, packages, services, memory, and\nmodels.
|
|
3027
|
-
"plainText": "Configure identity and privileged access Local stdio MCP created by wardby quickstart trusts the local operator. A shared HTTPS deployment needs an OAuth/OIDC identity provider. In delegating mode, that provider authenticates the caller and issues a signed JWT access token; Wardby verifies the token and enforces its scopes without administering the provider's users or exchanging authorization codes. Set the provider's resource audience, MCPCANONICALURI, and AUTHAUDIENCE to the exact same public MCP URL. Tokens need a stable subject, expiry, issuer, audience, and the granted Wardby scopes in scope or scp. Scopes authorize normal operations such as managing agents, runs, tools, datastores, secrets, webhooks, budgets, packages, services, memory, and models.
|
|
3661
|
+
"markdown": "\n# Configure identity and privileged access\n\nLocal stdio MCP created by `wardby quickstart` trusts the local operator. A\nshared HTTPS deployment needs an OAuth/OIDC identity provider. In delegating\nmode, that provider authenticates the caller and issues a signed JWT access\ntoken; Wardby verifies the token and enforces its scopes without administering\nthe provider's users or exchanging authorization codes.\n\nSet the provider's resource audience, `MCP_CANONICAL_URI`, and `AUTH_AUDIENCE`\nto the exact same public MCP URL. Tokens need a stable subject, expiry, issuer,\naudience, and the granted Wardby scopes in `scope` or `scp`.\n\nScopes authorize normal operations such as managing agents, runs, tools,\ndatastores, secrets, webhooks, budgets, packages, services, memory, and\nmodels. Seven sensitive permissions have an additional role requirement:\n\n- `agents:admin` requires the Wardby `admin` role.\n- `packages:approve` requires the `admin` or `package-approver` role.\n- `services:manage` requires the `admin` or `service-manager` role.\n- `admin:view` requires the `admin` role. It opens the read-only, deployment-wide\n admin viewer API; see [Watch live runs with the admin viewer API](admin-viewer.md).\n- `models:admin` requires the `admin` or `model-manager` role. It adds,\n overrides, disables, and resets model catalog entries; see\n [Models and pricing](models.md).\n- `hosts:admin` requires the `admin` or `host-manager` role. It registers host\n providers, approves their tools and, with `secrets:write`, replaces their secrets; see\n [Host providers](../docs/host-providers.md).\n- `power:manage` requires the `admin` role. It reads low-power state and\n sleeps the coding proxy and native gateway now (`power_status`,\n `power_sleep`); see\n [Low-power mode](../docs/getting-started-gke.md#low-power-mode).\n\nMap roles only from an IdP claim that users cannot self-assign. Removing a\nrole affects the next token the caller receives.\n\nWhen you upgrade a delegating-mode deployment, define any newly advertised\nscope, such as `admin:view`, in the provider before deploying. Clients\nthat request every advertised scope otherwise fail with `invalid_scope`.\n\nRead [`docs/getting-started-identity-provider.md`](../docs/getting-started-identity-provider.md)\nfor the required claims, scope list, role mapping, provider examples, and\nclient registration.\n\nFrom Wardby 0.7.0, to share an agent with one person or with everyone signed in, see the help article `sharing-agents`.\n",
|
|
3662
|
+
"plainText": "Configure identity and privileged access Local stdio MCP created by wardby quickstart trusts the local operator. A shared HTTPS deployment needs an OAuth/OIDC identity provider. In delegating mode, that provider authenticates the caller and issues a signed JWT access token; Wardby verifies the token and enforces its scopes without administering the provider's users or exchanging authorization codes. Set the provider's resource audience, MCPCANONICALURI, and AUTHAUDIENCE to the exact same public MCP URL. Tokens need a stable subject, expiry, issuer, audience, and the granted Wardby scopes in scope or scp. Scopes authorize normal operations such as managing agents, runs, tools, datastores, secrets, webhooks, budgets, packages, services, memory, and models. Seven sensitive permissions have an additional role requirement: agents:admin requires the Wardby admin role. packages:approve requires the admin or package-approver role. services:manage requires the admin or service-manager role. admin:view requires the admin role. It opens the read-only, deployment-wide admin viewer API; see Watch live runs with the admin viewer API. models:admin requires the admin or model-manager role. It adds, overrides, disables, and resets model catalog entries; see Models and pricing. hosts:admin requires the admin or host-manager role. It registers host providers, approves their tools and, with secrets:write, replaces their secrets; see Host providers. power:manage requires the admin role. It reads low-power state and sleeps the coding proxy and native gateway now (powerstatus, powersleep); see Low-power mode. Map roles only from an IdP claim that users cannot self-assign. Removing a role affects the next token the caller receives. When you upgrade a delegating-mode deployment, define any newly advertised scope, such as admin:view, in the provider before deploying. Clients that request every advertised scope otherwise fail with invalidscope. Read docs/getting-started-identity-provider.md for the required claims, scope list, role mapping, provider examples, and client registration. From Wardby 0.7.0, to share an agent with one person or with everyone signed in, see the help article sharing-agents.",
|
|
3028
3663
|
"headings": [
|
|
3029
3664
|
{
|
|
3030
3665
|
"level": 1,
|
|
@@ -3177,12 +3812,14 @@
|
|
|
3177
3812
|
"power_sleep",
|
|
3178
3813
|
"power_status",
|
|
3179
3814
|
"sleep now",
|
|
3180
|
-
"power:manage"
|
|
3815
|
+
"power:manage",
|
|
3816
|
+
"mcp",
|
|
3817
|
+
"coding-agents"
|
|
3181
3818
|
],
|
|
3182
3819
|
"appliesTo": ">=0.6.0",
|
|
3183
3820
|
"sourcePath": "low-power-mode.md",
|
|
3184
|
-
"markdown": "\n# Low-power mode on GKE\n\nLow-power mode reduces the cost of a GKE Autopilot deployment that runs agents\nonly occasionally. When it is on, the coding proxy and the native gateway scale\nto zero replicas after an idle window and wake when a run needs them. The\nheadroom placeholder is off, and the control plane runs 1 copy that scales to 2\nunder load.\n\nIt needs `JOB_LAUNCHER=kubernetes`. Without it Wardby logs `low_power_ignored`\nand the mode does nothing.\n\n## Turn it on or off\n\n```sh\nWARDBY_HOSTNAME=wardby.example.com WARDBY_LOW_POWER=1 deploy/gke/up.sh\n```\n\nRe-running `up.sh` without `WARDBY_LOW_POWER=1` turns it off: it removes the\nautoscaler `wardby-control-plane` and the Role and RoleBinding `wardby-power`\nand restores proxy 1, gateway 2, headroom 1, control plane 1.\n\n`WARDBY_LOW_POWER` accepts only unset, `0` or `1`; anything else fails `up.sh`\nand stops the control plane at start-up. `LOW_POWER_IDLE_MINUTES` is an integer\nfrom 5 to 1440 (default 30) set on the control-plane Deployment; it is read\nonly when `WARDBY_LOW_POWER=1`.\n\n## How it behaves\n\n- **Sleep.** Every minute the scheduler leader scales the coding proxy\n (`wardby-coding-proxy`) or native gateway (`wardby-native-gateway`) to 0 when\n nothing is pending or running for it and nothing finished within the idle\n window.
|
|
3185
|
-
"plainText": "Low-power mode on GKE Low-power mode reduces the cost of a GKE Autopilot deployment that runs agents only occasionally. When it is on, the coding proxy and the native gateway scale to zero replicas after an idle window and wake when a run needs them. The headroom placeholder is off, and the control plane runs 1 copy that scales to 2 under load. It needs JOBLAUNCHER=kubernetes. Without it Wardby logs lowpowerignored and the mode does nothing. Turn it on or off WARDBYHOSTNAME=wardby.example.com WARDBYLOWPOWER=1 deploy/gke/up.sh Re-running up.sh without WARDBYLOWPOWER=1 turns it off: it removes the autoscaler wardby-control-plane and the Role and RoleBinding wardby-power and restores proxy 1, gateway 2, headroom 1, control plane 1. WARDBYLOWPOWER accepts only unset, 0 or 1; anything else fails up.sh and stops the control plane at start-up. LOWPOWERIDLEMINUTES is an integer from 5 to 1440 (default 30) set on the control-plane Deployment; it is read only when WARDBYLOWPOWER=1. How it behaves Sleep. Every minute the scheduler leader scales the coding proxy (wardby-coding-proxy) or native gateway (wardby-native-gateway) to 0 when nothing is pending or running for it and nothing finished within the idle window.
|
|
3821
|
+
"markdown": "\n# Low-power mode on GKE\n\nLow-power mode reduces the cost of a GKE Autopilot deployment that runs agents\nonly occasionally. When it is on, the coding proxy and the native gateway scale\nto zero replicas after an idle window and wake when a run needs them. The\nheadroom placeholder is off, and the control plane runs 1 copy that scales to 2\nunder load.\n\nIt needs `JOB_LAUNCHER=kubernetes`. Without it Wardby logs `low_power_ignored`\nand the mode does nothing.\n\n## Turn it on or off\n\n```sh\nWARDBY_HOSTNAME=wardby.example.com WARDBY_LOW_POWER=1 deploy/gke/up.sh\n```\n\nRe-running `up.sh` without `WARDBY_LOW_POWER=1` turns it off: it removes the\nautoscaler `wardby-control-plane` and the Role and RoleBinding `wardby-power`\nand restores proxy 1, gateway 2, headroom 1, control plane 1.\n\n`WARDBY_LOW_POWER` accepts only unset, `0` or `1`; anything else fails `up.sh`\nand stops the control plane at start-up. `LOW_POWER_IDLE_MINUTES` is an integer\nfrom 5 to 1440 (default 30) set on the control-plane Deployment; it is read\nonly when `WARDBY_LOW_POWER=1`.\n\n## How it behaves\n\n- **Sleep.** Every minute the scheduler leader scales the coding proxy\n (`wardby-coding-proxy`) or native gateway (`wardby-native-gateway`) to 0 when\n nothing is pending or running for it and nothing finished within the idle\n window. For the gateway that means sandbox runs and coding runs with MCP\n tools, and it also needs no active session. Either target sleeps only\n once at least one idle window has passed since it was last woken (annotation\n `wardby.io/power-woke-at`) and since the control plane started, whichever is\n later. The check repeats just before scaling. Log: `power: proxy slept (idle 30m)`.\n- **Wake.** A coding run scales the proxy to 1 and waits for a ready endpoint;\n a sandbox run does the same for the gateway. A coding run with MCP tools\n wakes both at once, because its MCP calls go through the gateway; if the\n gateway does not wake it fails before launch with\n [`coding_failure_mcp_gateway_unavailable`](errors/coding-mcp-gateway-unavailable.md).\n The wait is at least 5 minutes.\n A `KUBERNETES_READY_TIMEOUT_MS` (the proxy, and the gateway wake of a coding\n run) or `NATIVE_SANDBOX_READY_TIMEOUT_MS` (the gateway wake of a sandbox run)\n above that, set on the control-plane Deployment, raises it. Expect\n about 1 to 2 minutes extra on a cold node. Log: `power: proxy woke`. A\n sandbox run woken this way may then wait for a gVisor node for its worker\n pod, so its first model call can come several minutes after it started. From\n 0.7.0 it shows as running the whole time and is not reaped as orphaned; only\n the wake and pod-start limits above can fail it.\n- **Preflight.** The first coding run after a control-plane restart also runs\n the cluster preflight canary, because start-up preflight is deferred while the\n proxy sleeps (`kubernetes_preflight_deferred`).\n- **Deploys.** Every `up.sh` run, including one that turns the mode off, marks\n the proxy and gateway as just woken before it brings them back up, so the\n control plane being replaced cannot scale them down mid-deploy. With the mode\n on they stay up through the deploy (its database checks need them) and sleep\n one idle window later.\n- **Control plane.** It scales 1 to 2 on CPU (20% target, scale down\n after 10 minutes). A run executes on the copy that started it, so scheduled\n runs stay on the scheduler leader; webhook and MCP-started runs spread. The\n autoscaler owns the replica count while the mode is on.\n\n## Sleep now\n\nTo skip the idle window, for example right after a test, call `power_sleep`.\nPass `target: \"proxy\"` or `target: \"gateway\"` to sleep one; omit it for both.\n\n- It scales the target to 0 at once, ignoring the idle window and the woke-at\n grace.\n- It never stops a run. A target with a pending or running run (for the\n gateway, a sandbox run or a coding run with MCP tools), or for the gateway an\n active gateway session, stays up, and its run ids are returned:\n `{ \"slept\": [\"proxy\"], \"blocked\": [{ \"target\": \"gateway\", \"runIds\": [\"...\"] }] }`.\n Recently finished runs do not block it.\n- The next run wakes the target as usual.\n- Each call is logged with `event: \"power.sleep\"` and the caller's principal.\n\n`power_status` returns, for each target, `replicas`, `ready`, `wokeAt` and\n`blockers` (the run ids keeping it busy; for the gateway these include\npending or running coding runs with MCP tools).\n\nBoth tools need the `power:manage` scope, which only the `admin` role grants\n(see [Identity and access](identity-and-access.md)). With the mode off,\n`power_sleep` fails with\n[`409 low_power_disabled`](errors/low-power-disabled.md) and `power_status`\nreturns `{ \"enabled\": false }`.\n\n## Trade-offs and requirements\n\n- With headroom off, the control plane has less protection against preemption.\n- The gateway runs 1 replica instead of 2 while awake: no redundancy.\n- `NATIVE_SANDBOX_WARM_POOL_SIZE` must be 0, or the control plane refuses to\n start.\n- The gateway must be in the same namespace as `KUBERNETES_NAMESPACE`.\n\n## Cost\n\nAutopilot bills Pod requests while a Pod exists. At us-central1 list prices\n($0.0445 per vCPU-hour, $0.0049225 per GiB-hour, 730 hours a month; use your\nregion's rates), always-on cost per workload is: control plane (1.1 vCPU / 2.125\nGiB) $43.37, coding proxy (1.1 / 3.125) $46.96, native gateway (0.35 / 0.625 per\nreplica, two replicas) $27.23, headroom (0.25 / 0.5) $9.92. In low-power mode\nthe proxy costs $0.0643 an hour and a gateway replica $0.0187 an hour only\nwhile awake, and headroom costs nothing. See\n[Getting started on GKE](../docs/getting-started-gke.md#low-power-mode) for the\nfull table.\n\n## Errors and log lines\n\n- [`low_power_wake_timeout`](errors/low-power-wake-timeout.md): the target did\n not become ready in time, or its Deployment does not exist.\n- [`coding_failure_mcp_gateway_unavailable`](errors/coding-mcp-gateway-unavailable.md):\n a coding run with MCP tools failed before launch because the gateway did not\n wake.\n- `native_sandbox_launch_abandoned` (0.7.0 and later): a sandbox run was\n stopped while the gateway woke, so no worker pod was made.\n- [`low_power_disabled`](errors/low-power-disabled.md): `power_sleep` was\n called while the mode is off.\n- [`low_power_scale_forbidden`](errors/low-power-scale-forbidden.md): the\n control plane may not read or scale a Deployment or read its Endpoints\n (Role `wardby-power` missing or out of date).\n- Also: `power_sleep_failed`, `low_power_access_check_failed`,\n `low_power_ignored`.\n\n## Local kind\n\n`WARDBY_LOW_POWER=1 deploy/kind-coding/up.sh` applies the Role. The kind control\nplane runs on your host, so set `WARDBY_LOW_POWER=1` (and optionally\n`LOW_POWER_IDLE_MINUTES`) in the environment of `wardby serve` too.\n\nRelated: [Deploy Wardby on GKE Autopilot](deploy-gke.md),\n[Run native agents in a sandbox](native-sandbox.md).\n",
|
|
3822
|
+
"plainText": "Low-power mode on GKE Low-power mode reduces the cost of a GKE Autopilot deployment that runs agents only occasionally. When it is on, the coding proxy and the native gateway scale to zero replicas after an idle window and wake when a run needs them. The headroom placeholder is off, and the control plane runs 1 copy that scales to 2 under load. It needs JOBLAUNCHER=kubernetes. Without it Wardby logs lowpowerignored and the mode does nothing. Turn it on or off WARDBYHOSTNAME=wardby.example.com WARDBYLOWPOWER=1 deploy/gke/up.sh Re-running up.sh without WARDBYLOWPOWER=1 turns it off: it removes the autoscaler wardby-control-plane and the Role and RoleBinding wardby-power and restores proxy 1, gateway 2, headroom 1, control plane 1. WARDBYLOWPOWER accepts only unset, 0 or 1; anything else fails up.sh and stops the control plane at start-up. LOWPOWERIDLEMINUTES is an integer from 5 to 1440 (default 30) set on the control-plane Deployment; it is read only when WARDBYLOWPOWER=1. How it behaves Sleep. Every minute the scheduler leader scales the coding proxy (wardby-coding-proxy) or native gateway (wardby-native-gateway) to 0 when nothing is pending or running for it and nothing finished within the idle window. For the gateway that means sandbox runs and coding runs with MCP tools, and it also needs no active session. Either target sleeps only once at least one idle window has passed since it was last woken (annotation wardby.io/power-woke-at) and since the control plane started, whichever is later. The check repeats just before scaling. Log: power: proxy slept (idle 30m). Wake. A coding run scales the proxy to 1 and waits for a ready endpoint; a sandbox run does the same for the gateway. A coding run with MCP tools wakes both at once, because its MCP calls go through the gateway; if the gateway does not wake it fails before launch with codingfailuremcpgatewayunavailable. The wait is at least 5 minutes. A KUBERNETESREADYTIMEOUTMS (the proxy, and the gateway wake of a coding run) or NATIVESANDBOXREADYTIMEOUTMS (the gateway wake of a sandbox run) above that, set on the control-plane Deployment, raises it. Expect about 1 to 2 minutes extra on a cold node. Log: power: proxy woke. A sandbox run woken this way may then wait for a gVisor node for its worker pod, so its first model call can come several minutes after it started. From 0.7.0 it shows as running the whole time and is not reaped as orphaned; only the wake and pod-start limits above can fail it. Preflight. The first coding run after a control-plane restart also runs the cluster preflight canary, because start-up preflight is deferred while the proxy sleeps (kubernetespreflightdeferred). Deploys. Every up.sh run, including one that turns the mode off, marks the proxy and gateway as just woken before it brings them back up, so the control plane being replaced cannot scale them down mid-deploy. With the mode on they stay up through the deploy (its database checks need them) and sleep one idle window later. Control plane. It scales 1 to 2 on CPU (20% target, scale down after 10 minutes). A run executes on the copy that started it, so scheduled runs stay on the scheduler leader; webhook and MCP-started runs spread. The autoscaler owns the replica count while the mode is on. Sleep now To skip the idle window, for example right after a test, call powersleep. Pass target: \"proxy\" or target: \"gateway\" to sleep one; omit it for both. It scales the target to 0 at once, ignoring the idle window and the woke-at grace. It never stops a run. A target with a pending or running run (for the gateway, a sandbox run or a coding run with MCP tools), or for the gateway an active gateway session, stays up, and its run ids are returned: { \"slept\": [\"proxy\"], \"blocked\": [{ \"target\": \"gateway\", \"runIds\": [\"...\"] }] }. Recently finished runs do not block it. The next run wakes the target as usual. Each call is logged with event: \"power.sleep\" and the caller's principal. powerstatus returns, for each target, replicas, ready, wokeAt and blockers (the run ids keeping it busy; for the gateway these include pending or running coding runs with MCP tools). Both tools need the power:manage scope, which only the admin role grants (see Identity and access). With the mode off, powersleep fails with 409 lowpowerdisabled and powerstatus returns { \"enabled\": false }. Trade-offs and requirements With headroom off, the control plane has less protection against preemption. The gateway runs 1 replica instead of 2 while awake: no redundancy. NATIVESANDBOXWARMPOOLSIZE must be 0, or the control plane refuses to start. The gateway must be in the same namespace as KUBERNETESNAMESPACE. Cost Autopilot bills Pod requests while a Pod exists. At us-central1 list prices ($0.0445 per vCPU-hour, $0.0049225 per GiB-hour, 730 hours a month; use your region's rates), always-on cost per workload is: control plane (1.1 vCPU / 2.125 GiB) $43.37, coding proxy (1.1 / 3.125) $46.96, native gateway (0.35 / 0.625 per replica, two replicas) $27.23, headroom (0.25 / 0.5) $9.92. In low-power mode the proxy costs $0.0643 an hour and a gateway replica $0.0187 an hour only while awake, and headroom costs nothing. See Getting started on GKE for the full table. Errors and log lines lowpowerwaketimeout: the target did not become ready in time, or its Deployment does not exist. codingfailuremcpgatewayunavailable: a coding run with MCP tools failed before launch because the gateway did not wake. nativesandboxlaunchabandoned (0.7.0 and later): a sandbox run was stopped while the gateway woke, so no worker pod was made. lowpowerdisabled: powersleep was called while the mode is off. lowpowerscaleforbidden: the control plane may not read or scale a Deployment or read its Endpoints (Role wardby-power missing or out of date). Also: powersleepfailed, lowpoweraccesscheckfailed, lowpowerignored. Local kind WARDBYLOWPOWER=1 deploy/kind-coding/up.sh applies the Role. The kind control plane runs on your host, so set WARDBYLOWPOWER=1 (and optionally LOWPOWERIDLEMINUTES) in the environment of wardby serve too. Related: Deploy Wardby on GKE Autopilot, Run native agents in a sandbox.",
|
|
3186
3823
|
"headings": [
|
|
3187
3824
|
{
|
|
3188
3825
|
"level": 1,
|
|
@@ -3228,7 +3865,7 @@
|
|
|
3228
3865
|
},
|
|
3229
3866
|
{
|
|
3230
3867
|
"id": "mcp-access",
|
|
3231
|
-
"title": "Connect
|
|
3868
|
+
"title": "Connect a client to Wardby",
|
|
3232
3869
|
"summary": "Use Wardby's local stdio or protected HTTP MCP transport safely.",
|
|
3233
3870
|
"audience": "developer",
|
|
3234
3871
|
"tags": [
|
|
@@ -3239,13 +3876,45 @@
|
|
|
3239
3876
|
],
|
|
3240
3877
|
"appliesTo": ">=0.2.1",
|
|
3241
3878
|
"sourcePath": "mcp.md",
|
|
3242
|
-
"markdown": "\n# Connect
|
|
3243
|
-
"plainText": "Connect
|
|
3879
|
+
"markdown": "\n# Connect a client to Wardby\n\nFor local use, `wardby quickstart` can register the local stdio MCP server with\nCodex or Claude Code. Local stdio trusts the local operator.\n\nFor remote access, Wardby exposes an OAuth 2.1-protected HTTP resource server.\nRun the service with `MCP_TRANSPORT=http`, set a canonical public URI, and use\nthe instance's configured identity-provider mode. Keep the MCP endpoint behind\nyour intended ingress and authentication boundary.\n\nMCP clients use Wardby to manage agents, budgets, tools, schedules, secrets,\ndatastores, and runs. They do not receive the provider or GitHub App\ncredentials held by Wardby's trusted components.\n\nWith the existing `agents:read` scope, clients can also use `search_help` to\nfind bundled self-hosted guidance with fuzzy matching and `get_help_article`\nto read a complete article by id. These tools use the same release-bundled,\noffline catalog as `wardby help`; they expose no instance data or credentials.\n\nSee [`docs/getting-started-identity-provider.md`](../docs/getting-started-identity-provider.md)\nfor the supported self-hosted and delegated identity-provider setup.\n\nFrom Wardby 0.8.0, Claude Code can show your runs in a pane beside the chat\nthrough the `wardby-runs` plugin: run `wardby claude-plugin install`, then\n`/wardby-runs`. Search help for \"claude code plugin\" (article\n`claude-code-run-pane`, Wardby 0.8.0 and later).\n\nTo follow what a run is doing, call `get_run_steps` (article `run-steps`).\n",
|
|
3880
|
+
"plainText": "Connect a client to Wardby For local use, wardby quickstart can register the local stdio MCP server with Codex or Claude Code. Local stdio trusts the local operator. For remote access, Wardby exposes an OAuth 2.1-protected HTTP resource server. Run the service with MCPTRANSPORT=http, set a canonical public URI, and use the instance's configured identity-provider mode. Keep the MCP endpoint behind your intended ingress and authentication boundary. MCP clients use Wardby to manage agents, budgets, tools, schedules, secrets, datastores, and runs. They do not receive the provider or GitHub App credentials held by Wardby's trusted components. With the existing agents:read scope, clients can also use searchhelp to find bundled self-hosted guidance with fuzzy matching and gethelparticle to read a complete article by id. These tools use the same release-bundled, offline catalog as wardby help; they expose no instance data or credentials. See docs/getting-started-identity-provider.md for the supported self-hosted and delegated identity-provider setup. From Wardby 0.8.0, Claude Code can show your runs in a pane beside the chat through the wardby-runs plugin: run wardby claude-plugin install, then /wardby-runs. Search help for \"claude code plugin\" (article claude-code-run-pane, Wardby 0.8.0 and later). To follow what a run is doing, call getrunsteps (article run-steps).",
|
|
3244
3881
|
"headings": [
|
|
3245
3882
|
{
|
|
3246
3883
|
"level": 1,
|
|
3247
|
-
"text": "Connect
|
|
3248
|
-
"slug": "connect-
|
|
3884
|
+
"text": "Connect a client to Wardby",
|
|
3885
|
+
"slug": "connect-a-client-to-wardby"
|
|
3886
|
+
}
|
|
3887
|
+
]
|
|
3888
|
+
},
|
|
3889
|
+
{
|
|
3890
|
+
"id": "mcp-servers",
|
|
3891
|
+
"title": "Remote MCP server tools for native and coding agents",
|
|
3892
|
+
"summary": "Register a remote MCP server, then attach an allowlist of its tools to a native, Claude Code or Codex agent; credentials stay in brokered secrets.",
|
|
3893
|
+
"audience": "operator",
|
|
3894
|
+
"tags": [
|
|
3895
|
+
"mcp",
|
|
3896
|
+
"mcp server",
|
|
3897
|
+
"coding-agent",
|
|
3898
|
+
"codex",
|
|
3899
|
+
"register_mcp_server",
|
|
3900
|
+
"attach_mcp_server",
|
|
3901
|
+
"readOnlyHint",
|
|
3902
|
+
"WARDBY_MCP_SERVERS"
|
|
3903
|
+
],
|
|
3904
|
+
"appliesTo": ">=0.8.0",
|
|
3905
|
+
"sourcePath": "mcp-servers.md",
|
|
3906
|
+
"markdown": "\n# Remote MCP server tools for native and coding agents\n\nA native, Claude Code or Codex agent can call tools from a remote MCP server (Streamable HTTP, HTTPS only).\n\n1. Create a [brokered secret](brokered-secrets.md) for the server's host, for example\n `Authorization: Bearer {value}`.\n2. `register_mcp_server` with a `name`, the `url` (`https://mcp.example.com/mcp`) and\n `secretNames`. Wardby saves the server's tool list.\n3. `attach_mcp_server` with the agent, the server and `allowedTools` (exact names, at least one).\n The agent sees each as `<server name>__<tool name>`.\n4. After the server changes its tools, `refresh_mcp_server` applies the new list at once. Allowed\n tools the server dropped show as `missingTools` in `get_agent`.\n\nEach call has `callTimeoutMs` (default `30000`, at most `WARDBY_TOOL_MAX_TIMEOUT_MS`, and never\npast the run's deadline). Results are untrusted input; the allowlist is the control. stdio servers\nand OAuth are not supported.\n\n`WARDBY_MCP_SERVERS` is `owners` (default), `admins` (registering needs `hosts:admin`) or `off`\n(only `detach_mcp_server` and `delete_mcp_server` still work, for cleanup).\n\nEach call opens a fresh MCP session, so a server that keeps state between calls in one session\nwon't see it. Arguments that aren't a JSON object return `invalid_arguments`.\n\n## Coding agents\n\n`attach_mcp_server` also takes a Claude Code or Codex agent. Its run reaches the tools only through\nthe coding proxy and the native gateway; the worker never sees the server's URL or secrets.\n\n- Claude Code agents see each tool as `mcp__wardby_mcp__<server name>__<tool name>` and may use any\n allowed tool.\n- Codex agents may use only tools the server marks `readOnlyHint: true`. Wardby checks this when\n you attach, when a run loads and on every call. Repository code in a Codex run can read the run's\n MCP token, so a Codex agent must not be given tools that change things. `readOnlyHint` is the\n server's claim, which Wardby can't verify, so the allowlist stays your control.\n- A run may make `WARDBY_MCP_MAX_CALLS_PER_RUN` calls (default `100`, failed calls count); more are\n refused with [`mcp_call_limit`](errors/mcp-call-limit.md).\n- The proxy needs `WARDBY_MCP_GATEWAY_URL`. Without it coding agents get no MCP tools\n ([`mcp_unavailable`](errors/mcp-unavailable.md)).\n- MCP for coding agents needs this release's Claude worker image and a new Codex driver image.\n Older images get no MCP tools, and runs don't fail.\n- A repository's MCP configuration is still never loaded.\n- Codex models that use tool search load MCP tools on demand. They need this release's coding\n proxy; an older one refuses their requests with `openai_tool_not_allowed:tool_search`.\n- Switching an agent to Codex with `update_agent` keeps its attachments, but tools not marked\n read-only won't reach Codex runs; the result's `warnings` names them.\n- The proxy gives up on a coding run's MCP call after 5 minutes, whatever\n `WARDBY_TOOL_MAX_TIMEOUT_MS` says ([`mcp_unavailable`](errors/mcp-unavailable.md)).\n\nShare a server with `grant_access` (`resourceType: \"mcp_server\"`; needs the `agents:write` scope,\nregistering needs `tools:write`). `use` lets the grantee attach it, and its tools then run with your\nsecrets. Revoking the grant, or lowering it to `read`, detaches the server from the grantee's agents\nat once, and their runs' next call is refused with `mcp_tool_not_allowed`.\n\nErrors a call can return: [`mcp_server_unreachable`](errors/mcp-server-unreachable.md),\n[`mcp_server_auth_failed`](errors/mcp-server-auth-failed.md),\n[`mcp_server_credentials_unavailable`](errors/mcp-server-credentials-unavailable.md),\n[`mcp_server_error`](errors/mcp-server-error.md),\n[`mcp_tool_not_allowed`](errors/mcp-tool-not-allowed.md),\n[`mcp_tool_removed`](errors/mcp-tool-removed.md),\n[`mcp_call_timeout`](errors/mcp-call-timeout.md),\n[`mcp_servers_off`](errors/mcp-servers-off.md), and for coding agents\n[`mcp_call_limit`](errors/mcp-call-limit.md) and [`mcp_unavailable`](errors/mcp-unavailable.md).\n\nFull guide: [Remote MCP servers](../docs/mcp-servers.md).\n",
|
|
3907
|
+
"plainText": "Remote MCP server tools for native and coding agents A native, Claude Code or Codex agent can call tools from a remote MCP server (Streamable HTTP, HTTPS only). Create a brokered secret for the server's host, for example Authorization: Bearer {value}. registermcpserver with a name, the url (https://mcp.example.com/mcp) and secretNames. Wardby saves the server's tool list. attachmcpserver with the agent, the server and allowedTools (exact names, at least one). The agent sees each as <server name<tool name. After the server changes its tools, refreshmcpserver applies the new list at once. Allowed tools the server dropped show as missingTools in getagent. Each call has callTimeoutMs (default 30000, at most WARDBYTOOLMAXTIMEOUTMS, and never past the run's deadline). Results are untrusted input; the allowlist is the control. stdio servers and OAuth are not supported. WARDBYMCPSERVERS is owners (default), admins (registering needs hosts:admin) or off (only detachmcpserver and deletemcpserver still work, for cleanup). Each call opens a fresh MCP session, so a server that keeps state between calls in one session won't see it. Arguments that aren't a JSON object return invalidarguments. Coding agents attachmcpserver also takes a Claude Code or Codex agent. Its run reaches the tools only through the coding proxy and the native gateway; the worker never sees the server's URL or secrets. Claude Code agents see each tool as mcpwardbymcp<server name<tool name and may use any allowed tool. Codex agents may use only tools the server marks readOnlyHint: true. Wardby checks this when you attach, when a run loads and on every call. Repository code in a Codex run can read the run's MCP token, so a Codex agent must not be given tools that change things. readOnlyHint is the server's claim, which Wardby can't verify, so the allowlist stays your control. A run may make WARDBYMCPMAXCALLSPERRUN calls (default 100, failed calls count); more are refused with mcpcalllimit. The proxy needs WARDBYMCPGATEWAYURL. Without it coding agents get no MCP tools (mcpunavailable). MCP for coding agents needs this release's Claude worker image and a new Codex driver image. Older images get no MCP tools, and runs don't fail. A repository's MCP configuration is still never loaded. Codex models that use tool search load MCP tools on demand. They need this release's coding proxy; an older one refuses their requests with openaitoolnotallowed:toolsearch. Switching an agent to Codex with updateagent keeps its attachments, but tools not marked read-only won't reach Codex runs; the result's warnings names them. The proxy gives up on a coding run's MCP call after 5 minutes, whatever WARDBYTOOLMAXTIMEOUTMS says (mcpunavailable). Share a server with grantaccess (resourceType: \"mcpserver\"; needs the agents:write scope, registering needs tools:write). use lets the grantee attach it, and its tools then run with your secrets. Revoking the grant, or lowering it to read, detaches the server from the grantee's agents at once, and their runs' next call is refused with mcptoolnotallowed. Errors a call can return: mcpserverunreachable, mcpserverauthfailed, mcpservercredentialsunavailable, mcpservererror, mcptoolnotallowed, mcptoolremoved, mcpcalltimeout, mcpserversoff, and for coding agents mcpcalllimit and mcpunavailable. Full guide: Remote MCP servers.",
|
|
3908
|
+
"headings": [
|
|
3909
|
+
{
|
|
3910
|
+
"level": 1,
|
|
3911
|
+
"text": "Remote MCP server tools for native and coding agents",
|
|
3912
|
+
"slug": "remote-mcp-server-tools-for-native-and-coding-agents"
|
|
3913
|
+
},
|
|
3914
|
+
{
|
|
3915
|
+
"level": 2,
|
|
3916
|
+
"text": "Coding agents",
|
|
3917
|
+
"slug": "coding-agents"
|
|
3249
3918
|
}
|
|
3250
3919
|
]
|
|
3251
3920
|
},
|
|
@@ -3408,19 +4077,25 @@
|
|
|
3408
4077
|
"schedules",
|
|
3409
4078
|
"subagents",
|
|
3410
4079
|
"zod",
|
|
3411
|
-
"paramsZod",
|
|
3412
4080
|
"create_tool",
|
|
3413
|
-
"dry_run_tool"
|
|
4081
|
+
"dry_run_tool",
|
|
4082
|
+
"timeoutMs",
|
|
4083
|
+
"mcp"
|
|
3414
4084
|
],
|
|
3415
4085
|
"appliesTo": ">=0.2.1",
|
|
3416
4086
|
"sourcePath": "native-capabilities.md",
|
|
3417
|
-
"markdown": "\n# Use native agents, tools, and data\n\nNative agents work through the Wardby control plane rather than a repository\ncheckout. Give each agent only the capabilities its job needs:\n\n- **Tools** for approved external actions or APIs.\n- **Secrets** as bindings to tools or agents; values remain in Wardby's trusted\n components rather than being returned through MCP.\n- **Datastores** for scoped application data and queries.\n- **Memory** for agent-owned durable context.\n- **Schedules and webhooks** to start event-driven work.\n- **Sub-agents** for delegated, bounded work with their own capability set.\n\nA tool's parameters are a Zod schema written as source text (`paramsZod` on\n`create_tool` and `update_tool`). Wardby compiles it inside the sandbox, both to\nderive the JSON Schema the model sees and to validate each call's arguments.\n\nWardby itself now uses Zod 4. For this release only, a tool's `paramsZod` is\nstill compiled with Zod 3 (Zod 4's built-in `zod/v3` API), so existing tools keep\nworking unchanged; a schema Zod 3 can't compile, such as one using `z.email()`,\nis compiled with Zod 4. **Zod 3 schemas stop working in the next release**,\nwhich compiles `paramsZod` with Zod 4 only. A schema that calls something Zod 4\nremoved, such as `.nonstrict()`, `.deepPartial()`, `z.ostring()` or\n`z.string().ip()`, will then fail every call's validation.\n\nWardby warns about each such tool now:\n\n- `create_tool`, `update_tool` and `dry_run_tool` results include a `warnings`\n list naming the tool and the removed methods;\n- in `list_tools` and in `get_agent`'s attached tools, each tool you own that is\n affected carries the same `warnings` list;\n- `wardby tool create` and bundle imports print the same warning;\n- the server logs one warning per affected tool at startup.\n\nTo check a schema before the next release, call `dry_run_tool` with the tool's\n`paramsZod` and sample arguments. With no `warnings` in the result, the schema\ncompiles with Zod 4 and Zod 4 treats those arguments the same way. Otherwise,\nrewrite the schema with the Zod 4 API (for example `z.looseObject()` for\n`.nonstrict()`, `z.string().optional()` for `z.ostring()`, and `z.ipv4()` or\n`z.ipv6()` for `.ip()`), dry-run it again, and save it with `update_tool`.\n\nUse a budget or shared budget group on every agent, and inspect runs before\nexpanding its access. An access grant is intentional delegation: use it only\nwhen an owner permits one agent to use another resource. Creating or changing\ntools, secrets, datastores, schedules, webhooks, memory, and budget groups\nrequires the matching MCP scope.\n\nSee [Operate agents](operating-agents.md) for run and budget management, and\n[`README.md`](../README.md) for the feature overview and MCP operations.\n",
|
|
3418
|
-
"plainText": "Use native agents, tools, and data Native agents work through the Wardby control plane rather than a repository checkout. Give each agent only the capabilities its job needs: Tools for approved external actions or APIs. Secrets as bindings to tools or agents; values remain in Wardby's trusted components rather than being returned through MCP. Datastores for scoped application data and queries. Memory for agent-owned durable context. Schedules and webhooks to start event-driven work. Sub-agents for delegated, bounded work with their own capability set. A tool's parameters are a Zod schema written as source text (paramsZod on createtool and updatetool). Wardby compiles it inside the sandbox, both to derive the JSON Schema the model sees and to validate each call's arguments. Wardby itself now uses Zod 4. For this release only, a tool's paramsZod is still compiled with Zod 3 (Zod 4's built-in zod/v3 API), so existing tools keep working unchanged; a schema Zod 3 can't compile, such as one using z.email(), is compiled with Zod 4. Zod 3 schemas stop working in the next release, which compiles paramsZod with Zod 4 only. A schema that calls something Zod 4 removed, such as .nonstrict(), .deepPartial(), z.ostring() or z.string().ip(), will then fail every call's validation. Wardby warns about each such tool now: createtool, updatetool and dryruntool results include a warnings list naming the tool and the removed methods; in listtools and in getagent's attached tools, each tool you own that is affected carries the same warnings list; wardby tool create and bundle imports print the same warning; the server logs one warning per affected tool at startup. To check a schema before the next release, call dryruntool with the tool's paramsZod and sample arguments. With no warnings in the result, the schema compiles with Zod 4 and Zod 4 treats those arguments the same way. Otherwise, rewrite the schema with the Zod 4 API (for example z.looseObject() for .nonstrict(), z.string().optional() for z.ostring(), and z.ipv4() or z.ipv6() for .ip()), dry-run it again, and save it with updatetool. Use a budget or shared budget group on every agent, and inspect runs before expanding its access. An access grant is intentional delegation: use it only when an owner permits one agent to use another resource. Creating or changing tools, secrets, datastores, schedules, webhooks, memory, and budget groups requires the matching MCP scope. See Operate agents for run and budget management, and README.md for the feature overview and MCP operations.",
|
|
4087
|
+
"markdown": "\n# Use native agents, tools, and data\n\nNative agents work through the Wardby control plane rather than a repository\ncheckout. Give each agent only the capabilities its job needs:\n\n- **Tools** for approved external actions or APIs.\n- **Secrets** as bindings to tools or agents; values remain in Wardby's trusted\n components rather than being returned through MCP.\n- **Datastores** for scoped application data and queries.\n- **Memory** for agent-owned durable context.\n- **Schedules and webhooks** to start event-driven work.\n- **Sub-agents** for delegated, bounded work with their own capability set.\n\nA tool's parameters are a Zod schema written as source text (`paramsZod` on\n`create_tool` and `update_tool`). Wardby compiles it inside the sandbox, both to\nderive the JSON Schema the model sees and to validate each call's arguments.\n\nWardby itself now uses Zod 4. For this release only, a tool's `paramsZod` is\nstill compiled with Zod 3 (Zod 4's built-in `zod/v3` API), so existing tools keep\nworking unchanged; a schema Zod 3 can't compile, such as one using `z.email()`,\nis compiled with Zod 4. **Zod 3 schemas stop working in the next release**,\nwhich compiles `paramsZod` with Zod 4 only. A schema that calls something Zod 4\nremoved, such as `.nonstrict()`, `.deepPartial()`, `z.ostring()` or\n`z.string().ip()`, will then fail every call's validation.\n\nWardby warns about each such tool now:\n\n- `create_tool`, `update_tool` and `dry_run_tool` results include a `warnings`\n list naming the tool and the removed methods;\n- in `list_tools` and in `get_agent`'s attached tools, each tool you own that is\n affected carries the same `warnings` list;\n- `wardby tool create` and bundle imports print the same warning;\n- the server logs one warning per affected tool at startup.\n\nTo check a schema before the next release, call `dry_run_tool` with the tool's\n`paramsZod` and sample arguments. With no `warnings` in the result, the schema\ncompiles with Zod 4 and Zod 4 treats those arguments the same way. Otherwise,\nrewrite the schema with the Zod 4 API (for example `z.looseObject()` for\n`.nonstrict()`, `z.string().optional()` for `z.ostring()`, and `z.ipv4()` or\n`z.ipv6()` for `.ip()`), dry-run it again, and save it with `update_tool`.\n\n## Tool time limits\n\nWardby 0.8.0 and later. Each call of a tool has 10 seconds by default. A tool that calls a slow API can\nask for more with `timeoutMs` (milliseconds, at least `1000`) on `create_tool`,\n`update_tool` or `dry_run_tool`, or `--timeout-ms` on `wardby tool create` and\n`wardby tool update`. Pass `timeoutMs: null` to `update_tool` (or\n`--timeout-ms default` to `wardby tool update`) to go back to the default.\n\n- The limit covers the whole call. Each `fetch` may run until the limit, and a\n timer (`setTimeout`) can't be set for longer than it.\n- The server's `WARDBY_TOOL_MAX_TIMEOUT_MS` (default `300000`, five minutes)\n caps it. A larger `timeoutMs` is refused with an error naming the ceiling. If\n the operator lowers the ceiling later, existing tools run with the ceiling.\n- A run keeps the value it loaded, as it does the tool's code.\n- A call never outlasts its run: stopping the run aborts it, and a sandboxed\n run's deadline cuts it off.\n- `list_tools` and `get_agent` show each tool's `timeoutMs` (`null` means the\n default).\n\nTest a slow tool with `dry_run_tool` and the same `timeoutMs` before you attach\nit. A call that runs out of time fails with a `timeout` error; the help article\n`errors/tool-timeout` explains what to do.\n\nUse a budget or shared budget group on every agent, and inspect runs before\nexpanding its access. An access grant is intentional delegation: use it only\nwhen an owner permits one agent to use another resource. Creating or changing\ntools, secrets, datastores, schedules, webhooks, memory, and budget groups\nrequires the matching MCP scope.\n\nNative agents can also call tools from remote MCP servers; see\n[Remote MCP servers](../docs/mcp-servers.md) (0.8.0+).\n\nSee [Operate agents](operating-agents.md) for run and budget management, and\n[`README.md`](../README.md) for the feature overview and MCP operations.\n",
|
|
4088
|
+
"plainText": "Use native agents, tools, and data Native agents work through the Wardby control plane rather than a repository checkout. Give each agent only the capabilities its job needs: Tools for approved external actions or APIs. Secrets as bindings to tools or agents; values remain in Wardby's trusted components rather than being returned through MCP. Datastores for scoped application data and queries. Memory for agent-owned durable context. Schedules and webhooks to start event-driven work. Sub-agents for delegated, bounded work with their own capability set. A tool's parameters are a Zod schema written as source text (paramsZod on createtool and updatetool). Wardby compiles it inside the sandbox, both to derive the JSON Schema the model sees and to validate each call's arguments. Wardby itself now uses Zod 4. For this release only, a tool's paramsZod is still compiled with Zod 3 (Zod 4's built-in zod/v3 API), so existing tools keep working unchanged; a schema Zod 3 can't compile, such as one using z.email(), is compiled with Zod 4. Zod 3 schemas stop working in the next release, which compiles paramsZod with Zod 4 only. A schema that calls something Zod 4 removed, such as .nonstrict(), .deepPartial(), z.ostring() or z.string().ip(), will then fail every call's validation. Wardby warns about each such tool now: createtool, updatetool and dryruntool results include a warnings list naming the tool and the removed methods; in listtools and in getagent's attached tools, each tool you own that is affected carries the same warnings list; wardby tool create and bundle imports print the same warning; the server logs one warning per affected tool at startup. To check a schema before the next release, call dryruntool with the tool's paramsZod and sample arguments. With no warnings in the result, the schema compiles with Zod 4 and Zod 4 treats those arguments the same way. Otherwise, rewrite the schema with the Zod 4 API (for example z.looseObject() for .nonstrict(), z.string().optional() for z.ostring(), and z.ipv4() or z.ipv6() for .ip()), dry-run it again, and save it with updatetool. Tool time limits Wardby 0.8.0 and later. Each call of a tool has 10 seconds by default. A tool that calls a slow API can ask for more with timeoutMs (milliseconds, at least 1000) on createtool, updatetool or dryruntool, or --timeout-ms on wardby tool create and wardby tool update. Pass timeoutMs: null to updatetool (or --timeout-ms default to wardby tool update) to go back to the default. The limit covers the whole call. Each fetch may run until the limit, and a timer (setTimeout) can't be set for longer than it. The server's WARDBYTOOLMAXTIMEOUTMS (default 300000, five minutes) caps it. A larger timeoutMs is refused with an error naming the ceiling. If the operator lowers the ceiling later, existing tools run with the ceiling. A run keeps the value it loaded, as it does the tool's code. A call never outlasts its run: stopping the run aborts it, and a sandboxed run's deadline cuts it off. listtools and getagent show each tool's timeoutMs (null means the default). Test a slow tool with dryruntool and the same timeoutMs before you attach it. A call that runs out of time fails with a timeout error; the help article errors/tool-timeout explains what to do. Use a budget or shared budget group on every agent, and inspect runs before expanding its access. An access grant is intentional delegation: use it only when an owner permits one agent to use another resource. Creating or changing tools, secrets, datastores, schedules, webhooks, memory, and budget groups requires the matching MCP scope. Native agents can also call tools from remote MCP servers; see Remote MCP servers (0.8.0+). See Operate agents for run and budget management, and README.md for the feature overview and MCP operations.",
|
|
3419
4089
|
"headings": [
|
|
3420
4090
|
{
|
|
3421
4091
|
"level": 1,
|
|
3422
4092
|
"text": "Use native agents, tools, and data",
|
|
3423
4093
|
"slug": "use-native-agents-tools-and-data"
|
|
4094
|
+
},
|
|
4095
|
+
{
|
|
4096
|
+
"level": 2,
|
|
4097
|
+
"text": "Tool time limits",
|
|
4098
|
+
"slug": "tool-time-limits"
|
|
3424
4099
|
}
|
|
3425
4100
|
]
|
|
3426
4101
|
},
|
|
@@ -3439,7 +4114,7 @@
|
|
|
3439
4114
|
"security",
|
|
3440
4115
|
"warm-pool"
|
|
3441
4116
|
],
|
|
3442
|
-
"appliesTo": ">=0.
|
|
4117
|
+
"appliesTo": ">=0.6.0",
|
|
3443
4118
|
"sourcePath": "native-sandbox.md",
|
|
3444
4119
|
"markdown": "\n# Run native agents in a sandbox\n\nBy default a native agent runs inside the Wardby server. Set its\n`nativeExecutionMode` to `sandbox` and its whole turn loop and user tools run in\na single-use Docker container or Kubernetes pod (the `wardby-native-worker`\nimage) instead. The\ncontainer has no credentials, no database access, no Docker socket, and no\nnetwork except the **native gateway**, a separate trusted container that holds\nthe LLM credentials and enforces each tool attachment's grants. The server and\ngateway are trusted; the agent loop and user tool code are not.\n\n## Turn it on\n\n1. Run the gateway: `wardby native-gateway` in a container with the server's\n database, LLM, secrets, and integration settings, listening on\n `NATIVE_GATEWAY_LISTEN` (default `0.0.0.0:8790`; `GET /healthz`). Give it no\n Docker socket.\n2. On the server (`wardby serve` or `wardby scheduler`) set\n `NATIVE_SANDBOX_LAUNCHER=docker`, `NATIVE_SANDBOX_WORKER_IMAGE` (a\n `repo@sha256:...` digest or local image id), and `NATIVE_GATEWAY_CONTAINER`\n (the gateway container's name). Optional: `NATIVE_GATEWAY_URL`,\n `NATIVE_SANDBOX_CPUS` (1), `NATIVE_SANDBOX_MEMORY_MB` (512),\n `NATIVE_SANDBOX_PIDS` (128).\n3. Set the mode with `create_agent` or `update_agent` (`nativeExecutionMode`:\n `control-plane` or `sandbox`; native agents only), or from the CLI with\n `wardby agent create ... --native-execution-mode sandbox` or\n `wardby agent mode <name> sandbox`. `sandbox` is refused when the server\n (or, for the CLI, its environment) has no native sandbox configured. Each\n run keeps the mode it started with; `get_run` shows it.\n\n### Kubernetes\n\nSet `NATIVE_SANDBOX_LAUNCHER=kubernetes` instead and the server starts one pod\nper run. Run the gateway as a Deployment in the run namespace with a ClusterIP\nService that exposes both 8790 and the deny port 8791, and a NetworkPolicy that\nadmits `wardby.io/component: native-run` pods on both ports (keep the 8791\nrule). On the server set `NATIVE_SANDBOX_WORKER_IMAGE` to a registry digest\n(`repo@sha256:...`; a local image id is not accepted), and optionally\n`NATIVE_SANDBOX_NAMESPACE` (default `KUBERNETES_NAMESPACE`, else\n`wardby-coding`), `KUBERNETES_CONTEXT`, `NATIVE_SANDBOX_RUNTIME_CLASS` (for\nexample gVisor), `NATIVE_GATEWAY_SERVICE` (default `wardby-native-gateway`),\n`NATIVE_SANDBOX_PRIORITY_CLASS` (not a `system-` class),\n`NATIVE_SANDBOX_MAX_CONCURRENT` (cap on simultaneous sandbox runs across all\nreplicas; unset means no cap), `NATIVE_SANDBOX_READY_TIMEOUT_MS` (default 120000) and `NATIVE_SANDBOX_ENFORCEMENT_TIMEOUT_MS` (default 30000).\n`NATIVE_SANDBOX_PIDS` applies to Docker only. On GKE Autopilot also set\n`KUBERNETES_PLATFORM=gke-autopilot`: pod resources are conformed to Autopilot's\nrules and the gVisor runtime class is required. On Amazon EKS with a gVisor node\ngroup set `KUBERNETES_PLATFORM=eks`, which also requires the gVisor runtime class. The shipped GKE deployment\nruns the gateway for you; see the GKE guide. The\nserver needs permission in that namespace to create, get, and delete pods,\nSecrets, and NetworkPolicies, list pods, exec into pods, and get Services.\n\nEach run starts \"not ready\": the gateway refuses the worker until the server\nhas verified the pod and its NetworkPolicy and proven from inside the pod that\nthe gateway answers while the deny port, the outside world, and the cloud\nmetadata endpoints do not. Failures\nthere are\n[native_sandbox_network_unenforced](errors/native-sandbox-network-unenforced.md),\n[native_sandbox_isolation_mismatch](errors/native-sandbox-isolation-mismatch.md),\n[native_sandbox_gateway_unavailable](errors/native-sandbox-gateway-unavailable.md),\nand [native_sandbox_worker_unready](errors/native-sandbox-worker-unready.md).\nA start past the concurrent cap or the namespace quota fails with\n[native_sandbox_capacity](errors/native-sandbox-capacity.md).\n\nThe full procedure, topology, and local compose overlay are in\n[Native sandbox](../docs/native-sandbox.md).\n\n### Warm pool\n\nSet `NATIVE_SANDBOX_WARM_POOL_SIZE` (0 to 50, default 0 = off) to keep that many\nidle, already-isolated workers ready, with either launcher. A run claims one\natomically through the database; its input and one-time gateway capability are\ndelivered over exec stdin only after the claim, and the worker is still\nsingle-use. `NATIVE_SANDBOX_WARM_MAX_AGE_MS` (60000 to 21600000, default 1800000) replaces idle workers older than that. With no idle worker, or one that\nfails the claim-time re-check, the run cold-launches as usual. If delivery fails\nand the worker cannot be confirmed gone within 30 seconds, the run fails with\n[native_sandbox_warm_delivery_failed](errors/native-sandbox-warm-delivery-failed.md).\n\nIdle workers are extra pods or containers: the Kubernetes ResourceQuota needs\nroom for `NATIVE_SANDBOX_MAX_CONCURRENT` plus the pool size, and each idle\nworker reserves its CPU and memory (billed on GKE Autopilot). Rebuild the worker\nimage so it can be a pool worker. Pool workers are named `wardby-nwarm-<token>`\nand labelled `wardby.io/pool=warm`; logs use module `native-warm-pool`. Details\nare in [Native sandbox](../docs/native-sandbox.md#warm-pool).\n\n## What to expect\n\n- The worker is read-only, non-root (uid 10001), has all capabilities dropped, a\n size-capped `/tmp`, and CPU, memory, and PID limits. Each run gets its own\n internal network shared only with the gateway.\n- The gateway is the budget authority: it reserves each model call's worst-case\n cost first and settles at actual usage. A call the budget cannot cover ends the\n run `budget_exhausted`.\n- Sub-agents of a sandboxed run are managed runs started by the scheduler\n leader on its next tick (about every 10 seconds), so the server or scheduler\n must be running. A coding agent child is resolved by the server when it\n starts (worker image, services, knowledge), so the gateway needs no `CODING_*`\n settings; a problem there (such as a `workerImageRef` that is not pinned by digest)\n shows as the child run `failed` or `refused`; the parent's `delegate_to_*`\n call receives `status: \"failed\"` with the `errorCode`, or for a refused child\n the refusal sentence, and the full error is on the child run (`get_run`).\n Upgrade `wardby serve` and `wardby scheduler` before or together with the\n gateway: an older server starts the child unresolved (a Codex child on the\n default image without its instructions, a Claude Code child failing with\n `coding_provider_not_configured:claude-code`).\n- A sandbox run has a 60-minute maximum lifetime.\n- `stop_run` stops a sandbox run: its gateway session ends so the worker exits\n at its next call, and a worker still running after 5 seconds is killed and\n removed (a warm pool worker is discarded, never reused). Search help for\n \"stop run\" (article `stop-run`, Wardby 0.7.0 and later).\n\n## Roll back\n\nSet the agent back to `control-plane`. Only new runs are affected: runs\nalready started in sandbox mode finish there.\n\n## Troubleshooting\n\nCheck the gateway with `GET /healthz`, list worker containers with\n`docker ps --all --filter label=io.wardby.component=native-worker`, and read the\nrun's error with `get_run`. On Kubernetes list worker pods with\n`kubectl get pods -n <namespace> -l wardby.io/component=native-run`. Error\ncodes:\n\n- [native_sandbox_unavailable](errors/native-sandbox-unavailable.md)\n- [native_sandbox_worker_exited](errors/native-sandbox-worker-exited.md)\n- [native_sandbox_gateway_error](errors/native-sandbox-gateway-error.md)\n- [native_sandbox_deadline_exceeded](errors/native-sandbox-deadline-exceeded.md)\n- [native_sandbox_worker_lost](errors/native-sandbox-worker-lost.md)\n- [native_sandbox_image_not_pinned](errors/native-sandbox-image-not-pinned.md)\n- [native_sandbox_docker_failed](errors/native-sandbox-docker-failed.md)\n- [native_sandbox_network_unenforced](errors/native-sandbox-network-unenforced.md)\n- [native_sandbox_isolation_mismatch](errors/native-sandbox-isolation-mismatch.md)\n- [native_sandbox_gateway_unavailable](errors/native-sandbox-gateway-unavailable.md)\n- [native_sandbox_worker_unready](errors/native-sandbox-worker-unready.md)\n- [native_sandbox_capacity](errors/native-sandbox-capacity.md)\n- [native_sandbox_warm_delivery_failed](errors/native-sandbox-warm-delivery-failed.md)\n- [native_sandbox_requires_catalog](errors/native-sandbox-requires-catalog.md)\n\nSee also [Use native agents, tools, and data](native-capabilities.md) and\n[Understand Wardby security boundaries](security.md).\n",
|
|
3445
4120
|
"plainText": "Run native agents in a sandbox By default a native agent runs inside the Wardby server. Set its nativeExecutionMode to sandbox and its whole turn loop and user tools run in a single-use Docker container or Kubernetes pod (the wardby-native-worker image) instead. The container has no credentials, no database access, no Docker socket, and no network except the native gateway, a separate trusted container that holds the LLM credentials and enforces each tool attachment's grants. The server and gateway are trusted; the agent loop and user tool code are not. Turn it on Run the gateway: wardby native-gateway in a container with the server's database, LLM, secrets, and integration settings, listening on NATIVEGATEWAYLISTEN (default 0.0.0.0:8790; GET /healthz). Give it no Docker socket. On the server (wardby serve or wardby scheduler) set NATIVESANDBOXLAUNCHER=docker, NATIVESANDBOXWORKERIMAGE (a repo@sha256:... digest or local image id), and NATIVEGATEWAYCONTAINER (the gateway container's name). Optional: NATIVEGATEWAYURL, NATIVESANDBOXCPUS (1), NATIVESANDBOXMEMORYMB (512), NATIVESANDBOXPIDS (128). Set the mode with createagent or updateagent (nativeExecutionMode: control-plane or sandbox; native agents only), or from the CLI with wardby agent create ... --native-execution-mode sandbox or wardby agent mode <name sandbox. sandbox is refused when the server (or, for the CLI, its environment) has no native sandbox configured. Each run keeps the mode it started with; getrun shows it. Kubernetes Set NATIVESANDBOXLAUNCHER=kubernetes instead and the server starts one pod per run. Run the gateway as a Deployment in the run namespace with a ClusterIP Service that exposes both 8790 and the deny port 8791, and a NetworkPolicy that admits wardby.io/component: native-run pods on both ports (keep the 8791 rule). On the server set NATIVESANDBOXWORKERIMAGE to a registry digest (repo@sha256:...; a local image id is not accepted), and optionally NATIVESANDBOXNAMESPACE (default KUBERNETESNAMESPACE, else wardby-coding), KUBERNETESCONTEXT, NATIVESANDBOXRUNTIMECLASS (for example gVisor), NATIVEGATEWAYSERVICE (default wardby-native-gateway), NATIVESANDBOXPRIORITYCLASS (not a system- class), NATIVESANDBOXMAXCONCURRENT (cap on simultaneous sandbox runs across all replicas; unset means no cap), NATIVESANDBOXREADYTIMEOUTMS (default 120000) and NATIVESANDBOXENFORCEMENTTIMEOUTMS (default 30000). NATIVESANDBOXPIDS applies to Docker only. On GKE Autopilot also set KUBERNETESPLATFORM=gke-autopilot: pod resources are conformed to Autopilot's rules and the gVisor runtime class is required. On Amazon EKS with a gVisor node group set KUBERNETESPLATFORM=eks, which also requires the gVisor runtime class. The shipped GKE deployment runs the gateway for you; see the GKE guide. The server needs permission in that namespace to create, get, and delete pods, Secrets, and NetworkPolicies, list pods, exec into pods, and get Services. Each run starts \"not ready\": the gateway refuses the worker until the server has verified the pod and its NetworkPolicy and proven from inside the pod that the gateway answers while the deny port, the outside world, and the cloud metadata endpoints do not. Failures there are nativesandboxnetworkunenforced, nativesandboxisolationmismatch, nativesandboxgatewayunavailable, and nativesandboxworkerunready. A start past the concurrent cap or the namespace quota fails with nativesandboxcapacity. The full procedure, topology, and local compose overlay are in Native sandbox. Warm pool Set NATIVESANDBOXWARMPOOLSIZE (0 to 50, default 0 = off) to keep that many idle, already-isolated workers ready, with either launcher. A run claims one atomically through the database; its input and one-time gateway capability are delivered over exec stdin only after the claim, and the worker is still single-use. NATIVESANDBOXWARMMAXAGEMS (60000 to 21600000, default 1800000) replaces idle workers older than that. With no idle worker, or one that fails the claim-time re-check, the run cold-launches as usual. If delivery fails and the worker cannot be confirmed gone within 30 seconds, the run fails with nativesandboxwarmdeliveryfailed. Idle workers are extra pods or containers: the Kubernetes ResourceQuota needs room for NATIVESANDBOXMAXCONCURRENT plus the pool size, and each idle worker reserves its CPU and memory (billed on GKE Autopilot). Rebuild the worker image so it can be a pool worker. Pool workers are named wardby-nwarm-<token and labelled wardby.io/pool=warm; logs use module native-warm-pool. Details are in Native sandbox. What to expect The worker is read-only, non-root (uid 10001), has all capabilities dropped, a size-capped /tmp, and CPU, memory, and PID limits. Each run gets its own internal network shared only with the gateway. The gateway is the budget authority: it reserves each model call's worst-case cost first and settles at actual usage. A call the budget cannot cover ends the run budgetexhausted. Sub-agents of a sandboxed run are managed runs started by the scheduler leader on its next tick (about every 10 seconds), so the server or scheduler must be running. A coding agent child is resolved by the server when it starts (worker image, services, knowledge), so the gateway needs no CODING settings; a problem there (such as a workerImageRef that is not pinned by digest) shows as the child run failed or refused; the parent's delegateto call receives status: \"failed\" with the errorCode, or for a refused child the refusal sentence, and the full error is on the child run (getrun). Upgrade wardby serve and wardby scheduler before or together with the gateway: an older server starts the child unresolved (a Codex child on the default image without its instructions, a Claude Code child failing with codingprovidernotconfigured:claude-code). A sandbox run has a 60-minute maximum lifetime. stoprun stops a sandbox run: its gateway session ends so the worker exits at its next call, and a worker still running after 5 seconds is killed and removed (a warm pool worker is discarded, never reused). Search help for \"stop run\" (article stop-run, Wardby 0.7.0 and later). Roll back Set the agent back to control-plane. Only new runs are affected: runs already started in sandbox mode finish there. Troubleshooting Check the gateway with GET /healthz, list worker containers with docker ps --all --filter label=io.wardby.component=native-worker, and read the run's error with getrun. On Kubernetes list worker pods with kubectl get pods -n <namespace -l wardby.io/component=native-run. Error codes: nativesandboxunavailable nativesandboxworkerexited nativesandboxgatewayerror nativesandboxdeadlineexceeded nativesandboxworkerlost nativesandboximagenotpinned nativesandboxdockerfailed nativesandboxnetworkunenforced nativesandboxisolationmismatch nativesandboxgatewayunavailable nativesandboxworkerunready nativesandboxcapacity nativesandboxwarmdeliveryfailed nativesandboxrequirescatalog See also Use native agents, tools, and data and Understand Wardby security boundaries.",
|
|
@@ -3518,8 +4193,8 @@
|
|
|
3518
4193
|
],
|
|
3519
4194
|
"appliesTo": ">=0.2.1",
|
|
3520
4195
|
"sourcePath": "operating-agents.md",
|
|
3521
|
-
"markdown": "\n# Operate managed agents\n\nEvery Wardby-managed agent has an owner, system prompt, model, per-run budget,\nand explicitly attached capabilities. A run starts only when its identity,\npolicy, and available budget agree.\n\nCreate, update, pause, trigger, and inspect agents through Wardby's MCP tools.\nThe CLI is the bootstrap and operations fallback. Scheduled work requires a\nrunning scheduler: `wardby serve` runs MCP, scheduler, and reconciliation in\none process; `wardby mcp` alone does not execute schedules.\n\nUse [Choose a native or coding agent](creating-agents.md) to select the least\npowerful execution model that can safely produce the desired outcome.\n\nBefore a run starts, Wardby reserves its allowed spend. The reservation is\nconstrained by the agent's own budget, any shared budget group, and any\nsub-agent run tree. See [Budget troubleshooting](troubleshooting/budgets.md)\nwhen a run is refused for lack of budget, and\n[Attribute agent spend to issues](cost-attribution.md) to see what runs cost\nper issue, epic, project, agent, or model.\n\nA running run's cost, token counts, and turn count update after each model\ncall, so `get_run` and `list_runs` show spend so far rather than zero until the\nrun finishes.\n\nTo stop a run that is pending, queued, or running (for example one a schedule\nstarted that you did not want), call `stop_run` with its id. It ends as\n`cancelled`, along with the sub-agent runs it still has in flight. Search help\nfor \"stop run\" (article `stop-run`, Wardby 0.7.0 and later).\n\nFor the full lifecycle and the controls applied to every managed run, read\n[`README.md`](../README.md).\n",
|
|
3522
|
-
"plainText": "Operate managed agents Every Wardby-managed agent has an owner, system prompt, model, per-run budget, and explicitly attached capabilities. A run starts only when its identity, policy, and available budget agree. Create, update, pause, trigger, and inspect agents through Wardby's MCP tools. The CLI is the bootstrap and operations fallback. Scheduled work requires a running scheduler: wardby serve runs MCP, scheduler, and reconciliation in one process; wardby mcp alone does not execute schedules. Use Choose a native or coding agent to select the least powerful execution model that can safely produce the desired outcome. Before a run starts, Wardby reserves its allowed spend. The reservation is constrained by the agent's own budget, any shared budget group, and any sub-agent run tree. See Budget troubleshooting when a run is refused for lack of budget, and Attribute agent spend to issues to see what runs cost per issue, epic, project, agent, or model. A running run's cost, token counts, and turn count update after each model call, so getrun and listruns show spend so far rather than zero until the run finishes. To stop a run that is pending, queued, or running (for example one a schedule started that you did not want), call stoprun with its id. It ends as cancelled, along with the sub-agent runs it still has in flight. Search help for \"stop run\" (article stop-run, Wardby 0.7.0 and later). For the full lifecycle and the controls applied to every managed run, read README.md.",
|
|
4196
|
+
"markdown": "\n# Operate managed agents\n\nEvery Wardby-managed agent has an owner, system prompt, model, per-run budget,\nand explicitly attached capabilities. A run starts only when its identity,\npolicy, and available budget agree.\n\nCreate, update, pause, trigger, and inspect agents through Wardby's MCP tools.\nThe CLI is the bootstrap and operations fallback. Scheduled work requires a\nrunning scheduler: `wardby serve` runs MCP, scheduler, and reconciliation in\none process; `wardby mcp` alone does not execute schedules.\n\nUse [Choose a native or coding agent](creating-agents.md) to select the least\npowerful execution model that can safely produce the desired outcome.\n\nBefore a run starts, Wardby reserves its allowed spend. The reservation is\nconstrained by the agent's own budget, any shared budget group, and any\nsub-agent run tree. See [Budget troubleshooting](troubleshooting/budgets.md)\nwhen a run is refused for lack of budget, and\n[Attribute agent spend to issues](cost-attribution.md) to see what runs cost\nper issue, epic, project, agent, or model.\n\nA running run's cost, token counts, and turn count update after each model\ncall, so `get_run` and `list_runs` show spend so far rather than zero until the\nrun finishes.\n\nTo see your runs across every agent, call `list_runs` without an `agentId`\n(Wardby 0.8.0 and later). Each row names its agent and leaves out the final\ntext; `active: true` keeps pending and running runs, and `since` (an ISO time)\nkeeps runs that started or finished since then plus any still active. You see\nevery run of the agents you own and only the runs you started on the others.\n`list_agents` with `summary: true` returns just each agent's id, name, kind,\nmodel, coding provider, budget, owner and your access, without the full\nconfiguration.\n\nFrom Wardby 0.8.0, `get_run` and `list_runs` without an `agentId` also return\n`triggerInfo` (the pull request or issue that started the run, and whether it\nwas a review or a mention), `outcomes` (pull requests opened, comments, checks)\nand `serviceReadiness` (each coding-run service's state). They use the admin\nviewer API's shapes. Match one run's pull-request outcome to another run's\ntrigger to follow a pull request through its review and fix rounds.\n\nTo stop a run that is pending, queued, or running (for example one a schedule\nstarted that you did not want), call `stop_run` with its id. It ends as\n`cancelled`, along with the sub-agent runs it still has in flight. Search help\nfor \"stop run\" (article `stop-run`, Wardby 0.7.0 and later).\n\nFor the full lifecycle and the controls applied to every managed run, read\n[`README.md`](../README.md).\n",
|
|
4197
|
+
"plainText": "Operate managed agents Every Wardby-managed agent has an owner, system prompt, model, per-run budget, and explicitly attached capabilities. A run starts only when its identity, policy, and available budget agree. Create, update, pause, trigger, and inspect agents through Wardby's MCP tools. The CLI is the bootstrap and operations fallback. Scheduled work requires a running scheduler: wardby serve runs MCP, scheduler, and reconciliation in one process; wardby mcp alone does not execute schedules. Use Choose a native or coding agent to select the least powerful execution model that can safely produce the desired outcome. Before a run starts, Wardby reserves its allowed spend. The reservation is constrained by the agent's own budget, any shared budget group, and any sub-agent run tree. See Budget troubleshooting when a run is refused for lack of budget, and Attribute agent spend to issues to see what runs cost per issue, epic, project, agent, or model. A running run's cost, token counts, and turn count update after each model call, so getrun and listruns show spend so far rather than zero until the run finishes. To see your runs across every agent, call listruns without an agentId (Wardby 0.8.0 and later). Each row names its agent and leaves out the final text; active: true keeps pending and running runs, and since (an ISO time) keeps runs that started or finished since then plus any still active. You see every run of the agents you own and only the runs you started on the others. listagents with summary: true returns just each agent's id, name, kind, model, coding provider, budget, owner and your access, without the full configuration. From Wardby 0.8.0, getrun and listruns without an agentId also return triggerInfo (the pull request or issue that started the run, and whether it was a review or a mention), outcomes (pull requests opened, comments, checks) and serviceReadiness (each coding-run service's state). They use the admin viewer API's shapes. Match one run's pull-request outcome to another run's trigger to follow a pull request through its review and fix rounds. To stop a run that is pending, queued, or running (for example one a schedule started that you did not want), call stoprun with its id. It ends as cancelled, along with the sub-agent runs it still has in flight. Search help for \"stop run\" (article stop-run, Wardby 0.7.0 and later). For the full lifecycle and the controls applied to every managed run, read README.md.",
|
|
3523
4198
|
"headings": [
|
|
3524
4199
|
{
|
|
3525
4200
|
"level": 1,
|
|
@@ -3608,8 +4283,8 @@
|
|
|
3608
4283
|
],
|
|
3609
4284
|
"appliesTo": ">=0.4.2",
|
|
3610
4285
|
"sourcePath": "related-pull-requests.md",
|
|
3611
|
-
"markdown": "\n# Related pull requests across repositories\n\nWhen one request produces pull requests in several repositories — a lead\nagent that delegates to one coding agent per repository, or several runs for\nthe same Jira or GitHub issue — Wardby adds a **Related pull requests** section to each\nof those pull requests' descriptions. It lists the others with links and\ntheir state, names the originating issue when there is one, and gives a\nmerge order: the one the delegating agent set, or else a suggested one.\n\nWithout a tracked issue, the list covers the pull requests opened by runs in\nthe same delegation tree (the same lead run and everything it started). With\na tracked issue (a Jira issue, or a GitHub issue whose `@<app-slug>` mention\nstarted the request), the list covers every pull request Wardby has recorded\nfor that issue across every run, merged and closed ones included, plus that\nrun tree's own siblings. The section names the issue the same way for both,\nfor example \"for Jira issue PROJ-123\" or \"for GitHub issue owner/repo#7\",\nlinked to the issue.\n\n- **Written by Wardby, not the model.** The list comes from Wardby's own run\n records, never from the agent's text. Edits you make inside the section\n are replaced on the next rewrite; text outside it is left alone.\n- **When.** A pull request already lists the ones opened earlier in the same\n request when it is opened. When the lead run finishes, Wardby rewrites the\n section on every open pull request of the request with the full list and\n current states. A later run that pushes to any pull request in the set\n refreshes the section on all of them the same way, and never removes it.\n With Wardby 0.6.0 or later, a reviewer linked to one of these pull requests does\n not review it until that same lead run finishes, however it ends. When the\n lead finishes normally the section has already been rewritten by then;\n when it is ended another way, such as being cancelled, reviews start\n without that rewrite, so reviewers should rely on `repo_pr_read`'s\n `relatedPullRequests` either way — see [Reviewing a pull request a\n delegated run\n opened](code-review-agents.md#reviewing-a-pull-request-a-delegated-run-opened).\n- **Merge order.** Without a `mergeOrder` (see below) on any pull request in\n the set, open (and draft) pull requests are numbered as a **Suggested merge\n order (the order Wardby's agent opened them in)** — delegation order, not a\n dependency analysis, and only reliable when the lead delegates repositories\n that own shared data first (see\n [Fanning out to several builders](../docs/agent-recipes.md#fanning-out-to-several-builders)).\n When any pull request in the set has a `mergeOrder` (open, merged or\n closed), the open ones that have one are numbered under **Merge order (set\n by the delegating agent; equal steps can merge in either order)** and\n labelled \"step k of n\" (equal values share a step and merge in either\n order relative to each other), and any open pull request without one is\n listed after under \"Not ordered:\". If only merged or closed pull requests\n have a `mergeOrder`, every open one is listed under \"Not ordered:\" and the\n \"Merge order\" heading is left out. Steps are counted over the whole set,\n merged and closed pull requests included, so \"step 2 of 3\" keeps its label\n after step 1 merges. Either way, check it before merging — neither is a\n guarantee. Merged and closed pull requests follow in a separate \"Already\n merged or closed\" list, as context only, with their step label when they\n have one.\n- Only open pull requests that Wardby's own GitHub App opened are edited;\n merged or closed ones are listed but never changed, and a pull request\n from a different Wardby deployment sharing the same App is never touched.\n- **Repository names are visible across the set.** The section (and the\n follow-up hints below) lists every pull request in the set by repository\n name and number, so a request that spans repositories of different\n visibility can show a private repository's name in a public repository's\n pull request. If you mix public and private repositories, keep such work in\n separate requests: separate issues, or separate lead agents.\n\nReviewers see the section in the pull request description, so a reviewer\nagent can tell that a field, route, or schema a change relies on is added by\na sibling pull request rather than missing. Because the description is only\nrewritten at the points above, a sibling opened (or merged, or closed) since\nthen can be missing from it or shown with an old state. With Wardby 0.6.0 or later,\n`repo_pr_read`'s `relatedPullRequests` field lists the request's pull\nrequests fresh on every call instead, so a reviewer should prefer it over\nthe description's section when they disagree. Its entry for the pull request\njust read always carries that pull request's live state; another entry\ncarries a state only when Wardby has one stored (pull requests linked to an\nissue) and omits it otherwise, so call `repo_pr_read` on that pull request\nfor its live state. `relatedPullRequests` is empty for a pull request on a\nlocal repository, which has no App-authored marker to resolve the request\nfrom. See the\nreviewer step in\n[Run GitHub code-review agents](code-review-agents.md#ci-and-sibling-pull-requests).\n\n## Setting a merge order\n\nA lead agent sets the order explicitly by passing `mergeOrder` on its\n`delegate_to_<name>` call to a coding sub-agent: an integer from 1 to 99,\nwhere 1 merges first. Give a repository that other repositories' changes\ndepend on a lower number than the ones that use it — for example a shared\nservice `1`, the API that calls it `2`, the client that calls the API `3`.\nGive two changes the same number when there is no order between them; they\nshare a step and either can merge first. A bad value (not an integer, or\noutside 1-99) is refused as a tool error, not silently dropped or clamped.\n\nSet it whenever one request's change spans several repositories and the\npull requests need to land in a specific sequence; leave it out and the set\nkeeps the delegation-order suggestion above. `mergeOrder` applies only to\ncoding sub-agents, since only a coding run's pull request can be ordered: a\nnative sub-agent ignores it, and its tool result notes that it did.\n\nEach pull request shows the value most recently set for it, by the run that\nopened it or a later continuation of it. A `continuePriorRun` call that\nomits `mergeOrder` keeps that current value, so a follow-up does not need to\nrepeat it to keep a pull request in its place; one that sets `mergeOrder`\nreplaces it.\n\nWith Wardby 0.6.0 or later, once a set has more than one `mergeOrder`, each\nopen or draft pull request Wardby opened in it also gets a check run named\n`wardby merge order`, tracking whether the pull requests it depends on have\nmerged yet. It's an informational check by default; search help for \"merge\norder check\" for its states and for requiring it in branch protection.\n\n## Follow-up runs and sibling pull requests\n\nWhen someone asks for a follow-up on one of these pull requests (an\n`@<app-slug>` mention, or a new Jira event on the issue), the task given to\nthe agent also lists every **open** sibling pull request in the set, with\nits link and the exact `continuePriorRun` value that continues it, together\nwith guidance not to open a duplicate pull request in a repository that\nalready has one open for this request. Automatic review fix rounds get no\nsuch hints: a fix round's task names only its own pull request. Merged and\nclosed pull requests are never listed as continuable: a change there needs a\nnew pull request, which joins the set once it is recorded.\n\nGive your own delivery or router agent's system prompt a line such as:\n\n Continue the pull request you were asked about, and any listed open\n sibling the change requires; never open a new pull request in a\n repository that already has an open sibling for this request.\n\nThe usual limits still apply: `maxDelegationsPerRun` and
|
|
3612
|
-
"plainText": "Related pull requests across repositories When one request produces pull requests in several repositories — a lead agent that delegates to one coding agent per repository, or several runs for the same Jira or GitHub issue — Wardby adds a Related pull requests section to each of those pull requests' descriptions. It lists the others with links and their state, names the originating issue when there is one, and gives a merge order: the one the delegating agent set, or else a suggested one. Without a tracked issue, the list covers the pull requests opened by runs in the same delegation tree (the same lead run and everything it started). With a tracked issue (a Jira issue, or a GitHub issue whose @<app-slug mention started the request), the list covers every pull request Wardby has recorded for that issue across every run, merged and closed ones included, plus that run tree's own siblings. The section names the issue the same way for both, for example \"for Jira issue PROJ-123\" or \"for GitHub issue owner/repo#7\", linked to the issue. Written by Wardby, not the model. The list comes from Wardby's own run records, never from the agent's text. Edits you make inside the section are replaced on the next rewrite; text outside it is left alone. When. A pull request already lists the ones opened earlier in the same request when it is opened. When the lead run finishes, Wardby rewrites the section on every open pull request of the request with the full list and current states. A later run that pushes to any pull request in the set refreshes the section on all of them the same way, and never removes it. With Wardby 0.6.0 or later, a reviewer linked to one of these pull requests does not review it until that same lead run finishes, however it ends. When the lead finishes normally the section has already been rewritten by then; when it is ended another way, such as being cancelled, reviews start without that rewrite, so reviewers should rely on repoprread's relatedPullRequests either way — see Reviewing a pull request a delegated run opened. Merge order. Without a mergeOrder (see below) on any pull request in the set, open (and draft) pull requests are numbered as a Suggested merge order (the order Wardby's agent opened them in) — delegation order, not a dependency analysis, and only reliable when the lead delegates repositories that own shared data first (see Fanning out to several builders). When any pull request in the set has a mergeOrder (open, merged or closed), the open ones that have one are numbered under Merge order (set by the delegating agent; equal steps can merge in either order) and labelled \"step k of n\" (equal values share a step and merge in either order relative to each other), and any open pull request without one is listed after under \"Not ordered:\". If only merged or closed pull requests have a mergeOrder, every open one is listed under \"Not ordered:\" and the \"Merge order\" heading is left out. Steps are counted over the whole set, merged and closed pull requests included, so \"step 2 of 3\" keeps its label after step 1 merges. Either way, check it before merging — neither is a guarantee. Merged and closed pull requests follow in a separate \"Already merged or closed\" list, as context only, with their step label when they have one. Only open pull requests that Wardby's own GitHub App opened are edited; merged or closed ones are listed but never changed, and a pull request from a different Wardby deployment sharing the same App is never touched. Repository names are visible across the set. The section (and the follow-up hints below) lists every pull request in the set by repository name and number, so a request that spans repositories of different visibility can show a private repository's name in a public repository's pull request. If you mix public and private repositories, keep such work in separate requests: separate issues, or separate lead agents. Reviewers see the section in the pull request description, so a reviewer agent can tell that a field, route, or schema a change relies on is added by a sibling pull request rather than missing. Because the description is only rewritten at the points above, a sibling opened (or merged, or closed) since then can be missing from it or shown with an old state. With Wardby 0.6.0 or later, repoprread's relatedPullRequests field lists the request's pull requests fresh on every call instead, so a reviewer should prefer it over the description's section when they disagree. Its entry for the pull request just read always carries that pull request's live state; another entry carries a state only when Wardby has one stored (pull requests linked to an issue) and omits it otherwise, so call repoprread on that pull request for its live state. relatedPullRequests is empty for a pull request on a local repository, which has no App-authored marker to resolve the request from. See the reviewer step in Run GitHub code-review agents. Setting a merge order A lead agent sets the order explicitly by passing mergeOrder on its delegateto<name call to a coding sub-agent: an integer from 1 to 99, where 1 merges first. Give a repository that other repositories' changes depend on a lower number than the ones that use it — for example a shared service 1, the API that calls it 2, the client that calls the API 3. Give two changes the same number when there is no order between them; they share a step and either can merge first. A bad value (not an integer, or outside 1-99) is refused as a tool error, not silently dropped or clamped. Set it whenever one request's change spans several repositories and the pull requests need to land in a specific sequence; leave it out and the set keeps the delegation-order suggestion above. mergeOrder applies only to coding sub-agents, since only a coding run's pull request can be ordered: a native sub-agent ignores it, and its tool result notes that it did. Each pull request shows the value most recently set for it, by the run that opened it or a later continuation of it. A continuePriorRun call that omits mergeOrder keeps that current value, so a follow-up does not need to repeat it to keep a pull request in its place; one that sets mergeOrder replaces it. With Wardby 0.6.0 or later, once a set has more than one mergeOrder, each open or draft pull request Wardby opened in it also gets a check run named wardby merge order, tracking whether the pull requests it depends on have merged yet. It's an informational check by default; search help for \"merge order check\" for its states and for requiring it in branch protection. Follow-up runs and sibling pull requests When someone asks for a follow-up on one of these pull requests (an @<app-slug mention, or a new Jira event on the issue), the task given to the agent also lists every open sibling pull request in the set, with its link and the exact continuePriorRun value that continues it, together with guidance not to open a duplicate pull request in a repository that already has one open for this request. Automatic review fix rounds get no such hints: a fix round's task names only its own pull request. Merged and closed pull requests are never listed as continuable: a change there needs a new pull request, which joins the set once it is recorded. Give your own delivery or router agent's system prompt a line such as: Continue the pull request you were asked about, and any listed open sibling the change requires; never open a new pull request in a repository that already has an open sibling for this request. The usual limits still apply: maxDelegationsPerRun and
|
|
4286
|
+
"markdown": "\n# Related pull requests across repositories\n\nWhen one request produces pull requests in several repositories — a lead\nagent that delegates to one coding agent per repository, or several runs for\nthe same Jira or GitHub issue — Wardby adds a **Related pull requests** section to each\nof those pull requests' descriptions. It lists the others with links and\ntheir state, names the originating issue when there is one, and gives a\nmerge order: the one the delegating agent set, or else a suggested one.\n\nWithout a tracked issue, the list covers the pull requests opened by runs in\nthe same delegation tree (the same lead run and everything it started). With\na tracked issue (a Jira issue, or a GitHub issue whose `@<app-slug>` mention\nstarted the request), the list covers every pull request Wardby has recorded\nfor that issue across every run, merged and closed ones included, plus that\nrun tree's own siblings. The section names the issue the same way for both,\nfor example \"for Jira issue PROJ-123\" or \"for GitHub issue owner/repo#7\",\nlinked to the issue.\n\n- **Written by Wardby, not the model.** The list comes from Wardby's own run\n records, never from the agent's text. Edits you make inside the section\n are replaced on the next rewrite; text outside it is left alone.\n- **When.** A pull request already lists the ones opened earlier in the same\n request when it is opened. When the lead run finishes, Wardby rewrites the\n section on every open pull request of the request with the full list and\n current states. A later run that pushes to any pull request in the set\n refreshes the section on all of them the same way, and never removes it.\n With Wardby 0.6.0 or later, a reviewer linked to one of these pull requests does\n not review it until that same lead run finishes, however it ends. When the\n lead finishes normally the section has already been rewritten by then;\n when it is ended another way, such as being cancelled, reviews start\n without that rewrite, so reviewers should rely on `repo_pr_read`'s\n `relatedPullRequests` either way — see [Reviewing a pull request a\n delegated run\n opened](code-review-agents.md#reviewing-a-pull-request-a-delegated-run-opened).\n- **Merge order.** Without a `mergeOrder` (see below) on any pull request in\n the set, open (and draft) pull requests are numbered as a **Suggested merge\n order (the order Wardby's agent opened them in)** — delegation order, not a\n dependency analysis, and only reliable when the lead delegates repositories\n that own shared data first (see\n [Fanning out to several builders](../docs/agent-recipes.md#fanning-out-to-several-builders)).\n When any pull request in the set has a `mergeOrder` (open, merged or\n closed), the open ones that have one are numbered under **Merge order (set\n by the delegating agent; equal steps can merge in either order)** and\n labelled \"step k of n\" (equal values share a step and merge in either\n order relative to each other), and any open pull request without one is\n listed after under \"Not ordered:\". If only merged or closed pull requests\n have a `mergeOrder`, every open one is listed under \"Not ordered:\" and the\n \"Merge order\" heading is left out. Steps are counted over the whole set,\n merged and closed pull requests included, so \"step 2 of 3\" keeps its label\n after step 1 merges. Either way, check it before merging — neither is a\n guarantee. Merged and closed pull requests follow in a separate \"Already\n merged or closed\" list, as context only, with their step label when they\n have one.\n- Only open pull requests that Wardby's own GitHub App opened are edited;\n merged or closed ones are listed but never changed, and a pull request\n from a different Wardby deployment sharing the same App is never touched.\n- **Repository names are visible across the set.** The section (and the\n follow-up hints below) lists every pull request in the set by repository\n name and number, so a request that spans repositories of different\n visibility can show a private repository's name in a public repository's\n pull request. If you mix public and private repositories, keep such work in\n separate requests: separate issues, or separate lead agents.\n\nReviewers see the section in the pull request description, so a reviewer\nagent can tell that a field, route, or schema a change relies on is added by\na sibling pull request rather than missing. Because the description is only\nrewritten at the points above, a sibling opened (or merged, or closed) since\nthen can be missing from it or shown with an old state. With Wardby 0.6.0 or later,\n`repo_pr_read`'s `relatedPullRequests` field lists the request's pull\nrequests fresh on every call instead, so a reviewer should prefer it over\nthe description's section when they disagree. Its entry for the pull request\njust read always carries that pull request's live state; another entry\ncarries a state only when Wardby has one stored (pull requests linked to an\nissue) and omits it otherwise, so call `repo_pr_read` on that pull request\nfor its live state. `relatedPullRequests` is empty for a pull request on a\nlocal repository, which has no App-authored marker to resolve the request\nfrom. See the\nreviewer step in\n[Run GitHub code-review agents](code-review-agents.md#ci-and-sibling-pull-requests).\n\n## Setting a merge order\n\nA lead agent sets the order explicitly by passing `mergeOrder` on its\n`delegate_to_<name>` call to a coding sub-agent: an integer from 1 to 99,\nwhere 1 merges first. Give a repository that other repositories' changes\ndepend on a lower number than the ones that use it — for example a shared\nservice `1`, the API that calls it `2`, the client that calls the API `3`.\nGive two changes the same number when there is no order between them; they\nshare a step and either can merge first. A bad value (not an integer, or\noutside 1-99) is refused as a tool error, not silently dropped or clamped.\n\nSet it whenever one request's change spans several repositories and the\npull requests need to land in a specific sequence; leave it out and the set\nkeeps the delegation-order suggestion above. `mergeOrder` applies only to\ncoding sub-agents, since only a coding run's pull request can be ordered: a\nnative sub-agent ignores it, and its tool result notes that it did.\n\nEach pull request shows the value most recently set for it, by the run that\nopened it or a later continuation of it. A `continuePriorRun` call that\nomits `mergeOrder` keeps that current value, so a follow-up does not need to\nrepeat it to keep a pull request in its place; one that sets `mergeOrder`\nreplaces it.\n\nWith Wardby 0.6.0 or later, once a set has more than one `mergeOrder`, each\nopen or draft pull request Wardby opened in it also gets a check run named\n`wardby merge order`, tracking whether the pull requests it depends on have\nmerged yet. It's an informational check by default; search help for \"merge\norder check\" for its states and for requiring it in branch protection.\n\n## Follow-up runs and sibling pull requests\n\nWhen someone asks for a follow-up on one of these pull requests (an\n`@<app-slug>` mention, or a new Jira event on the issue), the task given to\nthe agent also lists every **open** sibling pull request in the set, with\nits link and the exact `continuePriorRun` value that continues it, together\nwith guidance not to open a duplicate pull request in a repository that\nalready has one open for this request. Automatic review fix rounds get no\nsuch hints: a fix round's task names only its own pull request. Merged and\nclosed pull requests are never listed as continuable: a change there needs a\nnew pull request, which joins the set once it is recorded.\n\nWhen the sub-agent is a coding agent with a list of repositories, a\nfollow-up delegation passes `continuePriorRun` and takes its repository from\nthat run, so it needs no `repository` of its own.\n\nGive your own delivery or router agent's system prompt a line such as:\n\n Continue the pull request you were asked about, and any listed open\n sibling the change requires; never open a new pull request in a\n repository that already has an open sibling for this request.\n\nThe usual limits still apply: `maxDelegationsPerRun` and delegating to each\nsub-agent and repository at most once per run; every push to a sibling pull\nrequest gets its own review; fix rounds are capped per pull request and only one\nruns at a time on a pull request; and a continuation only ever reaches a\nsub-agent that shares the same owner as the one asked to continue it.\n\nA continuation never pushes to a pull request that has been merged or closed\nin the meantime: the coding run stops before it starts work (or right before\nit pushes) with failure category `continuation_closed`, and the delegating\nagent is told to make the change as a new pull request instead. See\n[Continuation's pull request is no longer open](errors/continuation-closed.md).\n\nWardby also keeps the recorded state of issue-linked pull requests current\neven when GitHub's merge or close webhook delivery was missed: it re-checks\nopen ones in the background, at most ten at a time, each at most every ten\nminutes, and applies the same comment and status move a normal webhook would\nhave triggered.\n",
|
|
4287
|
+
"plainText": "Related pull requests across repositories When one request produces pull requests in several repositories — a lead agent that delegates to one coding agent per repository, or several runs for the same Jira or GitHub issue — Wardby adds a Related pull requests section to each of those pull requests' descriptions. It lists the others with links and their state, names the originating issue when there is one, and gives a merge order: the one the delegating agent set, or else a suggested one. Without a tracked issue, the list covers the pull requests opened by runs in the same delegation tree (the same lead run and everything it started). With a tracked issue (a Jira issue, or a GitHub issue whose @<app-slug mention started the request), the list covers every pull request Wardby has recorded for that issue across every run, merged and closed ones included, plus that run tree's own siblings. The section names the issue the same way for both, for example \"for Jira issue PROJ-123\" or \"for GitHub issue owner/repo#7\", linked to the issue. Written by Wardby, not the model. The list comes from Wardby's own run records, never from the agent's text. Edits you make inside the section are replaced on the next rewrite; text outside it is left alone. When. A pull request already lists the ones opened earlier in the same request when it is opened. When the lead run finishes, Wardby rewrites the section on every open pull request of the request with the full list and current states. A later run that pushes to any pull request in the set refreshes the section on all of them the same way, and never removes it. With Wardby 0.6.0 or later, a reviewer linked to one of these pull requests does not review it until that same lead run finishes, however it ends. When the lead finishes normally the section has already been rewritten by then; when it is ended another way, such as being cancelled, reviews start without that rewrite, so reviewers should rely on repoprread's relatedPullRequests either way — see Reviewing a pull request a delegated run opened. Merge order. Without a mergeOrder (see below) on any pull request in the set, open (and draft) pull requests are numbered as a Suggested merge order (the order Wardby's agent opened them in) — delegation order, not a dependency analysis, and only reliable when the lead delegates repositories that own shared data first (see Fanning out to several builders). When any pull request in the set has a mergeOrder (open, merged or closed), the open ones that have one are numbered under Merge order (set by the delegating agent; equal steps can merge in either order) and labelled \"step k of n\" (equal values share a step and merge in either order relative to each other), and any open pull request without one is listed after under \"Not ordered:\". If only merged or closed pull requests have a mergeOrder, every open one is listed under \"Not ordered:\" and the \"Merge order\" heading is left out. Steps are counted over the whole set, merged and closed pull requests included, so \"step 2 of 3\" keeps its label after step 1 merges. Either way, check it before merging — neither is a guarantee. Merged and closed pull requests follow in a separate \"Already merged or closed\" list, as context only, with their step label when they have one. Only open pull requests that Wardby's own GitHub App opened are edited; merged or closed ones are listed but never changed, and a pull request from a different Wardby deployment sharing the same App is never touched. Repository names are visible across the set. The section (and the follow-up hints below) lists every pull request in the set by repository name and number, so a request that spans repositories of different visibility can show a private repository's name in a public repository's pull request. If you mix public and private repositories, keep such work in separate requests: separate issues, or separate lead agents. Reviewers see the section in the pull request description, so a reviewer agent can tell that a field, route, or schema a change relies on is added by a sibling pull request rather than missing. Because the description is only rewritten at the points above, a sibling opened (or merged, or closed) since then can be missing from it or shown with an old state. With Wardby 0.6.0 or later, repoprread's relatedPullRequests field lists the request's pull requests fresh on every call instead, so a reviewer should prefer it over the description's section when they disagree. Its entry for the pull request just read always carries that pull request's live state; another entry carries a state only when Wardby has one stored (pull requests linked to an issue) and omits it otherwise, so call repoprread on that pull request for its live state. relatedPullRequests is empty for a pull request on a local repository, which has no App-authored marker to resolve the request from. See the reviewer step in Run GitHub code-review agents. Setting a merge order A lead agent sets the order explicitly by passing mergeOrder on its delegateto<name call to a coding sub-agent: an integer from 1 to 99, where 1 merges first. Give a repository that other repositories' changes depend on a lower number than the ones that use it — for example a shared service 1, the API that calls it 2, the client that calls the API 3. Give two changes the same number when there is no order between them; they share a step and either can merge first. A bad value (not an integer, or outside 1-99) is refused as a tool error, not silently dropped or clamped. Set it whenever one request's change spans several repositories and the pull requests need to land in a specific sequence; leave it out and the set keeps the delegation-order suggestion above. mergeOrder applies only to coding sub-agents, since only a coding run's pull request can be ordered: a native sub-agent ignores it, and its tool result notes that it did. Each pull request shows the value most recently set for it, by the run that opened it or a later continuation of it. A continuePriorRun call that omits mergeOrder keeps that current value, so a follow-up does not need to repeat it to keep a pull request in its place; one that sets mergeOrder replaces it. With Wardby 0.6.0 or later, once a set has more than one mergeOrder, each open or draft pull request Wardby opened in it also gets a check run named wardby merge order, tracking whether the pull requests it depends on have merged yet. It's an informational check by default; search help for \"merge order check\" for its states and for requiring it in branch protection. Follow-up runs and sibling pull requests When someone asks for a follow-up on one of these pull requests (an @<app-slug mention, or a new Jira event on the issue), the task given to the agent also lists every open sibling pull request in the set, with its link and the exact continuePriorRun value that continues it, together with guidance not to open a duplicate pull request in a repository that already has one open for this request. Automatic review fix rounds get no such hints: a fix round's task names only its own pull request. Merged and closed pull requests are never listed as continuable: a change there needs a new pull request, which joins the set once it is recorded. When the sub-agent is a coding agent with a list of repositories, a follow-up delegation passes continuePriorRun and takes its repository from that run, so it needs no repository of its own. Give your own delivery or router agent's system prompt a line such as: Continue the pull request you were asked about, and any listed open sibling the change requires; never open a new pull request in a repository that already has an open sibling for this request. The usual limits still apply: maxDelegationsPerRun and delegating to each sub-agent and repository at most once per run; every push to a sibling pull request gets its own review; fix rounds are capped per pull request and only one runs at a time on a pull request; and a continuation only ever reaches a sub-agent that shares the same owner as the one asked to continue it. A continuation never pushes to a pull request that has been merged or closed in the meantime: the coding run stops before it starts work (or right before it pushes) with failure category continuationclosed, and the delegating agent is told to make the change as a new pull request instead. See Continuation's pull request is no longer open. Wardby also keeps the recorded state of issue-linked pull requests current even when GitHub's merge or close webhook delivery was missed: it re-checks open ones in the background, at most ten at a time, each at most every ten minutes, and applies the same comment and status move a normal webhook would have triggered.",
|
|
3613
4288
|
"headings": [
|
|
3614
4289
|
{
|
|
3615
4290
|
"level": 1,
|
|
@@ -3644,10 +4319,10 @@
|
|
|
3644
4319
|
"codex",
|
|
3645
4320
|
"claude-code"
|
|
3646
4321
|
],
|
|
3647
|
-
"appliesTo": ">=0.
|
|
4322
|
+
"appliesTo": ">=0.6.0",
|
|
3648
4323
|
"sourcePath": "repo-instructions-and-skills.md",
|
|
3649
|
-
"markdown": "\n# Repository instructions and skills in coding runs\n\nEvery coding run loads the repository's own instructions, and by default\nalso loads whatever agent skills the repository ships. This is on for both\nbuilders and cannot be turned off for instructions; skills can be turned off\nper agent.\n\n## Repository instructions (always on)\n\n| Builder | Gets |\n| ----------- | --------------------------------------------------------------------------------- |\n| Codex | `AGENTS.md`, read directly from the checkout |\n| Claude Code | `CLAUDE.md`, `.claude/CLAUDE.md`, and their `@path` imports (up to 5 levels deep) |\n\nA repository that only has `AGENTS.md` still gets it in Claude Code, through\na one-line `CLAUDE.md` wardby synthesizes for it. Subdirectory `CLAUDE.md`\nfiles (anything other than the repository root and `.claude/CLAUDE.md`) are\nnot loaded unless an imported file pulls them in.\n\nClaude Code's instructions and skills are bounded: at most 64 KiB per file,\n200 files, and 256 KiB combined; symlinks and non-UTF-8 files are refused. A\nfile that doesn't pass is left out of the run rather than failing it.\nRepository settings, hooks, `.mcp.json`, agents, and commands are never sent\nto Claude Code — only Markdown instruction files and\n`.claude/skills/<name>/SKILL.md` files are allowed through, whatever an\ninstruction file imports.\n\nRepository instructions and skills are untrusted guidance: they can shape a\nrun's work but never relax the worker's sandbox rules.\n\n## Repository skills\n\n`codingProfile.repoSkills` loads the repository's own agent skills into a\nrun. It defaults to `true`, and the agent owner or an admin can set it with\n`create_agent`/`update_agent`:\n\n```json\n{ \"id\": \"<agent-id>\", \"codingProfile\": { \"repoSkills\": false } }\n```\n\n| Builder | Reads skills from | `repoSkills: false` |\n| ----------- | ----------------------------------- | ---------------------------------- |\n| Codex | `.agents/skills/`, `.codex/skills/` | Every repository skill is disabled |\n| Claude Code | `.claude/skills/<name>/SKILL.md` | No skill context is collected |\n\nCodex's own four built-in skills (`imagegen`, `openai-docs`, `skill-creator`,\n`skill-installer`) are always disabled, whatever `repoSkills` is set to.\n\nA Claude Code skill ships to the worker as its `SKILL.md` only; its other\nfiles (scripts, references, data) stay in the repository checkout, read or\nrun through the command runner at `/workspace/.claude/skills/<name>/`.\n\n## Claude Code loading mode\n\n`codingProfile.claudeBareMode` (Claude Code agents only, default `true`)\ndecides how Claude Code uses its repository instructions and skills:\n\n- **`true` (default).** Claude Code's hardened bare mode stays on. Wardby\n adds the repository's instruction files to the system prompt in full, and\n lists each skill by name, description, and path; the model reads a\n skill's full `SKILL.md` itself with `run_command`.\n- **`false`.** Bare mode is off and Claude Code loads `CLAUDE.md` and skills\n itself, through its native Skill tool, instead of reading them from the\n system prompt.\n\nRepository settings, hooks, MCP configuration, agents, and commands are\nnever loaded in either mode.\n\n```json\n{ \"id\": \"<agent-id>\", \"codingProfile\": { \"claudeBareMode\": false } }\n```\n\n## See also\n\n- [Choose a native or coding agent](creating-agents.md) for `codingProfile`\n basics and the other fields it accepts.\n- [Bring-Your-Own Coding-Worker Images](../docs/coding-worker-byo-images.md)\n — a custom `workerImageRef` image must be rebuilt for the current release. A\n Codex agent's image built on an older driver base rejects\n `repoSkills: false` and keeps offering Codex's built-in skills.\n- [Build a tool runner image for a Claude Code agent](build-claude-code-image.md)\n to give a Claude Code agent's commands the tools your project needs.\n",
|
|
3650
|
-
"plainText": "Repository instructions and skills in coding runs Every coding run loads the repository's own instructions, and by default also loads whatever agent skills the repository ships. This is on for both builders and cannot be turned off for instructions; skills can be turned off per agent. Repository instructions (always on) | Builder | Gets | | ----------- | --------------------------------------------------------------------------------- | | Codex | AGENTS.md, read directly from the checkout | | Claude Code | CLAUDE.md, .claude/CLAUDE.md, and their @path imports (up to 5 levels deep) | A repository that only has AGENTS.md still gets it in Claude Code, through a one-line CLAUDE.md wardby synthesizes for it. Subdirectory CLAUDE.md files (anything other than the repository root and .claude/CLAUDE.md) are not loaded unless an imported file pulls them in. Claude Code's instructions and skills are bounded: at most 64 KiB per file, 200 files, and 256 KiB combined; symlinks and non-UTF-8 files are refused. A file that doesn't pass is left out of the run rather than failing it. Repository settings, hooks, .mcp.json, agents, and commands are never sent to Claude Code — only Markdown instruction files and .claude/skills/<name/SKILL.md files are allowed through, whatever an instruction file imports. Repository instructions and skills are untrusted guidance: they can shape a run's work but never relax the worker's sandbox rules. Repository skills codingProfile.repoSkills loads the repository's own agent skills into a run. It defaults to true, and the agent owner or an admin can set it with createagent/updateagent: { \"id\": \"<agent-id\", \"codingProfile\": { \"repoSkills\": false } } | Builder | Reads skills from | repoSkills: false | | ----------- | ----------------------------------- | ---------------------------------- | | Codex | .agents/skills/, .codex/skills/ | Every repository skill is disabled | | Claude Code | .claude/skills/<name/SKILL.md | No skill context is collected | Codex's own four built-in skills (imagegen, openai-docs, skill-creator, skill-installer) are always disabled, whatever repoSkills is set to. A Claude Code skill ships to the worker as its SKILL.md only; its other files (scripts, references, data) stay in the repository checkout, read or run through the command runner at /workspace/.claude/skills/<name/. Claude Code loading mode codingProfile.claudeBareMode (Claude Code agents only, default true) decides how Claude Code uses its repository instructions and skills: true (default). Claude Code's hardened bare mode stays on. Wardby adds the repository's instruction files to the system prompt in full, and lists each skill by name, description, and path; the model reads a skill's full SKILL.md itself with runcommand. false. Bare mode is off and Claude Code loads CLAUDE.md and skills itself, through its native Skill tool, instead of reading them from the system prompt. Repository settings, hooks, MCP configuration, agents, and commands are never loaded in either mode. { \"id\": \"<agent-id\", \"codingProfile\": { \"claudeBareMode\": false } } See also Choose a native or coding agent for codingProfile basics and the other fields it accepts. Bring-Your-Own Coding-Worker Images — a custom workerImageRef image must be rebuilt for the current release. A Codex agent's image built on an older driver base rejects repoSkills: false and keeps offering Codex's built-in skills. Build a tool runner image for a Claude Code agent to give a Claude Code agent's commands the tools your project needs.",
|
|
4324
|
+
"markdown": "\n# Repository instructions and skills in coding runs\n\nEvery coding run loads the repository's own instructions, and by default\nalso loads whatever agent skills the repository ships. This is on for both\nbuilders and cannot be turned off for instructions; skills can be turned off\nper agent.\n\n## Repository instructions (always on)\n\n| Builder | Gets |\n| ----------- | --------------------------------------------------------------------------------- |\n| Codex | `AGENTS.md`, read directly from the checkout |\n| Claude Code | `CLAUDE.md`, `.claude/CLAUDE.md`, and their `@path` imports (up to 5 levels deep) |\n\nA repository that only has `AGENTS.md` still gets it in Claude Code, through\na one-line `CLAUDE.md` wardby synthesizes for it. Subdirectory `CLAUDE.md`\nfiles (anything other than the repository root and `.claude/CLAUDE.md`) are\nnot loaded unless an imported file pulls them in.\n\nClaude Code's instructions and skills are bounded: at most 64 KiB per file,\n200 files, and 256 KiB combined; symlinks and non-UTF-8 files are refused. A\nfile that doesn't pass is left out of the run rather than failing it.\nRepository settings, hooks, `.mcp.json`, agents, and commands are never sent\nto Claude Code — only Markdown instruction files and\n`.claude/skills/<name>/SKILL.md` files are allowed through, whatever an\ninstruction file imports.\n\nRepository instructions and skills are untrusted guidance: they can shape a\nrun's work but never relax the worker's sandbox rules.\n\n## Repository skills\n\n`codingProfile.repoSkills` loads the repository's own agent skills into a\nrun. It defaults to `true`, and the agent owner or an admin can set it with\n`create_agent`/`update_agent`:\n\n```json\n{ \"id\": \"<agent-id>\", \"codingProfile\": { \"repoSkills\": false } }\n```\n\n| Builder | Reads skills from | `repoSkills: false` |\n| ----------- | ----------------------------------- | ---------------------------------- |\n| Codex | `.agents/skills/`, `.codex/skills/` | Every repository skill is disabled |\n| Claude Code | `.claude/skills/<name>/SKILL.md` | No skill context is collected |\n\nCodex's own four built-in skills (`imagegen`, `openai-docs`, `skill-creator`,\n`skill-installer`) are always disabled, whatever `repoSkills` is set to.\n\nA Claude Code skill ships to the worker as its `SKILL.md` only; its other\nfiles (scripts, references, data) stay in the repository checkout, read or\nrun through the command runner at `/workspace/.claude/skills/<name>/`.\n\n## Claude Code loading mode\n\n`codingProfile.claudeBareMode` (Claude Code agents only, default `true`)\ndecides how Claude Code uses its repository instructions and skills:\n\n- **`true` (default).** Claude Code's hardened bare mode stays on. Wardby\n adds the repository's instruction files to the system prompt in full, and\n lists each skill by name, description, and path; the model reads a\n skill's full `SKILL.md` itself with `run_command`.\n- **`false`.** Bare mode is off and Claude Code loads `CLAUDE.md` and skills\n itself, through its native Skill tool, instead of reading them from the\n system prompt.\n\nRepository settings, hooks, MCP configuration, agents, and commands are\nnever loaded in either mode.\n\n```json\n{ \"id\": \"<agent-id>\", \"codingProfile\": { \"claudeBareMode\": false } }\n```\n\n## See also\n\n- [Remote MCP servers](../docs/mcp-servers.md) (0.8.0+) are for native agents only; a coding run loads no\n MCP configuration.\n- [Choose a native or coding agent](creating-agents.md) for `codingProfile`\n basics and the other fields it accepts.\n- [Bring-Your-Own Coding-Worker Images](../docs/coding-worker-byo-images.md)\n — a custom `workerImageRef` image must be rebuilt for the current release. A\n Codex agent's image built on an older driver base rejects\n `repoSkills: false` and keeps offering Codex's built-in skills.\n- [Build a tool runner image for a Claude Code agent](build-claude-code-image.md)\n to give a Claude Code agent's commands the tools your project needs.\n",
|
|
4325
|
+
"plainText": "Repository instructions and skills in coding runs Every coding run loads the repository's own instructions, and by default also loads whatever agent skills the repository ships. This is on for both builders and cannot be turned off for instructions; skills can be turned off per agent. Repository instructions (always on) | Builder | Gets | | ----------- | --------------------------------------------------------------------------------- | | Codex | AGENTS.md, read directly from the checkout | | Claude Code | CLAUDE.md, .claude/CLAUDE.md, and their @path imports (up to 5 levels deep) | A repository that only has AGENTS.md still gets it in Claude Code, through a one-line CLAUDE.md wardby synthesizes for it. Subdirectory CLAUDE.md files (anything other than the repository root and .claude/CLAUDE.md) are not loaded unless an imported file pulls them in. Claude Code's instructions and skills are bounded: at most 64 KiB per file, 200 files, and 256 KiB combined; symlinks and non-UTF-8 files are refused. A file that doesn't pass is left out of the run rather than failing it. Repository settings, hooks, .mcp.json, agents, and commands are never sent to Claude Code — only Markdown instruction files and .claude/skills/<name/SKILL.md files are allowed through, whatever an instruction file imports. Repository instructions and skills are untrusted guidance: they can shape a run's work but never relax the worker's sandbox rules. Repository skills codingProfile.repoSkills loads the repository's own agent skills into a run. It defaults to true, and the agent owner or an admin can set it with createagent/updateagent: { \"id\": \"<agent-id\", \"codingProfile\": { \"repoSkills\": false } } | Builder | Reads skills from | repoSkills: false | | ----------- | ----------------------------------- | ---------------------------------- | | Codex | .agents/skills/, .codex/skills/ | Every repository skill is disabled | | Claude Code | .claude/skills/<name/SKILL.md | No skill context is collected | Codex's own four built-in skills (imagegen, openai-docs, skill-creator, skill-installer) are always disabled, whatever repoSkills is set to. A Claude Code skill ships to the worker as its SKILL.md only; its other files (scripts, references, data) stay in the repository checkout, read or run through the command runner at /workspace/.claude/skills/<name/. Claude Code loading mode codingProfile.claudeBareMode (Claude Code agents only, default true) decides how Claude Code uses its repository instructions and skills: true (default). Claude Code's hardened bare mode stays on. Wardby adds the repository's instruction files to the system prompt in full, and lists each skill by name, description, and path; the model reads a skill's full SKILL.md itself with runcommand. false. Bare mode is off and Claude Code loads CLAUDE.md and skills itself, through its native Skill tool, instead of reading them from the system prompt. Repository settings, hooks, MCP configuration, agents, and commands are never loaded in either mode. { \"id\": \"<agent-id\", \"codingProfile\": { \"claudeBareMode\": false } } See also Remote MCP servers (0.8.0+) are for native agents only; a coding run loads no MCP configuration. Choose a native or coding agent for codingProfile basics and the other fields it accepts. Bring-Your-Own Coding-Worker Images — a custom workerImageRef image must be rebuilt for the current release. A Codex agent's image built on an older driver base rejects repoSkills: false and keeps offering Codex's built-in skills. Build a tool runner image for a Claude Code agent to give a Claude Code agent's commands the tools your project needs.",
|
|
3651
4326
|
"headings": [
|
|
3652
4327
|
{
|
|
3653
4328
|
"level": 1,
|
|
@@ -3691,8 +4366,8 @@
|
|
|
3691
4366
|
],
|
|
3692
4367
|
"appliesTo": ">=0.7.0",
|
|
3693
4368
|
"sourcePath": "resume-runs-locally.md",
|
|
3694
|
-
"markdown": "\n# Resume Claude Code runs locally\n\n`sessionResume` makes a Claude Code agent keep a redacted copy of each run's\nconversation, so the session can be continued locally in Claude Code with\n`get_run_transcript` and `npx @wardby/cli@latest resume`. It is off by default and is not\navailable for Codex agents. It needs Claude Code worker images from Wardby\n0.7.0 or later.\n\n## Turn it on\n\n```json\n{ \"id\": \"<coding agent id>\", \"codingProfile\": { \"sessionResume\": true } }\n```\n\nUse `update_agent` or `create_agent`. The server needs a blob store\n(`BLOB_STORE`, with `BLOB_STORE_LOCAL_DIR`, `BLOB_STORE_GCS_BUCKET`, or\n`BLOB_STORE_S3_BUCKET` and `BLOB_STORE_S3_REGION`, plus the optional\n`BLOB_STORE_S3_ENDPOINT` for an S3-compatible store) set on the **server\nprocess** that launches coding runs, not only on the coding proxy. Without a\nblob store nothing is stored, and `update_agent` warns you.\n\n## What is stored\n\n- The conversation as Claude Code recorded it: user and assistant messages,\n tool calls and their results, compaction summaries, files and skills the\n agent loaded, and a session title (`wardby run <id>: <task>` when Claude\n Code made none).\n- Removed: thinking blocks, the system prompt, the worker's environment, date\n and budget reminders, account and organisation details, and billing\n records.\n- Redacted: the values of the agent's attached secrets, plus the run's\n capability and registry token by their token shape. If the agent's secrets\n cannot be loaded, nothing is stored.\n- Stored for runs that finish, stop at their budget, or fail. Not stored for\n runs stopped with `stop_run` or ended by their timeout.\n- Stored gzip-compressed under the `run-transcripts/` prefix. When the run's\n context was compacted, only what a resume loads is kept: the last\n compaction's summary, the messages it kept, and everything after it.\n- At most `RUN_TRANSCRIPT_MAX_BYTES` per run, measured before compression\n (default 10 MiB, at most 64 MiB). Each run records a status (`stored`,\n `too_large`, `not_captured` or `failed`) with a reason code.\n\n## Who can read it\n\nTranscripts are stored from the first run with `sessionResume` on. Anyone\nwho can read a run (its triggerer and the agent's owner, as for `get_run`)\ncan download its transcript, which includes\nwhat the agent saw in the repository and in command output. Redaction removes secret\nvalues, not other sensitive text. Turn this on only for agents whose runs you\nare comfortable sharing with everyone who can read them.\n\n## Continue a run on your machine\n\n1. Ask your MCP client to call `get_run_transcript` with the run id (same\n access as `get_run`). For a stored transcript it returns a download link\n that works for 10 minutes and the command to run; otherwise the status\n (`none`, `too_large`, `not_captured`, `failed`, `expired`, `unavailable`,\n `unsupported`) and what it means.\n2. Run the command in a terminal, `npx @wardby/cli@latest resume -`, and paste the link\n when it asks. (A link given as an argument stays in shell history and the\n process list.) For a GitHub repository, run it inside a clone of that\n repository. A `local:` repository is used only when the link comes from\n this machine (a stdio MCP server); otherwise pass `--here` or `--dir`.\n\nIt verifies the download's SHA-256, writes the session to\n`~/.wardby/sessions/<run id>/<session id>.jsonl` (mode 0600, never into\nClaude Code's own config directory), adds a detached git worktree of the\nrun's branch next to the repository (the base commit, with a warning, when\nthe branch is gone), and starts `claude --resume` there. A stand-in\n`wardby_tools` server shows the run's `run_command` calls but runs nothing,\nand a note tells the model `/workspace` is now the worktree.\n\nOptions: `--dir <path>` (worktree location), `--here` (no checkout),\n`--force` (replace a different imported session file), `--print` (print the\n`claude` command instead of starting it). The command passes\n`--system-prompt-snapshot off` so the move note applies; remove it for a\nClaude Code older than 2.1.257 when the version could not be read. Under\n`npx`, the MCP config points into the npx cache: run `wardby resume` again if\nthe cache was cleaned.\n\nThe link is a credential until it expires: do not share it. Over stdio it\npoints at a local port the MCP server opens, so keep your MCP client\nconnected until the download finishes. The token is in the link's query\nstring: keep `/run-transcripts/download` out of load-balancer and ingress\naccess logs. Refusals:\n[Run transcript download refused](errors/run-transcript-download.md).\n\n## Retention\n\n`RUN_TRANSCRIPT_RETENTION_DAYS` is a whole number from 1 to 3650 (default 30).\nExpired transcripts are pruned when new ones are stored. On GCS or S3 also add\na bucket lifecycle rule on the `run-transcripts/` prefix.\n\n## Set it up per deployment\n\nGive transcripts a bucket of their own, not the dependency cache bucket, that\nonly the control plane can use.\n\n- GKE: `session_transcripts_enabled` and `session_transcripts_bucket_name` in\n Terraform (optionally `session_transcripts_retention_days`), then\n `WARDBY_SESSION_TRANSCRIPTS=true deploy/gke/up.sh`. Terraform adds the\n lifecycle rule; `up.sh` passes the same retention to the control plane.\n- AWS: the same Terraform variables, then give the control plane `BLOB_STORE=s3`,\n the `session_transcripts_bucket` output as `BLOB_STORE_S3_BUCKET`,\n `BLOB_STORE_S3_REGION`, and the `session_transcripts_retention_days` output as\n `RUN_TRANSCRIPT_RETENTION_DAYS`.\n- kind harness and Docker quickstart: the server runs on your host. Set\n `BLOB_STORE=local` and `BLOB_STORE_LOCAL_DIR` in its environment (for the\n quickstart, in `.wardby/.env`).\n\n## Startup and custom images\n\nWith `JOB_LAUNCHER` set to `docker` or `kubernetes`, a half-set `BLOB_STORE`\nor an invalid `RUN_TRANSCRIPT_RETENTION_DAYS` or `RUN_TRANSCRIPT_MAX_BYTES` stops\nthe server at startup,\nnaming the variable. An agent with its own `workerImageRef` image must rebuild\nit from a release that includes session resume (see\n[Build a tool runner image for a Claude Code agent](help://build-claude-code-image)),\nor its runs fail at input with `worker_input_failed`.\n\nFull setup: [Resume a run locally](../docs/coding-agent-setup.md#resume-a-run-locally).\nSee also [Choose a native or coding agent](help://creating-agents).\n",
|
|
3695
|
-
"plainText": "Resume Claude Code runs locally sessionResume makes a Claude Code agent keep a redacted copy of each run's conversation, so the session can be continued locally in Claude Code with getruntranscript and npx @wardby/cli@latest resume. It is off by default and is not available for Codex agents. It needs Claude Code worker images from Wardby 0.7.0 or later. Turn it on { \"id\": \"<coding agent id\", \"codingProfile\": { \"sessionResume\": true } } Use updateagent or createagent. The server needs a blob store (BLOBSTORE, with BLOBSTORELOCALDIR, BLOBSTOREGCSBUCKET, or BLOBSTORES3BUCKET and BLOBSTORES3REGION, plus the optional BLOBSTORES3ENDPOINT for an S3-compatible store) set on the server process that launches coding runs, not only on the coding proxy. Without a blob store nothing is stored, and updateagent warns you. What is stored The conversation as Claude Code recorded it: user and assistant messages, tool calls and their results, compaction summaries, files and skills the agent loaded, and a session title (wardby run <id: <task when Claude Code made none). Removed: thinking blocks, the system prompt, the worker's environment, date and budget reminders, account and organisation details, and billing records. Redacted: the values of the agent's attached secrets, plus the run's capability and registry token by their token shape. If the agent's secrets cannot be loaded, nothing is stored. Stored for runs that finish, stop at their budget, or fail. Not stored for runs stopped with stoprun or ended by their timeout. Stored gzip-compressed under the run-transcripts/ prefix. When the run's context was compacted, only what a resume loads is kept: the last compaction's summary, the messages it kept, and everything after it. At most RUNTRANSCRIPTMAXBYTES per run, measured before compression (default 10 MiB, at most 64 MiB). Each run records a status (stored, toolarge, notcaptured or failed) with a reason code. Who can read it Transcripts are stored from the first run with sessionResume on. Anyone who can read a run (its triggerer and the agent's owner, as for getrun) can download its transcript, which includes what the agent saw in the repository and in command output. Redaction removes secret values, not other sensitive text. Turn this on only for agents whose runs you are comfortable sharing with everyone who can read them. Continue a run on your machine Ask your MCP client to call getruntranscript with the run id (same access as getrun). For a stored transcript it returns a download link that works for 10 minutes and the command to run; otherwise the status (none, toolarge, notcaptured, failed, expired, unavailable, unsupported) and what it means. Run the command in a terminal, npx @wardby/cli@latest resume -, and paste the link when it asks. (A link given as an argument stays in shell history and the process list.) For a GitHub repository, run it inside a clone of that repository. A local: repository is used only when the link comes from this machine (a stdio MCP server); otherwise pass --here or --dir. It verifies the download's SHA-256, writes the session to ~/.wardby/sessions/<run id/<session id.jsonl (mode 0600, never into Claude Code's own config directory), adds a detached git worktree of the run's branch next to the repository (the base commit, with a warning, when the branch is gone), and starts claude --resume there. A stand-in wardbytools server shows the run's runcommand calls but runs nothing, and a note tells the model /workspace is now the worktree. Options: --dir <path (worktree location), --here (no checkout), --force (replace a different imported session file), --print (print the claude command instead of starting it). The command passes --system-prompt-snapshot off so the move note applies; remove it for a Claude Code older than 2.1.257 when the version could not be read. Under npx, the MCP config points into the npx cache: run wardby resume again if the cache was cleaned. The link is a credential until it expires: do not share it. Over stdio it points at a local port the MCP server opens, so keep your MCP client connected until the download finishes. The token is in the link's query string: keep /run-transcripts/download out of load-balancer and ingress access logs. Refusals: Run transcript download refused. Retention RUNTRANSCRIPTRETENTIONDAYS is a whole number from 1 to 3650 (default 30). Expired transcripts are pruned when new ones are stored. On GCS or S3 also add a bucket lifecycle rule on the run-transcripts/ prefix. Set it up per deployment Give transcripts a bucket of their own, not the dependency cache bucket, that only the control plane can use. GKE: sessiontranscriptsenabled and sessiontranscriptsbucketname in Terraform (optionally sessiontranscriptsretentiondays), then WARDBYSESSIONTRANSCRIPTS=true deploy/gke/up.sh. Terraform adds the lifecycle rule; up.sh passes the same retention to the control plane. AWS: the same Terraform variables, then give the control plane BLOBSTORE=s3, the sessiontranscriptsbucket output as BLOBSTORES3BUCKET, BLOBSTORES3REGION, and the sessiontranscriptsretentiondays output as RUNTRANSCRIPTRETENTIONDAYS. kind harness and Docker quickstart: the server runs on your host. Set BLOBSTORE=local and BLOBSTORELOCALDIR in its environment (for the quickstart, in .wardby/.env). Startup and custom images With JOBLAUNCHER set to docker or kubernetes, a half-set BLOBSTORE or an invalid RUNTRANSCRIPTRETENTIONDAYS or RUNTRANSCRIPTMAXBYTES stops the server at startup, naming the variable. An agent with its own workerImageRef image must rebuild it from a release that includes session resume (see Build a tool runner image for a Claude Code agent), or its runs fail at input with workerinputfailed. Full setup: Resume a run locally. See also Choose a native or coding agent.",
|
|
4369
|
+
"markdown": "\n# Resume Claude Code runs locally\n\n`sessionResume` makes a Claude Code agent keep a redacted copy of each run's\nconversation, so the session can be continued locally in Claude Code with\n`get_run_transcript` and `npx @wardby/cli@latest resume`. It is off by default and is not\navailable for Codex agents. It needs Claude Code worker images from Wardby\n0.7.0 or later.\n\n## Turn it on\n\n```json\n{ \"id\": \"<coding agent id>\", \"codingProfile\": { \"sessionResume\": true } }\n```\n\nUse `update_agent` or `create_agent`. The server needs a blob store\n(`BLOB_STORE`, with `BLOB_STORE_LOCAL_DIR`, `BLOB_STORE_GCS_BUCKET`, or\n`BLOB_STORE_S3_BUCKET` and `BLOB_STORE_S3_REGION`, plus the optional\n`BLOB_STORE_S3_ENDPOINT` for an S3-compatible store) set on the **server\nprocess** that launches coding runs, not only on the coding proxy. Without a\nblob store nothing is stored, and `update_agent` warns you.\n\n## What is stored\n\n- The conversation as Claude Code recorded it: user and assistant messages,\n tool calls and their results, compaction summaries, files and skills the\n agent loaded, and a session title (`wardby run <id>: <task>` when Claude\n Code made none).\n- Removed: thinking blocks, the system prompt, the worker's environment, date\n and budget reminders, account and organisation details, and billing\n records.\n- Redacted: the values of the agent's attached secrets, plus the run's\n capability and registry token by their token shape. If the agent's secrets\n cannot be loaded, nothing is stored.\n- Stored for runs that finish, stop at their budget, or fail. Not stored for\n runs stopped with `stop_run` or ended by their timeout.\n- Stored gzip-compressed under the `run-transcripts/` prefix. When the run's\n context was compacted, only what a resume loads is kept: the last\n compaction's summary, the messages it kept, and everything after it.\n- At most `RUN_TRANSCRIPT_MAX_BYTES` per run, measured before compression\n (default 10 MiB, at most 64 MiB). Each run records a status (`stored`,\n `too_large`, `not_captured` or `failed`) with a reason code.\n\nFor a short line-per-step record of any run, without a blob store and without\ncontinuing it, see `run-steps`; from 0.9.0 its `detail` level is a lighter way to\nsee tool output without a transcript.\n\n## Who can read it\n\nTranscripts are stored from the first run with `sessionResume` on. Anyone\nwho can read a run (its triggerer and the agent's owner, as for `get_run`)\ncan download its transcript, which includes\nwhat the agent saw in the repository and in command output. Redaction removes secret\nvalues, not other sensitive text. Turn this on only for agents whose runs you\nare comfortable sharing with everyone who can read them.\n\n## Continue a run on your machine\n\n1. Ask your MCP client to call `get_run_transcript` with the run id (same\n access as `get_run`). For a stored transcript it returns a download link\n that works for 10 minutes and the command to run; otherwise the status\n (`none`, `too_large`, `not_captured`, `failed`, `expired`, `unavailable`,\n `unsupported`) and what it means.\n2. Run the command in a terminal, `npx @wardby/cli@latest resume -`, and paste the link\n when it asks. (A link given as an argument stays in shell history and the\n process list.) For a GitHub repository, run it inside a clone of that\n repository. A `local:` repository is used only when the link comes from\n this machine (a stdio MCP server); otherwise pass `--here` or `--dir`.\n\nIt verifies the download's SHA-256, writes the session to\n`~/.wardby/sessions/<run id>/<session id>.jsonl` (mode 0600, never into\nClaude Code's own config directory), adds a detached git worktree of the\nrun's branch next to the repository (the base commit, with a warning, when\nthe branch is gone), and starts `claude --resume` there. A stand-in\n`wardby_tools` server shows the run's `run_command` calls but runs nothing,\nand a note tells the model `/workspace` is now the worktree.\n\nOptions: `--dir <path>` (worktree location), `--here` (no checkout),\n`--force` (replace a different imported session file), `--print` (print the\n`claude` command instead of starting it). The command passes\n`--system-prompt-snapshot off` so the move note applies; remove it for a\nClaude Code older than 2.1.257 when the version could not be read. Under\n`npx`, the MCP config points into the npx cache: run `wardby resume` again if\nthe cache was cleaned.\n\nThe link is a credential until it expires: do not share it. Over stdio it\npoints at a local port the MCP server opens, so keep your MCP client\nconnected until the download finishes. The token is in the link's query\nstring: keep `/run-transcripts/download` out of load-balancer and ingress\naccess logs. Refusals:\n[Run transcript download refused](errors/run-transcript-download.md).\n\n## Retention\n\n`RUN_TRANSCRIPT_RETENTION_DAYS` is a whole number from 1 to 3650 (default 30).\nExpired transcripts are pruned when new ones are stored. On GCS or S3 also add\na bucket lifecycle rule on the `run-transcripts/` prefix.\n\n## Set it up per deployment\n\nGive transcripts a bucket of their own, not the dependency cache bucket, that\nonly the control plane can use.\n\n- GKE: `session_transcripts_enabled` and `session_transcripts_bucket_name` in\n Terraform (optionally `session_transcripts_retention_days`), then\n `WARDBY_SESSION_TRANSCRIPTS=true deploy/gke/up.sh`. Terraform adds the\n lifecycle rule; `up.sh` passes the same retention to the control plane.\n- AWS: the same Terraform variables, then give the control plane `BLOB_STORE=s3`,\n the `session_transcripts_bucket` output as `BLOB_STORE_S3_BUCKET`,\n `BLOB_STORE_S3_REGION`, and the `session_transcripts_retention_days` output as\n `RUN_TRANSCRIPT_RETENTION_DAYS`.\n- kind harness and Docker quickstart: the server runs on your host. Set\n `BLOB_STORE=local` and `BLOB_STORE_LOCAL_DIR` in its environment (for the\n quickstart, in `.wardby/.env`).\n\n## Startup and custom images\n\nWith `JOB_LAUNCHER` set to `docker` or `kubernetes`, a half-set `BLOB_STORE`\nor an invalid `RUN_TRANSCRIPT_RETENTION_DAYS` or `RUN_TRANSCRIPT_MAX_BYTES` stops\nthe server at startup,\nnaming the variable. An agent with its own `workerImageRef` image must rebuild\nit from a release that includes session resume (see\n[Build a tool runner image for a Claude Code agent](help://build-claude-code-image)),\nor its runs fail at input with `worker_input_failed`.\n\nFull setup: [Resume a run locally](../docs/coding-agent-setup.md#resume-a-run-locally).\nSee also [Choose a native or coding agent](help://creating-agents).\n\nThe `wardby-runs` Claude Code plugin can start the import from a run's detail\n(**Continue locally**); see `claude-code-run-pane` (Wardby 0.8.0 and later).\n",
|
|
4370
|
+
"plainText": "Resume Claude Code runs locally sessionResume makes a Claude Code agent keep a redacted copy of each run's conversation, so the session can be continued locally in Claude Code with getruntranscript and npx @wardby/cli@latest resume. It is off by default and is not available for Codex agents. It needs Claude Code worker images from Wardby 0.7.0 or later. Turn it on { \"id\": \"<coding agent id\", \"codingProfile\": { \"sessionResume\": true } } Use updateagent or createagent. The server needs a blob store (BLOBSTORE, with BLOBSTORELOCALDIR, BLOBSTOREGCSBUCKET, or BLOBSTORES3BUCKET and BLOBSTORES3REGION, plus the optional BLOBSTORES3ENDPOINT for an S3-compatible store) set on the server process that launches coding runs, not only on the coding proxy. Without a blob store nothing is stored, and updateagent warns you. What is stored The conversation as Claude Code recorded it: user and assistant messages, tool calls and their results, compaction summaries, files and skills the agent loaded, and a session title (wardby run <id: <task when Claude Code made none). Removed: thinking blocks, the system prompt, the worker's environment, date and budget reminders, account and organisation details, and billing records. Redacted: the values of the agent's attached secrets, plus the run's capability and registry token by their token shape. If the agent's secrets cannot be loaded, nothing is stored. Stored for runs that finish, stop at their budget, or fail. Not stored for runs stopped with stoprun or ended by their timeout. Stored gzip-compressed under the run-transcripts/ prefix. When the run's context was compacted, only what a resume loads is kept: the last compaction's summary, the messages it kept, and everything after it. At most RUNTRANSCRIPTMAXBYTES per run, measured before compression (default 10 MiB, at most 64 MiB). Each run records a status (stored, toolarge, notcaptured or failed) with a reason code. For a short line-per-step record of any run, without a blob store and without continuing it, see run-steps; from 0.9.0 its detail level is a lighter way to see tool output without a transcript. Who can read it Transcripts are stored from the first run with sessionResume on. Anyone who can read a run (its triggerer and the agent's owner, as for getrun) can download its transcript, which includes what the agent saw in the repository and in command output. Redaction removes secret values, not other sensitive text. Turn this on only for agents whose runs you are comfortable sharing with everyone who can read them. Continue a run on your machine Ask your MCP client to call getruntranscript with the run id (same access as getrun). For a stored transcript it returns a download link that works for 10 minutes and the command to run; otherwise the status (none, toolarge, notcaptured, failed, expired, unavailable, unsupported) and what it means. Run the command in a terminal, npx @wardby/cli@latest resume -, and paste the link when it asks. (A link given as an argument stays in shell history and the process list.) For a GitHub repository, run it inside a clone of that repository. A local: repository is used only when the link comes from this machine (a stdio MCP server); otherwise pass --here or --dir. It verifies the download's SHA-256, writes the session to ~/.wardby/sessions/<run id/<session id.jsonl (mode 0600, never into Claude Code's own config directory), adds a detached git worktree of the run's branch next to the repository (the base commit, with a warning, when the branch is gone), and starts claude --resume there. A stand-in wardbytools server shows the run's runcommand calls but runs nothing, and a note tells the model /workspace is now the worktree. Options: --dir <path (worktree location), --here (no checkout), --force (replace a different imported session file), --print (print the claude command instead of starting it). The command passes --system-prompt-snapshot off so the move note applies; remove it for a Claude Code older than 2.1.257 when the version could not be read. Under npx, the MCP config points into the npx cache: run wardby resume again if the cache was cleaned. The link is a credential until it expires: do not share it. Over stdio it points at a local port the MCP server opens, so keep your MCP client connected until the download finishes. The token is in the link's query string: keep /run-transcripts/download out of load-balancer and ingress access logs. Refusals: Run transcript download refused. Retention RUNTRANSCRIPTRETENTIONDAYS is a whole number from 1 to 3650 (default 30). Expired transcripts are pruned when new ones are stored. On GCS or S3 also add a bucket lifecycle rule on the run-transcripts/ prefix. Set it up per deployment Give transcripts a bucket of their own, not the dependency cache bucket, that only the control plane can use. GKE: sessiontranscriptsenabled and sessiontranscriptsbucketname in Terraform (optionally sessiontranscriptsretentiondays), then WARDBYSESSIONTRANSCRIPTS=true deploy/gke/up.sh. Terraform adds the lifecycle rule; up.sh passes the same retention to the control plane. AWS: the same Terraform variables, then give the control plane BLOBSTORE=s3, the sessiontranscriptsbucket output as BLOBSTORES3BUCKET, BLOBSTORES3REGION, and the sessiontranscriptsretentiondays output as RUNTRANSCRIPTRETENTIONDAYS. kind harness and Docker quickstart: the server runs on your host. Set BLOBSTORE=local and BLOBSTORELOCALDIR in its environment (for the quickstart, in .wardby/.env). Startup and custom images With JOBLAUNCHER set to docker or kubernetes, a half-set BLOBSTORE or an invalid RUNTRANSCRIPTRETENTIONDAYS or RUNTRANSCRIPTMAXBYTES stops the server at startup, naming the variable. An agent with its own workerImageRef image must rebuild it from a release that includes session resume (see Build a tool runner image for a Claude Code agent), or its runs fail at input with workerinputfailed. Full setup: Resume a run locally. See also Choose a native or coding agent. The wardby-runs Claude Code plugin can start the import from a run's detail (Continue locally); see claude-code-run-pane (Wardby 0.8.0 and later).",
|
|
3696
4371
|
"headings": [
|
|
3697
4372
|
{
|
|
3698
4373
|
"level": 1,
|
|
@@ -3769,6 +4444,56 @@
|
|
|
3769
4444
|
}
|
|
3770
4445
|
]
|
|
3771
4446
|
},
|
|
4447
|
+
{
|
|
4448
|
+
"id": "run-steps",
|
|
4449
|
+
"title": "See what a run is doing (run steps)",
|
|
4450
|
+
"summary": "Wardby records each run's steps, one line per tool call or model message, so you can follow a running run and read what a finished one did with get_run_steps. Run steps detail adds tool output.",
|
|
4451
|
+
"audience": "operator",
|
|
4452
|
+
"tags": [
|
|
4453
|
+
"run steps",
|
|
4454
|
+
"claude code run steps",
|
|
4455
|
+
"get_run_steps",
|
|
4456
|
+
"what is my run doing",
|
|
4457
|
+
"WARDBY_RUN_STEPS",
|
|
4458
|
+
"viewer step event"
|
|
4459
|
+
],
|
|
4460
|
+
"appliesTo": ">=0.9.0",
|
|
4461
|
+
"sourcePath": "run-steps.md",
|
|
4462
|
+
"markdown": "\n# See what a run is doing\n\nWardby records the steps of a run while it runs:\n\n- one line for each **tool call**: the tool, and its command, file or first\n argument, cut to about 100 characters, with its status once the result is\n back (`ok`, `error`, or `exit N` for a command that exited with code N);\n- one line for what the **model said**, cut to about 120 characters.\n\n## Levels\n\n| Level | Tool input | Tool result | Model text |\n| --------- | -------------------- | --------------------------------------- | -------------------- |\n| `off` | - | - | - |\n| `summary` | about 100 characters | status only (`ok`, `error`, `exit N`) | about 120 characters |\n| `detail` | up to about 4 KB | status and the last ~2 KB of its output | up to about 8 KB |\n\nAt `summary`, the default, tool output is never recorded. At `detail` each step\nalso keeps a **detail** text, at most 16 KB. When the output is cut at the\nstart, the partial first line is dropped if it ends within 256 characters;\notherwise only the first 256 characters are dropped, so a long single-line\noutput, such as a JSON result, keeps about its last 1.8 KB. At every level,\nterminal escape sequences (colour codes, links, clipboard writes, title changes)\nand every other control character except line breaks and tabs are removed from\nstep text before it is stored.\n\nA run's level is the lower of two settings, fixed when the run is dispatched (a\nchange reaches later runs only; lowering the ceiling also stops detail for runs\nalready in flight):\n\n- the instance's ceiling, `WARDBY_RUN_STEPS` (default `summary`);\n- the agent's `runSteps` (`off`, `summary` or `detail`), set by the agent's\n owner with `create_agent` or `update_agent`. Unset counts as `summary`. Set\n `null` to clear it.\n\nSo `detail` needs both the operator and the agent's owner. If `runSteps` asks\nfor more than the instance allows, the value is stored, `update_agent` and\n`get_agent` say so in `warnings`, and runs record at the ceiling.\n\n> **Warning: `detail` stores tool output.** Before a step is stored, every\n> secret value the run was given is removed and anything shaped like a token or\n> key is masked. A secret that exists only inside a repository file, or another\n> source the run read, and that matches no known shape, is not known to Wardby\n> and can remain in the detail text. That is why detail is off unless both the\n> operator and the agent's owner ask for it. Turn it on only for agents whose\n> tool output you are prepared to keep for the retention period.\n\nSteps are recorded for native runs (in the control plane and on the native\nsandbox) and for Claude Code and Codex runs. Every agent's shell command shows\nas `Bash`: a native agent's `run_command`, Claude Code's command tool, and\nCodex's `exec_command`, `shell`, `local_shell` and `shell_command`. Another tool\nshows under its own name (for example `apply_patch`), and a remote MCP tool as\n`mcp:<tool>`.\n\nA Claude Code or Codex run's final answer is one `said` step: the start of the\nsummary it returned (the pull request description), or `Finished` with the\noutcome (for example `Finished: changes ready`) when it returned none.\n\nFor Claude Code and Codex runs, the coding proxy reads the steps from the\nmodel's replies after relaying them and posts them to the server, which needs a\nlistener for them: `WARDBY_RUN_STEPS_LISTEN` on `wardby serve` and\n`WARDBY_RUN_STEPS_URL` on the proxy. The reference GKE manifests set both; the\nkind overlay sets only `WARDBY_RUN_STEPS_URL`, so set\n`WARDBY_RUN_STEPS_LISTEN` on the host's `wardby serve`. Without either, coding\nruns record no steps; native runs are not affected. A slow or unreachable listener loses steps; it never slows the run.\n\n## Read the steps\n\n- `get_run_steps` with `runId` lists a run's steps, oldest first, 50 at a time\n (`limit`, at most 200). `next` is what to pass as `after` for the next page.\n To follow a running run, call it again every few seconds with `after` set to\n the last `seq` you have.\n- `get_run` and `list_runs` (without `agentId`) include `lastStep`, the run's\n newest step as one line, for example `Bash: npm test (exit 1)`.\n- The `wardby-runs` Claude Code pane shows a running run's last steps and a\n finished run's steps; see `claude-code-run-pane`.\n- The admin viewer API sends a `step` event on `/admin/api/events` for each\n step and status, and `GET /admin/api/runs/<id>` lists the run's newest 200\n steps (see `admin-viewer`). The Wardby Viewer app shows them in a **Steps**\n section of a run's detail.\n\nAt `detail`, `get_run_steps` also returns each step's `detail` to the agent's\nowner and to the person who started the run (and to the stdio operator); anyone\nelse, including an admin who does not own the agent, gets the lines only. `lastStep`, the admin viewer API\nand its `step` events never include detail.\n\nYou can read a run's steps when you can read the run with `get_run`.\n\nA run records at most 2,000 steps. Later steps are not recorded; `dropped`\ncounts them.\n\n## Secrets\n\nBefore a step is stored, Wardby removes every secret value the run's agent has\n(its attached secrets, readable or brokered, and its MCP servers' secrets), the\nrun's own capability and registry token, and\nanything shaped like a token or key. A command that echoes a secret shows\n`[REDACTED]` in its place.\n\n## Retention\n\nSteps, and their detail, are deleted `RUN_STEP_RETENTION_DAYS` after they are\nrecorded (default 30). A change applies to steps recorded after it. `get_run_steps` reports `expired` when a run finished more than\n`RUN_STEP_RETENTION_DAYS` ago and has no steps left.\n\n## Settings\n\n| Variable | Default | What it does |\n| ------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `WARDBY_RUN_STEPS` | `summary` | `off` records no steps; `summary` the lines above; `detail` allows agents whose `runSteps` is `detail` to record detail. The ceiling for every run. Any other value stops start-up. |\n| `RUN_STEP_RETENTION_DAYS` | `30` | Days to keep a step, a whole number from 1 to 3650. Any other value stops start-up. |\n| `WARDBY_RUN_STEPS_LISTEN` | unset | On `wardby serve` only: `host:port` (or `:port`) of the listener the coding proxy posts coding runs' steps to. Unset: no listener. |\n| `WARDBY_RUN_STEPS_URL` | unset | On the coding proxy: the listener's origin, for example `http://<server host>:8792`, with no credentials or path. Unset: coding runs record no steps. |\n\nSet `WARDBY_RUN_STEPS` (including `detail`) and `RUN_STEP_RETENTION_DAYS` on\nevery process that writes steps: `wardby serve`,\n`wardby scheduler`, `wardby run`, `wardby mcp` and `wardby native-gateway`. The\ncoding proxy reads `WARDBY_RUN_STEPS` too: with `off`, or with\n`WARDBY_RUN_STEPS_URL` unset, no step text leaves the proxy. For a coding\nrun's steps use `wardby serve` (the only process that runs the listener), not\nthe stdio `wardby mcp`.\n\nFor coding runs at `detail`, set `WARDBY_RUN_STEPS=detail` on the coding proxy\ntoo: below `detail`, the proxy never sends any tool output to the server.\n\nThe listener is a second network path into the server, from the coding proxy\nonly; keep it off any load balancer. See\n[Run steps](../docs/security-deployment.md#run-steps) for how to restrict it.\n\nThe full guide is\n[Debugging agent runs](../docs/debugging-agent-runs.md#run-steps).\n",
|
|
4463
|
+
"plainText": "See what a run is doing Wardby records the steps of a run while it runs: one line for each tool call: the tool, and its command, file or first argument, cut to about 100 characters, with its status once the result is back (ok, error, or exit N for a command that exited with code N); one line for what the model said, cut to about 120 characters. Levels | Level | Tool input | Tool result | Model text | | --------- | -------------------- | --------------------------------------- | -------------------- | | off | - | - | - | | summary | about 100 characters | status only (ok, error, exit N) | about 120 characters | | detail | up to about 4 KB | status and the last ~2 KB of its output | up to about 8 KB | At summary, the default, tool output is never recorded. At detail each step also keeps a detail text, at most 16 KB. When the output is cut at the start, the partial first line is dropped if it ends within 256 characters; otherwise only the first 256 characters are dropped, so a long single-line output, such as a JSON result, keeps about its last 1.8 KB. At every level, terminal escape sequences (colour codes, links, clipboard writes, title changes) and every other control character except line breaks and tabs are removed from step text before it is stored. A run's level is the lower of two settings, fixed when the run is dispatched (a change reaches later runs only; lowering the ceiling also stops detail for runs already in flight): the instance's ceiling, WARDBYRUNSTEPS (default summary); the agent's runSteps (off, summary or detail), set by the agent's owner with createagent or updateagent. Unset counts as summary. Set null to clear it. So detail needs both the operator and the agent's owner. If runSteps asks for more than the instance allows, the value is stored, updateagent and getagent say so in warnings, and runs record at the ceiling. Warning: detail stores tool output. Before a step is stored, every secret value the run was given is removed and anything shaped like a token or key is masked. A secret that exists only inside a repository file, or another source the run read, and that matches no known shape, is not known to Wardby and can remain in the detail text. That is why detail is off unless both the operator and the agent's owner ask for it. Turn it on only for agents whose tool output you are prepared to keep for the retention period. Steps are recorded for native runs (in the control plane and on the native sandbox) and for Claude Code and Codex runs. Every agent's shell command shows as Bash: a native agent's runcommand, Claude Code's command tool, and Codex's execcommand, shell, localshell and shellcommand. Another tool shows under its own name (for example applypatch), and a remote MCP tool as mcp:<tool. A Claude Code or Codex run's final answer is one said step: the start of the summary it returned (the pull request description), or Finished with the outcome (for example Finished: changes ready) when it returned none. For Claude Code and Codex runs, the coding proxy reads the steps from the model's replies after relaying them and posts them to the server, which needs a listener for them: WARDBYRUNSTEPSLISTEN on wardby serve and WARDBYRUNSTEPSURL on the proxy. The reference GKE manifests set both; the kind overlay sets only WARDBYRUNSTEPSURL, so set WARDBYRUNSTEPSLISTEN on the host's wardby serve. Without either, coding runs record no steps; native runs are not affected. A slow or unreachable listener loses steps; it never slows the run. Read the steps getrunsteps with runId lists a run's steps, oldest first, 50 at a time (limit, at most 200). next is what to pass as after for the next page. To follow a running run, call it again every few seconds with after set to the last seq you have. getrun and listruns (without agentId) include lastStep, the run's newest step as one line, for example Bash: npm test (exit 1). The wardby-runs Claude Code pane shows a running run's last steps and a finished run's steps; see claude-code-run-pane. The admin viewer API sends a step event on /admin/api/events for each step and status, and GET /admin/api/runs/<id lists the run's newest 200 steps (see admin-viewer). The Wardby Viewer app shows them in a Steps section of a run's detail. At detail, getrunsteps also returns each step's detail to the agent's owner and to the person who started the run (and to the stdio operator); anyone else, including an admin who does not own the agent, gets the lines only. lastStep, the admin viewer API and its step events never include detail. You can read a run's steps when you can read the run with getrun. A run records at most 2,000 steps. Later steps are not recorded; dropped counts them. Secrets Before a step is stored, Wardby removes every secret value the run's agent has (its attached secrets, readable or brokered, and its MCP servers' secrets), the run's own capability and registry token, and anything shaped like a token or key. A command that echoes a secret shows [REDACTED] in its place. Retention Steps, and their detail, are deleted RUNSTEPRETENTIONDAYS after they are recorded (default 30). A change applies to steps recorded after it. getrunsteps reports expired when a run finished more than RUNSTEPRETENTIONDAYS ago and has no steps left. Settings | Variable | Default | What it does | | ------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | WARDBYRUNSTEPS | summary | off records no steps; summary the lines above; detail allows agents whose runSteps is detail to record detail. The ceiling for every run. Any other value stops start-up. | | RUNSTEPRETENTIONDAYS | 30 | Days to keep a step, a whole number from 1 to 3650. Any other value stops start-up. | | WARDBYRUNSTEPSLISTEN | unset | On wardby serve only: host:port (or :port) of the listener the coding proxy posts coding runs' steps to. Unset: no listener. | | WARDBYRUNSTEPSURL | unset | On the coding proxy: the listener's origin, for example http://<server host:8792, with no credentials or path. Unset: coding runs record no steps. | Set WARDBYRUNSTEPS (including detail) and RUNSTEPRETENTIONDAYS on every process that writes steps: wardby serve, wardby scheduler, wardby run, wardby mcp and wardby native-gateway. The coding proxy reads WARDBYRUNSTEPS too: with off, or with WARDBYRUNSTEPSURL unset, no step text leaves the proxy. For a coding run's steps use wardby serve (the only process that runs the listener), not the stdio wardby mcp. For coding runs at detail, set WARDBYRUNSTEPS=detail on the coding proxy too: below detail, the proxy never sends any tool output to the server. The listener is a second network path into the server, from the coding proxy only; keep it off any load balancer. See Run steps for how to restrict it. The full guide is Debugging agent runs.",
|
|
4464
|
+
"headings": [
|
|
4465
|
+
{
|
|
4466
|
+
"level": 1,
|
|
4467
|
+
"text": "See what a run is doing",
|
|
4468
|
+
"slug": "see-what-a-run-is-doing"
|
|
4469
|
+
},
|
|
4470
|
+
{
|
|
4471
|
+
"level": 2,
|
|
4472
|
+
"text": "Levels",
|
|
4473
|
+
"slug": "levels"
|
|
4474
|
+
},
|
|
4475
|
+
{
|
|
4476
|
+
"level": 2,
|
|
4477
|
+
"text": "Read the steps",
|
|
4478
|
+
"slug": "read-the-steps"
|
|
4479
|
+
},
|
|
4480
|
+
{
|
|
4481
|
+
"level": 2,
|
|
4482
|
+
"text": "Secrets",
|
|
4483
|
+
"slug": "secrets"
|
|
4484
|
+
},
|
|
4485
|
+
{
|
|
4486
|
+
"level": 2,
|
|
4487
|
+
"text": "Retention",
|
|
4488
|
+
"slug": "retention"
|
|
4489
|
+
},
|
|
4490
|
+
{
|
|
4491
|
+
"level": 2,
|
|
4492
|
+
"text": "Settings",
|
|
4493
|
+
"slug": "settings"
|
|
4494
|
+
}
|
|
4495
|
+
]
|
|
4496
|
+
},
|
|
3772
4497
|
{
|
|
3773
4498
|
"id": "security-boundaries",
|
|
3774
4499
|
"title": "Understand Wardby security boundaries",
|
|
@@ -3921,8 +4646,8 @@
|
|
|
3921
4646
|
],
|
|
3922
4647
|
"appliesTo": ">=0.7.0",
|
|
3923
4648
|
"sourcePath": "stop-run.md",
|
|
3924
|
-
"markdown": "\n# Stop or cancel a run\n\nCall the MCP tool `stop_run` with the run's id to stop a run that has not\nfinished. Add an optional `reason`; it is recorded on the run.\n\n```text\nstop_run {\"runId\": \"<run id>\", \"reason\": \"unwanted scheduled run\"}\n```\n\nFind the id with `list_runs` (filter with `\"status\": \"pending\"` or\n`\"running\"`). To stop a schedule from creating more runs, disable it with\n`disable_schedule` as well; `stop_run` stops one run, not the schedule.\n\n## What happens\n\nThe run ends as `cancelled`, with `Stopped by <your id> with stop_run: <reason>`\nin its `stopRequestReason` (and, for a native run, in its `error`).\n\n| The run is | `stop_run` |\n| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Pending, or a coding run queued for a slot | Ends it now. It never starts. |\n| A running native run in the control plane | Ends it now; the run stops at its next step
|
|
3925
|
-
"plainText": "Stop or cancel a run Call the MCP tool stoprun with the run's id to stop a run that has not finished. Add an optional reason; it is recorded on the run. stoprun {\"runId\": \"<run id\", \"reason\": \"unwanted scheduled run\"} Find the id with listruns (filter with \"status\": \"pending\" or \"running\"). To stop a schedule from creating more runs, disable it with disableschedule as well; stoprun stops one run, not the schedule. What happens The run ends as cancelled, with Stopped by <your id with stoprun: <reason in its stopRequestReason (and, for a native run, in its error). | The run is | stoprun | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Pending, or a coding run queued for a slot | Ends it now. It never starts. | | A running native run in the control plane | Ends it now; the run stops at its next step
|
|
4649
|
+
"markdown": "\n# Stop or cancel a run\n\nCall the MCP tool `stop_run` with the run's id to stop a run that has not\nfinished. Add an optional `reason`; it is recorded on the run.\n\n```text\nstop_run {\"runId\": \"<run id>\", \"reason\": \"unwanted scheduled run\"}\n```\n\nFind the id with `list_runs` (filter with `\"status\": \"pending\"` or\n`\"running\"`). To stop a schedule from creating more runs, disable it with\n`disable_schedule` as well; `stop_run` stops one run, not the schedule.\n\n## What happens\n\nThe run ends as `cancelled`, with `Stopped by <your id> with stop_run: <reason>`\nin its `stopRequestReason` (and, for a native run, in its `error`).\n\n| The run is | `stop_run` |\n| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Pending, or a coding run queued for a slot | Ends it now. It never starts. |\n| A running native run in the control plane | Ends it now; the run stops at its next step. A model turn already under way finishes first; a tool call already under way is aborted within a few seconds. |\n| A running native run in the sandbox | Ends it now and ends its gateway session, so the worker's next call is refused and it exits. A worker still running after a short grace (5 seconds) is killed and removed; a warm pool worker is never reused. |\n| A running coding run | Ends it, cancels its model proxy session, and stops and removes its worker. It opens or updates no pull request afterwards. |\n| Already finished (any other status) | Changes nothing and returns its status. Calling `stop_run` again is safe. |\n\nSub-agent runs the stopped run delegated, and that are still pending or running,\nare stopped too (their ids are in `stoppedChildRunIds`).\n\nSpend already recorded stays counted against the budget. A stopped run is not a\nfailure: Slack notifications say it was cancelled, and no defect is filed.\n\nIf the result still shows `pending` or `running`, the stop has been recorded\nbut has not landed yet; check again with `get_run`.\n\n## Who can stop a run\n\nYou need the `runs:trigger` scope and `execute` access to the run's agent, the\nsame as `trigger_agent`. The agent's owner can stop any of its runs, including\nscheduled ones; anyone else can stop only runs they triggered. A run you cannot\nsee returns `Run \"<id>\" not found.`, exactly like a missing one; a run you\ntriggered but whose agent you can no longer execute returns a 403.\n\n## Related\n\n- [Operate managed agents](operating-agents.md)\n- [Run native agents in a sandbox](native-sandbox.md)\n- [Slack notifications](slack-notifications.md)\n- [Run lost](errors/run-lost.md), for runs a deploy interrupted\n",
|
|
4650
|
+
"plainText": "Stop or cancel a run Call the MCP tool stoprun with the run's id to stop a run that has not finished. Add an optional reason; it is recorded on the run. stoprun {\"runId\": \"<run id\", \"reason\": \"unwanted scheduled run\"} Find the id with listruns (filter with \"status\": \"pending\" or \"running\"). To stop a schedule from creating more runs, disable it with disableschedule as well; stoprun stops one run, not the schedule. What happens The run ends as cancelled, with Stopped by <your id with stoprun: <reason in its stopRequestReason (and, for a native run, in its error). | The run is | stoprun | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Pending, or a coding run queued for a slot | Ends it now. It never starts. | | A running native run in the control plane | Ends it now; the run stops at its next step. A model turn already under way finishes first; a tool call already under way is aborted within a few seconds. | | A running native run in the sandbox | Ends it now and ends its gateway session, so the worker's next call is refused and it exits. A worker still running after a short grace (5 seconds) is killed and removed; a warm pool worker is never reused. | | A running coding run | Ends it, cancels its model proxy session, and stops and removes its worker. It opens or updates no pull request afterwards. | | Already finished (any other status) | Changes nothing and returns its status. Calling stoprun again is safe. | Sub-agent runs the stopped run delegated, and that are still pending or running, are stopped too (their ids are in stoppedChildRunIds). Spend already recorded stays counted against the budget. A stopped run is not a failure: Slack notifications say it was cancelled, and no defect is filed. If the result still shows pending or running, the stop has been recorded but has not landed yet; check again with getrun. Who can stop a run You need the runs:trigger scope and execute access to the run's agent, the same as triggeragent. The agent's owner can stop any of its runs, including scheduled ones; anyone else can stop only runs they triggered. A run you cannot see returns Run \"<id\" not found., exactly like a missing one; a run you triggered but whose agent you can no longer execute returns a 403. Related Operate managed agents Run native agents in a sandbox Slack notifications Run lost, for runs a deploy interrupted",
|
|
3926
4651
|
"headings": [
|
|
3927
4652
|
{
|
|
3928
4653
|
"level": 1,
|
|
@@ -3981,6 +4706,9 @@
|
|
|
3981
4706
|
"audience": "operator",
|
|
3982
4707
|
"tags": [
|
|
3983
4708
|
"coding-agents",
|
|
4709
|
+
"get_run",
|
|
4710
|
+
"request",
|
|
4711
|
+
"requestUnavailable",
|
|
3984
4712
|
"quota",
|
|
3985
4713
|
"coding_queue_timeout",
|
|
3986
4714
|
"docker",
|
|
@@ -4001,8 +4729,8 @@
|
|
|
4001
4729
|
],
|
|
4002
4730
|
"appliesTo": ">=0.2.1",
|
|
4003
4731
|
"sourcePath": "troubleshooting/coding-workers.md",
|
|
4004
|
-
"markdown": "\n# Troubleshoot coding workers\n\nBefore enabling a coding agent, configure an immutable worker image, the\ntrusted coding proxy, a scoped GitHub App installation, and the selected job\nlauncher. Run `wardby coding preflight` after changing the Docker or Kubernetes\nconfiguration.\n\nWardby refuses to weaken an isolation profile when a required host feature,\nnetwork setting, mount, environment, or cleanup guarantee cannot be verified.\nInvestigate the host configuration instead of bypassing the refusal.\n\nCodex and Claude Code workers have different supported launcher combinations.\nReview the deployment guide for your target before assigning a coding profile.\n\nFor the specific isolation refusal, read [Coding-worker isolation unavailable](../errors/docker-isolation-unsupported.md).\n\n## Cluster preflight at start-up (Kubernetes)\n\nWith `JOB_LAUNCHER=kubernetes`, a long-running server process (`wardby\nserve`, `wardby mcp` over either transport, or `wardby scheduler`) starts\nthe cluster preflight as soon as it starts, instead of waiting for the\nfirst coding run. Check the process's start-up log for the result: an info\nline when the preflight passes, or a warning naming the failure code (the\nsame `kubernetes_isolation_unsupported:<check>` codes `wardby coding\npreflight` reports) when it does not.\n\nA failed start-up preflight is logged and retried on the next coding run,\nnot left failing until a restart: fix the underlying configuration and the\nnext run checks the cluster again on its own. If a run was already\nstarting at the moment the start-up preflight failed, that one run still\nfails with the logged error — it was waiting on that same check — but the\nrun after it retries. This differs from a preflight failure a coding run\ntriggers itself (no start-up check ran, or the cluster is still broken when\nthe next run checks it): that failure does stick, failing every subsequent\nrun in that process until it is restarted. Run `wardby coding preflight` at\nany time for a one-off check against the same cluster.\n\n## Runs that stop at the turn limit\n\nA Claude Code run whose failure category is `turn_limit` reached its agent's\nturn limit (worker error `coding_turn_limit`): 200 model calls by default. The\nwork was too large for the limit, or the agent was looping. Read the run's\nsummary and debug trace (`codingProfile.debugTraceMinutes`) to tell which;\nraise `codingProfile.maxTurns` (up to 1000) with `update_agent` for the first,\nor narrow the task for the second. Codex runs have no turn limit. See\n[Coding run reached its turn limit](../errors/coding-turn-limit.md).\n\n## Claude Code replies that exceed the output token maximum\n\nA Claude Code run caps each model reply at 32000 output tokens by default,\nthinking included. When a reply needs more, Claude Code ends with an error\nthat the response exceeded the output token maximum and the run fails as a\nstream failure. Raise `codingProfile.maxOutputTokens` (1024 to 128000; `null`\nrestores the default) with `update_agent`, for example\n`{ \"id\": \"<agent id>\", \"codingProfile\": { \"maxOutputTokens\": 64000 } }`. The\ncoding proxy reserves `maxOutputTokens` × the model's output price against the\nrun's budget for every model request, so a higher value needs a larger\n`budgetUsd`; a request whose reservation does not fit ends the run as\n`budget_exhausted` (see the help article `errors/budget-exhausted`), so a small\nbudget runs out sooner. Codex agents refuse the\nsetting. The default and the setting need a Claude Code worker image from\nWardby 0.7.0 or later: an older pinned image still caps replies at 4096 tokens\nand rejects a run whose agent sets `maxOutputTokens`.\n\n## Runs refused because the provider is out of credit\n\nA diagnostic of `job_coding_stream_quota_exceeded` means the model provider\nbehind the coding proxy refused the run because its account is out of credit or\nover a spend limit, not that the run's own budget ran out. Every run on that\naccount fails the same way until the limit is raised; see the help article\n`errors/coding-stream-quota-exceeded`.\n\n## Runs that die while running checks (out of memory)\n\nA run that fails with `coding_failure_executor` while it runs a linter, a type\ncheck or a test suite has often run out of memory. Each coding pod gets\n`CODING_MEMORY_MB` (2048 MiB by default) and `CODING_CPUS` (1 by default). In a\nCodex run the agent and its commands share that pod. In a Claude Code run the\ncommands run in a tool-runner container limited to at most 512 MiB and 0.25 CPU.\n\n1. Turn on a debug trace (below) and run it again. A Node.js crash shows as\n `Aborted` with exit code 134 in a command's output.\n2. Raise `CODING_MEMORY_MB` and `CODING_CPUS` on the control plane. On GKE, deploy\n with `CODING_MEMORY_MB=6144 CODING_CPUS=2 deploy/gke/up.sh` (see the GKE deploy\n guide). This applies to every coding run.\n3. For a Claude Code agent with heavy checks, run it on Codex instead, since raising\n the pod's memory doesn't raise the tool runner's limit.\n\n## Debug trace\n\nWhen a run's fixed error code or a slow run doesn't say enough, an admin can\ntrace the agent's runs for a while:\n`update_agent { \"id\": \"<agent id>\", \"codingProfile\": { \"debugTraceMinutes\": 30 } }`.\nEach run dispatched in that window writes its whole agent stream, redacted, to\nits worker container's log under a `debugTrace` key. That covers Codex events,\nor, for Claude Code (Wardby 0.7.0 or later), every Agent SDK message:\neach command the agent ran with its output, the final usage and duration, plus\nstream failures in full. For Claude Code, the time between a command's\n`tool_use` and its `tool_result` line is how long that command took. A run's\ntrace stops at 2 MiB by default; set `codingProfile.debugTraceMaxMb` (1 to 64,\nadmin only) for more. The trace can hold prompts and repository content, so\nkeep it on briefly. See\n[the debug trace section](../../docs/coding-worker-isolation.md#debug-trace)\nfor where the log lives and what is redacted.\n\n## Runs that wait for cluster capacity\n\nOn Kubernetes, a run whose pod would not fit the namespace quota waits instead\nof failing. With `KUBERNETES_RESOURCE_QUOTA` set, it is held before it starts;\nwithout it, or if the quota fills up meanwhile, the cluster refuses the pod and\nthe run returns to the queue. Either way it stays `pending` with\n`codingQueuedAt` set, like a run over `CODING_MAX_CONCURRENT`, and is retried\n(a refused run no sooner than about a minute later). A refused run shows\n`running` briefly, then `pending` again.\n\nA run still waiting after `CODING_QUEUE_TIMEOUT_SEC` fails with\n`coding_queue_timeout`. That can mean either the concurrency limit or the\nnamespace quota. To tell which, look for the control-plane log line\n`coding run waiting for capacity: the cluster refused its pod` (quota), and run\n`kubectl describe resourcequota -n <namespace>` to compare used against hard\nlimits. If the quota is full, raise it, lower the run pods' size, or lower\n`CODING_MAX_CONCURRENT` so fewer runs compete; size the quota for\n`CODING_MAX_CONCURRENT` times the run pod's requests. If the log line\n`kubernetes_resource_quota_unconfigured` appears, set `KUBERNETES_RESOURCE_QUOTA`\nto the named quota and grant the launcher `get` on it. See\n[the queue section](../../docs/coding-worker-isolation.md#control-plane-configuration).\n\nA lead agent with `parallelDelegations` starts several coding runs together;\nexpect some of them to queue when the lead fans out wider than the free slots.\n\n## Service refusals and failures\n\nA repository can declare services such as PostgreSQL in `.wardby/services.yaml`\non its base branch. Wardby checks the declaration, the service catalog, and the\nagent's `codingProfile.services` before a run starts, and refuses the run with a\n`service_*` code when they disagree. The run's `error` (from `get_run`) is the\ncode followed by a sentence the requester also sees on the run's status comment.\n\n- [`service_declaration_invalid`](../errors/service-declaration-invalid.md):\n the file on the base branch is not a valid declaration.\n- [`service_declaration_unavailable`](../errors/service-declaration-unavailable.md):\n Wardby could not read the file through the GitHub App.\n- [`service_unknown`](../errors/service-unknown.md): the catalog has no such\n name and version.\n- [`service_not_allowed`](../errors/service-not-allowed.md): the agent does not\n allow that service.\n- [`service_launcher_unsupported`](../errors/service-launcher-unsupported.md):\n services need the Kubernetes or Docker job launcher.\n- [`service_unready`](../errors/service-unready.md): the run started but a\n service never became ready (launcher error `coding_service_unready:<name>`).\n\nSee [Coding services](../coding-services.md).\n",
|
|
4005
|
-
"plainText": "Troubleshoot coding workers Before enabling a coding agent, configure an immutable worker image, the trusted coding proxy, a scoped GitHub App installation, and the selected job launcher. Run wardby coding preflight after changing the Docker or Kubernetes configuration. Wardby refuses to weaken an isolation profile when a required host feature, network setting, mount, environment, or cleanup guarantee cannot be verified. Investigate the host configuration instead of bypassing the refusal. Codex and Claude Code workers have different supported launcher combinations. Review the deployment guide for your target before assigning a coding profile. For the specific isolation refusal, read Coding-worker isolation unavailable. Cluster preflight at start-up (Kubernetes) With JOBLAUNCHER=kubernetes, a long-running server process (wardby serve, wardby mcp over either transport, or wardby scheduler) starts the cluster preflight as soon as it starts, instead of waiting for the first coding run. Check the process's start-up log for the result: an info line when the preflight passes, or a warning naming the failure code (the same kubernetesisolationunsupported:<check codes wardby coding preflight reports) when it does not. A failed start-up preflight is logged and retried on the next coding run, not left failing until a restart: fix the underlying configuration and the next run checks the cluster again on its own. If a run was already starting at the moment the start-up preflight failed, that one run still fails with the logged error — it was waiting on that same check — but the run after it retries. This differs from a preflight failure a coding run triggers itself (no start-up check ran, or the cluster is still broken when the next run checks it): that failure does stick, failing every subsequent run in that process until it is restarted. Run wardby coding preflight at any time for a one-off check against the same cluster. Runs that stop at the turn limit A Claude Code run whose failure category is turnlimit reached its agent's turn limit (worker error codingturnlimit): 200 model calls by default. The work was too large for the limit, or the agent was looping. Read the run's summary and debug trace (codingProfile.debugTraceMinutes) to tell which; raise codingProfile.maxTurns (up to 1000) with updateagent for the first, or narrow the task for the second. Codex runs have no turn limit. See Coding run reached its turn limit. Claude Code replies that exceed the output token maximum A Claude Code run caps each model reply at 32000 output tokens by default, thinking included. When a reply needs more, Claude Code ends with an error that the response exceeded the output token maximum and the run fails as a stream failure. Raise codingProfile.maxOutputTokens (1024 to 128000; null restores the default) with updateagent, for example { \"id\": \"<agent id\", \"codingProfile\": { \"maxOutputTokens\": 64000 } }. The coding proxy reserves maxOutputTokens × the model's output price against the run's budget for every model request, so a higher value needs a larger budgetUsd; a request whose reservation does not fit ends the run as budgetexhausted (see the help article errors/budget-exhausted), so a small budget runs out sooner. Codex agents refuse the setting. The default and the setting need a Claude Code worker image from Wardby 0.7.0 or later: an older pinned image still caps replies at 4096 tokens and rejects a run whose agent sets maxOutputTokens. Runs refused because the provider is out of credit A diagnostic of jobcodingstreamquotaexceeded means the model provider behind the coding proxy refused the run because its account is out of credit or over a spend limit, not that the run's own budget ran out. Every run on that account fails the same way until the limit is raised; see the help article errors/coding-stream-quota-exceeded. Runs that die while running checks (out of memory) A run that fails with codingfailureexecutor while it runs a linter, a type check or a test suite has often run out of memory. Each coding pod gets CODINGMEMORYMB (2048 MiB by default) and CODINGCPUS (1 by default). In a Codex run the agent and its commands share that pod. In a Claude Code run the commands run in a tool-runner container limited to at most 512 MiB and 0.25 CPU. Turn on a debug trace (below) and run it again. A Node.js crash shows as Aborted with exit code 134 in a command's output. Raise CODINGMEMORYMB and CODINGCPUS on the control plane. On GKE, deploy with CODINGMEMORYMB=6144 CODINGCPUS=2 deploy/gke/up.sh (see the GKE deploy guide). This applies to every coding run. For a Claude Code agent with heavy checks, run it on Codex instead, since raising the pod's memory doesn't raise the tool runner's limit. Debug trace When a run's fixed error code or a slow run doesn't say enough, an admin can trace the agent's runs for a while: updateagent { \"id\": \"<agent id\", \"codingProfile\": { \"debugTraceMinutes\": 30 } }. Each run dispatched in that window writes its whole agent stream, redacted, to its worker container's log under a debugTrace key. That covers Codex events, or, for Claude Code (Wardby 0.7.0 or later), every Agent SDK message: each command the agent ran with its output, the final usage and duration, plus stream failures in full. For Claude Code, the time between a command's tooluse and its toolresult line is how long that command took. A run's trace stops at 2 MiB by default; set codingProfile.debugTraceMaxMb (1 to 64, admin only) for more. The trace can hold prompts and repository content, so keep it on briefly. See the debug trace section for where the log lives and what is redacted. Runs that wait for cluster capacity On Kubernetes, a run whose pod would not fit the namespace quota waits instead of failing. With KUBERNETESRESOURCEQUOTA set, it is held before it starts; without it, or if the quota fills up meanwhile, the cluster refuses the pod and the run returns to the queue. Either way it stays pending with codingQueuedAt set, like a run over CODINGMAXCONCURRENT, and is retried (a refused run no sooner than about a minute later). A refused run shows running briefly, then pending again. A run still waiting after CODINGQUEUETIMEOUTSEC fails with codingqueuetimeout. That can mean either the concurrency limit or the namespace quota. To tell which, look for the control-plane log line coding run waiting for capacity: the cluster refused its pod (quota), and run kubectl describe resourcequota -n <namespace to compare used against hard limits. If the quota is full, raise it, lower the run pods' size, or lower CODINGMAXCONCURRENT so fewer runs compete; size the quota for CODINGMAXCONCURRENT times the run pod's requests. If the log line kubernetesresourcequotaunconfigured appears, set KUBERNETESRESOURCEQUOTA to the named quota and grant the launcher get on it. See the queue section. A lead agent with parallelDelegations starts several coding runs together; expect some of them to queue when the lead fans out wider than the free slots. Service refusals and failures A repository can declare services such as PostgreSQL in .wardby/services.yaml on its base branch. Wardby checks the declaration, the service catalog, and the agent's codingProfile.services before a run starts, and refuses the run with a service code when they disagree. The run's error (from getrun) is the code followed by a sentence the requester also sees on the run's status comment. servicedeclarationinvalid: the file on the base branch is not a valid declaration. servicedeclarationunavailable: Wardby could not read the file through the GitHub App. serviceunknown: the catalog has no such name and version. servicenotallowed: the agent does not allow that service. servicelauncherunsupported: services need the Kubernetes or Docker job launcher. serviceunready: the run started but a service never became ready (launcher error codingserviceunready:<name). See Coding services.",
|
|
4732
|
+
"markdown": "\n# Troubleshoot coding workers\n\nBefore enabling a coding agent, configure an immutable worker image, the\ntrusted coding proxy, a scoped GitHub App installation, and the selected job\nlauncher. Run `wardby coding preflight` after changing the Docker or Kubernetes\nconfiguration.\n\nWardby refuses to weaken an isolation profile when a required host feature,\nnetwork setting, mount, environment, or cleanup guarantee cannot be verified.\nInvestigate the host configuration instead of bypassing the refusal.\n\nCodex and Claude Code workers have different supported launcher combinations.\nReview the deployment guide for your target before assigning a coding profile.\n\nFor the specific isolation refusal, read [Coding-worker isolation unavailable](../errors/docker-isolation-unsupported.md).\n\n## Cluster preflight at start-up (Kubernetes)\n\nWith `JOB_LAUNCHER=kubernetes`, a long-running server process (`wardby\nserve`, `wardby mcp` over either transport, or `wardby scheduler`) starts\nthe cluster preflight as soon as it starts, instead of waiting for the\nfirst coding run. Check the process's start-up log for the result: an info\nline when the preflight passes, or a warning naming the failure code (the\nsame `kubernetes_isolation_unsupported:<check>` codes `wardby coding\npreflight` reports) when it does not.\n\nA failed start-up preflight is logged and retried on the next coding run,\nnot left failing until a restart: fix the underlying configuration and the\nnext run checks the cluster again on its own. If a run was already\nstarting at the moment the start-up preflight failed, that one run still\nfails with the logged error — it was waiting on that same check — but the\nrun after it retries. This differs from a preflight failure a coding run\ntriggers itself (no start-up check ran, or the cluster is still broken when\nthe next run checks it): that failure does stick, failing every subsequent\nrun in that process until it is restarted. Run `wardby coding preflight` at\nany time for a one-off check against the same cluster.\n\n## Runs that stop at the turn limit\n\nA Claude Code run whose failure category is `turn_limit` reached its agent's\nturn limit (worker error `coding_turn_limit`): 200 model calls by default. The\nwork was too large for the limit, or the agent was looping. Read the run's\nsummary and debug trace (`codingProfile.debugTraceMinutes`) to tell which;\nraise `codingProfile.maxTurns` (up to 1000) with `update_agent` for the first,\nor narrow the task for the second. Codex runs have no turn limit. See\n[Coding run reached its turn limit](../errors/coding-turn-limit.md).\n\n## Claude Code replies that exceed the output token maximum\n\nA Claude Code run caps each model reply at 32000 output tokens by default,\nthinking included. When a reply needs more, Claude Code ends with an error\nthat the response exceeded the output token maximum and the run fails as a\nstream failure. Raise `codingProfile.maxOutputTokens` (1024 to 128000; `null`\nrestores the default) with `update_agent`, for example\n`{ \"id\": \"<agent id>\", \"codingProfile\": { \"maxOutputTokens\": 64000 } }`. The\ncoding proxy reserves `maxOutputTokens` × the model's output price against the\nrun's budget for every model request, so a higher value needs a larger\n`budgetUsd`; a request whose reservation does not fit ends the run as\n`budget_exhausted` (see the help article `errors/budget-exhausted`), so a small\nbudget runs out sooner. Codex agents refuse the\nsetting. The default and the setting need a Claude Code worker image from\nWardby 0.7.0 or later: an older pinned image still caps replies at 4096 tokens\nand rejects a run whose agent sets `maxOutputTokens`.\n\n## Runs refused because the provider is out of credit\n\nA diagnostic of `job_coding_stream_quota_exceeded` means the model provider\nbehind the coding proxy refused the run because its account is out of credit or\nover a spend limit, not that the run's own budget ran out. Every run on that\naccount fails the same way until the limit is raised; see the help article\n`errors/coding-stream-quota-exceeded`.\n\n## Runs that die while running checks (out of memory)\n\nA run that fails with `coding_failure_executor` while it runs a linter, a type\ncheck or a test suite has often run out of memory. Each coding pod gets\n`CODING_MEMORY_MB` (2048 MiB by default) and `CODING_CPUS` (1 by default). In a\nCodex run the agent and its commands share that pod. In a Claude Code run the\ncommands run in a tool-runner container limited to at most 512 MiB and 0.25 CPU.\n\n1. Turn on a debug trace (below) and run it again. A Node.js crash shows as\n `Aborted` with exit code 134 in a command's output.\n2. Raise `CODING_MEMORY_MB` and `CODING_CPUS` on the control plane. On GKE, deploy\n with `CODING_MEMORY_MB=6144 CODING_CPUS=2 deploy/gke/up.sh` (see the GKE deploy\n guide). This applies to every coding run.\n3. For a Claude Code agent with heavy checks, run it on Codex instead, since raising\n the pod's memory doesn't raise the tool runner's limit.\n\n## See what a run was asked to do\n\nFrom Wardby 0.8.0, `get_run` returns a coding run's `request`: the task it\nreceived from `trigger_agent`, a webhook or a lead, without the agent's standing\ninstructions. Use it to check what a lead told a coding agent. The agent's secret\nvalues and token-shaped values are masked. If the secrets can't be read, you get\n`requestUnavailable: true` instead of the text.\n\n## Debug trace\n\nWhen a run's fixed error code or a slow run doesn't say enough, an admin can\ntrace the agent's runs for a while:\n`update_agent { \"id\": \"<agent id>\", \"codingProfile\": { \"debugTraceMinutes\": 30 } }`.\nEach run dispatched in that window writes its whole agent stream, redacted, to\nits worker container's log under a `debugTrace` key. That covers Codex events,\nor, for Claude Code (Wardby 0.7.0 or later), every Agent SDK message:\neach command the agent ran with its output, the final usage and duration, plus\nstream failures in full. For Claude Code, the time between a command's\n`tool_use` and its `tool_result` line is how long that command took. A run's\ntrace stops at 2 MiB by default; set `codingProfile.debugTraceMaxMb` (1 to 64,\nadmin only) for more. The trace can hold prompts and repository content, so\nkeep it on briefly. See\n[the debug trace section](../../docs/coding-worker-isolation.md#debug-trace)\nfor where the log lives and what is redacted.\n\n## Runs that wait for cluster capacity\n\nOn Kubernetes, a run whose pod would not fit the namespace quota waits instead\nof failing. With `KUBERNETES_RESOURCE_QUOTA` set, it is held before it starts;\nwithout it, or if the quota fills up meanwhile, the cluster refuses the pod and\nthe run returns to the queue. Either way it stays `pending` with\n`codingQueuedAt` set, like a run over `CODING_MAX_CONCURRENT`, and is retried\n(a refused run no sooner than about a minute later). A refused run shows\n`running` briefly, then `pending` again.\n\nA run still waiting after `CODING_QUEUE_TIMEOUT_SEC` fails with\n`coding_queue_timeout`. That can mean either the concurrency limit or the\nnamespace quota. To tell which, look for the control-plane log line\n`coding run waiting for capacity: the cluster refused its pod` (quota), and run\n`kubectl describe resourcequota -n <namespace>` to compare used against hard\nlimits. If the quota is full, raise it, lower the run pods' size, or lower\n`CODING_MAX_CONCURRENT` so fewer runs compete; size the quota for\n`CODING_MAX_CONCURRENT` times the run pod's requests. If the log line\n`kubernetes_resource_quota_unconfigured` appears, set `KUBERNETES_RESOURCE_QUOTA`\nto the named quota and grant the launcher `get` on it. See\n[the queue section](../../docs/coding-worker-isolation.md#control-plane-configuration).\n\nA lead agent with `parallelDelegations` starts several coding runs together;\nexpect some of them to queue when the lead fans out wider than the free slots.\n\n## Service refusals and failures\n\nA repository can declare services such as PostgreSQL in `.wardby/services.yaml`\non its base branch. Wardby checks the declaration, the service catalog, and the\nagent's `codingProfile.services` before a run starts, and refuses the run with a\n`service_*` code when they disagree. The run's `error` (from `get_run`) is the\ncode followed by a sentence the requester also sees on the run's status comment.\n\n- [`service_declaration_invalid`](../errors/service-declaration-invalid.md):\n the file on the base branch is not a valid declaration.\n- [`service_declaration_unavailable`](../errors/service-declaration-unavailable.md):\n Wardby could not read the file through the GitHub App.\n- [`service_unknown`](../errors/service-unknown.md): the catalog has no such\n name and version.\n- [`service_not_allowed`](../errors/service-not-allowed.md): the agent does not\n allow that service.\n- [`service_launcher_unsupported`](../errors/service-launcher-unsupported.md):\n services need the Kubernetes or Docker job launcher.\n- [`service_unready`](../errors/service-unready.md): the run started but a\n service never became ready (launcher error `coding_service_unready:<name>`).\n\nSee [Coding services](../coding-services.md).\n",
|
|
4733
|
+
"plainText": "Troubleshoot coding workers Before enabling a coding agent, configure an immutable worker image, the trusted coding proxy, a scoped GitHub App installation, and the selected job launcher. Run wardby coding preflight after changing the Docker or Kubernetes configuration. Wardby refuses to weaken an isolation profile when a required host feature, network setting, mount, environment, or cleanup guarantee cannot be verified. Investigate the host configuration instead of bypassing the refusal. Codex and Claude Code workers have different supported launcher combinations. Review the deployment guide for your target before assigning a coding profile. For the specific isolation refusal, read Coding-worker isolation unavailable. Cluster preflight at start-up (Kubernetes) With JOBLAUNCHER=kubernetes, a long-running server process (wardby serve, wardby mcp over either transport, or wardby scheduler) starts the cluster preflight as soon as it starts, instead of waiting for the first coding run. Check the process's start-up log for the result: an info line when the preflight passes, or a warning naming the failure code (the same kubernetesisolationunsupported:<check codes wardby coding preflight reports) when it does not. A failed start-up preflight is logged and retried on the next coding run, not left failing until a restart: fix the underlying configuration and the next run checks the cluster again on its own. If a run was already starting at the moment the start-up preflight failed, that one run still fails with the logged error — it was waiting on that same check — but the run after it retries. This differs from a preflight failure a coding run triggers itself (no start-up check ran, or the cluster is still broken when the next run checks it): that failure does stick, failing every subsequent run in that process until it is restarted. Run wardby coding preflight at any time for a one-off check against the same cluster. Runs that stop at the turn limit A Claude Code run whose failure category is turnlimit reached its agent's turn limit (worker error codingturnlimit): 200 model calls by default. The work was too large for the limit, or the agent was looping. Read the run's summary and debug trace (codingProfile.debugTraceMinutes) to tell which; raise codingProfile.maxTurns (up to 1000) with updateagent for the first, or narrow the task for the second. Codex runs have no turn limit. See Coding run reached its turn limit. Claude Code replies that exceed the output token maximum A Claude Code run caps each model reply at 32000 output tokens by default, thinking included. When a reply needs more, Claude Code ends with an error that the response exceeded the output token maximum and the run fails as a stream failure. Raise codingProfile.maxOutputTokens (1024 to 128000; null restores the default) with updateagent, for example { \"id\": \"<agent id\", \"codingProfile\": { \"maxOutputTokens\": 64000 } }. The coding proxy reserves maxOutputTokens × the model's output price against the run's budget for every model request, so a higher value needs a larger budgetUsd; a request whose reservation does not fit ends the run as budgetexhausted (see the help article errors/budget-exhausted), so a small budget runs out sooner. Codex agents refuse the setting. The default and the setting need a Claude Code worker image from Wardby 0.7.0 or later: an older pinned image still caps replies at 4096 tokens and rejects a run whose agent sets maxOutputTokens. Runs refused because the provider is out of credit A diagnostic of jobcodingstreamquotaexceeded means the model provider behind the coding proxy refused the run because its account is out of credit or over a spend limit, not that the run's own budget ran out. Every run on that account fails the same way until the limit is raised; see the help article errors/coding-stream-quota-exceeded. Runs that die while running checks (out of memory) A run that fails with codingfailureexecutor while it runs a linter, a type check or a test suite has often run out of memory. Each coding pod gets CODINGMEMORYMB (2048 MiB by default) and CODINGCPUS (1 by default). In a Codex run the agent and its commands share that pod. In a Claude Code run the commands run in a tool-runner container limited to at most 512 MiB and 0.25 CPU. Turn on a debug trace (below) and run it again. A Node.js crash shows as Aborted with exit code 134 in a command's output. Raise CODINGMEMORYMB and CODINGCPUS on the control plane. On GKE, deploy with CODINGMEMORYMB=6144 CODINGCPUS=2 deploy/gke/up.sh (see the GKE deploy guide). This applies to every coding run. For a Claude Code agent with heavy checks, run it on Codex instead, since raising the pod's memory doesn't raise the tool runner's limit. See what a run was asked to do From Wardby 0.8.0, getrun returns a coding run's request: the task it received from triggeragent, a webhook or a lead, without the agent's standing instructions. Use it to check what a lead told a coding agent. The agent's secret values and token-shaped values are masked. If the secrets can't be read, you get requestUnavailable: true instead of the text. Debug trace When a run's fixed error code or a slow run doesn't say enough, an admin can trace the agent's runs for a while: updateagent { \"id\": \"<agent id\", \"codingProfile\": { \"debugTraceMinutes\": 30 } }. Each run dispatched in that window writes its whole agent stream, redacted, to its worker container's log under a debugTrace key. That covers Codex events, or, for Claude Code (Wardby 0.7.0 or later), every Agent SDK message: each command the agent ran with its output, the final usage and duration, plus stream failures in full. For Claude Code, the time between a command's tooluse and its toolresult line is how long that command took. A run's trace stops at 2 MiB by default; set codingProfile.debugTraceMaxMb (1 to 64, admin only) for more. The trace can hold prompts and repository content, so keep it on briefly. See the debug trace section for where the log lives and what is redacted. Runs that wait for cluster capacity On Kubernetes, a run whose pod would not fit the namespace quota waits instead of failing. With KUBERNETESRESOURCEQUOTA set, it is held before it starts; without it, or if the quota fills up meanwhile, the cluster refuses the pod and the run returns to the queue. Either way it stays pending with codingQueuedAt set, like a run over CODINGMAXCONCURRENT, and is retried (a refused run no sooner than about a minute later). A refused run shows running briefly, then pending again. A run still waiting after CODINGQUEUETIMEOUTSEC fails with codingqueuetimeout. That can mean either the concurrency limit or the namespace quota. To tell which, look for the control-plane log line coding run waiting for capacity: the cluster refused its pod (quota), and run kubectl describe resourcequota -n <namespace to compare used against hard limits. If the quota is full, raise it, lower the run pods' size, or lower CODINGMAXCONCURRENT so fewer runs compete; size the quota for CODINGMAXCONCURRENT times the run pod's requests. If the log line kubernetesresourcequotaunconfigured appears, set KUBERNETESRESOURCEQUOTA to the named quota and grant the launcher get on it. See the queue section. A lead agent with parallelDelegations starts several coding runs together; expect some of them to queue when the lead fans out wider than the free slots. Service refusals and failures A repository can declare services such as PostgreSQL in .wardby/services.yaml on its base branch. Wardby checks the declaration, the service catalog, and the agent's codingProfile.services before a run starts, and refuses the run with a service code when they disagree. The run's error (from getrun) is the code followed by a sentence the requester also sees on the run's status comment. servicedeclarationinvalid: the file on the base branch is not a valid declaration. servicedeclarationunavailable: Wardby could not read the file through the GitHub App. serviceunknown: the catalog has no such name and version. servicenotallowed: the agent does not allow that service. servicelauncherunsupported: services need the Kubernetes or Docker job launcher. serviceunready: the run started but a service never became ready (launcher error codingserviceunready:<name). See Coding services.",
|
|
4006
4734
|
"headings": [
|
|
4007
4735
|
{
|
|
4008
4736
|
"level": 1,
|
|
@@ -4034,6 +4762,11 @@
|
|
|
4034
4762
|
"text": "Runs that die while running checks (out of memory)",
|
|
4035
4763
|
"slug": "runs-that-die-while-running-checks-out-of-memory"
|
|
4036
4764
|
},
|
|
4765
|
+
{
|
|
4766
|
+
"level": 2,
|
|
4767
|
+
"text": "See what a run was asked to do",
|
|
4768
|
+
"slug": "see-what-a-run-was-asked-to-do"
|
|
4769
|
+
},
|
|
4037
4770
|
{
|
|
4038
4771
|
"level": 2,
|
|
4039
4772
|
"text": "Debug trace",
|
|
@@ -4051,6 +4784,33 @@
|
|
|
4051
4784
|
}
|
|
4052
4785
|
]
|
|
4053
4786
|
},
|
|
4787
|
+
{
|
|
4788
|
+
"id": "troubleshooting/debugging-agent-runs",
|
|
4789
|
+
"title": "Debug an agent run",
|
|
4790
|
+
"summary": "Triage a run that failed, opened no pull request, or missed what you expected, using the MCP tools and GitHub without server logs.",
|
|
4791
|
+
"audience": "operator",
|
|
4792
|
+
"tags": [
|
|
4793
|
+
"debugging",
|
|
4794
|
+
"triage",
|
|
4795
|
+
"get_run",
|
|
4796
|
+
"list_runs",
|
|
4797
|
+
"failureCategory",
|
|
4798
|
+
"diagnosticId",
|
|
4799
|
+
"get_run_transcript",
|
|
4800
|
+
"no_changes"
|
|
4801
|
+
],
|
|
4802
|
+
"appliesTo": ">=0.7.0",
|
|
4803
|
+
"sourcePath": "troubleshooting/debugging-agent-runs.md",
|
|
4804
|
+
"markdown": "\n# Debug an agent run\n\nFind the run with `list_runs`, read it with `get_run`, then follow what you see.\nWithout an `agentId`, `list_runs` lists your runs across every agent (from\nWardby 0.8.0); add `active: true` or `since` to narrow it.\n\n| What you see | What to check |\n| ----------------------------- | -------------------------------------------------------------------------------------------------- |\n| No run started | `list_repositories` on the router: is a link holding the trigger you used? |\n| Failed or refused | `status`, `error`, `failureCategory` and the final text. Call `search_help` with the category |\n| Lead ran, no coding run | The lead's final text, which should say why it didn't delegate |\n| Succeeded, no pull request | `codingResult.outcome`: `no_changes`, `budget_exhausted`, or `branch_pushed` on a local repository |\n| Pull request missed the point | The diff, the review, the original request, and `request` on `get_run` (from Wardby 0.8.0) |\n\nA failed coding run's specific reason is only in the server log. Send an operator\nthe run ID and its `diagnosticId`. For Claude Code agents with `sessionResume` on,\n`get_run_transcript` shows what the agent did; see\n[Resume Claude Code runs locally](../resume-runs-locally.md).\n\nThe full guide is [Debugging an agent run](../../docs/debugging-agent-runs.md).\n",
|
|
4805
|
+
"plainText": "Debug an agent run Find the run with listruns, read it with getrun, then follow what you see. Without an agentId, listruns lists your runs across every agent (from Wardby 0.8.0); add active: true or since to narrow it. | What you see | What to check | | ----------------------------- | -------------------------------------------------------------------------------------------------- | | No run started | listrepositories on the router: is a link holding the trigger you used? | | Failed or refused | status, error, failureCategory and the final text. Call searchhelp with the category | | Lead ran, no coding run | The lead's final text, which should say why it didn't delegate | | Succeeded, no pull request | codingResult.outcome: nochanges, budgetexhausted, or branchpushed on a local repository | | Pull request missed the point | The diff, the review, the original request, and request on getrun (from Wardby 0.8.0) | A failed coding run's specific reason is only in the server log. Send an operator the run ID and its diagnosticId. For Claude Code agents with sessionResume on, getruntranscript shows what the agent did; see Resume Claude Code runs locally. The full guide is Debugging an agent run.",
|
|
4806
|
+
"headings": [
|
|
4807
|
+
{
|
|
4808
|
+
"level": 1,
|
|
4809
|
+
"text": "Debug an agent run",
|
|
4810
|
+
"slug": "debug-an-agent-run"
|
|
4811
|
+
}
|
|
4812
|
+
]
|
|
4813
|
+
},
|
|
4054
4814
|
{
|
|
4055
4815
|
"id": "troubleshooting/repository-access",
|
|
4056
4816
|
"title": "Troubleshoot repository access",
|