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
Runningopencastle 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
| Flag | Description |
|---|---|
--json | Machine-readable output |
--help, -h | Show 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
| Flag | Description |
|---|---|
--customize, --reconfigure | Choose IDEs and integrations manually instead of accepting detection |
--yes, -y | Accept the detected setup without asking |
--dry-run | Preview what would be created without writing anything |
--allow-downgrade | Re-run with this OpenCastle even though a newer one compiled the project |
--help, -h | Show help |
What it does
- Finds your assistants — any of
CLAUDE.mdor.claude/,.cursorrulesor.cursor/rules,.github/copilot-instructions.md,.windsurfrulesor.windsurf/rules,GEMINI.md,.codex, oropencode.jsonmakes that assistant a compile target.AGENTS.mdcounts, as Codex CLI, only when none of those is present. - 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 frompackage.json; Python ones frompyproject.tomlorrequirements.txt(FastAPI, Django, Flask), Go ones fromgo.mod(Gin, Echo, chi, Fiber); a Makefile, justfile orscripts/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. - 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 withinit --customizedoes not rewrite the agents already compiled. - Leaves your writing alone — what you wrote in
CLAUDE.md,.cursorrulesand 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 nextsync; 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:initandsyncmove 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
| Flag | Description |
|---|---|
--check | Compare against a fresh compile and exit non-zero on drift; writes nothing |
--json | Machine-readable report (with --check) |
--dry-run | Preview what would change |
--force | Recompile even when everything already matches its sources |
--allow-downgrade | Recompile with this OpenCastle, or an installed baseline, even though a newer one compiled the project |
--reconfigure | Choose the integrations again (tech and team tools); to change assistants, run init --customize |
--yes | Skip confirmation prompts |
--help, -h | Show 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
| Flag | Description |
|---|---|
--list | Show every available pack |
--dry-run | Preview without writing |
--help, -h | Show 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
| Flag | Description |
|---|---|
--keep-files | Keep generated files; drop the manifest and the memory hooks |
--all | Delete every generated file |
--dry-run | Preview without changing anything |
--yes | Skip the confirmation |
--help, -h | Show 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 runtimeopencastle 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
| Flag | Description |
|---|---|
--yes, -y | With a task: run the plan without asking |
--dry-run | With 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 |
--verbose | Stream agent output |
--json | With no task: the last run, as JSON |
--help, -h | Show help |
Subcommands
| Command | What it does | Its options |
|---|---|---|
opencastle convoy | The 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 resume | Continue the newest run that is not done. retry is another name for it | --dry-run, --adapter, --concurrency, --verbose |
opencastle convoy dashboard | The 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].
--yesruns 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-runstops 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 init | Runtime | Command |
|---|---|---|
| Claude Code | claude | claude |
| VS Code (GitHub Copilot) | copilot | copilot |
| Cursor | cursor | cursor-agent (or Cursor's agent) |
| OpenCode | opencode | opencode |
| Codex CLI | codex | codex |
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
| Flag | Description |
|---|---|
--help, -h | Show 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 setsrequirePinned. - Failure — a package OpenCastle knows is not on npm (one an earlier release wrote, or one since unpublished), or a remote server in
.mcp.jsonwith 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.jsonand 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 runscripts named in team content thatpackage.jsondoes 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 verifyorlesson archiveas the fix.
Examples
npx opencastle doctor Run all checks
Exit codes
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 assync 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
| Flag | Description |
|---|---|
--all | List OpenCastle's own skills, agents, commands and workflows one by one too, not only the team's |
--json | Machine-readable output |
--help, -h | Show 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
| Flag | Description |
|---|---|
--base <ref> | What to compare against (default: HEAD; on a GitHub Actions pull request, origin/<base branch>) |
--markdown | Print Markdown, e.g. for a pull request comment |
--json | Machine-readable output |
--help, -h | Show 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
| Flag | Description |
|---|---|
--owners <team> | Also route changes to .opencastle/lock.json and .opencastle/config.json to these reviewers in CODEOWNERS |
--force | Replace an existing workflow file |
--dry-run | Print what would be written, and write nothing |
--help, -h | Show 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 inextends. 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
| Flag | Description |
|---|---|
--name <pkg> | Package name for init (default: @your-org/opencastle-baseline) |
--json | Machine-readable output for check |
--help, -h | Show 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
| Flag | Description |
|---|---|
--check | build 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) |
--json | check: machine-readable output |
--help, -h | Show 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
| Flag | Description |
|---|---|
--to <dir> | skill: a baseline or Agent Plugin directory to put it in |
--from <dir> | memory: read memory files from this directory instead |
--force | skill: replace a team skill with the same name |
--dry-run | Say what would be written, and write nothing |
--json | memory: one line of JSON, and exit 0 whatever happens — what the memory hook runs |
--help, -h | Show 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_DIRif you set it), or whereverautoMemoryDirectorypoints. 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.mdwhose 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
| Flag | Description |
|---|---|
--title, --category, --severity, --problem | add: required. Severity is high, medium or low; npx opencastle lesson --help lists the categories |
--wrong, --correct, --why | add: 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-run | Print what would be written, and write nothing |
--help, -h | Show 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
| Flag | Description |
|---|---|
--json | Machine-readable output |
--help, -h | Show 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