protean dx
The protean dx command group writes and maintains the agent-facing files that
make a coding agent correct with the installed framework version. The files are
composed from data that ships inside the protean package, so an agent reads
guidance that matches the installed code.
It writes two sets of files into a target project. The canonical set:
AGENTS.md: the canonical, cross-agent instruction file. Its body has two layers. The first is the positive guidance from the packaged AGENTS.md source. The second is the negative hard-rules section, one rule for every error-level diagnostic code Protean can raise, built from the same diagnostics registry asprotean docs generate --type=agents. Both layers are stamped with the installed version.CLAUDE.md: a one-line bridge,@AGENTS.md, that points Claude Code at the canonical file..mcp.json: the registration a client reads to launch Protean's MCP server (protean mcp). It is a structured JSON merge scoped to themcpServers.proteankey-path, so an existing.mcp.jsonkeeps every other server you configured.installwrites and reconciles only its own entry.
The per-editor set, one file each for Cursor, Copilot, and opencode:
.cursor/rules/protean.mdc: Cursor's rule file. It carries MDC frontmatter withglobs: "**/*.py", which applies the rule to Python files. It also carries the same composed guidance asAGENTS.md. Cursor readsAGENTS.mdnatively for the always-on layer, so this rule is scoped to code. Protean owns the whole file, since the MDC frontmatter must start at line 1 and leaves no room for a marker above it..github/copilot-instructions.md: Copilot's instructions, the composed guidance in an HTML-comment managed block, so the file stays co-owned with your own Copilot instructions.opencode.json: opencode's config. It manages onemcp.proteanentry with opencode's launch shape (type: "local",command: ["protean", "mcp"],enabled: true) and keeps every other key. opencode readsAGENTS.mdnatively, so it gets no separate instruction file: this config only supplies the MCP registration.
Managed regions
Each file is co-owned, except the Cursor rule file, which Protean owns whole. For
the Markdown files (AGENTS.md, CLAUDE.md, .github/copilot-instructions.md),
the framework writes a block framed by two HTML comment markers,
<!-- PROTEAN:BEGIN protean --> and <!-- PROTEAN:END protean -->, and you own
every line around it. For the JSON files (.mcp.json, opencode.json), the
framework owns only its own key-path (mcpServers.protean, mcp.protean) and you
own every other key, including your other servers. For the Cursor rule file, the
framework owns the whole file, so any hand edit to it is a conflict. Re-running
install or refresh rewrites the framework's region and preserves your own
edits around it.
A state file at .protean/dx-state.json records what the writer last wrote per
target. It tells a version change (a safe rewrite) apart from an edit you made
inside the framework's region (a conflict the writer refuses to overwrite). The
conflict line names the region it means: the managed block for a Markdown file,
the managed key (mcpServers.protean, mcp.protean) for a JSON file, the whole
file for the Cursor rule. Commit the state file so the conflict check works across
machines. The design is recorded in
ADR-0037.
install refuses any pre-existing managed-block Markdown file (AGENTS.md,
CLAUDE.md, and .github/copilot-instructions.md) that has no PROTEAN
markers. It writes nothing to that file, so it never overwrites a file you
wrote by hand. This covers a .github/copilot-instructions.md you already
keep, an AGENTS.md you wrote yourself, and the marker-less AGENTS.md a
protean new before 0.18 wrote. It reports an error until you remove or rename
that file and run install, which then writes the managed version.
A project made with protean new from 0.18 on needs none of this. protean new
writes the same managed AGENTS.md and CLAUDE.md bridge that install writes, at
the same version, and records them in .protean/dx-state.json. So a fresh project is
already dx-managed: install, refresh, and check all work on it with no manual
step. protean new writes only this baseline; .mcp.json and the per-editor files
stay install choices, since you pick your own editors. refresh keeps the
project that way. It re-renders what the project already has and never adds an
optional file, so upgrading a scaffolded project leaves the project
baseline-only until you run install.
Verbs
protean dx install # write the canonical and per-editor files
protean dx refresh # re-render what is installed, to the installed version
protean dx diff # preview what install would change (unified diff); write nothing
protean dx check # exit non-zero when a target has drifted; write nothing
protean dx build-plugin # render the packaged skills into the Claude Code plugin tree
install creates a missing file and refreshes a stale managed region, across every
target. It is the verb that opts a project into .mcp.json and the per-editor
files. You run refresh after upgrading Protean. It is the same idempotent
apply, scoped to what the project already has: the required baseline plus every
optional target already installed. So refresh updates a project without
adding a file you did not choose. diff and check write nothing: diff is
the preview, printing a unified diff of each pending change, and check is the
CI gate. Unlike the other verbs, build-plugin renders Protean's own committed
plugin tree and writes no files in your project. It is described in
Building the Claude Code plugin below.
A target has drifted when it is missing, its managed region is stale against the
installed version, or you edited inside that region. check reports each verified
target, naming the region it means, and exits non-zero when any has drifted.
check verifies a required baseline plus whatever else is installed, the same
scope refresh writes. AGENTS.md and the CLAUDE.md bridge are the required
baseline, always verified. .mcp.json and the per-editor files are optional:
check verifies one only once it is present on disk or recorded in
.protean/dx-state.json. A freshly scaffolded project carries only the baseline, so
it passes. A project missing the baseline fails. An editor file you never chose is
not counted as drift. Because the two share a scope, refresh fixes exactly what
check reports. diff, the preview, is not scoped this way: it always previews
every managed target, including a pending create for an optional file you have not
installed.
Options
--path,-p: The project directory to write into or check. Defaults to the current directory. A path that exists but is not a directory is rejected.
Exit codes
0: the command succeeded. Forcheck, every target is up to date.1: forcheck, a target has drifted. Forinstallandrefresh, a managed region conflicts with a hand edit and was left untouched.2: a filesystem error, such as an unreadable or malformed target, an unreadable or corrupt.protean/dx-state.json, a--paththat is not a directory, or a pack that cannot render.
A conflict on one file does not stop the others. install applies every file it
safely can, reports the conflict, and then exits non-zero.
In CI
Wire check into a pipeline so a project's agent files stay in step with the
framework. It writes nothing and fails the job on drift.
protean dx check
Building the Claude Code plugin
build-plugin renders Protean's teaching skills into a Claude Code plugin. It
is a maintainer command for the Protean repository itself, and you do not run
it in your own project. It renders the packaged skills at
src/protean/dx/pack/skills/ into a committed plugin tree that a Claude Code
user can install.
It writes two manifests and the skill tree:
.claude-plugin/marketplace.jsonat the repo root names theproteanhqmarketplace and lists one plugin,protean, sourced from./plugins/protean.plugins/protean/.claude-plugin/plugin.jsonnames the plugin and stamps it with the installed framework version, so a consumer can tell which version's guidance the skills carry.plugins/protean/skills/<name>/holds each skill'sSKILL.mdand anyassets/andreferences/, copied byte for byte from the pack.plugins/protean/references/holds the pack's shared reference pages that the skills link to from their own subtree, so those links still open in an installed plugin.
This version of the plugin carries skills only: no commands, agents, or hooks.
The MCP server registration stays with the .mcp.json file that install writes.
protean dx build-plugin # write (or regenerate) the committed tree
protean dx build-plugin --check # exit non-zero when the tree has drifted; write nothing
Without --check, build-plugin writes the tree to match its render exactly.
It prunes any file a removed skill left behind. --check is the drift guard:
it re-renders in memory, compares byte for byte against the committed tree,
writes nothing, and exits 1 when a file is missing, stale, or orphaned. The
framework version in plugin.json moves with a release (through a
.bumpversion.toml entry), so the committed tree stays in step and the drift
check does not fail on a version bump.
Installing it in Claude Code
A Claude Code user adds the marketplace from the repository and installs the plugin:
/plugin marketplace add proteanhq/protean
/plugin install protean@proteanhq
Installing the plugin makes the bundled skills available in Claude Code.