xcaffold import: From Existing Configs to a Managed Project in Minutes
You already have a .claude/ directory with agents, skills, and rules you spent hours crafting. xcaffold import turns your existing configuration into typed .xcaf manifests without overwriting a single file.
Every developer who has used Claude Code for more than a few weeks ends up with the same artifact: a .claude/ directory full of agents, skills, and rules that represent real engineering effort. Carefully tuned system prompts. Tool permissions calibrated through trial and error. Rules that encode hard-won project knowledge.
And every one of those developers knows, somewhere in the back of their mind, that this directory is fragile. There is no schema. No validation. No way to detect when a colleague's well-intentioned edit silently breaks an agent's behavior. The .claude/ directory is a collection of loose markdown files held together by convention and hope.
xcaffold import changes that. It reads your existing provider configuration and produces typed, validated .xcaf manifests -- without touching your original files.
What xcaffold import Does
The import command runs a four-stage pipeline:
- Detect -- scans the current directory for known provider patterns (
.claude/,.cursor/rules/,.github/copilot-instructions.md, etc.) - Extract -- each detected provider's importer reads native files and maps them to xcaffold resource types (agents, skills, rules, hooks, settings, MCP servers, memory)
- Merge -- when multiple providers are detected, smart assembly reconciles overlapping resources into base files plus provider-specific overrides
- Write -- emits a
project.xcafand the fullxcaf/directory tree
Your original .claude/ directory (or .cursor/, or any other provider directory) is never modified. The import is additive -- it creates new files alongside your existing setup.
Single-Provider Import
The simplest case: you have one provider and you want to take ownership of its configuration.
xcaffold import --target claude
The --target flag tells xcaffold to import from a specific provider. Every extracted resource is tagged with targets: [claude] in its manifest, recording where it came from.
For Claude Code, the importer maps native files to xcaffold resources:
| Source | Extracted to |
|---|---|
.claude/agents/*.md | xcaf/agents/<name>/agent.xcaf |
.claude/skills/*/SKILL.md | xcaf/skills/<name>/skill.xcaf (with references/ preserved) |
.claude/rules/*.md | xcaf/rules/<name>/rule.xcaf |
.claude/settings.json | xcaf/settings/default/settings.xcaf |
.mcp.json | xcaf/mcp/<name>/mcp.xcaf (one per server) |
If you omit --target, xcaffold auto-detects every provider present in the directory. When only one is found, the behavior is identical to specifying it explicitly.
The Dry-Run Preview
Before writing anything to disk, you can preview exactly what the import would produce:
xcaffold import --target claude --dry-run
The --dry-run flag runs the full detection and extraction pipeline, then prints the list of resources that would be created -- without writing any files. This lets you verify the decomposition before committing to it.
You can combine --dry-run with kind filters to focus on specific resource types:
xcaffold import --target claude --dry-run --agent --skill
This previews only agents and skills, ignoring rules, hooks, settings, and MCP servers. The kind filters (--agent, --skill, --rule, --workflow, --mcp, --hook, --setting, --memory) work the same way with or without --dry-run.
Multi-Provider Import with Smart Assembly
Here is where xcaffold earns its keep. If your project uses both Claude Code and Cursor, a plain xcaffold import (no --target flag) detects both providers and runs a merge import.
xcaffold import
The merge uses smart assembly to handle overlapping resources:
| Scenario | What xcaffold does |
|---|---|
| Same resource name, identical content across providers | Creates a single base file |
| Same resource name, different frontmatter fields | Creates a base file with shared content, plus provider-specific override files |
| Same resource name, different body content | Base file gets the common content; overrides carry the divergent body |
| Resource exists in only one provider | Single file with a targets tag identifying the source provider |
The provider with the fewest provider-specific fields becomes the base. Override files contain only the fields that differ, keeping the directory clean.
For example, if you have a code review agent defined in both Claude Code and Cursor, but Claude's version includes extra tool permissions, the import produces:
xcaf/agents/code-review/
agent.xcaf # base definition (shared fields)
agent.claude.xcaf # Claude-specific overrides (extra tools)
agent.cursor.xcaf # Cursor-specific overrides (if any)
Directory Layout After Import
After a multi-provider import, the xcaf/ directory follows a consistent structure:
xcaf/
agents/
researcher/
agent.xcaf
agent.claude.xcaf
agent.cursor.xcaf
memory/
skills/
code-review/
skill.xcaf
skill.claude.xcaf
rules/
security/
rule.xcaf
hooks/
default/
hooks.xcaf
mcp/
github-mcp/
mcp.xcaf
mcp.claude.xcaf
settings/
default/
settings.xcaf
Each resource type gets its own top-level directory. Each resource gets a subdirectory named after its ID. Base definitions use the kind name as the filename (agent.xcaf, skill.xcaf, rule.xcaf). Provider overrides append the provider name (agent.claude.xcaf, skill.cursor.xcaf).
The root project.xcaf is minimal -- it declares the project name and target providers:
kind: project
version: "1.0"
name: my-api-service
targets:
- claude
- cursor
Resources are auto-discovered from the xcaf/ directory tree. There is no need to list them in the project file.
Taking Ownership: The Workflow Shift
Once the import is complete, the mental model changes. The xcaf/ directory is now your source of truth. You edit .xcaf manifests, then compile them into provider-native output:
xcaffold validate # schema validation, catches errors before compile
xcaffold apply # compiles xcaf/ into .claude/, .cursor/, etc.
| Before import | After import |
|---|---|
Edit .claude/agents/code-reviewer.md directly | Edit xcaf/agents/code-reviewer/agent.xcaf, then run xcaffold apply |
| No validation -- any text is valid markdown | Parser rejects unknown fields and malformed values |
| Drift between providers is invisible | One source, compiled to every target |
| Single provider at a time | One manifest, multiple provider outputs |
If you ever need to start fresh -- perhaps after significant manual changes to your provider directories -- the --force flag deletes the existing project.xcaf and xcaf/ directory before reimporting:
xcaffold import --force
The -y flag skips confirmation prompts if you want to run import non-interactively:
xcaffold import --target claude -y
From Loose Files to a Compiled Pipeline
The migration from hand-managed provider directories to xcaffold manifests is a one-command operation. The import handles the mechanical extraction. What takes longer is the conceptual shift: understanding that the files in .claude/ or .cursor/rules/ are no longer the source of truth -- they are compiled output.
That shift is the point. It is what turns agent configuration from artisanal file editing into a repeatable, validated, multi-provider pipeline.
Ready to try xcaffold? Already have .claude/ or .cursor/ configs? Import them in 5 minutes.