OpenCastle

Docs / CLI Reference

All commands are run via npx opencastle <command>. Every command supports --help for quick reference. Add --debug to a command to see the stack trace of an unexpected error.

npx opencastle <command> [options]

Commands:
  (none)      Show project status and what to do next
  init        Set up this project (detects your stack and existing config)
  sync        Recompile the generated config for every target
  add         Add an integration, e.g. "add supabase"
  doctor      Diagnose setup problems
  remove      Remove OpenCastle from this project

Teams:
  explain     What every assistant here is given, and what you need to set up
  review      What a change does to the assistants (for pull requests)
  ci          Add the drift and policy check to GitHub Actions
  baseline    Create or check a baseline many repositories extend
  plugin      Check an Agent Plugin, build Claude Code's files, index a marketplace
  promote     Make a skill or memory from your own assistant the team's
  fleet       Versions and drift across many repositories

Experimental:
  convoy      Plan multi-step work and run it with agents in parallel

Options:
  --dry-run        Preview changes without writing files
  --yes            Skip confirmation prompts
  --json           Machine-readable output where supported
  --help, -h       Show help for a command
  --version, -v    Show version number

--debug, with any command, prints the stack trace of an error.

Setup

opencastle (no command)

Show project status and what to run next

Running opencastle with no arguments reports which assistants it compiles for, whether the generated files are current, which assistants are configured in the repo but not being compiled, and the single command that resolves whatever it found. It is the one command worth remembering.

Usage

npx opencastle

Options

FlagDescription
--jsonMachine-readable output
--help, -hShow help

Examples

npx opencastle

Status and the next step

npx opencastle --json

Same, for scripts

opencastle init

Set up this project

Reads the repository, proposes a complete setup, and asks once. Detects which assistants already have config, which framework, database, and test runner the project uses, and whether it is hosted on GitHub or GitLab, then compiles the config for every assistant it found.

Usage

npx opencastle init [options]

Options

FlagDescription
--customize, --reconfigureChoose IDEs and integrations manually instead of accepting detection
--yes, -yAccept the detected setup without asking
--dry-runPreview what would be created without writing anything
--allow-downgradeRe-run with this OpenCastle even though a newer one compiled the project
--help, -hShow help

What it does

  1. Finds your assistants — any of CLAUDE.md or .claude/, .cursorrules or .cursor/rules, .github/copilot-instructions.md, .windsurfrules or .windsurf/rules, GEMINI.md, .codex, or opencode.json makes that assistant a compile target. AGENTS.md counts, as Codex CLI, only when none of those is present.
  2. Scans the stack — frameworks, databases, CMSes, deployment targets, test runners, monorepo tools — and writes what it read into .opencastle/: versions, commands, routes, models, migrations, environment variable names. JavaScript and TypeScript projects are read from package.json; Python ones from pyproject.toml or requirements.txt (FastAPI, Django, Flask), Go ones from go.mod (Gin, Echo, chi, Fiber); a Makefile, justfile or scripts/ adds its commands to any of them. A Python or Go service with no web interface gets no TypeScript or web-interface rules, and no browser to test with.
  3. Shows the plan and asks once — then compiles agents, skills, instructions, and MCP config for each target. On a project that is already set up it asks Re-initialize? [y/N] first. A re-run keeps the order the manifest lists its tools in, new ones after, so adding an assistant with init --customize does not rewrite the agents already compiled.
  4. Leaves your writing alone — what you wrote in CLAUDE.md, .cursorrules and the other root files stays above a managed block. A file of yours inside a directory OpenCastle generates (.cursor/rules/, .claude/agents/, .agents/skills/, …) is named in the summary and removed by the next sync; move it into .opencastle/ and it is compiled for every assistant. A skill another tool wrote there — Devin, Claude Code or Copilot creating one — is kept instead: init and sync move it into .opencastle/skills/ for you.

Examples

npx opencastle init

Detect, show the plan, confirm once

npx opencastle init --yes

No prompts, for CI or scripted setup

npx opencastle init --customize

Pick IDEs and integrations by hand

Lifecycle

opencastle sync

Recompile every target from source

