You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Preview JSON suppresses presentation notes. If a repair check has an advisory
196
+
note, the human preview can print it, but JSON consumers should use `findings`,
197
+
`changes`, `warnings`, `effects`, `diffs`, and `skipped`.
198
+
117
199
Exit behavior:
118
200
119
201
-`0`: no findings at or above the selected severity threshold
@@ -124,35 +206,41 @@ Exit behavior:
124
206
example, `openclaw doctor --lint --severity-min error` can print no findings and
125
207
exit `0` even when lower-severity `info` or `warning` findings exist.
126
208
127
-
## Structured Health Checks
209
+
## Structured health checks
128
210
129
211
Modern doctor checks use a small structured contract:
130
212
131
213
```ts
132
-
detect(ctx, scope?) ->HealthFinding[]
133
-
repair?(ctx, findings) ->HealthRepairResult
214
+
run(ctx) ->HealthCheckRunResult
134
215
```
135
216
136
-
`detect()` powers `doctor--lint`. `repair()` is optional and is only considered
137
-
by `doctor--fix` / `doctor--repair`. Checks that have not migrated to this
138
-
shape continue to use the legacy doctor contribution flow.
217
+
The main branch in the contract is `ctx.repair`:
218
+
219
+
-`ctx.repair === false`: inspect state and return findings plus any repair
220
+
plan that can be computed without mutation.
221
+
-`ctx.repair === true`: inspect the same state, return the same structured
222
+
plan, and apply the repair when possible.
223
+
224
+
Checks that are naturally analysis-first can still use the split
225
+
`detect(ctx)`/`repair(ctx, findings)` adapter. The registry normalizes both
226
+
styles to the same `run(ctx)` shape before the runner presents lint, preview,
227
+
diff, JSON, or fix output.
139
228
140
-
The split is intentional: `detect()` owns diagnosis, while `repair()` owns
141
-
reporting what it changed or would change. Repair contexts can carry
142
-
`dryRun`/`diff` requests, and repair results can return structured `diffs` for
143
-
config/file edits plus `effects` for service, process, package, state, or other
144
-
side effects. That lets converted checks grow toward `doctor--fix--dry-run`
145
-
and diff reporting without moving mutation planning into `detect()`.
229
+
Repair results can return structured `diffs` for config/file edits plus
230
+
`effects` for service, process, package, state, or other side effects. Lint
231
+
reads findings from the non-mutating run, repair preview reads the returned
232
+
plan, and fix applies only when `ctx.repair` is true.
146
233
147
-
`repair()` reports whether it attempted the requested repair with `status:
148
-
"repaired"|"skipped"|"failed"`. Omitted status means `repaired`, so simple
149
-
repair checks only need to return changes. When repair returns `skipped` or
150
-
`failed`, doctor reports the reason and does not run validation for that check.
234
+
A non-mutating repair plan returns `status: "repairable"`. Applied repair
235
+
results use `"repaired"`, `"skipped"`, or `"failed"`. When a repair returns
236
+
`skipped` or `failed`, doctor reports the reason and does not run validation for
237
+
that check.
151
238
152
-
After a successful structured repair, doctor re-runs `detect()` with the
153
-
repaired findings as scope. Checks can use selected findings, paths, or `ocPath`
154
-
values for focused validation. If the finding is still present, doctor reports a
155
-
repair warning instead of treating the change as silently complete.
239
+
Detect-after validation is opt-in for the repair runner. When enabled after a
240
+
successful structured repair, doctor re-runs the check with the repaired
241
+
findings as scope. Checks can use selected findings, paths, or `ocPath` values
242
+
for focused validation. If the finding is still present, doctor reports a repair
243
+
warning instead of treating the change as silently complete.
156
244
157
245
A finding includes:
158
246
@@ -190,9 +278,9 @@ Notes:
190
278
- In Nix mode (`OPENCLAW_NIX_MODE=1`), read-only doctor checks still work, but `doctor --fix`, `doctor --repair`, `doctor --yes`, and `doctor --generate-gateway-token` are disabled because `openclaw.json` is immutable. Edit the Nix source for this install instead; for nix-openclaw, use the agent-first [Quick Start](https://github.com/openclaw/nix-openclaw#quick-start).
191
279
- Interactive prompts (like keychain/OAuth fixes) only run when stdin is a TTY and `--non-interactive` is **not** set. Headless runs (cron, Telegram, no terminal) will skip prompts.
192
280
- Performance: non-interactive `doctor` runs skip eager plugin loading so headless health checks stay fast. Interactive doctor sessions still load the plugin surfaces needed by the legacy health and repair flow.
-`--lint` is stricter than `--non-interactive`: it is always read-only, never prompts, and never applies safe migrations. Run `doctor --fix --dry-run` when you want a repair plan, or `doctor --fix` /`doctor --repair` when you want doctor to make changes.
194
282
-`--fix` (alias for `--repair`) writes a backup to `~/.openclaw/openclaw.json.bak` and drops unknown config keys, listing each removal.
- Modernized health checks can expose repair plans through `run(ctx)` for `doctor --fix`, `--dry-run`, and `--diff`; checks that do not expose one continue through the existing doctor repair flow.
196
284
-`doctor --fix --non-interactive` reports missing or stale gateway service definitions but does not install or rewrite them outside update repair mode. Run `openclaw gateway install` for a missing service, or `openclaw gateway install --force` when you intentionally want to replace the launcher.
197
285
- State integrity checks now detect orphan transcript files in the sessions directory. Archiving them as `.deleted.<timestamp>` requires an interactive confirmation; `--fix`, `--yes`, and headless runs leave them in place.
198
286
- Doctor also scans `~/.openclaw/cron/jobs.json` (or `cron.store`) for legacy cron job shapes and can rewrite them in place before the scheduler has to auto-normalize them at runtime.
0 commit comments