Skip to content
Back to skills

Omd Doctor

ASecurity

Diagnose an oh-my-dsh installation — host version, registration counts, Config model resolvability, MCP smoke, .omd/ writability, probe matrix — as a checklist table with fix suggestions

  • 8 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 13, 2026
ai-agentsgoshellnodegitapibackend

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 13, 2026

npx -y skills add 1225Sakura/oh-my-deepseekharness --skill omd-doctor --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Omd Doctor?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Omd Doctor
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/1225sakura-omd-doctor/badge)](https://www.skillsdirectory.com/skills/1225sakura-omd-doctor)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: omd-doctor
description: Diagnose an oh-my-dsh installation — host version, registration counts, Config model resolvability, MCP smoke, .omd/ writability, probe matrix — as a checklist table with fix suggestions
when-to-use: Invoked via the `/omd-cancel`-sibling command `/omd-doctor` (the command is a thin shell that loads this skill), or when the user asks to verify/diagnose their omd installation ("doctor", "check omd", "omd not working"). Not a substitute for E2E release gates.
---

# omd-doctor

Original omd skill — the diagnostic brain behind the `/omd-doctor` command (the command is a thin forwarder; this skill is the single source of truth, spec §6.3). Runs a fixed checklist, prints one result table, and gives a fix suggestion for every failing item.

## How to run the checks

Work through the checklist in order. Every check lands in the final table with a status: ✅ pass / ⚠️ warning / ❌ fail. A ❌ or ⚠️ row MUST carry a concrete fix suggestion.

### 1. Host version vs peerDependencies

- Determine the running dsh host version (session runtime context, or the installed `@deepseek-ai/dsh-*` package versions).
- Compare against the plugin's peerDep ranges (**authoritative source = omd `package.json` peerDependencies**; since 0.4.3 they cover the 0.1.2/0.1.5/0.1.7 legacy lines plus the 0.2.0-rc line: `>=0.1.2-rc.1 <0.1.3 || >=0.1.5-rc.1 <0.1.6 || >=0.1.7-rc.1 <0.2.0 || >=0.2.0-rc.1 <0.3.0`).
- **Actually evaluate satisfies (guards against silent rc-line drift, U9 S-4)**: substitute the real host version into each peerDependencies range and evaluate satisfies (e.g. `node -e` with semver, or manual comparison against version samples); if the host version satisfies none of them → ⚠️ "host version outside the declared compat ranges" (the npm test sample matrix cannot cover future unlisted rc lines — this check is the runtime backstop).
- Below the ranges → ❌ (fix: upgrade dsh, or accept best-effort degraded operation — omd warns but does not refuse to load, spec §6.1). Outside the declared ranges (newer) → ⚠️ "newer than declared compat ranges".

### 2. Registration counts

Count what is actually visible in this session and compare with expectations:

| Item | Expected | How to count |
|---|---|---|
| Skills | **44** (full roster in `tests/assets/skills.test.js` EXPECTED) | session skill catalog |
| Role cards | **33** `omd-agent-*` (roster in `tests/assets/agents.test.js` TIERS) | skill catalog entries prefixed `omd-agent-` |
| Commands | **2** (`/omd-doctor`, `/omd-cancel`) | command list |
| Plugin tools | **4** (`omd_memory_set/get/delete` + `omd_delegate`) | tool list |
| MCP tools | **49** `mcp__omd-state__*` (state×5, notepad×6, prd×4, handoff×3, team×16, trace×4, hud×2, codeintel×9) | tool list prefix count |

Any shortfall → ❌ with the missing names (fix: check that `assets/skills` / `assets/agents` shipped intact and the loader registered them with `source: 'oh-my-dsh'`; check cordis.patch.yml mount). **When the memory tools (omd_memory_*) are missing**: check that omd's `inject` declaration includes `storage` and that the current profile is base-backed (dsh-base mounts the dsh-storage trio — a non-base profile missing storage is expected degradation) — this is an omd-declaration/profile-layer matter, not a host defect.

### 3. Config model identifier resolvability

- Read the effective omd Config: `tiers.low/medium/high` and any `roleOverrides` — read the effective values from the model routing table in the omd protocol section of the system prompt (the model cannot read plugin Config directly).
- For each configured value: `inherit` is always valid; anything else must be resolvable as a model identifier by the host LLM service.
- **Verify empirically (U9 2g-C — do not judge statically)**: use `list_subagent_models` — list providers, then each provider's model catalog, then probe each non-`inherit` tiers/roleOverrides value as an exact model; "not allowed" / absent from the catalog → treat as unresolvable. Hard-won evidence (2026-10-12, dsh 0.2.0-rc.2): the default `glm-5.3-flash` is not in this deployment's sakura provider allowlist (k3/MiniMax-M3 only), and `omd_delegate` hard-routed to it died twice with `stopReason=error`; workarounds = subagent inheriting the main session, or passing an explicitly allowed provider/model.
- Unresolvable identifier → ❌ (fix: correct the identifier in the plugin config, or set it to `inherit` to follow the main session model). Note the MVP caveat: model routing is hard only on the `workflow`/`omd_delegate` paths; `subagent` inherits the main session (soft routing), so a broken identifier degrades rather than crashes there.

### 4. MCP server smoke

- Call `mcp__omd-state__state_get_status` once. A structured response (even "no active modes") → ✅.
- Tool missing or call fails → ❌ (fix: check the MCP mount in cordis.patch.yml / the dynamic mount in `apply()`; `failOnStartupError: false` means a dead server fails silently — look for the degradation announcement in the protocol layer; reconnect is the host mcp-client's job).

### 5. `.omd/` writability + .gitignore

- Write and delete a probe file under `.omd/` (e.g. `.omd/.doctor-probe`) to prove writability. Not writable → ❌ (fix: directory permissions; on read-only workspaces expect full degradation to conversation-only operation).
- Check `.gitignore` covers `.omd/`. Missing → ⚠️ (fix: add `.omd/` to `.gitignore` — omd suggests but never edits user files unprompted, spec §5.5).

### 6. Probe four-state overview

Render the capability probe results (protocol-layer probe.js + apply-time additions) as a table — one row per item with its four-state result:

| Probe item | ok / unavailable / failure / timeout | Detail |
|---|---|---|
| core (four inject services) | … | … |
| `ctx.storage` backend (domain-API shape check) | … | … |
| hooksBridge (phase-2 prerequisite, M3 keyword hooks — unavailable is NOT a degradation) | … | … |
| mcpServer (apply-time dynamic mount result: mounted/failure) | … | … |
| memoryTools / commands (registration outcome) | … | see "memoryTools render gate" below — **registration alone is NOT sufficient** |

#### memoryTools render gate (registration ≠ callable)

`memoryTools:ok` only proves `defineTool({...})` returned a tool whose `output` passed the registry's `typeof output.render === 'function'` gate. The host `defineTool` (lib/types/schema.js, near the userRender closure) actually captures `options.output.render` into a closure named `userRender`; registration sees the outer wrapper function (typeof passes) but at runtime `tool.output.render(args, value)` calls `userRender(args, value)`. When `options.output.render` was undefined, the captured `userRender` is undefined → first invoke throws `output.render failed: userRender is not a function`. To verify the gate is real, each of `omd_memory_set`, `omd_memory_get`, `omd_memory_delete` must additionally show a callable `render present & callable` check (e.g. `tool.output.render(sampleArgs, sampleValue)` returns a non-empty ContentBlock without throwing). Failure here → ❌ with the specific tool name(s); fix per "Host render contract" below.

#### Host render contract (≤120 words)

The host `defineTool(options)` reads `options.output.render` once at registration, captures it into the closure as `userRender`, and replaces `tool.output.render(args, value)` with a wrapper calling `userRender(args, value)`. The capture happens before the registry's `typeof output.render === 'function'` gate runs, so an undefined render slips past registration (the wrapper itself is a function). The contract for plugin authors: every tool's `output` MUST carry `render: (args, value) => ContentBlock[]` returning at least one `{ type: 'text', text: <string> }` block; never share one `output` object across multiple `defineTool` calls (factory pattern), otherwise all three tools capture the same broken closure. Fix: `output: { schema: <json-schema>, render: (args, value) => [{ type: 'text', text: '...' }] }`.

Note: host tools like goal/ralph/subagent/workflow/ask_user_question are **not statically probed** (spec §7-6) — treat their actual invocation results as authoritative; try calling them if verification is needed. Core services (`tools`/`skills`/`systemPrompt`/`commands`) missing would have failed startup already — if reachable here, mark ❌ "should have been a startup error". Any non-`ok` that triggers a degradation → ⚠️ with the degradation path (spec §6.1 matrix).

### 7. Profile patch layering (best effort)

- If `dsh --profile <name> --dump-config` is runnable, verify the omd bundle patch expanded correctly (plugin instance present, config values landed; the MCP server is mounted dynamically at apply() runtime and won't appear in the patch — that's normal, item 4's smoke check is authoritative). Note: bare `dsh --dump-config` without a profile errors out (exit code 1, observed).
- Not runnable in-session → mark "not checked (manual step)" rather than guessing.

## Output format

One summary table plus details:

```
omd doctor — <date>

| # | Check | Status | Detail |
|---|-------|--------|--------|
| 1 | Host version vs peerDep (per package.json) | ✅/⚠️/❌ | host=<v> |
| 2 | Registration counts (44/33/2/4/49) | … | missing: … |
| 3 | Config model identifiers | … | … |
| 4 | MCP smoke (state_get_status) | … | … |
| 5 | .omd/ writable + .gitignore | … | … |
| 6 | Probe four-state matrix | … | N not-ok |
| 7 | Patch layering (--dump-config) | … | … |

Fixes:
- ❌ <check>: <concrete fix>
- ⚠️ <check>: <concrete suggestion>
```

## Closing disclaimer (always print)

> doctor checks installation and wiring health only. **It does not prove end-to-end usability** — the E2E gates (autopilot / ralph / team each run once for real) are a separate, manual release gate (spec §6.4).

## State Contract (状态契约)

omd-doctor is read-only diagnostics and **holds no mode state**: no `state_write`/`state_clear`, and the only filesystem touch is the create-then-delete writability probe at `.omd/.doctor-probe`. It never modifies Config, patches, or plugin files.

Files in this skill

  • SKILL.md10 KB
  • SKILL.zh.md9.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.