Compiles the framework sources into each configured assistant format, preserving everything under .opencastle/. Run it after upgrading the package, or when opencastle reports that generated files are older than their sources.

Usage

npx opencastle sync [options]

Options

FlagDescription
--checkCompare against a fresh compile and exit non-zero on drift; writes nothing
--jsonMachine-readable report (with --check)
--dry-runPreview what would change
--forceRecompile even when everything already matches its sources
--allow-downgradeRecompile with this OpenCastle, or an installed baseline, even though a newer one compiled the project
--reconfigureChoose the integrations again (tech and team tools); to change assistants, run init --customize
--yesSkip confirmation prompts
--help, -hShow help

What is preserved

.opencastle/ is never overwritten, nor your text around the managed block in a root file. Generated directories are rewritten whole, so a file of yours placed in one is removed; keep it in .opencastle/. The exception is a skill another tool wrote — a <name>/SKILL.md folder in a compiled skills directory that no source produces, the lock does not record, and that carries no OpenCastle marker: sync copies it into .opencastle/skills/<name>/ and compiles it for every assistant (--dry-run says Would keep). An MCP server entry you edited stays as you left it; one still exactly as an earlier release wrote it is updated to the current default, and named.

Team sources and the lock

sync writes .opencastle/lock.json, the record of what every assistant is given; commit it. When .opencastle/config.json exists, it is resolved first — baselines, the project's own content, MCP servers, policy — and any error, such as a baseline that is not installed or a server the policy refuses, means nothing is written. See OpenCastle for Teams.

A project compiled by a newer OpenCastle than the one you run is refused, and so is an installed baseline older than the one the lock records (run npm install). --allow-downgrade goes back on purpose.

sync --check

Compiles to a scratch directory and compares, writing nothing. It fails when a generated file was edited by hand or not recompiled, when the lock is missing or stale, when the team's sources do not resolve or break the policy, when the memory hook is missing or out of date, and on any MCP problem doctor fails on. A skill another tool added to a compiled folder is listed under Skills another tool added, not Not produced by any source, because the next sync keeps it; it still fails the check until sync runs, since the other assistants do not have it yet. On GitHub Actions it annotates each drifted file with its fix and writes a table to the job summary; --json leaves the annotations out.

opencastle ci writes the GitHub Actions workflow. On any other CI, install dependencies, with opencastle as a devDependency, and run npx opencastle sync --check.

Previously called update

opencastle update still works.

Examples

npx opencastle sync

Recompile all targets

npx opencastle sync --check

Fail on drift, for CI

npx opencastle sync --dry-run

See what would change

opencastle add

Adopt an integration and recompile

Adds one or more packs — a framework, database, CMS, deployment target, or team tool — to the project and recompiles so its skills and MCP configuration reach every target.

Usage

npx opencastle add <pack>...

Options

FlagDescription
--listShow every available pack
--dry-runPreview without writing
--help, -hShow help

Examples

npx opencastle add supabase

Add one integration

npx opencastle add nextjs vercel sentry

Add several at once

npx opencastle add --list

See what is available

opencastle remove

Remove OpenCastle from this project

Asks whether to keep the generated files — making them standalone so you can uninstall the package — or delete everything it created. Always previews before touching anything.

Usage

npx opencastle remove [options]

Options

FlagDescription
--keep-filesKeep generated files; drop the manifest and the memory hooks
--allDelete every generated file
--dry-runPreview without changing anything
--yesSkip the confirmation
--help, -hShow help

What --all keeps

A file that also holds your writing — CLAUDE.md, .cursorrules, opencode.json — loses only the OpenCastle block or servers. .opencastle/ is moved to .opencastle.removed/, with your conventions and lessons, for you to delete when you are sure.

Examples

npx opencastle remove

Ask, then remove

npx opencastle remove --keep-files

Make the files standalone

npx opencastle remove --all --dry-run

See exactly what a full delete would remove

Runtime

opencastle convoy

Experimental: plan multi-step work and run it with agents in parallel

