Skip to content

feat(doctor): wire into the 9 per-type templates, the Windows dispatcher, and the plugin-path SKILL.md - #660

Open
fujibee wants to merge 2 commits into
mainfrom
doctor-wiring
Open

feat(doctor): wire into the 9 per-type templates, the Windows dispatcher, and the plugin-path SKILL.md#660
fujibee wants to merge 2 commits into
mainfrom
doctor-wiring

Conversation

@fujibee

@fujibee fujibee commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Wires doctor (default = whole install, --project/--type/--team/--redacted) into the command reference every install path deploys. doctor itself already shipped (#654); this PR is purely wiring, no behavior changes to doctor.sh.

Addresses part of #267.

Why 11 files, not 9 or 10

There are two separate install paths, each deploying its own copy of the command reference, and both needed wiring:

  1. ./install.sh deploys scripts/drivers/types/<type>/template.md, one per agent type — 9 files (agmsg-app has no template; it's spawnable=no, the desktop app's own identity, not a spawnable CLI type, so it's correctly excluded, not a 10th type I missed).
  2. The Claude Code plugin-marketplace install path does not run install.sh at all — it drops this repo's root SKILL.md straight into ~/.claude/plugins/cache/ as the deployed skill content (see SKILL.md's own Step 0 comment). This is a 10th file, easy to miss by only looking at install.sh's deployment tree.

Plus scripts/windows/dispatch.sh (the one dispatch/router file in the repo, confirmed via tests/test_dispatch.bats as its regression coverage) — 11th file.

Checklist — please verify all 11 are present and non-trivially changed:

  • scripts/drivers/types/antigravity/template.md
  • scripts/drivers/types/claude-code/template.md
  • scripts/drivers/types/codex/template.md
  • scripts/drivers/types/copilot/template.md
  • scripts/drivers/types/cursor/template.md
  • scripts/drivers/types/gemini/template.md
  • scripts/drivers/types/grok-build/template.md
  • scripts/drivers/types/hermes/template.md
  • scripts/drivers/types/opencode/template.md
  • scripts/windows/dispatch.sh
  • SKILL.md (repo root — the plugin-path deployed copy, not a per-type template)

Mechanical check used while writing this: grep -c doctor <file> on all 11 before/after — every target went from 0 mentions to a non-zero count; no target already mentioned doctor beforehand (no partial/stale-reference risk).

What each file gets

The 9 templates: a bare doctor bullet in the post-join command summary, plus an argument-dispatch block. Each matches that template's own existing conventions (invocation prefix — /__SKILL_NAME__ vs $__SKILL_NAME__; hermes's natural-language "ask X" phrasing instead of a slash form) rather than one block copy-pasted into all nine — a template that doesn't match its own type's conventions can still pass CI silently.

Every dispatch block documents bare doctor (no flags) as the normal form, with --project/--type/--team/--redacted described as optional narrowing — not the headline usage — since the default scope is already the whole installation.

scripts/windows/dispatch.sh: a doctor case that passes its argv straight through, with no identity resolution. doctor needs no TEAM/AGENT, and this dispatcher's own --project/--type/--team globals serve a different purpose (identity-resolution context for other commands) than doctor's own same-named scope flags — conflating them would silently change what a Windows user's --project/--type meant depending on which subcommand followed. Two new tests in tests/test_dispatch.bats cover: no-identity-needed default scan, and flags passing through untouched by the dispatcher's own globals.

SKILL.md (root): one addition to the "Shell (any agent)" command block, written in that section's own existing prose-comment style, not the templates' numbered-dispatch style — it's a different kind of document (a distributed end-product, not a per-type instruction template), so it follows its own existing shape rather than the templates'.

