DOS

August 24, 2026 · View on GitHub

One install for the three runtime surfaces. This plugin bundles the DOS hooks, the DOS MCP server, and the generic skill pack so a Claude Code user binds the trust substrate to their fleet in a single step — instead of hand-editing settings.json, registering an MCP server, and copying skills out of the wheel separately.

The plugin ships JSON + markdown, plus the prebuilt native dos-hook binary (bin/, per-platform) that serves the hooks fast. The brains — the verify / arbitrate / refuse syscalls the hooks and MCP server call — ship as the dos-kernel Python package. So the one prerequisite is:

pip install "dos-kernel[mcp]"

(from PyPI; tracking unreleased master is pip install "dos-kernel[mcp] @ git+https://github.com/anthony-chaudhary/dos-kernel.git"), installed into the same interpreter Claude Code launches (python on its PATH). The [mcp] extra is what the bundled MCP server needs; the core hooks need only the base package. If the package isn't importable, the hooks fail safe (emit nothing, exit 0 — they never break a turn) and the MCP server prints an install hint in /mcp.

Install

# 1. the prerequisite (see above)
pip install "dos-kernel[mcp]"

# 2. inside Claude Code:
/plugin marketplace add anthony-chaudhary/dos-kernel
/plugin install dos-kernel@dos

# 3. confirm + orient (a read-only check skill):
/dos-kernel:dos-setup

To test a local clone before publishing, point Claude Code at this directory:

claude --plugin-dir ./claude-plugin

Private / company marketplace

Distributing DOS through your own internal marketplace — a private repo with a pinned plugin source — instead of the public one above? The end-to-end playbook (the four private source shapes, shipping the dos-kernel pip prerequisite to the fleet, strictKnownMarketplaces lockdown, air-gapped seeding, and the private-repo auth gotcha) is docs/PRIVATE-MARKETPLACE.md.

Claude Cowork

Cowork runs the same Claude Code agent harness, and plugins (skills + MCP) work there too — so this bundle's MCP server and skills serve a Cowork session as they do a Claude Code one. The hooks half is wired but dormant: Cowork does not fire hooks yet (anthropics/claude-code#63360), so until that closes the plugin's working surfaces in Cowork are advisory. Details and the per-surface state: docs/298.

What's in the bundle

SurfaceFileWhat it does
Hookshooks/hooks.jsonPreToolUsedos hook pretool (DENY a structurally-refused call before it runs) · Stopdos hook stop (refuse to stop on an unverified claim). The advisory PostToolUse checkpoint is intentionally omitted: Codex renders every declared hook in the foreground, and stalled-stream recovery remains on the Stop/watchdog path. Served by the bundled native dos-hook binary (bin/) in ~10 ms, with a Python fallback.
Observabilitybin/dos-hookthe native binary counts and logs every hook call to .dos/metrics/observations.jsonl. Fold it into a report — counts by verb/outcome, the delegate + stop-block rates, per-verb latency — with "${CLAUDE_PLUGIN_ROOT}/bin/dos-hook" stats (or the /dos-kernel:dos-stats skill). Read-only; no scrape endpoint (a hook is one-shot — the durable log is the surface).
MCP server.mcp.jsonlaunches python -m dos_mcp.server — exposes dos_verify, dos_arbitrate, dos_commit_audit, dos_refuse_reasons / dos_check_reason, dos_status, dos_recall, dos_citation_resolve, dos_doctor as tools.
Skillsskills/the generic skill pack (dos-next-up, dos-dispatch, dos-witness-claim, …) + the plugin-only dos-setup (onboarding) and dos-stats (observability) skills. Namespaced as /dos-kernel:<skill>.
Catalog../.claude-plugin/marketplace.jsonthe repo-root marketplace that /plugin marketplace add reads; its one plugin entry points back here (source: ./claude-plugin).

Why python -m, not the dos / dos-mcp scripts

Both the hooks and the MCP server invoke the package via python -m dos.cli … / python -m dos_mcp.server, not the dos / dos-mcp console scripts. pip puts those scripts in the interpreter's Scripts/bin dir, which is not guaranteed to be on the PATH of the subprocess Claude Code spawns for a hook or an MCP server. python -m resolves the module through the interpreter directly, so it works wherever the package is importable — the robust choice for a bundle a stranger installs.

Fail-safe by design

The three hook verbs are the shipped DOS sensors, and every one degrades to a no-op on any failure (no stdin, bad JSON, an I/O error, the package not importable): it prints nothing and exits 0. The PreToolUse deny is advisory by default — a behavioral deny needs a ruling handler wired; out of the box the plugin only observes and re-surfaces, never silently blocks your work. (DOS is a PDP, not a PEP: it reports and proposes; the runtime acts.)

Multi-account/headless dispatch: prefer the project-skill fallback

A namespaced invocation such as /dos-kernel:dos-dispatch-loop is resolved from the active account's plugin cache. When a fleet rotates CLAUDE_CONFIG_DIR, a fresh account can have the plugin registration but not its cached skill files; Claude Code currently reports Unknown command and may still exit 0. Do not use that exit code as evidence that a worker started.

For unattended multi-account launchers, install the generic skills into the workspace (dos init --skills) and invoke the git-tracked project skill instead:

/dos-dispatch-loop --lane <LANE>

This bare form resolves from .claude/skills/dos-dispatch-loop/SKILL.md in the repo, independent of each account's plugin cache. Before spawning a fleet, verify that file exists; treat Unknown command or a run with zero kernel decisions as a failed launch, even when the host process exits 0. Interactive single-account sessions with a healthy plugin cache can continue using the namespaced form.

Maintenance — the skills are generated, not hand-edited

The bundled skills/ are a faithful copy of the single source under ../src/dos/skills/ (which also ships as wheel package-data), plus the plugin-only dos-setup and dos-stats skills authored by the build. A Claude Code plugin must physically contain its skills — a component path can't escape the plugin root, and a symlink outside the marketplace is dropped — so the copy is regenerated by a script rather than maintained by hand:

python scripts/build_plugin.py          # regenerate claude-plugin/skills/ from source
python scripts/build_plugin.py --check  # verify in sync (exit 1 if drifted); writes nothing

Do not edit claude-plugin/skills/*/SKILL.md directly. For generic skills, edit the source under src/dos/skills/; for the plugin-only dos-setup and dos-stats, edit their authored content in scripts/build_plugin.py. Then re-run the build. The lockstep is pinned by tests/test_plugin_manifest.py, which fails if the copy drifts, if a hook stops naming a real verb, if the MCP server doesn't build, or if the plugin version falls out of step with the package.

Where this sits in the layering

The plugin operates on the package, never inside it — the same one-way arrow as the release scripts and the .claude/ dev tooling (see the repo's CLAUDE.md, "Four things live OUTSIDE the four layers"). It imports nothing; it shells dos verbs and launches dos_mcp. Nothing under src/dos/ depends on it. It is a distribution surface for the kernel, not part of the kernel.