If you've been building AI agents with Claude Code, you've probably hit this wall: your SKILL.md starts as a clean 50-line file, and three months later it's a 400-line monolith that nobody wants to touch.
There's a better way.
The Problem with Monolithic Prompts
As your Claude Code projects grow, a single SKILL.md tends to accumulate everything:
- Role definitions
- Domain knowledge (account codes, product catalogs, compliance rules)
- Output format specs
- Conditional logic for edge cases
- Changelog notes
The result is a file that's hard to read, hard to test, and impossible to share across skills. When your "accounting assistant" and your "invoice generator" both need the same tax code definitions, you end up copy-pasting — and then maintaining two diverging copies.
Sound familiar?
The Solution: @include and @delegate
dotmd-parser introduces two directives that bring modular design to prompt engineering.
@include — inline composition
@include path/to/file.md
At runtime, the contents of the referenced file are inserted inline — exactly like #include in C or import in Python. The final prompt seen by the model is the fully expanded text.
Example:
# Invoice Generator
@include shared/role-accountant.md
@include shared/tax-codes.md
@include shared/output-format.md
## Task
Generate an invoice for the following items: {{items}}
Each shared file stays focused on one thing. role-accountant.md defines who the model is. tax-codes.md is your master reference for tax rates. output-format.md specifies the JSON schema you expect back.
When tax rates change, you update one file — and every skill that @includes it picks up the change automatically.
@delegate — agent composition
@delegate path/to/agent.md
@delegate path/to/agent.md --parallel
Where @include expands content, @delegate hands off execution to a sub-agent. The referenced file is not expanded inline — it's a separate agent that runs independently (or in parallel with --parallel).
Example:
# Document Processing Pipeline
@include shared/role-orchestrator.md
## Steps
1. Extract text from uploaded document
@delegate agents/ocr-extractor.md
2. Classify document type
@delegate agents/doc-classifier.md --parallel
3. Route to appropriate handler
@delegate agents/routing-agent.md
This is how you build multi-agent workflows without everything living in one file.
A Real-World Example: Customer Support Skill
Here's how a customer support skill looks when broken into modules:
support/
├── SKILL.md # Root — orchestrates everything
├── shared/
│ ├── role.md # "You are a support specialist..."
│ ├── product-catalog.md # Product names, SKUs, pricing
│ ├── escalation-rules.md # When to escalate to human
│ └── response-format.md # JSON output schema
└── agents/
├── intent-classifier.md # Classifies ticket intent
└── kb-search.md # Searches knowledge base
SKILL.md ties it together:
# Customer Support Skill
@include shared/role.md
@include shared/product-catalog.md
@include shared/escalation-rules.md
@include shared/response-format.md
## Workflow
Classify the customer intent first:
@delegate agents/intent-classifier.md
Then search for relevant articles:
@delegate agents/kb-search.md --parallel
The dependency graph looks like this:
SKILL.md
├── shared/role.md
├── shared/product-catalog.md
├── shared/escalation-rules.md
├── shared/response-format.md
├── agents/intent-classifier.md
└── agents/kb-search.md
Clean. Readable. Each file has a single responsibility.
When It Gets Complex: dotmd-parser
Once you have 10+ files referencing each other, questions start coming up:
- "I want to update
shared/escalation-rules.md— what else will break?" - "Is there a circular reference somewhere in this skill tree?"
- "What
{{variables}}are left unresolved after expansion?"
This is where dotmd-parser comes in.
pip install dotmd-parser
Build the dependency graph
from dotmd_parser import build_graph, summary
graph = build_graph("./support/")
print(summary(graph))
# Nodes: 7 (skill:1, shared:4, agent:2)
# Edges: 6 (include:4, delegate:2)
# Warnings: 0
Find what breaks before you edit
from dotmd_parser import build_graph, dependents_of
graph = build_graph("./support/")
affected = dependents_of(graph, "/abs/path/to/shared/product-catalog.md")
# → ["/abs/path/to/support/SKILL.md"]
One call tells you the full blast radius of your change.
Detect circular references
graph = build_graph("./bad-skill/")
# Warnings: 1
# [CIRCULAR] 循環参照: bad-skill/SKILL.md -> b.md -> bad-skill/SKILL.md
Circular references are caught at parse time — not when your agent starts looping at runtime.
Expand @include to final text
from dotmd_parser import resolve
result = resolve("./support/SKILL.md", variables={"items": "laptop, mouse"})
print(result["content"]) # Fully expanded prompt
print(result["placeholders"]) # Any unresolved {{variables}}
The @include Convention
There's no official spec for @include in Claude Code — this is a convention we've been building on top of SKILL.md. The format is intentionally simple:
@include relative/path/to/file.md
@delegate relative/path/to/agent.md
@delegate relative/path/to/agent.md --parallel
dotmd-parser also tracks Read \path/to/file.md`references (runtime reads that don't expand inline) and{{variable}}` placeholders.
If you're building anything non-trivial with Claude Code, we'd encourage you to try this pattern. The overhead is low — it's just Markdown files — and the payoff in maintainability is significant.
What's Next: dotmd-io
dotmd-parser is the open-source core. We're building dotmd-io on top of it — a web platform that gives your whole team a visual interface for managing SKILL.md dependencies:
- Dependency graph visualization (ReactFlow + D3)
- Monaco Editor with
@include/@delegatesyntax highlighting - A/B testing and prompt scoring via Claude API
- Git-based version control with one-click rollback
- RBAC for non-engineers to safely edit prompts
If that sounds useful, watch the repo: github.com/dotmd-projects/dotmd-parser
Getting Started
`bash
pip install dotmd-parser
`
Start with a small skill and try extracting one shared file:
`plaintext
my-skill/
├── SKILL.md # @include shared/role.md
└── shared/
└── role.md # Just the role definition
`
Run the parser to verify:
`bash
dotmd-parser ./my-skill/
Nodes: 2 (skill:1, shared:1)
Edges: 1 (include:1)
Warnings: 0
`
Once it clicks, you'll find yourself refactoring every prompt you write.
Built something with @include? We'd love to see it — open an issue or drop a comment below.
Tags: claudecode promptengineering python ai opensource
Top comments (0)