Testing

  1. bats tests/test_doctor.bats — 35 ok, 0 not ok (unchanged from feat(doctor): default to the whole installation, filter with --project/--type/--team #654; doctor.sh itself is untouched by this PR).
  2. bats tests/test_dispatch.bats — 8 ok, 0 not ok (6 pre-existing + 2 new for the doctor case).
  3. bats tests/test_delivery.bats — adjacent suite, all green.
  4. Packaging smoke: ran install.sh into an isolated HOME, confirmed the deployed claude-code/template.md mentions doctor and the deployed scripts/windows/dispatch.sh routes -- doctor to the real doctor.sh, reporting a clean empty installation end-to-end.

fujibee added 2 commits August 7, 2026 14:46
…her, and the plugin-path SKILL.md

Two install paths deploy separate copies of the command reference, and both
needed wiring:
  - ./install.sh deploys scripts/drivers/types/<type>/template.md per type
    (9 types; agmsg-app has no template -- it's spawnable=no, the desktop
    app's own identity, not a spawnable CLI type).
  - The Claude Code plugin-marketplace install path does not run install.sh
    at all -- it drops this repo's root SKILL.md straight into
    ~/.claude/plugins/cache/ as the deployed skill content. Missing this
    would have meant plugin-installed users never saw doctor mentioned
    anywhere. Found and reported mid-implementation, not assumed from the
    9-template + dispatcher enumeration alone.

Each of the 9 templates gets a bare `doctor` bullet in the post-join command
summary and an argument-dispatch block, matching that template's own
existing conventions (invocation prefix, "ask X" vs slash-command phrasing)
rather than one copy-pasted block -- a template that doesn't match its own
type's conventions can still pass CI. Every dispatch block documents bare
`doctor` (no flags) as the normal form and --project/--type/--team/--redacted
as optional narrowing, not the headline usage, since the default scope is
already the whole installation.

scripts/windows/dispatch.sh gets a `doctor` case that passes its argv
straight through with no identity resolution -- doctor needs no TEAM/AGENT,
and this dispatcher's own --project/--type/--team globals serve a different
purpose (identity-resolution context for other commands) from doctor's
same-named scope flags.

Root SKILL.md gets one addition to its "Shell (any agent)" style command
block, written in that file's own existing prose-comment style rather than
the templates' numbered-dispatch style, per its own established shape.

Confirmed via grep that no target already mentioned "doctor" before this
change (no partial/stale reference risk), and verified the deployed
artifact end-to-end after a real install.sh run into an isolated HOME:
the Windows dispatcher's `doctor` case reaches the real doctor.sh and
reports a clean, empty installation correctly.
…ity/join gate

co2's review of #660 caught a real placement bug: every template's (and
root SKILL.md's) doctor dispatch lived inside the argument-handling section
that comes AFTER the mandatory Identity gate -- whoami.sh first, and if
not_joined=true, a full interactive join flow ("You MUST use join.sh")
before ever reaching Execute. Two consequences:

- On a fresh/empty installation, asking for "doctor" started first-time
  team setup instead of running the diagnostic.
- On an installation where registration resolution itself is broken (whoami
  fails), doctor was permanently unreachable -- exactly the situation it
  exists to diagnose.

Fixed by adding an explicit branch before the Identity section (before
Step 1 in root SKILL.md) in all 10 documents: if the argument is "doctor",
skip whoami.sh and the join flow entirely, go straight to the existing
doctor dispatch under Execute, and stop. The Execute-section block itself
is untouched -- this only changes precedence, not what doctor.sh gets
called with.

scripts/windows/dispatch.sh was not affected: its `doctor)` case already
never calls resolve_identity (confirmed by re-reading the dispatch table,
not just by the existing passing tests).

Verified mechanically for all 10 (9 templates + SKILL.md): the new
precedence note's line number is before the Identity/Step-1 heading's line
number in every file, not just present somewhere in the document.
@fujibee

fujibee commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Why this cannot simply be retargeted to integration/remote

Releases are currently cut from integration/remote (rc.1 → rc.3), and this PR
plus #661 target main. Retargeting them as-is would document an interface the
shipping branch does not have.

main holds exactly one commit that integration/remote does not:

$ git merge-base --is-ancestor origin/main origin/integration/remote ; echo $?
1
$ git rev-list --count origin/integration/remote..origin/main
1
$ git log origin/integration/remote..origin/main --format='%h %s'
4d3202d feat(doctor): default to the whole installation, narrow with --project/--type/--team (#654)

That commit is the one that changed doctor's interface. The two branches parse
different arguments today:

$ git show "origin/integration/remote:scripts/doctor.sh" | grep -nE '^# Usage|--project|--redacted\)'
6:# Usage: doctor.sh <project_path> <agent_type> [--redacted]
52:    --redacted) REDACTED=1; shift ;;
53:    *) echo "doctor: unknown option: $1" >&2; exit 2 ;;

$ git show "origin/main:scripts/doctor.sh" | grep -nE '^# Usage|--project\)'
6:# Usage: doctor.sh [--project <path>] [--type <type>] [--team <team>] [--redacted]
65:    --project)

So on integration/remote, --project / --type / --team are rejected as
unknown options, and the positional project path and agent type are required.

This PR's wiring — and #661's README/llms.txt text — describe bare doctor as
the normal form and the three flags as the way to narrow it. That description is
accurate for main and wrong for integration/remote.

Ordering

#654 has to reach integration/remote before the wiring or the human-facing
docs land there, or the documentation ships ahead of the implementation. Merges
in that direction already exist (#657, 0672a2c, 1f24501), so the mechanism
is routine; only the ordering matters.

Either sequence works:

  1. #654 merges into integration/remote first, then fix(install): refuse to guess between multiple installs on --update with no --cmd #659/feat(doctor): wire into the 9 per-type templates, the Windows dispatcher, and the plugin-path SKILL.md #660/docs: cover doctor on the human-facing surfaces (README, README.ja, llms.txt) #661 retarget; or
  2. fix(install): refuse to guess between multiple installs on --update with no --cmd #659/feat(doctor): wire into the 9 per-type templates, the Windows dispatcher, and the plugin-path SKILL.md #660/docs: cover doctor on the human-facing surfaces (README, README.ja, llms.txt) #661 merge into main, and the next mainintegration/remote
    merge carries all of it together.

Both routes pass through a merge into or out of main, which is not something a
seat can perform.

Measured, not run

The above is read from the two trees' argument parsing. Neither version was
executed for this note.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant