gws doctor
Run programmatic checks against the GetWebstack failure-mode catalog. This is the diagnose step in the /gws-setup and /gws-debug loops — it's how the AI knows what to fix.
Two tiers of checks:
- Artifact checks (always run today) — look at
gws.json, generated Dockerfiles, and K8s manifests for known foot-guns:USERdirective in a Dockerfile, server bound to127.0.0.1, port mismatch between DockerfileEXPOSE/gws.jsonport/ K8scontainerPort, multi-stage / distroless base image (breaks file sync), placeholder values left in generated artifacts. - Cluster checks (Phase 3b — registry shipped, command wiring still landing) —
CrashLoopBackOfflog fetch + diagnosis from a regex catalog, pod ↔ service selector mismatch, HTTP probe failures with status codes, file-sync session / exec-probe / log-error rules.
The cluster rule registry is fully populated, but gws doctor itself currently invokes only the artifact runner — so today the command behaves as if --artifacts-only were always set, regardless of the flag. The flag surface (-p, -w, --all-worktrees) is wired ahead of the runner switch.
Usage
gws doctor [options]
| Flag | Description | Default |
|---|---|---|
-p, --project <name> | Project to diagnose. | inferred from gws.json in cwd |
-w, --worktree <name> | Worktree to diagnose. | active worktree |
--all-worktrees | Diagnose every worktree of the current project. (No-op in Phase 3a — wired ahead of cluster checks.) | false |
--service <name> | Limit checks to one service. | all services |
--artifacts-only | Skip cluster checks. | false (true today; see above) |
--json | Emit machine-readable JSON instead of human text. | false |
Auth: not required.
Exit code
| Code | Meaning |
|---|---|
0 | No errors (warnings allowed) |
1 | At least one finding with severity error |
That makes gws doctor safe to drop into a CI step — fail the build if gws config import produced anything broken.
Output
Human:
Ran 1 check: 1 error, 0 warnings.
ERROR [api] dockerfile.user-directive .gws/services/api/Dockerfile:14
USER directive in Dockerfile breaks bidirectional file sync.
fix: Remove the USER line — dev-mode containers run as root by design.
JSON (--json):
{
"summary": { "checked": 1, "errors": 1, "warnings": 0 },
"findings": [
{
"severity": "error",
"check": "dockerfile.user-directive",
"service": "api",
"file": ".gws/services/api/Dockerfile",
"line": 14,
"message": "USER directive in Dockerfile breaks bidirectional file sync.",
"fix": "Remove the USER line — dev-mode containers run as root by design."
}
]
}
Findings are ordered errors-first, then warnings, preserving discovery order within a tier.
Common findings
Check IDs are stable and namespaced — safe to grep / filter on. Live source: gws/src/libs/doctor/rules.ts (artifact rules) and gws/src/libs/doctor/cluster/ (cluster rules).
Artifact rules (always run):
| Check id | Symptom | Suggested fix |
|---|---|---|
dockerfile.user-directive | Container exits immediately on dev-mode start. | Remove the USER directive. |
dockerfile.multi-stage-minimal-runtime | File sync silently doesn't work. | Switch to single-stage with the source in the final image. |
dockerfile.distroless-base | File sync silently doesn't work. | Use a full base image (no distroless/scratch). |
dockerfile.port-mismatch | Service URL returns 502/503. | Make Dockerfile EXPOSE, gws.json port, and K8s containerPort agree. |
source.localhost-bind | Pod runs but Service can't reach it. | Bind to 0.0.0.0. |
artifact.placeholder | Generated artifact still contains {{…}} placeholders or is missing. | Re-run gws generate-template / fill in the placeholder. |
Cluster rules (registered; runner wiring in progress — see top of page):
| Check id | What it catches |
|---|---|
cluster.crashloop | CrashLoopBackOff, fetches logs and tags from the regex catalog. |
cluster.selector-mismatch | Pod labels don't match the Service selector. |
cluster.http-probe | Service URL probe failed; reports the HTTP status. |
cluster.file-sync.session | gws-file-sync SSH sidecar isn't reachable. |
cluster.file-sync.exec-probe | File-sync exec probe failed inside the pod. |
cluster.file-sync.log-errors | Sync sidecar emitted error logs. |
Examples
# Diagnose everything
gws doctor
# JSON — for /gws-debug and CI
gws doctor --json
# Limit to one service
gws doctor --service api --json
# Pre-import gate
gws doctor --artifacts-only && gws config import gws.json && gws up
See also
- Zero-Config Setup with AI —
/gws-setupcallsgws doctor --jsonaftergws upand iterates on findings gws status— for live cluster state (until cluster checks land here)gws config validate— schema-only check, no other artifact rules