Skip to main content

Extension Spec

An Extension is a named capability family contributed to drwn through its in-code registry (cli/core/extensions/registry.ts). An extension models a third-party tool — Beads, Parallel, MarkItDown — as a single coherent unit: the commands it needs on PATH, the skills it ships, the MCP servers it declares, and the project-config keys it consumes.

This page defines the producer/consumer contract: what an ExtensionDefinition must declare, how project config keys flip extension behavior, and what doctor/status reports promise.

Definition Shape

Type: ExtensionDefinition (cli/core/extensions/types.ts:27-37).

interface ExtensionDefinition {
id: string;
displayName: string;
description: string;
scopes: ExtensionScope[]; // ("global" | "project")[]
defaultModes: ExtensionMode[]; // ("cli" | "skills" | "mcp" | "hooks")[]
commands: ExtensionCommandRequirement[];
skills: ExtensionSkillReference[];
mcpServers: ExtensionMcpReference[];
docs: Array<{ label: string; url: string }>;
}
FieldMeaning
idStable lowercase identifier. Used as the key in project config extensions.<id> and CLI subcommands.
displayNameHuman-readable label for status/doctor output.
descriptionOne-line summary surfaced by drwn library extensions list.
scopesWhere the extension is meaningful. global = machine-wide; project = per-project; both = "mixed" (surfaced as scope: "mixed" in ExtensionStatus).
defaultModesThe surface area the extension contributes by default: cli (a CLI exists), skills (ships repo skills), mcp (declares MCP servers), hooks (wants harness hooks).
commandsRequired and optional executables the extension expects on PATH. See below.
skillsRepo-native skill directories the extension ships and their default-included status.
mcpServersMCP servers the extension declares for harness wiring.
docsAuthor-curated upstream documentation links.

ExtensionCommandRequirement

cli/core/extensions/types.ts:8-13:

{ name: string; required: boolean; installHints: string[]; purpose?: "runtime" | "installer" }

required: true commands gate available in status. installHints is an ordered list of one-line shell commands that should install the dependency; doctor surfaces them when a required command is missing. purpose lets a definition mark a command as the runtime binary versus the installer for it (e.g., markitdown runtime + uv installer).

ExtensionSkillReference

cli/core/extensions/types.ts:15-19:

{ name: string; source: "repo" | "package"; defaultIncluded: boolean }

defaultIncluded: true skills are added to machine defaults.skills on first init. source: "repo" means the skill ships in the drwn repo; source: "package" reserves the surface for skills shipped by an npm bundle.

ExtensionMcpReference

cli/core/extensions/types.ts:21-25:

{ name: string; defaultEnabled: boolean; scope: "global" | "project" }

The name matches the key in CanonicalRegistry.servers. scope declares where the server is wired by default.

Project Config Shape

When a project wants to configure an extension, it writes a ProjectExtensionConfig (cli/core/types.ts:86-93) under extensions.<id> in <project>/.agents/drwn/config.json:

type ProjectExtensionConfig = {
enabled?: boolean;
skills?: boolean;
mcp?: boolean;
targets?: string[];
includeSkill?: boolean;
[key: string]: unknown; // escape hatch for per-extension keys
};

Application semantics live in applyProjectExtensionConfig (cli/core/extensions/project-config.ts:18-61). Each registered extension applies these keys differently — the rules below are normative.

parallel

cli/core/extensions/project-config.ts:25-41:

  • If parallel.enabled === false:
    • config.parallel.cli.enabled = false
    • config.parallel.mcp.enabled = false
    • All parallel skill names are added to the project skill exclude set.
  • Otherwise (enabled or unset with the block present):
    • config.parallel.cli.enabled = true
    • config.parallel.mcp.enabled = (parallel.mcp === true) — strictly true enables; any other value (including undefined) leaves it off.
    • If parallel.skills === false, all parallel skill names are added to exclude; otherwise added to include.

beads

cli/core/extensions/project-config.ts:43-50:

  • If beads.enabled === false: beads-task-tracking is added to exclude.
  • Else if beads.includeSkill === true: beads-task-tracking is added to include.
  • Else: no skill change. The Beads CLI and hooks still surface in status, but the skill stays at whatever the machine default chose.

markitdown

cli/core/extensions/project-config.ts:52-60:

  • If markitdown.enabled === false: all markitdown skill names are added to exclude.
  • Otherwise: if markitdown.skills === false, added to exclude; otherwise added to include.

Escape Hatch

The [key: string]: unknown index signature on ProjectExtensionConfig lets an extension consume additional semantic keys without changing the global schema. Unknown keys are preserved through reads and writes; only the application logic in cli/core/extensions/project-config.ts interprets them.

Doctor and Status Contracts

Two report shapes carry extension health (cli/core/extensions/types.ts:39-77):

ExtensionStatus

Produced by drwn status for each extension. Required fields: id, displayName, available (boolean), scope ("global" | "project" | "mixed"), commands[], skills[], mcpServers[], warnings[]. Optional project block carries the project's CWD, the discovered config path, whether the extension is configured/enabled in that project, and (for Beads) whether the issue directory exists.

  • commands[].available is true when the binary is on PATH.
  • skills[].present is true when the skill directory exists in the resolved skill set; curated is true when the skill is in machine defaults.skills.
  • mcpServers[].configured is true when the server is in the effective registry; active is true when it is enabled.

ExtensionDoctorReport

Produced by drwn doctor. Required fields: id, displayName, issues[], warnings[]. issues are blocking — a missing required command produces an issue. warnings are advisory — optional missing tools, scope mismatches, etc.

A consumer that reads these reports should treat issues.length === 0 as the green-light condition for the extension.

Registered Extensions

The full set of registered extensions today (cli/core/extensions/registry.ts):

beads

  • Display name — Beads
  • Description — Project-scoped issue tracking and agent memory through the bd CLI.
  • Scopesproject only.
  • Default modescli, skills, hooks.
  • Commandsbd (required; install hints: brew install beads, npm install -g @beads/bd, the steveyegge/beads install script). beads-mcp (optional; install only if an MCP-only client needs it).
  • Skillsbeads-task-tracking (repo, default-excluded).
  • MCP serversbeads (default-disabled, scope project).
  • Docs — Beads docs, IDE setup, MCP guide.

parallel

  • Display name — Parallel
  • Description — Web search, extraction, research, and enrichment through Parallel CLI-backed skills.
  • Scopesglobal, project.
  • Default modescli, skills.
  • Commandsparallel-cli (required; install hints: curl -fsSL https://parallel.ai/install.sh | bash, then parallel-cli login).
  • Skillsparallel-web-search, parallel-web-extract, parallel-deep-research, parallel-data-enrichment (all repo, all default-included).
  • MCP serversparallel-search, parallel-task (both default-disabled, scope global).
  • Docs — Parallel developer quickstart, CLI, MCP quickstart.

markitdown

  • Display name — MarkItDown
  • Description — Document-to-Markdown conversion through Microsoft's markitdown CLI.
  • Scopesglobal, project.
  • Default modescli, skills.
  • Commandsmarkitdown (required, purpose runtime; install hint: uv tool install --python 3.12 'markitdown[all]'). uv (optional, purpose installer; install hints: brew install uv, the Astral install script).
  • Skillsmarkitdown-document-conversion (repo, default-included).
  • MCP servers — none.
  • Docs — MarkItDown README, PyPI, uv tools.