agpm-cli 0.4.14

AGent Package Manager - A Git-based package manager for coding agents
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
# Markdown Templating

AGPM supports powerful Tera-based templating for Markdown resources, enabling dynamic content generation during installation. Templates allow resources to reference each other, access installation metadata, and adapt to different environments.

## Table of Contents

- [Overview]#overview
- [Template Variables Reference]#template-variables-reference
- [Syntax and Features]#syntax-and-features
  - [Custom Filters]#custom-filters
- [Examples]#examples
- [Controlling Templating]#controlling-templating
- [Security and Sandboxing]#security-and-sandboxing
- [Migration Guide]#migration-guide

## Overview

When you install a Markdown resource (agent, snippet, command, etc.) that has templating enabled via frontmatter, AGPM processes any template syntax it contains. This allows you to:

- **Reference other resources**: Access install paths and versions of dependencies
- **Access installation metadata**: Use project paths, versions, and source information
- **Use conditional logic**: Show/hide content based on context
- **Iterate over collections**: Loop through dependencies or other data
- **Normalize paths**: Convert between platform-specific path formats

Templates use the [Tera](https://keats.github.io/tera/) template engine with a restricted, secure configuration.

**Templating is opt-in**: Resources must explicitly enable templating in their YAML frontmatter by setting `agpm.templating: true`. By default, all template syntax is preserved as literal text.

## Template Variables Reference

This is the canonical reference for all variables available in AGPM templates. All documentation references this table.

### Current Resource Variables

| Variable | Type | Description | Example Value |
|----------|------|-------------|---------------|
| `agpm.resource.type` | string | Resource type | `agent`, `snippet`, `command`, `mcp-server`, `script`, `hook` |
| `agpm.resource.name` | string | Logical manifest name | `helper-snippet` |
| `agpm.resource.install_path` | string | Resolved install target (platform-native separators*) | `.claude/agents/agpm/helper.md` |
| `agpm.resource.source` | string \| null | Source identifier (null for local resources) | `community` |
| `agpm.resource.version` | string \| null | Resolved version (null for local resources) | `v1.2.0` |
| `agpm.resource.resolved_commit` | string \| null | Git SHA if applicable | `abc123def456...` |
| `agpm.resource.checksum` | string | SHA256 checksum of content | `sha256:...` |
| `agpm.resource.path` | string | Source-relative path in repository | `agents/helper.md` |

**\*Platform-Native Path Separators**: The `install_path` variable uses backslashes on Windows (`.claude\agents\agpm\helper.md`) and forward slashes on Unix/macOS (`.claude/agents/agpm/helper.md`). This ensures paths match the user's platform conventions. See [Cross-Platform Path Handling](#cross-platform-path-handling) for details.

### Dependency Variables

Dependencies declared in YAML frontmatter are available in templates, organized by category and accessed by their logical name.

| Variable Pattern | Type | Description | Example |
|-----------------|------|-------------|---------|
| `agpm.deps.<category>.<name>.install_path` | string | Install path for dependency | `.agpm/snippets/utils.md` |
| `agpm.deps.<category>.<name>.version` | string \| null | Dependency version | `v1.0.0` |
| `agpm.deps.<category>.<name>.resolved_commit` | string \| null | Dependency commit SHA | `def456...` |
| `agpm.deps.<category>.<name>.checksum` | string | Dependency checksum | `sha256:...` |
| `agpm.deps.<category>.<name>.source` | string \| null | Dependency source | `community` |
| `agpm.deps.<category>.<name>.path` | string | Source-relative path | `snippets/utils.md` |
| `agpm.deps.<category>.<name>.content` | string \| null | Processed file content (Markdown: frontmatter stripped, JSON: metadata removed) | `"# Example\n..."` |

**Category Names** (plural forms): `agents`, `snippets`, `commands`, `scripts`, `hooks`, `mcp-servers`

**Example - Declaring and Accessing Dependencies**:

First, declare dependencies in your resource's YAML frontmatter:
```yaml
---
dependencies:
  snippets:
    - path: snippets/helper-utils.md
      version: v1.0.0
  agents:
    - path: agents/code-reviewer.md
---
```

Then access them in your template (note: hyphens in filenames become underscores in variable names):
```jinja2
{{ agpm.deps.snippets.helper_utils.install_path }}
{{ agpm.deps.agents.code_reviewer.version }}
```

The variable name comes from the filename (not the path), with hyphens converted to underscores.

### Project Variables

Project-specific template variables provide context to AI agents about your project's conventions, documentation, and standards. Define arbitrary variables in the `[project]` section of `agpm.toml` with any structure you want.

| Variable Pattern | Type | Description | Example |
|-----------------|------|-------------|---------|
| `agpm.project.<name>` | any | User-defined project variable | `{{ agpm.project.style_guide }}` |
| `agpm.project.<section>.<name>` | any | Nested project variables | `{{ agpm.project.paths.architecture }}` |

**Configuration** (in `agpm.toml`):

```toml
[project]
# Arbitrary structure - organize however makes sense for your project
style_guide = "docs/STYLE_GUIDE.md"
max_line_length = 100
test_framework = "pytest"

# Optional nested organization (just for clarity)
[project.paths]
architecture = "docs/ARCHITECTURE.md"
conventions = "docs/CONVENTIONS.md"

[project.standards]
indent_style = "spaces"
indent_size = 4
```

**Template Usage**:

```markdown
---
name: code-reviewer
---
# Code Reviewer

Follow our style guide at: {{ agpm.project.style_guide }}

## Standards
- Max line length: {{ agpm.project.max_line_length }}
- Indentation: {{ agpm.project.standards.indent_size }} {{ agpm.project.standards.indent_style }}

## Documentation
Refer to:
- Architecture: {{ agpm.project.paths.architecture }}
- Conventions: {{ agpm.project.paths.conventions }}
```

**Key Features**:
- **Completely flexible structure** - No predefined fields, organize variables however you want
- **Nested sections supported** - Use dotted paths for organization (`project.paths.style_guide`)
- **All TOML types work** - Strings, numbers, booleans, arrays, tables
- **Optional** - Project section is entirely optional, templates work without it

See the [Manifest Reference](manifest-reference.md#project-variables) for more details.

### Templating Dependency Paths

Project variables can be used in **transitive dependency paths** within resource frontmatter. This enables dynamic dependency resolution based on project configuration.

**Use Case**: Language-specific or framework-specific dependency paths.

**Example** - Language-specific style guide:

```yaml
---
dependencies:
  snippets:
    - path: snippets/standards/{{ agpm.project.language }}-guide.md
      version: v1.0.0
---
# Code Reviewer Agent

Reviews code according to language-specific standards.
```

With `agpm.toml`:
```toml
[project]
language = "rust"
```

The dependency path resolves to: `snippets/standards/rust-guide.md`

**Example** - Framework-specific configuration:

```yaml
---
dependencies:
  commands:
    - path: commands/{{ agpm.project.framework }}/deploy.md
---
# Deployment Agent
```

**Optional Variables**: Use the `default` filter for optional variables:

```yaml
---
dependencies:
  snippets:
    - path: configs/{{ agpm.project.env | default(value="development") }}-config.md
---
```

**Opt-Out**: Disable templating for specific resources using `agpm.templating: false`:

```yaml
---
agpm:
  templating: false
dependencies:
  snippets:
    # Template syntax preserved literally - not rendered
    - path: examples/{{ literal_syntax }}.md
---
```

**Key Features**:
- ✅ Uses same `agpm.project.*` variables as content templates
- ✅ Respects per-resource `agpm.templating` opt-out setting
- ✅ Works in both YAML frontmatter and JSON dependencies
- ✅ Errors on undefined variables (use `default` filter for optional vars)

See [Transitive Dependencies](manifest-reference.md#transitive-dependencies) for more details on dependency declaration.

### Important Notes

**Resource Name Sanitization**: Resource names containing hyphens are automatically converted to underscores in template variable names to avoid conflicts with Tera's minus operator. For example:
- A resource named `helper-snippet` in your manifest
- Is accessed in templates as `helper_snippet`
- Example: `{{ agpm.deps.snippets.helper_snippet.install_path }}`

## Syntax and Features

### Variable Substitution

Use double curly braces to insert variables:

```markdown
# {{ agpm.resource.name }}

This resource is installed at: `{{ agpm.resource.install_path }}`
Version: {{ agpm.resource.version }}
```

### Conditional Logic

Use `{% if %}` blocks for conditional content:

```markdown
{% if agpm.resource.source %}
This resource is from the {{ agpm.resource.source }} source.
{% else %}
This is a local resource.
{% endif %}

{% if agpm.resource.version %}
Version: {{ agpm.resource.version }}
{% endif %}
```

### Loops

Iterate over dependencies or other collections:

```markdown
## Available Helpers

{% for name, snippet in agpm.deps.snippets %}
- **{{ name }}**: `{{ snippet.install_path }}` ({{ snippet.version }})
{% endfor %}
```

### Comments

Use `{# #}` for template comments (not included in output):

```markdown
{# This comment won't appear in the installed file #}
# {{ agpm.resource.name }}
```

### Custom Filters

#### `content` Filter

Read and embed project-specific files (style guides, architecture docs, team conventions) directly into your templates:

```markdown
{{ 'path/to/file.md' | content }}
```

**Use Cases**:
- Embed company coding standards
- Include team-specific conventions
- Reference architecture documentation
- Pull in project-specific guidelines

**Security**:
- Path validation prevents directory traversal attacks
- Only text files allowed: `.md`, `.txt`, `.json`, `.toml`, `.yaml`
- Absolute paths rejected
- Files must exist in project root
- File size limit: 1 MB by default (configurable in `~/.agpm/config.toml`)

**Content Processing**:
- **Markdown (.md)**: YAML/TOML frontmatter automatically stripped
- **JSON (.json)**: Parsed and pretty-printed
- **Other files**: Raw text content

**Recursive Rendering**: Project files can reference other project files using template syntax, up to 10 levels deep. The template engine automatically re-renders until no template syntax remains or the depth limit is reached.

**Example - Basic Usage**:

```markdown
---
agpm.templating: true
---
# Code Review Agent

## Company Style Guide
{{ 'project/styleguide.md' | content }}

## Team Conventions
{{ 'docs/conventions.txt' | content }}
```

**Example - Recursive Project Files**:

Main agent (`.claude/agents/agpm/reviewer.md`):
```markdown
---
agpm.templating: true
---
# Code Reviewer

{{ 'project/styleguide.md' | content }}
```

Style guide (`project/styleguide.md`):
```markdown
# Coding Standards

## Language-Specific Rules
{{ 'project/rust-style.md' | content }}
{{ 'project/python-style.md' | content }}
```

**Combining with Dependency Content**:

Use both `content` filter (for local files) and dependency `.content` fields (for versioned AGPM resources) together:

```markdown
---
agpm.templating: true
dependencies:
  snippets:
    - path: snippets/rust-patterns.md
      name: rust_patterns
    - path: snippets/error-handling.md
      name: error_handling
---
# Rust Code Reviewer

## Shared Rust Patterns (versioned, from AGPM)
{{ agpm.deps.snippets.rust_patterns.content }}

## Project-Specific Style Guide (local)
{{ 'project/rust-style.md' | content }}

## Error Handling Best Practices (versioned, from AGPM)
{{ agpm.deps.snippets.error_handling.content }}

## Team Conventions (local)
{{ 'docs/team-conventions.txt' | content }}
```

**When to Use Each**:
- **`agpm.deps.<type>.<name>.content`**: Versioned content from AGPM repositories (shared patterns, reusable snippets)
- **`content` filter**: Project-local files (team docs, company standards, living documentation)

## Examples

### Basic Agent with Metadata

```markdown
---
title: {{ agpm.resource.name }}
---
# {{ agpm.resource.name }}

**Version**: {{ agpm.resource.version }}
**Install Location**: `{{ agpm.resource.install_path }}`
**Source**: {{ agpm.resource.source }}

## Description

This agent is managed by AGPM and automatically installed.
```

### Agent Referencing Dependencies

First, declare dependencies in frontmatter:

```yaml
---
title: Code Reviewer
dependencies:
  snippets:
    - path: snippets/style-guide.md
      version: v1.0.0
    - path: snippets/best-practices.md
      version: v1.0.0
  agents:
    - path: agents/documentation-helper.md
      version: v2.0.0
---
```

Then reference them in your template:

```markdown
# Code Reviewer Agent

This agent uses the following helper resources:

{% if agpm.deps.snippets %}
## Helper Snippets
{% for name, snippet in agpm.deps.snippets %}
- [{{ name }}]{{ snippet.install_path }} - {{ snippet.version }}
{% endfor %}
{% endif %}

{% if agpm.deps.agents.documentation_helper %}
## Related Agent
This reviewer works with the [Documentation Helper]({{ agpm.deps.agents.documentation_helper.install_path }}).
{% endif %}
```

**Note**: The loop variable `name` will contain the sanitized filename with underscores (e.g., `style_guide`, `best_practices`), not the original filename with hyphens.

### Embedding Content from Dependencies

You can embed the actual content of dependencies directly into your templates. This is especially useful for including snippets, guidelines, or reusable documentation without creating separate files.

First, declare a dependency with `install: false` to prevent file creation:

```yaml
---
title: Code Review Agent
dependencies:
  snippets:
    - path: snippets/coding-standards.md
      version: v1.0.0
      install: false  # Don't create a separate file
      name: coding_standards
---
```

Then embed the content directly in your template:

```markdown
# Code Review Agent

## Coding Standards

Below are the coding standards this agent enforces:

{{ agpm.deps.snippets.coding_standards.content }}

## Review Process

When reviewing code, I will check compliance with the standards above...
```

**Key Points**:
- `install: false` prevents creating `.agpm/snippets/coding-standards.md`
- Content is automatically processed (YAML frontmatter stripped from Markdown)
- The `content` field is available for ALL dependencies (not just `install: false`)
- Returns `null` if content extraction fails (with warning logged)

**Template Syntax Preservation**:

Dependencies with `templating: false` have their template syntax preserved literally when embedded. This is useful for documentation examples that show template usage:

```yaml
---
title: Template Examples Snippet
agpm:
  templating: false
---
# Template Usage Examples

Here's how to reference a dependency:
```
{{ agpm.deps.snippets.helper.content }}
```

The Vue syntax {{ user.name }} is preserved.
```

When this snippet is embedded in a parent agent with `templating: true`:

```markdown
---
agpm:
  templating: true
dependencies:
  snippets:
    - path: snippets/template-examples.md
      install: false
---
# Documentation Agent

{{ agpm.deps.snippets.template_examples.content }}
```

The output will contain the literal template syntax from the snippet, perfect for documentation that teaches template usage.

**Rendering Strategy**:
- Dependencies with `templating: true` are rendered with their own context before embedding
- Dependencies with `templating: false` have frontmatter stripped but template syntax preserved
- Parent resources render once with pre-processed dependency content already in context
- This single-pass approach ensures predictable, deterministic output

### Conditional Content

```markdown
# Installation Info

{% if agpm.resource.source %}
This resource is from the **{{ agpm.resource.source }}** repository ({{ agpm.resource.version }}).
{% else %}
This is a local resource.
{% endif %}

Install location: `{{ agpm.resource.install_path }}`
```

### Dynamic Documentation

```markdown
---
title: Project Setup
---
# Resource Dependencies

This {{ agpm.resource.type }} resource has the following dependencies:

{% if agpm.deps.agents %}
## Agents ({{ agpm.deps.agents | length }})
{% for name, agent in agpm.deps.agents %}
- `{{ agent.install_path }}` - {{ agent.version }}
{% endfor %}
{% endif %}

{% if agpm.deps.snippets %}
## Snippets ({{ agpm.deps.snippets | length }})
{% for name, snippet in agpm.deps.snippets %}
- `{{ snippet.install_path }}` - {{ snippet.version }}
{% endfor %}
{% endif %}
```

## Controlling Templating

### Enabling Templating Per-Resource

Templating is **disabled by default** for all resources. To enable template processing for a specific resource, add `templating: true` to its YAML frontmatter:

```markdown
---
title: My Agent
agpm:
  templating: true
---
# {{ agpm.resource.name }}

This resource will have its template syntax processed during installation.
```

### Disabling Templating (Default)

By default, all template syntax is kept literal and not processed. To explicitly document this intent, you can set `templating: false`:

```markdown
---
title: My Agent
agpm:
  templating: false
---
# This file contains literal {{ template.syntax }}

The template syntax above will be preserved as-is.
```

This default behavior is useful for:
- Resources that contain literal template syntax for documentation
- Example code that shows template usage
- Resources that don't need dynamic content

### Files Without Template Syntax

Plain Markdown files without any `{{`, `{%`, or `{#` syntax are passed through unchanged with minimal overhead.

## Caching Behavior

AGPM intelligently caches rendered template output to improve installation performance. Understanding how caching works helps you predict when re-rendering will occur.

### Cache Key Components

The cache is based on two factors:

1. **Source file content**: The raw Markdown file content (before rendering)
2. **Template context**: Dependency versions, installation paths, and other metadata from the lockfile

When either component changes, the cache is invalidated and the template is re-rendered.

### Automatic Cache Invalidation

Templates are automatically re-rendered when:

- **Source file changes**: Any modification to the Markdown file content
- **Dependency version updates**: A dependency updates to a new version (even if the dependency's file content hasn't changed)
- **Dependency path changes**: A dependency's installation path changes
- **New dependencies added**: Additional resources are added to the lockfile
- **Dependencies removed**: Resources are removed from the lockfile

### Cache Hits

Templates are NOT re-rendered when:

- **Source and context unchanged**: Both the source file and all dependency metadata remain identical
- **Unrelated dependency changes**: Changes to dependencies not referenced in the template
- **Non-templated files**: Plain Markdown files without template syntax skip rendering entirely

### Example Scenarios

**Scenario 1: Dependency version update**
```yaml
# Before: agpm.toml
[snippets]
helper = { source = "community", path = "snippets/helper.md", version = "v1.0.0" }

# After: agpm.toml
helper = { source = "community", path = "snippets/helper.md", version = "v1.1.0" }
```

**Result**: Any agent using `{{ agpm.deps.snippets.helper.version }}` will be re-rendered with the new version, even if `helper.md`'s content didn't change.

**Scenario 2: Unrelated dependency change**
```markdown
# agent.md
---
dependencies:
  snippets:
    - path: snippets/helper.md
---
# My Agent

Uses helper: {{ agpm.deps.snippets.helper.version }}
```

If `snippets/other-unrelated.md` updates, `agent.md` will NOT be re-rendered because it doesn't reference the changed dependency.

### Force Fresh Installation

To bypass the cache and force fresh clones of all repositories:

```bash
agpm install --no-cache
```

This is useful for:
- Debugging template rendering issues
- Verifying that templates produce expected output
- Recovering from corrupted cache state (rare)

**Note**: `--no-cache` clones repositories fresh, which may be slower for large projects. Normal cache invalidation handles most scenarios automatically.

## Security and Sandboxing

AGPM's templating engine is configured with strict security restrictions:

### Disabled Features

For safety, the following Tera features are **disabled**:
- `{% include %}` tags (no file system access)
- `{% extends %}` tags (no template inheritance)
- `{% import %}` tags (no external template imports)
- Custom functions that access the file system or network

### Safe Operations

The following operations are fully supported and safe:
- Variable substitution
- Conditional logic (`{% if %}`)
- Loops (`{% for %}`)
- Built-in filters (string manipulation, formatting)
- Template comments

### Error Handling

If a template fails to render:
- **Syntax errors**: Install fails with a descriptive error message
- **Unknown variables**: Install fails with suggestions for available variables
- **Missing dependencies**: Clear error indicating which dependency is missing

## Migration Guide

### Upgrading Existing Resources

If you have existing Markdown resources with hard-coded paths:

**Before (hard-coded)**:
```markdown
This agent is installed at `.claude/agents/agpm/helper.md`.
See also: `.claude/snippets/utils.md`
```

**After (templated)** (note: hyphens become underscores):
```markdown
This agent is installed at `{{ agpm.resource.install_path }}`.
See also: `{{ agpm.deps.snippets.utils_snippet.install_path }}`
```

### Escaping Literal Braces

If you need literal `{{` or `}}` characters in your documentation:

```markdown
To use Tera syntax, write: {{ "{{" }} variable {{ "}}" }}
Or use raw blocks for code examples:

{% raw %}
{{ this.is.literal.syntax }}
{% endraw %}
```

### Testing Templates

Before committing templated resources:

1. Install locally to verify rendering:
   ```bash
   agpm install
   cat .claude/agents/agpm/your-agent.md
   ```

2. Check for template errors in the output

3. Verify all dependency references resolve correctly

### Gradual Adoption

You can mix templated and non-templated resources:
- New resources can use templates immediately
- Existing resources can be updated incrementally
- Use `agpm: { templating: false }` for resources that should remain static

## Best Practices

1. **Use descriptive variable names in manifests** - Template references use manifest names (sanitized with underscores)
2. **Avoid hyphens in resource names** - Use underscores instead to avoid confusion with template variable names
3. **Test with different dependency combinations** - Ensure conditionals work when dependencies are missing
4. **Document template variables** - Add comments explaining what each template section does
5. **Keep templates simple** - Avoid complex logic for better maintainability
6. **Test locally first** - Always install and verify templated resources locally before committing
7. **Understand cross-platform path behavior** - Template paths use platform-native separators (see below)

### Cross-Platform Path Handling

Template variables like `{{ agpm.resource.install_path }}` automatically use platform-native path separators:

- **Windows**: Paths render with backslashes (`.claude\agents\helper.md`)
- **Unix/macOS**: Paths render with forward slashes (`.claude/agents/agpm/helper.md`)

This ensures that paths in installed content match what users see in their file explorer. However, **lockfiles always use forward slashes** for cross-platform compatibility, so teams on different platforms can share the same `agpm.lock` file.

**Example**: A template like this:

```markdown
This agent is installed at: {{ agpm.resource.install_path }}
```

Will render differently based on platform:

- **Windows**: `This agent is installed at: .claude\agents\example.md`
- **Unix/macOS**: `This agent is installed at: .claude/agents/agpm/example.md`

This means the **installed content will differ by platform**, but the lockfile remains consistent.

## Configuration

### File Size Limit

The `content` filter enforces a file size limit to prevent memory exhaustion when embedding large files. By default, the limit is **1 MB (1,048,576 bytes)**.

You can customize this limit in your global AGPM configuration (`~/.agpm/config.toml`):

```toml
# Global file size limit (applies to template content filter and other operations)
max_content_file_size = 2097152  # 2 MB in bytes
```

**Common Size Values**:
- 512 KB: `524288`
- 1 MB (default): `1048576`
- 2 MB: `2097152`
- 5 MB: `5242880`
- 10 MB: `10485760`

If a file exceeds the configured limit, the template rendering will fail with a clear error message showing both the file size and the limit.

## Troubleshooting

### "Template rendering failed"

- **Cause**: Syntax error in template
- **Solution**: Check the error message for line/column information, verify bracket matching

### "Unknown variable: agpm.deps.snippets.xyz"

- **Cause**: Referenced dependency not in lockfile
- **Solution**: Ensure the dependency is declared in `agpm.toml` and installed

### Template syntax not processed

- **Cause**: Templating disabled by default (resources must opt-in via frontmatter)
- **Solution**: Add `templating: true` to the resource's YAML frontmatter under the `agpm` key

### "Variable not found" with hyphenated names

- **Cause**: Resource names with hyphens are sanitized to underscores
- **Solution**: Use underscores in template variable names (e.g., `helper_utils` instead of `helper-utils`)

## See Also

- [Tera Template Documentation]https://keats.github.io/tera/docs/ - Full Tera syntax reference
- [AGPM Manifest Reference]manifest.md - How to declare dependencies
- [AGPM CLI Reference]cli/ - Command-line flags and options