@wardby/cli 0.8.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/deploy/local/docker-compose.quickstart-coding.yml +5 -0
- package/dist/claude-plugin/command.d.ts +4 -1
- package/dist/claude-plugin/command.js +7 -4
- package/dist/cli.js +24 -0
- package/dist/coding/transcript/recorder.js +2 -8
- package/dist/core/dispatch.js +3 -0
- package/dist/core/engine-native.d.ts +2 -0
- package/dist/core/engine-native.js +13 -0
- package/dist/core/error-code.js +1 -0
- package/dist/core/listen-address.d.ts +10 -0
- package/dist/core/listen-address.js +14 -0
- 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/retention-days.d.ts +5 -0
- package/dist/core/retention-days.js +14 -0
- 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 +4 -0
- package/dist/core/runner.js +15 -1
- package/dist/generated/prisma/browser.d.ts +8 -0
- package/dist/generated/prisma/client.d.ts +8 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +30 -0
- 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 +11 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +103 -1
- package/dist/generated/prisma/internal/prismaNamespace.js +19 -1
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +19 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +19 -1
- package/dist/generated/prisma/models/Agent.d.ts +101 -1
- package/dist/generated/prisma/models/CodingProxySession.d.ts +41 -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.d.ts +1 -0
- package/dist/help-index.json +102 -14
- package/dist/mcp/auth/access.d.ts +1 -0
- package/dist/mcp/context.d.ts +3 -0
- package/dist/mcp/index.js +10 -0
- package/dist/mcp/tools/agents.js +37 -7
- package/dist/mcp/tools/power.js +2 -2
- 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 +10 -2
- package/dist/native-worker/gateway-server.d.ts +4 -1
- package/dist/native-worker/gateway-server.js +10 -2
- package/dist/native-worker/gateway.d.ts +3 -0
- package/dist/native-worker/gateway.js +8 -0
- package/dist/native-worker/http-server.d.ts +2 -4
- package/dist/native-worker/http-server.js +2 -8
- package/dist/providers/coding-proxy/memory-ledger.js +1 -0
- package/dist/providers/coding-proxy/prisma-ledger.js +9 -3
- package/dist/providers/coding-proxy/proxy.d.ts +26 -0
- package/dist/providers/coding-proxy/proxy.js +133 -42
- 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 +7 -0
- package/dist/providers/coding-proxy/runtime.js +55 -3
- package/dist/providers/coding-proxy/types.d.ts +5 -0
- package/dist/providers/engine/types.d.ts +26 -0
- package/dist/providers/executor/container.d.ts +14 -0
- package/dist/providers/executor/container.js +8 -1
- package/dist/providers/jobs/kubernetes.d.ts +8 -0
- package/dist/providers/jobs/kubernetes.js +22 -4
- package/dist/quickstart-images.json +1 -1
- 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/openapi.js +2 -1
- package/dist/viewer/run-detail.d.ts +2 -0
- package/dist/viewer/run-detail.js +26 -1
- package/docs/claude-code-plugin.md +57 -13
- package/docs/coding-agent-setup.md +17 -0
- package/docs/coding-worker-isolation.md +16 -0
- package/docs/debugging-agent-runs.md +112 -0
- package/docs/getting-started-gke.md +28 -7
- package/docs/mcp-servers.md +9 -0
- package/docs/native-sandbox.md +6 -0
- package/docs/security-deployment.md +51 -0
- package/docs/viewer-api.md +21 -12
- package/docs/viewer-api.openapi.yml +78 -2
- package/help/admin-viewer.md +1 -0
- package/help/claude-code-run-pane.md +27 -4
- package/help/deploy-gke.md +5 -0
- package/help/errors/coding-mcp-gateway-unavailable.md +46 -0
- package/help/low-power-mode.md +19 -8
- package/help/mcp.md +2 -0
- package/help/resume-runs-locally.md +4 -0
- package/help/run-steps.md +140 -0
- package/package.json +1 -1
- 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 +52 -0
package/help/admin-viewer.md
CHANGED
|
@@ -27,6 +27,7 @@ Endpoints, all `GET`:
|
|
|
27
27
|
|
|
28
28
|
- `/admin/api/graph?since=1h&limit=500`: a snapshot of runs in a time window.
|
|
29
29
|
- `/admin/api/runs/<id>`: one run in full, including its final text and error.
|
|
30
|
+
From Wardby 0.9.0 it also lists the run's newest 200 steps (see `run-steps`).
|
|
30
31
|
- `/admin/api/infra`: how this deployment runs coding jobs (launcher, Kubernetes namespace, platform, run labels).
|
|
31
32
|
- `/admin/api/events`: a Server-Sent Events stream of live changes.
|
|
32
33
|
|
|
@@ -3,8 +3,8 @@ id: claude-code-run-pane
|
|
|
3
3
|
title: See your runs in Claude Code (the wardby-runs plugin)
|
|
4
4
|
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.
|
|
5
5
|
audience: operator
|
|
6
|
-
tags: [claude code, plugin, wardby-runs, pane, claude-plugin, runs,
|
|
7
|
-
appliesTo:
|
|
6
|
+
tags: [run steps, get_run_steps, claude code, plugin, wardby-runs, pane, claude-plugin, runs, auto mode, permissions]
|
|
7
|
+
appliesTo: >=0.8.0
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# See your runs in Claude Code
|
|
@@ -25,8 +25,10 @@ server named `wardby` yet. Or install it yourself with
|
|
|
25
25
|
`/wardby-runs`.
|
|
26
26
|
|
|
27
27
|
If the pane says auto mode refused a call, allow `mcp__wardby__list_runs`,
|
|
28
|
-
`mcp__wardby__list_agents`, `mcp__wardby__get_run
|
|
29
|
-
`mcp__wardby__get_run_transcript` in
|
|
28
|
+
`mcp__wardby__list_agents`, `mcp__wardby__get_run`,
|
|
29
|
+
`mcp__wardby__get_run_transcript` and `mcp__wardby__get_run_steps` in
|
|
30
|
+
`/permissions`. Run `wardby claude-plugin install` again to add a rule a newer
|
|
31
|
+
pane needs.
|
|
30
32
|
|
|
31
33
|
In the terminal, the pane takes clicks and sits beside the chat only in Claude
|
|
32
34
|
Code's fullscreen view (`"tui": "fullscreen"`); otherwise use ctrl+x tab and the
|
|
@@ -37,4 +39,25 @@ keys it shows. The desktop app needs no setting.
|
|
|
37
39
|
uninstall` removes the plugin and the rules install added. To continue a run
|
|
38
40
|
from the pane, see `resume-runs-locally`.
|
|
39
41
|
|
|
42
|
+
A running run's detail shows its **Recent steps** (the last 8 tool calls and
|
|
43
|
+
messages: a ✓ or the exit code of a failed command, then the tool and its
|
|
44
|
+
command; what the model said wraps to about two lines); a finished run's shows all its
|
|
45
|
+
**Steps**, 200 at a time. In the list, a running or failed run shows its newest
|
|
46
|
+
step under its name. Against a server without `get_run_steps` the pane shows no
|
|
47
|
+
steps and checks again every few refreshes; with run steps off it says "Steps
|
|
48
|
+
are off on this server." See `run-steps`. Steps need Wardby 0.9.0 or later
|
|
49
|
+
on the server. From 0.9.0, a step with detail, or a longer message, has a ▸ at
|
|
50
|
+
its right that opens it; in the terminal, `j`/`k` also move between such steps
|
|
51
|
+
and `e` shows or hides one. An open command shows "$ command", its exit status
|
|
52
|
+
and its output, without Codex's framing lines. Detail appears only for the
|
|
53
|
+
agent's owner and the run's starter (and the stdio operator), on a server at
|
|
54
|
+
the detail level. An open detail shows its last 40 lines, with a count of the
|
|
55
|
+
lines above them.
|
|
56
|
+
|
|
57
|
+
Each section of a run's detail is a card, coloured by its kind (a bar on the
|
|
58
|
+
desktop, the border in the terminal). On the desktop each card, an error and an
|
|
59
|
+
open step's detail have a **Copy** button that copies the full text as the
|
|
60
|
+
server sent it, an open step's detail included in full; in the terminal, **Copy section** (`y`) copies the open
|
|
61
|
+
step's detail.
|
|
62
|
+
|
|
40
63
|
The full guide is [Claude Code plugin](../docs/claude-code-plugin.md).
|
package/help/deploy-gke.md
CHANGED
|
@@ -49,6 +49,11 @@ grants fail, `up.sh` stops before the rollout with a non-zero exit;
|
|
|
49
49
|
without changing anything. See
|
|
50
50
|
[Upgrading an existing deployment](../docs/getting-started-gke.md#upgrading-an-existing-deployment).
|
|
51
51
|
|
|
52
|
+
`up.sh` works from its own one-cluster copy of the cluster's
|
|
53
|
+
kubeconfig context, so switching contexts in another terminal mid-deploy can't
|
|
54
|
+
send a step to another cluster. Run one deploy of a cluster at a time: a second
|
|
55
|
+
stops with `another operation (install/upgrade/rollback) is in progress`.
|
|
56
|
+
|
|
52
57
|
The Kubernetes launcher runs Codex and Claude Code coding workers; a Claude
|
|
53
58
|
Code pod adds a tool-runner sidecar with its own image. Configure an identity
|
|
54
59
|
provider and GitHub App before allowing people to use the public endpoint.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: errors/coding-mcp-gateway-unavailable
|
|
3
|
+
title: A coding run failed before launch because the native gateway did not wake
|
|
4
|
+
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.
|
|
5
|
+
audience: operator
|
|
6
|
+
tags: [error, mcp, coding-agents, low-power, coding_failure_mcp_gateway_unavailable, coding_mcp_gateway_unavailable]
|
|
7
|
+
appliesTo: ">=0.8.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# A coding run failed before launch because the native gateway did not wake
|
|
11
|
+
|
|
12
|
+
## What happened
|
|
13
|
+
|
|
14
|
+
The run's error starts with `coding_failure_mcp_gateway_unavailable`, followed
|
|
15
|
+
by a diagnostic id. It happens only in [low-power mode](../low-power-mode.md).
|
|
16
|
+
|
|
17
|
+
A coding run with MCP tools sends every MCP call through the coding proxy to
|
|
18
|
+
the native gateway (`wardby-native-gateway`). In low-power mode the gateway
|
|
19
|
+
may be scaled to zero, so before such a run launches, wardby wakes the gateway
|
|
20
|
+
together with the proxy and waits for a ready endpoint. The gateway did not
|
|
21
|
+
become ready in time, so wardby failed the run rather than start it without
|
|
22
|
+
its MCP tools. Nothing was launched, so the run made no changes.
|
|
23
|
+
|
|
24
|
+
The run's error contains only the code and the diagnostic id. The control
|
|
25
|
+
plane log has the cause at `warn`, under the same diagnostic id, with the
|
|
26
|
+
internal code `coding_mcp_gateway_unavailable` and the underlying wake error,
|
|
27
|
+
usually [`low_power_wake_timeout`](low-power-wake-timeout.md) or
|
|
28
|
+
[`low_power_scale_forbidden`](low-power-scale-forbidden.md).
|
|
29
|
+
|
|
30
|
+
## What to do
|
|
31
|
+
|
|
32
|
+
1. Search the control plane log for the diagnostic id and read the wake error.
|
|
33
|
+
2. For `low_power_wake_timeout`, check why the gateway pod did not become
|
|
34
|
+
ready: `kubectl -n <namespace> describe deployment wardby-native-gateway`
|
|
35
|
+
and the events of its pod. A cold Autopilot node can take a few minutes.
|
|
36
|
+
The wait is at least 5 minutes; for coding runs a
|
|
37
|
+
`KUBERNETES_READY_TIMEOUT_MS` above that, set on the control-plane
|
|
38
|
+
Deployment, raises it.
|
|
39
|
+
3. For `low_power_scale_forbidden`, re-run `up.sh` with `WARDBY_LOW_POWER=1` to
|
|
40
|
+
apply the `wardby-power` Role.
|
|
41
|
+
4. Trigger the agent again once the gateway is ready.
|
|
42
|
+
|
|
43
|
+
Runs without MCP tools do not wake the gateway and never fail this way.
|
|
44
|
+
|
|
45
|
+
See [Remote MCP servers for coding agents](../../docs/mcp-servers.md#coding-agents)
|
|
46
|
+
and [Low-power mode](../low-power-mode.md).
|
package/help/low-power-mode.md
CHANGED
|
@@ -3,7 +3,7 @@ id: low-power-mode
|
|
|
3
3
|
title: Low power mode on GKE
|
|
4
4
|
summary: Low power mode: scale the coding proxy and native gateway to zero when idle to cut the cost of a lightly used GKE deployment, and what changes when they wake.
|
|
5
5
|
audience: operator
|
|
6
|
-
tags: [gke, cost, low-power, scale-to-zero, kubernetes, autoscaling, idle, power_sleep, power_status, sleep now, power:manage]
|
|
6
|
+
tags: [gke, cost, low-power, scale-to-zero, kubernetes, autoscaling, idle, power_sleep, power_status, sleep now, power:manage, mcp, coding-agents]
|
|
7
7
|
appliesTo: ">=0.6.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -38,14 +38,20 @@ only when `WARDBY_LOW_POWER=1`.
|
|
|
38
38
|
- **Sleep.** Every minute the scheduler leader scales the coding proxy
|
|
39
39
|
(`wardby-coding-proxy`) or native gateway (`wardby-native-gateway`) to 0 when
|
|
40
40
|
nothing is pending or running for it and nothing finished within the idle
|
|
41
|
-
window.
|
|
41
|
+
window. For the gateway that means sandbox runs and coding runs with MCP
|
|
42
|
+
tools, and it also needs no active session. Either target sleeps only
|
|
42
43
|
once at least one idle window has passed since it was last woken (annotation
|
|
43
44
|
`wardby.io/power-woke-at`) and since the control plane started, whichever is
|
|
44
45
|
later. The check repeats just before scaling. Log: `power: proxy slept (idle 30m)`.
|
|
45
46
|
- **Wake.** A coding run scales the proxy to 1 and waits for a ready endpoint;
|
|
46
|
-
a sandbox run does the same for the gateway.
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
a sandbox run does the same for the gateway. A coding run with MCP tools
|
|
48
|
+
wakes both at once, because its MCP calls go through the gateway; if the
|
|
49
|
+
gateway does not wake it fails before launch with
|
|
50
|
+
[`coding_failure_mcp_gateway_unavailable`](errors/coding-mcp-gateway-unavailable.md).
|
|
51
|
+
The wait is at least 5 minutes.
|
|
52
|
+
A `KUBERNETES_READY_TIMEOUT_MS` (the proxy, and the gateway wake of a coding
|
|
53
|
+
run) or `NATIVE_SANDBOX_READY_TIMEOUT_MS` (the gateway wake of a sandbox run)
|
|
54
|
+
above that, set on the control-plane Deployment, raises it. Expect
|
|
49
55
|
about 1 to 2 minutes extra on a cold node. Log: `power: proxy woke`. A
|
|
50
56
|
sandbox run woken this way may then wait for a gVisor node for its worker
|
|
51
57
|
pod, so its first model call can come several minutes after it started. From
|
|
@@ -71,15 +77,17 @@ Pass `target: "proxy"` or `target: "gateway"` to sleep one; omit it for both.
|
|
|
71
77
|
|
|
72
78
|
- It scales the target to 0 at once, ignoring the idle window and the woke-at
|
|
73
79
|
grace.
|
|
74
|
-
- It never stops a run. A target with a pending or running run
|
|
75
|
-
gateway
|
|
80
|
+
- It never stops a run. A target with a pending or running run (for the
|
|
81
|
+
gateway, a sandbox run or a coding run with MCP tools), or for the gateway an
|
|
82
|
+
active gateway session, stays up, and its run ids are returned:
|
|
76
83
|
`{ "slept": ["proxy"], "blocked": [{ "target": "gateway", "runIds": ["..."] }] }`.
|
|
77
84
|
Recently finished runs do not block it.
|
|
78
85
|
- The next run wakes the target as usual.
|
|
79
86
|
- Each call is logged with `event: "power.sleep"` and the caller's principal.
|
|
80
87
|
|
|
81
88
|
`power_status` returns, for each target, `replicas`, `ready`, `wokeAt` and
|
|
82
|
-
`blockers` (the run ids keeping it busy
|
|
89
|
+
`blockers` (the run ids keeping it busy; for the gateway these include
|
|
90
|
+
pending or running coding runs with MCP tools).
|
|
83
91
|
|
|
84
92
|
Both tools need the `power:manage` scope, which only the `admin` role grants
|
|
85
93
|
(see [Identity and access](identity-and-access.md)). With the mode off,
|
|
@@ -111,6 +119,9 @@ full table.
|
|
|
111
119
|
|
|
112
120
|
- [`low_power_wake_timeout`](errors/low-power-wake-timeout.md): the target did
|
|
113
121
|
not become ready in time, or its Deployment does not exist.
|
|
122
|
+
- [`coding_failure_mcp_gateway_unavailable`](errors/coding-mcp-gateway-unavailable.md):
|
|
123
|
+
a coding run with MCP tools failed before launch because the gateway did not
|
|
124
|
+
wake.
|
|
114
125
|
- `native_sandbox_launch_abandoned` (0.7.0 and later): a sandbox run was
|
|
115
126
|
stopped while the gateway woke, so no worker pod was made.
|
|
116
127
|
- [`low_power_disabled`](errors/low-power-disabled.md): `power_sleep` was
|
package/help/mcp.md
CHANGED
|
@@ -33,3 +33,5 @@ From Wardby 0.8.0, Claude Code can show your runs in a pane beside the chat
|
|
|
33
33
|
through the `wardby-runs` plugin: run `wardby claude-plugin install`, then
|
|
34
34
|
`/wardby-runs`. Search help for "claude code plugin" (article
|
|
35
35
|
`claude-code-run-pane`, Wardby 0.8.0 and later).
|
|
36
|
+
|
|
37
|
+
To follow what a run is doing, call `get_run_steps` (article `run-steps`).
|
|
@@ -49,6 +49,10 @@ blob store nothing is stored, and `update_agent` warns you.
|
|
|
49
49
|
(default 10 MiB, at most 64 MiB). Each run records a status (`stored`,
|
|
50
50
|
`too_large`, `not_captured` or `failed`) with a reason code.
|
|
51
51
|
|
|
52
|
+
For a short line-per-step record of any run, without a blob store and without
|
|
53
|
+
continuing it, see `run-steps`; from 0.9.0 its `detail` level is a lighter way to
|
|
54
|
+
see tool output without a transcript.
|
|
55
|
+
|
|
52
56
|
## Who can read it
|
|
53
57
|
|
|
54
58
|
Transcripts are stored from the first run with `sessionResume` on. Anyone
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: run-steps
|
|
3
|
+
title: See what a run is doing (run steps)
|
|
4
|
+
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.
|
|
5
|
+
audience: operator
|
|
6
|
+
tags: [run steps, claude code run steps, get_run_steps, what is my run doing, WARDBY_RUN_STEPS, viewer step event]
|
|
7
|
+
appliesTo: >=0.9.0
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# See what a run is doing
|
|
11
|
+
|
|
12
|
+
Wardby records the steps of a run while it runs:
|
|
13
|
+
|
|
14
|
+
- one line for each **tool call**: the tool, and its command, file or first
|
|
15
|
+
argument, cut to about 100 characters, with its status once the result is
|
|
16
|
+
back (`ok`, `error`, or `exit N` for a command that exited with code N);
|
|
17
|
+
- one line for what the **model said**, cut to about 120 characters.
|
|
18
|
+
|
|
19
|
+
## Levels
|
|
20
|
+
|
|
21
|
+
| Level | Tool input | Tool result | Model text |
|
|
22
|
+
| --------- | -------------------- | --------------------------------------- | -------------------- |
|
|
23
|
+
| `off` | - | - | - |
|
|
24
|
+
| `summary` | about 100 characters | status only (`ok`, `error`, `exit N`) | about 120 characters |
|
|
25
|
+
| `detail` | up to about 4 KB | status and the last ~2 KB of its output | up to about 8 KB |
|
|
26
|
+
|
|
27
|
+
At `summary`, the default, tool output is never recorded. At `detail` each step
|
|
28
|
+
also keeps a **detail** text, at most 16 KB. When the output is cut at the
|
|
29
|
+
start, the partial first line is dropped if it ends within 256 characters;
|
|
30
|
+
otherwise only the first 256 characters are dropped, so a long single-line
|
|
31
|
+
output, such as a JSON result, keeps about its last 1.8 KB. At every level,
|
|
32
|
+
terminal escape sequences (colour codes, links, clipboard writes, title changes)
|
|
33
|
+
and every other control character except line breaks and tabs are removed from
|
|
34
|
+
step text before it is stored.
|
|
35
|
+
|
|
36
|
+
A run's level is the lower of two settings, fixed when the run is dispatched (a
|
|
37
|
+
change reaches later runs only; lowering the ceiling also stops detail for runs
|
|
38
|
+
already in flight):
|
|
39
|
+
|
|
40
|
+
- the instance's ceiling, `WARDBY_RUN_STEPS` (default `summary`);
|
|
41
|
+
- the agent's `runSteps` (`off`, `summary` or `detail`), set by the agent's
|
|
42
|
+
owner with `create_agent` or `update_agent`. Unset counts as `summary`. Set
|
|
43
|
+
`null` to clear it.
|
|
44
|
+
|
|
45
|
+
So `detail` needs both the operator and the agent's owner. If `runSteps` asks
|
|
46
|
+
for more than the instance allows, the value is stored, `update_agent` and
|
|
47
|
+
`get_agent` say so in `warnings`, and runs record at the ceiling.
|
|
48
|
+
|
|
49
|
+
> **Warning: `detail` stores tool output.** Before a step is stored, every
|
|
50
|
+
> secret value the run was given is removed and anything shaped like a token or
|
|
51
|
+
> key is masked. A secret that exists only inside a repository file, or another
|
|
52
|
+
> source the run read, and that matches no known shape, is not known to Wardby
|
|
53
|
+
> and can remain in the detail text. That is why detail is off unless both the
|
|
54
|
+
> operator and the agent's owner ask for it. Turn it on only for agents whose
|
|
55
|
+
> tool output you are prepared to keep for the retention period.
|
|
56
|
+
|
|
57
|
+
Steps are recorded for native runs (in the control plane and on the native
|
|
58
|
+
sandbox) and for Claude Code and Codex runs. Every agent's shell command shows
|
|
59
|
+
as `Bash`: a native agent's `run_command`, Claude Code's command tool, and
|
|
60
|
+
Codex's `exec_command`, `shell`, `local_shell` and `shell_command`. Another tool
|
|
61
|
+
shows under its own name (for example `apply_patch`), and a remote MCP tool as
|
|
62
|
+
`mcp:<tool>`.
|
|
63
|
+
|
|
64
|
+
A Claude Code or Codex run's final answer is one `said` step: the start of the
|
|
65
|
+
summary it returned (the pull request description), or `Finished` with the
|
|
66
|
+
outcome (for example `Finished: changes ready`) when it returned none.
|
|
67
|
+
|
|
68
|
+
For Claude Code and Codex runs, the coding proxy reads the steps from the
|
|
69
|
+
model's replies after relaying them and posts them to the server, which needs a
|
|
70
|
+
listener for them: `WARDBY_RUN_STEPS_LISTEN` on `wardby serve` and
|
|
71
|
+
`WARDBY_RUN_STEPS_URL` on the proxy. The reference GKE manifests set both; the
|
|
72
|
+
kind overlay sets only `WARDBY_RUN_STEPS_URL`, so set
|
|
73
|
+
`WARDBY_RUN_STEPS_LISTEN` on the host's `wardby serve`. Without either, coding
|
|
74
|
+
runs record no steps; native runs are not affected. A slow or unreachable listener loses steps; it never slows the run.
|
|
75
|
+
|
|
76
|
+
## Read the steps
|
|
77
|
+
|
|
78
|
+
- `get_run_steps` with `runId` lists a run's steps, oldest first, 50 at a time
|
|
79
|
+
(`limit`, at most 200). `next` is what to pass as `after` for the next page.
|
|
80
|
+
To follow a running run, call it again every few seconds with `after` set to
|
|
81
|
+
the last `seq` you have.
|
|
82
|
+
- `get_run` and `list_runs` (without `agentId`) include `lastStep`, the run's
|
|
83
|
+
newest step as one line, for example `Bash: npm test (exit 1)`.
|
|
84
|
+
- The `wardby-runs` Claude Code pane shows a running run's last steps and a
|
|
85
|
+
finished run's steps; see `claude-code-run-pane`.
|
|
86
|
+
- The admin viewer API sends a `step` event on `/admin/api/events` for each
|
|
87
|
+
step and status, and `GET /admin/api/runs/<id>` lists the run's newest 200
|
|
88
|
+
steps (see `admin-viewer`). The Wardby Viewer app shows them in a **Steps**
|
|
89
|
+
section of a run's detail.
|
|
90
|
+
|
|
91
|
+
At `detail`, `get_run_steps` also returns each step's `detail` to the agent's
|
|
92
|
+
owner and to the person who started the run (and to the stdio operator); anyone
|
|
93
|
+
else, including an admin who does not own the agent, gets the lines only. `lastStep`, the admin viewer API
|
|
94
|
+
and its `step` events never include detail.
|
|
95
|
+
|
|
96
|
+
You can read a run's steps when you can read the run with `get_run`.
|
|
97
|
+
|
|
98
|
+
A run records at most 2,000 steps. Later steps are not recorded; `dropped`
|
|
99
|
+
counts them.
|
|
100
|
+
|
|
101
|
+
## Secrets
|
|
102
|
+
|
|
103
|
+
Before a step is stored, Wardby removes every secret value the run's agent has
|
|
104
|
+
(its attached secrets, readable or brokered, and its MCP servers' secrets), the
|
|
105
|
+
run's own capability and registry token, and
|
|
106
|
+
anything shaped like a token or key. A command that echoes a secret shows
|
|
107
|
+
`[REDACTED]` in its place.
|
|
108
|
+
|
|
109
|
+
## Retention
|
|
110
|
+
|
|
111
|
+
Steps, and their detail, are deleted `RUN_STEP_RETENTION_DAYS` after they are
|
|
112
|
+
recorded (default 30). A change applies to steps recorded after it. `get_run_steps` reports `expired` when a run finished more than
|
|
113
|
+
`RUN_STEP_RETENTION_DAYS` ago and has no steps left.
|
|
114
|
+
|
|
115
|
+
## Settings
|
|
116
|
+
|
|
117
|
+
| Variable | Default | What it does |
|
|
118
|
+
| ------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
+
| `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. |
|
|
120
|
+
| `RUN_STEP_RETENTION_DAYS` | `30` | Days to keep a step, a whole number from 1 to 3650. Any other value stops start-up. |
|
|
121
|
+
| `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. |
|
|
122
|
+
| `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. |
|
|
123
|
+
|
|
124
|
+
Set `WARDBY_RUN_STEPS` (including `detail`) and `RUN_STEP_RETENTION_DAYS` on
|
|
125
|
+
every process that writes steps: `wardby serve`,
|
|
126
|
+
`wardby scheduler`, `wardby run`, `wardby mcp` and `wardby native-gateway`. The
|
|
127
|
+
coding proxy reads `WARDBY_RUN_STEPS` too: with `off`, or with
|
|
128
|
+
`WARDBY_RUN_STEPS_URL` unset, no step text leaves the proxy. For a coding
|
|
129
|
+
run's steps use `wardby serve` (the only process that runs the listener), not
|
|
130
|
+
the stdio `wardby mcp`.
|
|
131
|
+
|
|
132
|
+
For coding runs at `detail`, set `WARDBY_RUN_STEPS=detail` on the coding proxy
|
|
133
|
+
too: below `detail`, the proxy never sends any tool output to the server.
|
|
134
|
+
|
|
135
|
+
The listener is a second network path into the server, from the coding proxy
|
|
136
|
+
only; keep it off any load balancer. See
|
|
137
|
+
[Run steps](../docs/security-deployment.md#run-steps) for how to restrict it.
|
|
138
|
+
|
|
139
|
+
The full guide is
|
|
140
|
+
[Debugging agent runs](../docs/debugging-agent-runs.md#run-steps).
|
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- Run steps: one line per tool call or model message, and the count of steps past the per-run cap.
|
|
2
|
+
ALTER TABLE "Run" ADD COLUMN "stepsDropped" INTEGER NOT NULL DEFAULT 0;
|
|
3
|
+
|
|
4
|
+
CREATE TABLE "RunStep" (
|
|
5
|
+
"id" TEXT NOT NULL,
|
|
6
|
+
"runId" TEXT NOT NULL,
|
|
7
|
+
"seq" INTEGER NOT NULL,
|
|
8
|
+
"at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
9
|
+
"kind" TEXT NOT NULL,
|
|
10
|
+
"tool" TEXT,
|
|
11
|
+
"callId" TEXT,
|
|
12
|
+
"summary" TEXT NOT NULL,
|
|
13
|
+
"status" TEXT,
|
|
14
|
+
"detail" TEXT,
|
|
15
|
+
"expiresAt" TIMESTAMP(3) NOT NULL,
|
|
16
|
+
CONSTRAINT "RunStep_pkey" PRIMARY KEY ("id")
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
CREATE UNIQUE INDEX "RunStep_runId_seq_key" ON "RunStep"("runId", "seq");
|
|
20
|
+
|
|
21
|
+
CREATE INDEX "RunStep_runId_callId_idx" ON "RunStep"("runId", "callId");
|
|
22
|
+
|
|
23
|
+
CREATE INDEX "RunStep_expiresAt_idx" ON "RunStep"("expiresAt");
|
|
24
|
+
|
|
25
|
+
ALTER TABLE "RunStep" ADD CONSTRAINT "RunStep_runId_fkey"
|
|
26
|
+
FOREIGN KEY ("runId") REFERENCES "Run"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
-- Live run steps for the admin viewer (docs/viewer-api.md): a `step` event when a
|
|
2
|
+
-- step is recorded and when its status arrives. Only stored columns are sent:
|
|
3
|
+
-- the summary is already redacted when the row is written; the call id and the
|
|
4
|
+
-- detail text are never sent. Every other branch is unchanged.
|
|
5
|
+
CREATE OR REPLACE FUNCTION wardby_viewer_notify() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
6
|
+
DECLARE
|
|
7
|
+
payload jsonb;
|
|
8
|
+
BEGIN
|
|
9
|
+
IF TG_TABLE_NAME = 'Run' THEN
|
|
10
|
+
IF TG_OP = 'UPDATE'
|
|
11
|
+
AND NEW."status" IS NOT DISTINCT FROM OLD."status"
|
|
12
|
+
AND NEW."turns" IS NOT DISTINCT FROM OLD."turns"
|
|
13
|
+
AND NEW."costUsd" IS NOT DISTINCT FROM OLD."costUsd"
|
|
14
|
+
AND NEW."tokensIn" IS NOT DISTINCT FROM OLD."tokensIn"
|
|
15
|
+
AND NEW."tokensOut" IS NOT DISTINCT FROM OLD."tokensOut"
|
|
16
|
+
AND NEW."finishedAt" IS NOT DISTINCT FROM OLD."finishedAt"
|
|
17
|
+
AND NEW."parentRunId" IS NOT DISTINCT FROM OLD."parentRunId" THEN
|
|
18
|
+
RETURN NULL; -- heartbeat-only and other invisible updates
|
|
19
|
+
END IF;
|
|
20
|
+
payload := jsonb_build_object(
|
|
21
|
+
'kind', 'run', 'runId', NEW."id", 'parentRunId', NEW."parentRunId", 'agentId', NEW."agentId",
|
|
22
|
+
'status', NEW."status", 'turns', NEW."turns", 'tokensIn', NEW."tokensIn", 'tokensOut', NEW."tokensOut",
|
|
23
|
+
'costUsd', NEW."costUsd"::float8,
|
|
24
|
+
'finishedAt', to_char(NEW."finishedAt", 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'));
|
|
25
|
+
ELSIF TG_TABLE_NAME = 'CodingRunServiceStatus' THEN
|
|
26
|
+
payload := jsonb_build_object(
|
|
27
|
+
'kind', 'service', 'runId', NEW."runId", 'name', NEW."name", 'state', NEW."state", 'attempts', NEW."attempts");
|
|
28
|
+
ELSIF TG_TABLE_NAME = 'IssuePullRequest' THEN
|
|
29
|
+
payload := jsonb_build_object('kind', 'outcome', 'runId', NEW."openedByRunId", 'source', 'pull_request');
|
|
30
|
+
ELSIF TG_TABLE_NAME = 'RunHostStatus' THEN
|
|
31
|
+
payload := jsonb_build_object('kind', 'outcome', 'runId', NEW."runId", 'source', 'host_status');
|
|
32
|
+
ELSIF TG_TABLE_NAME = 'RunIssueStatus' THEN
|
|
33
|
+
payload := jsonb_build_object('kind', 'outcome', 'runId', NEW."runId", 'source', 'issue_status');
|
|
34
|
+
ELSIF TG_TABLE_NAME = 'RunHostCheck' THEN
|
|
35
|
+
payload := jsonb_build_object('kind', 'outcome', 'runId', NEW."runId", 'source', 'host_check');
|
|
36
|
+
ELSIF TG_TABLE_NAME = 'RunStep' THEN
|
|
37
|
+
IF TG_OP = 'UPDATE' AND NEW."status" IS NOT DISTINCT FROM OLD."status" THEN
|
|
38
|
+
RETURN NULL; -- only a step's status is shown as it changes
|
|
39
|
+
END IF;
|
|
40
|
+
payload := jsonb_build_object(
|
|
41
|
+
'kind', 'step', 'runId', NEW."runId", 'seq', NEW."seq", 'stepKind', NEW."kind", 'tool', NEW."tool",
|
|
42
|
+
'summary', NEW."summary", 'status', NEW."status",
|
|
43
|
+
'at', to_char(NEW."at", 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'));
|
|
44
|
+
ELSE
|
|
45
|
+
RETURN NULL;
|
|
46
|
+
END IF;
|
|
47
|
+
-- A viewer event must never fail the write that caused it (e.g. a payload
|
|
48
|
+
-- over NOTIFY's 8000-byte limit).
|
|
49
|
+
BEGIN
|
|
50
|
+
PERFORM pg_notify('wardby_viewer', payload::text);
|
|
51
|
+
EXCEPTION WHEN OTHERS THEN
|
|
52
|
+
NULL;
|
|
53
|
+
END;
|
|
54
|
+
RETURN NULL;
|
|
55
|
+
END;
|
|
56
|
+
$$;
|
|
57
|
+
|
|
58
|
+
CREATE TRIGGER "RunStep_viewer_notify" AFTER INSERT OR UPDATE ON "RunStep"
|
|
59
|
+
FOR EACH ROW EXECUTE FUNCTION wardby_viewer_notify();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- Run steps detail level: the owner's per-agent setting, the level fixed on each run at
|
|
2
|
+
-- dispatch, and the proxy session's copy of it. Additive, nullable: existing rows mean "unset".
|
|
3
|
+
CREATE TYPE "RunStepsLevel" AS ENUM ('off', 'summary', 'detail');
|
|
4
|
+
|
|
5
|
+
ALTER TABLE "Agent" ADD COLUMN "runSteps" "RunStepsLevel";
|
|
6
|
+
|
|
7
|
+
ALTER TABLE "Run" ADD COLUMN "runStepsLevel" "RunStepsLevel";
|
|
8
|
+
|
|
9
|
+
ALTER TABLE "CodingProxySession" ADD COLUMN "runStepsLevel" "RunStepsLevel";
|
package/prisma/schema.prisma
CHANGED
|
@@ -87,6 +87,9 @@ model Agent {
|
|
|
87
87
|
/// single-use worker container/pod. Each Run snapshots this at creation
|
|
88
88
|
/// (Run.nativeExecutionMode), so a change reaches only later runs.
|
|
89
89
|
nativeExecutionMode NativeExecutionMode @default(control_plane)
|
|
90
|
+
/// The owner's run steps level for this agent's runs; null = unset (summary). A run records
|
|
91
|
+
/// min(WARDBY_RUN_STEPS, this), fixed at dispatch (Run.runStepsLevel). Owner-only.
|
|
92
|
+
runSteps RunStepsLevel?
|
|
90
93
|
|
|
91
94
|
/// Un-phased: sub-agent composition edges (see AgentSubAgent below). An
|
|
92
95
|
/// agent can be a parent (has children it can delegate to) and/or a
|
|
@@ -144,6 +147,15 @@ enum AgentKind {
|
|
|
144
147
|
coding
|
|
145
148
|
}
|
|
146
149
|
|
|
150
|
+
/// Run steps level (docs/debugging-agent-runs.md#run-steps): off records nothing, summary one
|
|
151
|
+
/// redacted line per step, detail also a redacted detail text (tool input, the tail of tool
|
|
152
|
+
/// output, model text).
|
|
153
|
+
enum RunStepsLevel {
|
|
154
|
+
off
|
|
155
|
+
summary
|
|
156
|
+
detail
|
|
157
|
+
}
|
|
158
|
+
|
|
147
159
|
/// Where a native agent's runs execute (Agent.nativeExecutionMode).
|
|
148
160
|
enum NativeExecutionMode {
|
|
149
161
|
control_plane @map("control-plane")
|
|
@@ -400,6 +412,12 @@ model Run {
|
|
|
400
412
|
/// run through the server's executor and clears this.
|
|
401
413
|
stopRequestedAt DateTime?
|
|
402
414
|
stopRequestReason String?
|
|
415
|
+
/// Run steps (RunStep) not recorded because the run already had MAX_RUN_STEPS (2,000).
|
|
416
|
+
stepsDropped Int @default(0)
|
|
417
|
+
/// The run steps level this run records, fixed at dispatch: min(WARDBY_RUN_STEPS, Agent.runSteps
|
|
418
|
+
/// or summary). Null on runs from before the field (they record at most summary).
|
|
419
|
+
runStepsLevel RunStepsLevel?
|
|
420
|
+
steps RunStep[]
|
|
403
421
|
|
|
404
422
|
/// Un-phased: sub-agent dispatch (see AgentSubAgent). Null for a
|
|
405
423
|
/// top-level run; set when this run was created by a parent run's
|
|
@@ -652,6 +670,37 @@ model RunTranscript {
|
|
|
652
670
|
@@index([expiresAt])
|
|
653
671
|
}
|
|
654
672
|
|
|
673
|
+
/// One line of what a run did: a tool call (with its status once the result is back) or what the
|
|
674
|
+
/// model said. Derived by trusted code from model traffic and written only by the control plane's
|
|
675
|
+
/// RunStepWriter, after exact-value redaction against the run's secret values
|
|
676
|
+
/// (docs/debugging-agent-runs.md#run-steps). Never tool output at the summary level.
|
|
677
|
+
model RunStep {
|
|
678
|
+
id String @id @default(cuid())
|
|
679
|
+
runId String
|
|
680
|
+
run Run @relation(fields: [runId], references: [id], onDelete: Cascade)
|
|
681
|
+
/// Order within the run, from 1.
|
|
682
|
+
seq Int
|
|
683
|
+
at DateTime @default(now())
|
|
684
|
+
/// "tool" | "said"
|
|
685
|
+
kind String
|
|
686
|
+
/// The tool's display name (Bash for every agent's shell tool, mcp:<name>, Edit, ...); null for "said".
|
|
687
|
+
tool String?
|
|
688
|
+
/// The provider's call id (to attach the result), or a said:<key> id; never returned by MCP.
|
|
689
|
+
callId String?
|
|
690
|
+
/// Redacted, at most 300 characters.
|
|
691
|
+
summary String
|
|
692
|
+
/// ok | error | exit N, set when the result arrives.
|
|
693
|
+
status String?
|
|
694
|
+
/// The detail level's text: redacted tool input (~4 KB), then the last ~2 KB of its output once
|
|
695
|
+
/// the result is back, or the model's text (~8 KB). At most 16,384 characters. Null below detail.
|
|
696
|
+
detail String?
|
|
697
|
+
expiresAt DateTime
|
|
698
|
+
|
|
699
|
+
@@unique([runId, seq])
|
|
700
|
+
@@index([runId, callId])
|
|
701
|
+
@@index([expiresAt])
|
|
702
|
+
}
|
|
703
|
+
|
|
655
704
|
/// Coding-run services (docs/coding-services.md): the catalog a repository's
|
|
656
705
|
/// .wardby/services.yaml names entries from. Admin-managed over MCP
|
|
657
706
|
/// (list/get_service: agents:read; create/update/delete_service:
|
|
@@ -909,6 +958,9 @@ model CodingProxySession {
|
|
|
909
958
|
mcpTools Json?
|
|
910
959
|
/// SHA-256 (base64url) of the run's MCP token; null when the run has no MCP tools.
|
|
911
960
|
mcpTokenHash String? @unique
|
|
961
|
+
/// The run's Run.runStepsLevel, copied at session creation: the proxy sends a tool result's
|
|
962
|
+
/// output tail to the run-steps listener only at detail. Null on older sessions (= summary).
|
|
963
|
+
runStepsLevel RunStepsLevel?
|
|
912
964
|
/// MCP tools/call count for this run (capped by WARDBY_MCP_MAX_CALLS_PER_RUN).
|
|
913
965
|
mcpCallCount Int @default(0)
|
|
914
966
|
|