Including Files¶
The include directive lets you compose prompts from multiple files.
Basic Usage¶
---
title: Full Review
parameters:
code: null
---
<%= include 'common/header.md' %>
Review this code:
<%= code %>
<%= include 'common/footer.md' %>
How Includes Work¶
Each included file goes through the full processing pipeline:
- HTML comments stripped
- YAML metadata extracted
- Shell expansion applied
- ERB rendered (with the parent's parameter values)
The included file's rendered content replaces the <%= include ... %> tag.
Path Resolution¶
Include paths are resolved relative to the parent file's directory:
prompts/
review.md # contains: <%= include 'common/header.md' %>
common/
header.md # resolved from prompts/common/header.md
Parameter Passing¶
The parent's parameter values are passed to included files. Child files can use the same parameter names:
Nested Includes¶
Includes can be nested. File A can include File B, which includes File C:
<!-- a.md -->
<%= include 'b.md' %>
<!-- b.md -->
<%= include 'c.md' %>
<!-- c.md -->
Content from C
Circular Include Detection¶
PM detects circular includes and raises an error:
<!-- circular_a.md -->
<%= include 'circular_b.md' %>
<!-- circular_b.md -->
<%= include 'circular_a.md' %>
Includes Metadata¶
After calling to_s, the parent's metadata has an includes key with a tree of what was included:
parsed = PM.parse('full_review.md')
parsed.to_s('code' => source)
parsed.metadata.includes
#=> [
# {
# path: "/prompts/common/header.md",
# depth: 1,
# metadata: { title: "Header", ... },
# includes: []
# },
# {
# path: "/prompts/common/footer.md",
# depth: 1,
# metadata: { title: "Footer", ... },
# includes: []
# }
# ]
Nested includes form a tree -- each entry's includes array contains its own children.
The includes array is nil before to_s is called and is reset on each call.
insert / read — Raw File Insertion¶
Use insert (or its alias read) to insert a file's content verbatim. Unlike include, the content is not parsed, shell-expanded, or ERB-rendered:
### Differences from `include`
| | `insert` | `include` |
|---|---|---|
| File types | Any | `.md` only |
| ERB in content | Preserved as literal text | Rendered |
| Shell expansion | Not applied | Applied |
| Recursion | None | Nested includes supported |
| Metadata tracking | None | `metadata.includes` tree |
### Path resolution
Same as `include` — paths resolve relative to the parent file's directory. Absolute paths work from any context, including string-parsed prompts.
### Missing files
Raises an error:
```ruby
PM.parse("---\n---\n<%= insert '/no/such/file' %>").to_s
#=> RuntimeError: insert: file not found: /no/such/file
Requirements¶
- The
includedirective requires file context. Using it with string-parsed prompts raises an error:
PM.parse("---\n---\n<%= include 'other.md' %>").to_s
#=> RuntimeError: include requires a file context (use PM.parse with a file path)
- When
erb: false, the include directive does not execute andmetadata.includesis an empty array.