feat: behold doctor — the read-only first-touch diagnosis (#236) - #244
Merged
Conversation
Seven lines, each pass/warn/fail with a one-line fix: the project's kind (chant project, estate root, neither), the chant install behold will actually shell and its version against behold's declared floor, declared lexicons against what's installed, the envs the picker will infer, the kube context chant binds versus the ambient one, substrate readiness without starting a server, and committed Ops plus whether chant's MCP is reachable at all. Exit 0 iff nothing failed; `--json` for machines. A reuse surface, not new probing: every fact comes from the module the server already reads it from. Three pieces of detection that were missing went into the shared modules rather than into doctor — `detectProjectShape` (project.ts: chant.config.* / `.behold.json` members / npm workspaces), which `cli.ts`'s startup warning now shares so an estate root gets the member list instead of "no chant.config.ts"; and `resolveChant`/`resolveLexicons`/`chantFloor`/`meetsFloor` (chant.ts), with `chantBin` re-expressed through the first of them. `resolveChant` compares package roots, not requires, to tell the project's own chant from behold's fallback: Node resolution walks up parent directories, so every bundled example resolves behold's chant without having one, and the check that exists to catch a missing install would have missed it. The severity split is the point. A fail stops behold serving the project (no chant in the project's node_modules is the common first-touch one). A warn costs the live half, not the graph — no envs, no cluster binding, a down emulator — so a k8s project with no kube context warns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 10, 2026
lex00
added a commit
that referenced
this pull request
Aug 10, 2026
#249) (#251) Six dependabot alerts (five hono, one @hono/node-server) all had compatible fixes — hono ^4.6.0 → ^4.12.34 stays within its major, @hono/node-server ^1.13.0 → ^2.0.5 needed a major bump (no fix landed on 1.x) but its only two breaking changes don't touch us: Node ≥20 (CI already pins 24) and the removed Vercel adapter (never imported). Reasoning and the alert table are recorded as a comment on #248. Docs freshness: example-argo-estate/README.md's logical-lens bullet still described the control-plane-alone view as the headline from before behold#224 taught the composed estate to draw the projection — reworded to lead with the composed picture. example-flux-estate/README.md and AGENTS.md were checked against current src/server.ts behavior and are already accurate (fixed by #241 and #244 respectively, no change needed). Root README's painter section gained three paragraphs — lexicon-native icons (#227), hand layout (#228), the identity pass (#229) — the only features among the four named in #249 with zero prior README coverage; doctor (#236) already has one. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #236.
behold doctor [dir] [--json]— a read-only console report of everything behold needs to serve a project well. Seven lines, each pass/warn/fail with a one-line fix, exit 0 iff nothing failed.The checks
detectProjectShape(project.ts)resolveChant(chant.ts)resolveLexicons(chant.ts)detectProjectloadKubeconfig+resolveK8sTarget(k8s-target.ts)detectSubstrates(substrates.ts)discoverEstateOps(ops.ts)A fail is something that stops behold serving the project. A warn costs the live half — which is why a k8s project with no kube context warns rather than fails, per the acceptance list.
Reuse, not new probing
Every fact comes from the module the server already reads it from — including
k8s-target.tsexactly as-is (nochant-k8s-client; #231 stays its own lane). Where a check needed detection the server didn't have, the logic went into the shared module:project.ts—detectProjectShape(chant.config.* /.behold.jsonmembers/ npmworkspaces) andchantConfigPath.cli.ts'swarnIfNotChantProjectnow shares it, sobehold serveon an estate root points at the members instead of reporting a missing chant.config.ts.chant.ts—resolveChant/resolveLexicons/chantFloor/meetsFloor, withchantBinre-expressed throughresolveChantandchantBinFromkept as a wrapper over the newchantPackageFrom.resolveChantcompares package roots, not requires, to tell the project's own chant from behold's fallback. Node resolution walks up parent directories, so every bundled example resolves behold's chant without having one of its own — reported as "the project's", the check would have missed the exact missing install it exists to catch.Estates are diagnosed across their members: per-member chant and lexicon lines, unioned envs and lexicons,
discoverEstateOpsfor the Ops, and the serve hint names the members rather than the unservable root.Tests
src/doctor.test.ts— healthy project (all pass), no-project dir (single fail + fix), missing install (fail namingnpm install), k8s with no context (warn), bound context resolved, ambient/declared mismatch, down substrate, no envs, no Ops, estate via.behold.jsonand via workspaces. Plus a--jsonshape test (key order, one check per name, fix present iff not pass) and an inline snapshot of the console output. Fixtures are built in the OS tmpdir and cleaned up —example-writes' node_modules is absent in a fresh checkout and present afterjust example-install, so a test keyed on either state would pass half the time. The two live probes (kubeconfig, substrates) are injected, so nothing depends on the host's Docker or kubeconfig.Docs: README quickstart, AGENTS.md discovery step, and the "Open your own project" docs page.
just checkgreen.🤖 Generated with Claude Code