@fr-nan-ai/anvil
v0.8.2
Published
Agent-first CLI — make any project AI-agent compatible
Maintainers
Readme
Agent-first CLI — make any project AI-agent compatible.
Anvil installs, projects, and maintains AI agent components (skills, recipes, hooks, agents) in each agent's native format. Write once, deploy to Copilot, Claude, Cursor, or OpenCode — then promote recipes to autonomous GitHub Agentic Workflows. Multiple surfaces can be active simultaneously.
Components are loaded from the official marketplace (synced on first use) and optional external marketplaces.
How to use anvil — the human story
If you have never used anvil before, read this first. The detailed command reference comes later.
Anvil works in two simple steps, and you only need to remember one CLI command. The rest happens in your AI agent (Copilot, Claude, or Cursor) in plain natural language.
Step 1 — Initialize the project with the CLI
In your terminal, at the root of any project (legacy or new):
anvil init --agent copilotReplace copilot by claude, cursor, or opencode if you use one of those instead. You can also target multiple agents at once by separating them with a comma:
anvil init --agent claude,opencodeThat's it for the CLI — anvil prepares the project (creates .anvil/, syncs the marketplace, installs the bootstrap skills) and stops.
Step 2 — Open your IDE and ask the AI agent to take over
Open your project in VSCode (Copilot), Claude Code, Cursor, or OpenCode, and simply tell your AI agent:
« Initialize the project » (or in French: « Initialise le projet »)
That's it. The agent will:
- Detect your stack (Java? Node? Python? Spring Boot? React?)
- Check that the tools you need are installed
- Suggest which AI components fit your project
- Build a complete project wiki in
.anvil/wiki/— architecture, stack, conventions, known issues, and a "clone-install-run" README — by analyzing your codebase and validating each page with you - Configure everything specific to your team (Jira? Linear? GitHub Issues?)
You stay in control the whole time. The agent explains what it does before doing it, asks before installing things, and you can stop at any moment.
What you get when it's done
A .anvil/ directory at the root of your project, ready to be committed and shared with your team:
.anvil/
config.json ← project configuration
wiki/ ← navigable project knowledge base (architecture, stack, features, ...)
state/ ← installed AI componentsYour teammates clone the repo, open their AI agent, and the wiki + the installed skills give the agent everything it needs to be useful immediately on a project they have never seen before. No more "the AI hallucinates because it doesn't know our codebase".
Day-to-day usage
After the initial setup, you keep talking to the agent in natural language:
- « Is the wiki up to date? » → the agent checks what changed and offers to refresh
- « Implement this ticket: PROJ-123 » → the agent uses the installed recipes
- « Review my code » → the agent uses the installed code-reviewer agent
- « What does the orders module do? » → the agent reads the wiki first and answers from grounded context
You almost never need to touch the anvil CLI again after anvil init. The agent uses anvil for you.
Special case — onboard a legacy app
If you are parachuted on a legacy app that nobody documents anymore, use the dedicated bundle when initializing:
anvil init --agent copilot --preset legacy-archaeologyThen ask the agent to « Initialize the project » as above. The agent will run a deep cartography of the codebase (dependency graph, entry points, patterns, tech debt) and produce a full validated wiki — typically 30 to 90 minutes of dialogue, after which your team can actually understand the app.
Quick Start (command reference)
The detailed list below is for advanced users and CI scripts. For day-to-day work, follow the "human story" above.
npm install -g @fr-nan-ai/anvil
# Initialize a project for GitHub Copilot
anvil init --agent copilot
# Or with a bundle (installs a curated set of components)
anvil init --agent copilot --preset full-stack
# Install components from the catalog
anvil install skill coding-principles
anvil install skill test-driven-development
anvil install hook pre-commit-check
# Customize a component for your team
anvil customize skill coding-principles
# Edit .anvil/state/local/skills/coding-principles/index.md
anvil generate
# Create a brand new local component
anvil create skill my-team-guidelines
# Promote a recipe to an autonomous GitHub workflow
anvil promote recipe my-workflow --target gh-aw
# Validate project integrity
anvil validate
# Check what's installed
anvil statusMulti-Surface Mode
Anvil can maintain multiple agent surfaces simultaneously. When several targets are active, every install, generate, create, remove, update, and customize command projects components to all active surfaces at once.
Initializing with multiple targets
# Initialize with two targets at once
anvil init --agent claude,opencode
# Initialize with three targets
anvil init --agent copilot,claude,opencodeAdding or removing surfaces on an existing project
# Add a surface without touching existing ones
anvil switch --add opencode
# Remove a surface (cleans up its files)
anvil switch --remove cursor
# Set the exact list of active targets (replaces the current set)
anvil switch --agent claude,opencode,copilotHow it works
The agent field in .anvil/config.json accepts either a single string (backward compatible) or an array:
{
"version": 2,
"agent": ["claude", "opencode"]
}When agent is an array, every command that touches the surface iterates over all adapters. State is shared — components are stored once in .anvil/state/ and projected to each target's native layout.
Checking active surfaces
anvil status
# Agent(s): claude, opencode
# Components (5):
# ...Surface isolation
Each adapter writes to its own directory tree, so there are no conflicts:
| Target | Owned paths |
|--------|-------------|
| copilot | .github/instructions/, .github/prompts/ |
| claude | AGENTS.md, .claude/ |
| cursor | .cursor/rules/ |
| opencode | AGENTS.md, .opencode/ |
Note:
claudeandopencodeboth writeAGENTS.md. When both are active, the last adapter to run writes the file. In practice both produce equivalent routing content, so this is harmless.
Supported Targets
| Target | Surface |
|--------|---------|
| copilot | .github/copilot-instructions.md, .github/instructions/, .github/prompts/ |
| claude | AGENTS.md, .claude/skills/ |
| cursor | .cursor/rules/*.mdc |
| opencode | AGENTS.md, .opencode/skills/ |
| gh-aw (promotion) | .github/workflows/*.md + .github/workflows/*.lock.yml |
Multi-surface mode: You can activate several targets at once. Every
anvil install,generate,create,remove,update, andcustomizecommand will project components to all active surfaces simultaneously. See Multi-Surface Mode below.
How It Works
Anvil follows a state-then-project architecture with a copy-on-customize model:
catalog (official + external marketplaces)
│
▼ anvil install
│
.anvil/state/framework/ ← installed components (read-only)
│
├── anvil customize ──► .anvil/state/local/ ← editable copies
│
▼ anvil generate
│
.github/instructions/ ← Copilot surface ┐
.claude/skills/ ← Claude surface │ all active
.opencode/skills/ ← OpenCode surface │ surfaces
.cursor/rules/ ← Cursor surface ┘anvil installcopies a component from the catalog into.anvil/state/framework/anvil customizecopies it to.anvil/state/local/for editinganvil generateprojects state into the agent's native surface (auto-selects local or framework)anvil updatemerges upstream changes into customized components (3-way merge with backup)anvil promotecompiles a recipe into a GitHub Agentic Workflow (.md+.lock.yml)- Components are tracked with SHA-256 hashes for version detection
Commands
| Command | Description |
|---------|-------------|
| anvil init --agent <target[,target2]> | Initialize a project for one or more AI agents |
| anvil switch --agent <target[,target2]> | Set the exact list of active agent targets |
| anvil switch --add <target> | Add an agent surface without removing existing ones |
| anvil switch --remove <target> | Remove an agent surface from the active set |
| anvil install <type> <name> | Install a component from the catalog |
| anvil remove <type> <name> | Remove an installed component |
| anvil customize <type> <name> | Copy a component to local for editing |
| anvil uncustomize <type> <name> | Restore the framework version |
| anvil create <type> <name> | Scaffold a new local component |
| anvil status | Show installed components and their state |
| anvil generate | Re-project state to agent surface files |
| anvil catalog | Browse available components |
| anvil inspect <type> <name> | Show component details before installing |
| anvil diff | Compare installed components with source |
| anvil update <type> <name> | Update a component from source |
| anvil update <type> <name> --preview | Preview changes without applying |
| anvil update <type> <name> --restore | Restore from backup after a bad merge |
| anvil marketplace list | List configured marketplace sources |
| anvil marketplace add <name> | Add an external marketplace |
| anvil marketplace remove <name> | Remove a marketplace source |
| anvil marketplace sync | Sync marketplace catalogs |
| anvil marketplace enable <name> | Enable a marketplace |
| anvil marketplace disable <name> | Disable a marketplace |
| anvil marketplace pin <name> | Pin a marketplace to a specific commit SHA |
| anvil marketplace unpin <name> | Remove a pinned commit SHA |
| anvil marketplace init <path> | Scaffold a new marketplace repository |
| anvil promote recipe <name> --target gh-aw | Promote a recipe to a GitHub Agentic Workflow |
| anvil promote --recompile <name> | Recompile a promoted workflow after recipe update |
| anvil validate | Validate project integrity (config, state, promotions) |
| anvil doctor | Diagnose installation health |
| anvil changelog | Show the anvil CHANGELOG (optionally since a given version) |
| anvil onboard complete | Mark project as onboarded |
Global Flags
| Flag | Description |
|------|-------------|
| --json | Output as structured JSON |
| --yes | Skip confirmation prompts (also ANVIL_YES=1) |
| --verbose | Verbose output |
| --quiet | Suppress non-essential output |
| --force | Force operation (skip guards) |
| --from <marketplace> | Specify source marketplace |
| --all | Apply to all components |
| --agent <target> | Target agent(s) for init / switch (comma-separated for multi) |
| --add <target> | Add an agent surface (anvil switch --add opencode) |
| --remove <target> | Remove an agent surface (anvil switch --remove cursor) |
| --preset <name> | Use a preset during init |
| --preview | Dry-run for update (show diff without writing) |
| --restore | Restore last backup after update |
| --since <version> | Starting version for anvil changelog |
| --tag <name> | Filter catalog / create by tag |
| --no-preserve | Bypass user-block preservation on anvil generate |
| --target <target> | Promotion target (currently gh-aw) |
| --trigger <event> | Trigger event for promoted workflow |
| --recompile | Recompile a promoted workflow |
| --dry-run | Simulate promotion without writing files |
| --help | Show help |
| --version | Show version |
Customization
Anvil uses a copy-on-customize model: framework components are read-only, and customization creates an editable local copy.
# Customize a framework component
anvil customize skill coding-principles
# Edit the local copy
# .anvil/state/local/skills/coding-principles/index.md
# Re-project to surface
anvil generate
# When upstream updates are available
anvil update skill coding-principles --preview # preview the diff
anvil update skill coding-principles # merge with auto-backup
anvil update skill coding-principles --restore # undo if merge was bad
# Revert to the framework version
anvil uncustomize skill coding-principlesCreating Local Components
# Create a brand new skill (not from catalog)
anvil create skill my-guidelines
# Create a recipe
anvil create recipe my-workflow
# Local components are stored in .anvil/state/local/
# and projected to the active surface automaticallyPromotion (GitHub Agentic Workflows)
Recipes with interactions and providers can be promoted to autonomous GitHub Agentic Workflows. Promotion compiles a recipe (with its dependent skills inlined) into a .md workflow and a .lock.yml lockfile.
# Promote a recipe to GitHub Agentic Workflow
anvil promote recipe us-to-pr --target gh-aw
# Preview what would be generated (dry-run)
anvil promote recipe us-to-pr --target gh-aw --dry-run
# Specify a custom trigger event
anvil promote recipe us-to-pr --target gh-aw --trigger "issues:labeled:ready"
# After updating a promoted recipe, recompile the workflow
anvil update recipe us-to-pr
# ⚠ Warning: promoted workflow is stale
anvil promote --recompile us-to-prGenerated files:
.github/workflows/<name>.md— workflow with frontmatter (trigger, tools, permissions) + recipe content + inlined skills.github/workflows/<name>.lock.yml— lockfile with recipe hash, compiled timestamp, interaction mappings
Interactions & Providers
Recipes can declare interactions (human-in-the-loop points) and providers (external integrations) in component.yaml:
interactions:
- id: validate-approach
phase: analysis
mode: interactive
fallback: comment
providers:
- type: ticket
name: ticket-source
required: trueThese are visible via anvil inspect recipe <name> and compiled into the workflow during promotion.
Hooks Runtime
Hooks with a script field in component.yaml execute shell scripts in response to events:
name: post-install-check
type: hook
event: post.install
script: scripts/check.sh
timeout: 5000Supported events: session.start, session.end, prompt.submitted, tool.pre, tool.post.success, tool.post.failure, post.install, post.remove, post.generate.
Scripts run via execFile (no shell, preventing metacharacter interpretation). Hooks are not sandboxed — they execute with the current user's privileges and filesystem/network access. The environment is filtered: only ANVIL_* variables plus a minimal allowlist (HOME, PATH, USER, SHELL, LANG, TMPDIR, and Windows equivalents like USERPROFILE, SYSTEMROOT, APPDATA) are forwarded. Host secrets (GITHUB_TOKEN, AWS_*, NPM_TOKEN, etc.) are NOT exposed to hook scripts.
Validation
# Full project integrity check
anvil validateValidates: catalog schema, config consistency, component state, hash integrity, surface projections, promotion consistency (workflow + lockfile exist, stale detection), and orphan components.
Marketplaces
Anvil supports multiple component sources. The official marketplace is fetched from GitHub and cached locally. You can add external sources via git or local path.
The URL of the official marketplace is set at anvil init time from either the environment variable ANVIL_OFFICIAL_MARKETPLACE_REMOTE or the built-in default. To override it for a given project, set the env var before running anvil init, or edit .anvil/config.json directly.
# Add a team marketplace from a git repo
anvil marketplace add myteam --git https://github.com/org/anvil-components.git
# Add a local marketplace (useful for development)
anvil marketplace add local-dev --local /path/to/components
# Sync all marketplaces
anvil marketplace sync
# Browse the unified catalog (all sources)
anvil catalog
# Install from a specific marketplace
anvil install skill my-skill --from myteam
# Scaffold a new marketplace repository
anvil marketplace init ./my-marketplaceWhen a component name exists in multiple marketplaces, anvil requires --from to disambiguate.
Extending onboarding for teams and organizations
Teams can ship their own prerequisites, component recommendations, and
checks without forking the official onboarding skill. Publish a regular
skill on your marketplace with the onboarding-extension tag and an
onboarding-phase field declared in component.yaml:
# component.yaml
schema: anvil.component/v1
name: team-nantes-onboarding
type: skill
version: 0.1.0
description: Équipe Nantes — prérequis internes
onboarding-phase: prerequisitesAnd tag the catalog entry on your marketplace's catalog.yaml:
items:
- name: team-nantes-onboarding
type: skill
path: skills/team-nantes-onboarding
description: Équipe Nantes — prérequis internes
tags: [onboarding-extension]Or use the CLI to do both at once (when run inside a marketplace repo):
anvil create skill team-nantes-onboarding \
--tag onboarding-extension \
--onboarding-phase prerequisitesThe skill's markdown body describes what to check, recommend, or do. The official onboarding will query the catalog at the appropriate phase, load every matching extension, and integrate its content into the flow.
Users opt in by adding the team marketplace before running onboarding
— either manually (anvil marketplace add team-nantes --git <url>) or
via the conversational Phase 0 question, where they can paste the URL
on first launch.
Supported phases
| Value | Phase | When it runs |
|-----------------|-------|----------------------------------------------------|
| prerequisites | 2 | After standard tool checks |
| components | 3 | During component recommendations |
| documentation | 4 | After wiki generation |
| configuration | 5 | After standard overrides |
| finalize | 6 | Before marking onboarding complete |
Where the field lives
The onboarding-phase field MUST be declared in component.yaml. It
is not read from frontmatter of index.md — that convention is
not supported. Anvil resolves the field at catalog load time (for items
tagged onboarding-extension) and exposes it via anvil catalog --json,
so downstream agents can filter on a JSON field without reading
component files themselves.
Multiple extensions can coexist (company + BU + team). They run in marketplace priority order.
Custom adapters
Anvil ships with built-in adapters for copilot, claude, cursor, and opencode. The marketplace of AI coding tools moves quickly; forking or waiting on a PR to try a new target (e.g. Poolside, Continue, Aider, an in-house agent) is not always acceptable. You can declare a custom adapter directly in .anvil/config.json:
{
"version": 2,
"agent": "poolside",
"agents": {
"poolside": { "module": "./local-adapters/poolside/index.js" }
},
"...": "..."
}The referenced module must export the same contract as the built-in adapters — see lib/adapters/shared.js::REQUIRED_METHODS:
name(string)getProjectionPath(projectRoot, componentType, componentName, source)→stringprojectComponent(projectRoot, componentType, componentName, source, stateDir)→Promise<string>removeProjection(projectRoot, componentType, componentName, source)→Promise<void>generateBase(projectRoot, config)→Promise<void>generateAll(projectRoot, config, stateStore)→Promise<void>listSurfacePaths(projectRoot, config)→string[](used byanvil switchto clean up old output)
Security posture
- Built-ins always win. A custom
agents.copilotpointing at an attacker-controlled module cannot shadow the realcopilotadapter. - Path confinement. The
modulepath is resolved relative toprojectRootand must remain under it. An attempt to point at/tmp/evil.jsor../../host-file.jsfails withCUSTOM_ADAPTER_UNCONFINED. SetANVIL_ALLOW_UNCONFINED_ADAPTERS=1to opt out — only do this when you explicitly want to load an adapter from outside the project. - Visible warning. Every custom-adapter load emits a
Warning: Loading custom adapter "<name>" from <path>line on stderr so you always see what third-party code Anvil is about to execute. - Contract validation. The loaded module is checked against the full adapter contract before any method is called. A missing required method fails with
ADAPTER_INVALIDat load time rather than silently at projection time.
Environment variables
ANVIL_OFFICIAL_MARKETPLACE_REMOTE— overrides the default URL of the official marketplace atanvil inittime.ANVIL_ALLOW_UNCONFINED_ADAPTERS=1— allowsconfig.agents.*.modulepaths to resolve outsideprojectRoot. Off by default.
Bundles (Presets)
Bundles are curated sets of components for common use cases, hosted in the marketplace:
anvil init --agent copilot --preset full-stackAvailable bundles: full-stack, tech-lead. Browse them with anvil catalog --type bundle.
Component Lifecycle
# Inspect before installing
anvil inspect skill coding-principles
# Install
anvil install skill coding-principles
# Customize for your team
anvil customize skill coding-principles
# Check for updates
anvil diff
# Update with 3-way merge (auto-backup)
anvil update skill coding-principles
# Preview update without writing
anvil update skill coding-principles --preview
# Restore backup if merge was bad
anvil update skill coding-principles --restore
# Update all non-customized components
anvil update --all
# Revert customization
anvil uncustomize skill coding-principles
# Remove (with dependency guard)
anvil remove skill coding-principlesProject Structure
After anvil init --agent copilot, your project will have:
.anvil/
config.json ← project config (v2 schema)
state/
framework/
official/ ← official catalog components
external/ ← external marketplace components
local/ ← customized + created components
backups/ ← automatic backups before merges
cache/
marketplaces/ ← synced marketplace catalogs
docs/ ← project documentation for agents
.gitignoreComponent Types
| Type | Description | Copilot | Claude | Cursor | OpenCode |
|------|-------------|---------|--------|--------|----------|
| skill | Reusable guidance | .github/instructions/*.instructions.md | .claude/skills/*.md | .cursor/rules/*.mdc | .opencode/skills/*.md |
| hook | Event-driven instructions | .github/instructions/*-hook.instructions.md | .claude/skills/*-hook.md | .cursor/rules/*-hook.mdc | .opencode/skills/*-hook.md |
| agent | Specialized AI agents | .github/instructions/*.instructions.md | .claude/skills/*.md | .cursor/rules/*.mdc | .opencode/agents/*.md |
| recipe | Multi-step workflows | .github/prompts/*.prompt.md | .claude/skills/*.md | .cursor/rules/*.mdc | .opencode/skills/*.md |
Component Format
Each component lives in its own directory with:
skills/coding-principles/
component.yaml ← metadata (type, name, version, targets, depends)
index.md ← contentConfiguration
.anvil/config.json uses a v2 schema:
{
"version": 2,
"agent": ["claude", "opencode"],
"marketplaces": {
"official": { "kind": "git", "enabled": true, "priority": 0, "remote": "https://github.com/FR-NAN-AI/anvil-marketplace.git", "ref": "main" },
"myteam": { "kind": "git", "enabled": true, "priority": 10, "remote": "..." }
},
"components": {
"skills": {
"coding-principles": {
"marketplace": "official",
"hash": "...",
"customized": false,
"frameworkHash": null
}
}
},
"promotions": {
"us-to-pr": {
"target": "gh-aw",
"recipeHash": "...",
"promotedAt": "...",
"trigger": "issues:labeled:agent-ready",
"workflowPath": ".github/workflows/us-to-pr.md",
"lockfilePath": ".github/workflows/us-to-pr.lock.yml",
"stale": false
}
},
"onboarded": false
}Doctor
anvil doctor runs comprehensive health checks:
- Node.js version (>= 18)
.anvil/structure integrity- Component state consistency (config ↔ state ↔ surface)
- SHA-256 hash integrity (detects manual edits)
- Orphan components (state without config entry)
- Orphan projections (surface files without matching component)
- Customized components with outdated upstream
- Stale backups (> 30 days)
- Marketplace cache status
Versioning
- 0.1.x: Copilot target, official catalog
- 0.2.x: Multi-target (Claude, Cursor), external marketplaces, presets
- 0.3.x: Customization (copy-on-customize), create, 3-way merge, backups
- 0.4.x: Promotion (gh-aw), validate, hooks runtime, interactions/providers
- 0.5.x: Remote official marketplace, educational onboarding, improved adapters
- 0.7.x: OpenCode adapter, multi-surface mode (multiple agents simultaneously)
- v1.0.0: Stable API, production ready
Development
# Run E2E tests
node test/e2e-phase1.js # 42 tests — core commands
node test/e2e-phase2.js # 57 tests — marketplaces, adapters, lifecycle
node test/e2e-phase3.js # 62 tests — customization, create, merge, backups
node test/e2e-phase4.js # 49 tests — promotion, validate, hooks runtime
# Test manually
node bin/anvil --help
node bin/anvil --versionArchitecture
bin/anvil ← entry point
lib/
cli/
parse-args.js ← argument parser (Node 18+ util.parseArgs)
output.js ← structured output (JSON/text)
core/
config.js ← .anvil/config.json v2
state-store.js ← .anvil/state/ management
hash.js ← SHA-256 component tracking
catalog.js ← catalog reader + multi-source merge
marketplace.js ← marketplace registry (add/remove/enable)
marketplace-sync.js ← git clone + cache management
marketplace-cmd.js ← anvil marketplace CLI handler (+ init)
preset.js ← preset loading + apply
dependencies.js ← dependency graph + remove guard
init.js ← anvil init (+ preset support)
install.js ← anvil install (multi-source)
remove.js ← anvil remove (with dependency check)
customize.js ← anvil customize + uncustomize
create.js ← anvil create (scaffold local component)
backup.js ← automatic backups before merge
merge.js ← 3-way merge engine
status.js ← anvil status
generate.js ← anvil generate
inspect.js ← anvil inspect
diff.js ← anvil diff
update.js ← anvil update (+ merge, --preview, --restore)
promote.js ← anvil promote (recipe → gh-aw workflow)
validate.js ← anvil validate (project integrity)
hooks-runtime.js ← hooks script execution (filtered env, execFile)
doctor.js ← anvil doctor (hash integrity, orphans)
onboard.js ← anvil onboard
adapters/
shared.js ← adapter interface contract
index.js ← adapter registry
copilot/transform.js ← Copilot adapter (.github/)
claude/transform.js ← Claude adapter (AGENTS.md, .claude/)
cursor/transform.js ← Cursor adapter (.cursor/rules/)
opencode/transform.js ← OpenCode adapter (AGENTS.md, .opencode/)
gh-aw/transform.js ← GitHub Agentic Workflow adapter (promotion)
skills/
onboarding/ ← embedded fallback (auto-installed on init)
anvil-cli-reference/ ← embedded fallback (auto-installed on init)
catalog-browser/ ← embedded fallback (auto-installed on init)License
MIT — see LICENSE