Plans multi-step work without changing anything, shows you the plan and asks once, then runs it on the agent runtime opencastle init set up: each task in its own git worktree, independent tasks at the same time, the result on a branch of its own. Your checkout is never touched. Runs are recorded in .opencastle/convoy.db, so an interrupted or failed run resumes instead of starting over. Worked runs, with their time and cost, are on Use cases.

Usage

npx opencastle convoy [task] [options]

Options

FlagDescription
--yes, -yWith a task: run the plan without asking
--dry-runWith a task: plan and write the spec, but do not run it. With run or resume: show what would run
--adapter, -a <name>Agent runtime: claude, codex, cursor, opencode or copilot (default: the one opencastle init set up)
--concurrency, -c <n>Tasks at once, 1 to 50
--verboseStream agent output
--jsonWith no task: the last run, as JSON
--help, -hShow help

Subcommands

CommandWhat it doesIts options
opencastle convoyThe last run and the one next step--json
opencastle convoy "<task>"Plan it, show the plan, ask, then run it--yes, --dry-run, --adapter, --concurrency, --verbose
opencastle convoy run <spec.yml>Run a spec, one you wrote or one the planner wrote to .opencastle/convoys/--dry-run, --adapter, --concurrency, --verbose
opencastle convoy resumeContinue the newest run that is not done. retry is another name for it--dry-run, --adapter, --concurrency, --verbose
opencastle convoy dashboardThe Observability dashboard, live, on 127.0.0.1: totals across every run, and for each run its tasks and what they wait for, tokens and cost, reviews, checks, retries, failure reasons and the event timeline, read from .opencastle/convoy.db--port <n> (default 4300, moving up while busy; 0 picks a free one), --no-open
opencastle convoy plan --prd <file>Plan again from a PRD you edited--yes, --dry-run, --adapter, --concurrency, --verbose

Each subcommand has its own help: opencastle convoy run --help.

Plan, ask, run

opencastle convoy "<task>" plans without changing anything. A small change is planned straight from the request; larger work first gets a PRD in .opencastle/prds/, reviewed while the tasks are planned from it. The spec goes to .opencastle/convoys/, and the plan is printed as a table — each task, its agent, what it waits for and the files it may change — with the branch, the runtime and the checks that run at the end. Then it asks Run it? [Y/n].

  • --yes runs it without asking, after one more agent session reviews the plan.
  • No answer — stdin closed, as in a script — means no: nothing runs, and the command to run it later is printed.
  • --dry-run stops after writing the spec.

A run prints each task as it starts and finishes, with its time and cost. It ends with the branch and the git diff and git merge commands for it, the lessons workers recorded (committed on the branch, so they are reviewed with the work), the bugs they found outside their tasks, and the tokens and cost spent. On a terminal outside CI it also starts the live dashboard. Ctrl+C stops the agents and exits 130; opencastle convoy resume carries on. It exits 0 when every task is done and every check passed, 1 otherwise.

Runtime

The runtime is the first of: --adapter, the spec's adapter, the assistant opencastle init set up, or the first agent CLI found on PATH. A runtime that is named but not installed is an error, never a quiet switch to another. The run's first lines say which it chose and why.

Assistant set up by initRuntimeCommand
Claude Codeclaudeclaude
VS Code (GitHub Copilot)copilotcopilot
Cursorcursorcursor-agent (or Cursor's agent)
OpenCodeopencodeopencode
Codex CLIcodexcodex

OpenCastle has no runtime adapter for Windsurf (Devin Desktop) or Antigravity, so they are compile targets only; a project set up only for them runs on the first agent CLI found on PATH, or the one --adapter names.

Models

A task with no model in its spec runs on its agent's capability tier. Claude Code maps premium, standard and economy to its own opus, sonnet and haiku aliases; reviews run on economy, and the planner writes on standard and checks on economy. The other runtimes run on their own default model. A model in the spec, on a task or under defaults, always wins.

Experimental

This namespace may change or be removed. The compiler does not depend on it. How it works inside is in ARCHITECTURE.md.

Examples

npx opencastle convoy "Add tags to notes, and reject a note without a title"

Plan, show the plan, ask, run

npx opencastle convoy

Where the last run stands, and what to do next

npx opencastle convoy run .opencastle/convoys/note-tags.convoy.yml --dry-run

Check a spec and see what would run

npx opencastle convoy resume

Continue what is not done

npx opencastle convoy dashboard --no-open

Print the dashboard's address without opening a browser

Diagnostics

opencastle doctor

Diagnose setup problems

Checks the manifest, per-assistant generated files, the skill matrix, MCP configuration, and required environment variables, audits what each MCP config launches, and says how to fix what it can. It also says when .opencastle/project.instructions.md is still a template, how much is left to describe, when the lessons index agents read before every task has grown past about 2,000 tokens, and when an assistant the project is not compiled for keeps memories about it that the team does not have.

Usage

npx opencastle doctor [options]

Options

FlagDescription
--help, -hShow help

What it checks in MCP configs

Every target's MCP config, including servers you added yourself:

  • Warning — a package launched without an exact version (@latest, a range, or none), so each machine runs whatever was published last. A failure instead when the team's policy sets requirePinned.
  • Failure — a package OpenCastle knows is not on npm (one an earlier release wrote, or one since unpublished), or a remote server in .mcp.json with no "type", which Claude Code reads as a stdio server and never loads.
  • Failure — a credential written into the file, or a server the team's policy does not allow, whether by name or by the host it connects to.

Each finding names its fix.

Team sources and lessons

  • Team sources — .opencastle/config.json and the baselines it extends resolve, and what they contribute.
  • Always-loaded context — the tokens every assistant loads before a task (instructions plus the skill and agent index, estimated at four characters per token), against the budget a layer set; a warning past it, naming the three largest contributors.
  • Team instructions match this repository — npm run scripts named in team content that package.json does not define, and backticked paths in the project's own content that do not exist.
  • OpenCastle version — a failure when you run an older release than the one that compiled the project.
  • Lessons — one whose cited code changed since it was verified, with lesson verify or lesson archive as the fix.

Examples

npx opencastle doctor

Run all checks

Exit codes

0All checks passed (may have warnings)
1One or more checks failed

Teams

Baselines, policy and the lock these commands work with are explained in OpenCastle for Teams.

opencastle explain

What every assistant here is given, and what you need to set up

Onboarding in one command. Resolves the project exactly as sync does and shows the layers, what every assistant loads before each task and what it costs, the team's skills, agents, prompts and workflows by where they come from, the MCP servers every assistant can start, the team's policy, and — under Your setup — the environment variables you have not set and the servers that will ask you to sign in.

Usage

npx opencastle explain [options]

Options

FlagDescription
--allList OpenCastle's own skills, agents, commands and workflows one by one too, not only the team's
--jsonMachine-readable output
--help, -hShow help

What it shows

  🏰 What the AI assistants in this repository are given

  Layers  OpenCastle 1.0.0 → @acme/opencastle-baseline 1.5.0 → this project  (later layers add to and override earlier ones)
  Targets Claude Code, Cursor, VS Code, OpenCode

  Always loaded — ~2779 tokens before every task: instructions ~613, the skill and agent index ~2167
  …
  Your setup
    ✗ ACME_DOCS_TOKEN — used by the internal-docs MCP server (@acme/opencastle-baseline/dev.opencastle/config.json); set it in .env or your shell
    ✗ ACME_DB_URL — used by the acme-db MCP server (.opencastle/config.json); set it in .env or your shell
    → Linear: your assistant opens a browser to sign in the first time it starts the server
  …

The full run is in the worked example. A variable counts as set when it is in your shell or in .env at the project root. Warnings about the team's sources are listed at the end. It exits 1, saying why, when the sources do not resolve.

Examples

npx opencastle explain

What this repository gives every assistant

npx opencastle explain --all --json

Everything, for a script

opencastle review

What a change does to the assistants, for pull requests

Reads .opencastle/lock.json as committed at a base ref, compares it with what the current sources compile to, and says in sentences what every assistant gains, loses or gets changed: baselines and their versions, skills, agents and always-loaded instructions, MCP servers, policy, and context size. What deserves a careful look is marked ⚠️.

Usage

npx opencastle review [options]

Options

FlagDescription
--base <ref>What to compare against (default: HEAD; on a GitHub Actions pull request, origin/<base branch>)
--markdownPrint Markdown, e.g. for a pull request comment
--jsonMachine-readable output
--help, -hShow help

What gets ⚠️

  • A baseline added or dropped, or one whose contents changed without a version change
  • A new or changed always-loaded instruction, and a required item that moved or was removed
  • Every new MCP server, and one that now launches differently, reads different variables, or has different environment values or headers (a version bump of the same package is not marked)
  • An allowlist or host list widened or removed, pinning no longer required, an item no longer required, the context budget removed
  • Always-loaded context up by more than 10%, or over the budget

In CI

On GitHub Actions the Markdown is also appended to the job summary, beside the drift table sync --check writes. The base defaults to origin/<base branch> there, so check out with fetch-depth: 0. When the committed lock is not what the sources compile to, it says so first.

It explains; it does not gate. It exits 0 whatever the change is, and 1 only when it cannot compare — not a git repository, a base that is not a commit here, or sources that do not resolve. sync --check is the gate.

Examples

npx opencastle review

What your uncommitted changes do, compared with HEAD

npx opencastle review --base origin/main --markdown

A branch, as Markdown for a pull request

opencastle ci

Add the drift and policy check to GitHub Actions

Writes .github/workflows/opencastle.yml: check out with full history, set up Node 22, install dependencies with the package manager your lockfile names so baselines resolve, run sync --check, and on pull requests run review against the base branch.

Usage

npx opencastle ci [options]

Options

FlagDescription
--owners <team>Also route changes to .opencastle/lock.json and .opencastle/config.json to these reviewers in CODEOWNERS
--forceReplace an existing workflow file
--dry-runPrint what would be written, and write nothing
--help, -hShow help

Which OpenCastle it runs

When opencastle is one of the project's devDependencies, the workflow runs that copy — npx --no opencastle, pnpm exec opencastle or yarn opencastle — so laptops and CI run the version the lockfile pins. Otherwise it pins the release that last compiled the project, npx -y opencastle@<version>, and suggests adding the devDependency.

Monorepos and CODEOWNERS

Run from a subdirectory, it writes opencastle-<dir>.yml at the repository root, filtered to that directory's paths and running in it, and installs dependencies where the lockfile is. --owners appends two lines, for the lock and the team config, to the CODEOWNERS file GitHub reads — .github/, the root or docs/, the first it finds — creating .github/CODEOWNERS only when there is none, and leaves the file alone if it already routes the lock.

Examples

npx opencastle ci --owners @acme/platform

Workflow plus owners for what assistants are given

npx opencastle ci --dry-run

See the workflow first

opencastle baseline

Create or check a baseline many repositories extend

A baseline is an npm package that carries an organisation's instructions, skills, agents, MCP servers and policy. Repositories install it as a devDependency and name it in extends. One that init creates is also an Agent Plugin, so assistants that read Agent Plugins can install it as it is. init scaffolds one; check validates it the way every repository extending it will, and the way assistants load it.

Usage

npx opencastle baseline <init|check> [dir] [options]

Options

FlagDescription
--name <pkg>Package name for init (default: @your-org/opencastle-baseline)
--jsonMachine-readable output for check
--help, -hShow help

init

Creates ./opencastle-baseline, or the directory you name, laid out as an Agent Plugin: plugin.json, an example skill in skills/code-review/, mcp.json for servers any assistant can start as they are, and in dev.opencastle/ what the standard does not cover — an example instruction and the policy, in config.json. Also Claude Code's .claude-plugin/plugin.json, a package.json declaring "opencastle": { "baseline": "." }, a README on publishing and adopting it, and a workflow that runs check. It refuses a directory that already has a package.json.

check

Resolves the baseline in a scratch project that extends it, and reports what it contributes and how many tokens a repository extending it loads up front. For an Agent Plugin it also checks the manifest, every skill against the Agent Skills spec and every portable server, as plugin check does. It exits 1 when package.json does not declare the layer or declares one outside the package, when "files" would leave part of it out of npm publish, when the layer directory is missing, when the Agent Plugin check finds an error or Claude Code's files are out of date, or when its config, content or policy has an error.

Examples

npx opencastle baseline init --name @acme/opencastle-baseline

Scaffold the package

npx opencastle baseline check

Validate the baseline in this directory before publishing

opencastle plugin

Check an Agent Plugin, build Claude Code's files, index a marketplace

Agent Plugins 1.0 is the open package format for skills and MCP servers: plugin.json, skills/<name>/SKILL.md and mcp.json. GitHub Copilot, VS Code, Cursor, Codex, Kiro and Devin install one as it is. plugin checks one, writes the files Claude Code reads instead, and writes the marketplace file each assistant indexes plugins with.

Usage

npx opencastle plugin <check|build|index> [dir] [options]

Options

FlagDescription
--checkbuild and index: change nothing; exit 1 if a file is out of date
--name <name>index: the marketplace name (default: from package.json or the directory)
--owner <name>index: who maintains it (default: from package.json)
--jsoncheck: machine-readable output
--help, -hShow help

check

Loads the plugin the way a conformant client does and reports what such a client would refuse, skip or ignore: a manifest outside the closed schema, a skill whose name does not match its directory or whose description is missing or too long, an MCP server with a shell string for a command, a plain-http remote, a header given twice. It also fails when .claude-plugin/plugin.json or .mcp.json no longer matches the portable files.

build

Claude Code reads .claude-plugin/plugin.json and .mcp.json, not the standard's files. build writes both from plugin.json and mcp.json — ./ commands become ${CLAUDE_PLUGIN_ROOT}/…, streamable-http becomes http. Anything only Claude Code reads that you put in its manifest — userConfig, hooks, agents — is kept.

index

For a repository of plugins under plugins/<name>/, writes .claude-plugin/marketplace.json (read by Claude Code and Copilot CLI), .cursor-plugin/marketplace.json (Cursor team marketplaces) and .agents/plugins/marketplace.json (Codex). Teammates then add the repository once in each assistant.

Examples

npx opencastle plugin check

Check the plugin in this directory

npx opencastle plugin build --check

In CI: fail when Claude Code's files are stale

npx opencastle plugin index --owner "Acme Platform"

List every plugin under plugins/ for each assistant

opencastle promote

Make a skill or memory from your own assistant the team's

Moves a skill one developer wrote for their own assistant, or what an assistant remembered on one laptop, into the team's sources — this repository's .opencastle/ or a baseline — where the next sync compiles it into every assistant. It lands as a change in your working tree, for a pull request.

Usage

npx opencastle promote <skill|memory> [name|path] [options]

Options

FlagDescription
--to <dir>skill: a baseline or Agent Plugin directory to put it in
--from <dir>memory: read memory files from this directory instead
--forceskill: replace a team skill with the same name
--dry-runSay what would be written, and write nothing
--jsonmemory: one line of JSON, and exit 0 whatever happens — what the memory hook runs
--help, -hShow help

skill

Finds the skill by name in ~/.claude/skills, ~/.agents/skills, ~/.codex/skills, ~/.cursor/skills or ~/.copilot/skills, or takes a path. It is checked against the Agent Skills spec — a name that does not match its directory is refused, as assistants that follow the spec skip it — and every file is scanned for credentials. Then it is copied, with its scripts and references, to .opencastle/skills/<name>/, or with --to into a baseline's skills/.

memory

Reads what the assistants on this machine remember about this repository and writes it as lessons in .opencastle/lessons/:

  • Claude Code — its auto memory, ~/.claude/projects/<repository>/memory/ (under $CLAUDE_CONFIG_DIR if you set it), or wherever autoMemoryDirectory points. Corrections (feedback), project notes, pointers to where things live (reference) and memories with no type; memories about you (user) are left out.
  • VS Code (GitHub Copilot Chat) — the repository memory its agents keep for this folder, in VS Code's workspace storage, stable and Insiders. One lesson per memory file. Your user memory is about you, and is left out.
  • Codex — the blocks of $CODEX_HOME/memories/MEMORY.md whose directory is this repository: their reusable knowledge and failures, not the user preferences or the session list.

Cursor keeps its memories on its own servers, and Copilot Memory lives on GitHub, so neither can be read. Memories that hold a credential, and ones already promoted, are left out, and paths in your home directory are written as ~. Each lesson records which memory it came from, so running it again adds only what is new.

You rarely run it yourself. init and sync add a hook that runs promote memory --json when an agent stops: on SessionEnd in Claude Code's .claude/settings.json, beside any hooks of yours, and on Stop in VS Code's .github/hooks/opencastle.json. --json prints one line of JSON and always exits 0, as a hook needs. sync --check fails when the hook is missing, and remove takes it back. How lessons reach the team: Team Memory.

Examples

npx opencastle promote skill deploy-runbook

Your skill, in every teammate's assistant after the next sync

npx opencastle promote skill deploy-runbook --to ../ai-standard

Into the baseline every repository extends

npx opencastle promote memory --dry-run

See which of your assistant's memories would become lessons

npx opencastle promote memory --json

What the memory hook runs: one line of JSON, exit 0

opencastle lesson

Record, verify or archive a lesson

Agents run it, from their instructions, when they confirm something true for anyone working in the repository: one file per lesson in .opencastle/lessons/, and the index they read first, .opencastle/LESSONS-LEARNED.md, rewritten. You run verify and archive when doctor names a lesson whose cited code has changed. It is left out of --help for that reason.

Usage

npx opencastle lesson [add] --title <text> --category <cat> --severity <level> --problem <text> [options]
npx opencastle lesson verify <id> [--cite <path[:line]>]...
npx opencastle lesson archive <id> --into <file>

Options

FlagDescription
--title, --category, --severity, --problemadd: required. Severity is high, medium or low; npx opencastle lesson --help lists the categories
--wrong, --correct, --whyadd: what was tried, what works, and the root cause
--cite <path[:line]>The code the lesson is about; repeat for more. On verify, replaces the citations
--into <file>archive: the skill or instruction file the lesson now lives in, or an item such as skills/deploy-runbook that a baseline gives this repository
--customizations-dir <p>Use this .opencastle directory instead of finding one
--dry-runPrint what would be written, and write nothing
--help, -hShow help

verify and archive

verify says a lesson still holds: it stamps today's date and what the cited files hold now, so doctor stops reporting them. archive marks a lesson merged into the file --into names; it stays on record and leaves the list agents read. A lesson every repository needs goes into the baseline's skill: once the baseline version carrying it is installed, --into skills/<name> names that skill. How lessons reach the team: Team Memory.

Examples

npx opencastle lesson verify 2026-10-02-always-quote-shell-variables

It still holds

npx opencastle lesson archive 2026-10-02-always-quote-shell-variables --into .opencastle/skills/git-workflow/SKILL.md

It now lives in a skill

opencastle fleet

Versions and drift across many repositories

Reads the committed .opencastle/lock.json of each directory you give it — nothing is installed and nothing is fetched — and shows which OpenCastle and baseline versions each repository runs, which lag behind the newest, and which MCP servers launch differently across them.

Usage

npx opencastle fleet <dir...> [options]

Options

FlagDescription
--jsonMachine-readable output
--help, -hShow help

What it shows

  …
  • shop        opencastle 1.0.0  @acme/opencastle-baseline@1.5.0  4 target(s), 6 MCP server(s), ~2779 tokens up front
  …
  @acme/opencastle-baseline: 1.4.0 (1), 1.5.0 (1) — 1 behind 1.5.0: admin

  MCP servers running differently across repositories
    ~ acme-db
      npx -y @acme/db-mcp@2.2.0  — shop
      npx -y @acme/db-mcp@2.1.0  — admin

From the worked example. Directories without .opencastle/ are skipped, one without a lock is listed as not yet synced by a release that writes one, and one whose lock this release cannot read is listed as such. Each repository is named by its package.json name, or else its directory.

Examples

npx opencastle fleet ~/src/*

Every checkout in a directory

npx opencastle fleet ../web ../api --json

Two repositories, for a script