Skip to content

Commit b3ff603

Browse files
committed
Add plan 73: unify template and processing directives
Addresses #68 (unify template syntax) and #70 (central directive documentation). Proposes a two-kind marker model (generator vs constraint), resolving the {{.field}} syntax ambiguity, and a comprehensive directive guide. https://claude.ai/code/session_015XXFMqS3iqmbyMsNJFeCeY
1 parent 331f2c8 commit b3ff603

1 file changed

Lines changed: 234 additions & 0 deletions

File tree

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
---
2+
id: 73
3+
title: Unify template and processing directives
4+
status: "🔲"
5+
summary: >-
6+
Evaluate unifying catalog templates,
7+
required-structure patterns, and processing
8+
directives under a single user model with a
9+
simple mental model and a comprehensive guide.
10+
---
11+
# Unify template and processing directives
12+
13+
Addresses [#68](https://github.com/jeduden/mdsmith/issues/68)
14+
(unify template syntax) and
15+
[#70](https://github.com/jeduden/mdsmith/issues/70)
16+
(central directive documentation).
17+
18+
## Problem
19+
20+
mdsmith exposes three separate mini-languages
21+
for in-document directives:
22+
23+
1. **Go `text/template`** in catalog `row`/`header`
24+
/`footer` parameters
25+
(`{{.title}}`, `{{.filename}}`)
26+
2. **Pattern placeholders** in required-structure
27+
heading templates (`{{.field}}` matched as
28+
regex wildcards)
29+
3. **Processing-instruction markers** with YAML
30+
bodies (`<?catalog ... ?>`, `<?include ... ?>`,
31+
`<?require ... ?>`, `<?allow-empty-section?>`)
32+
33+
A user must learn all three to use the tool
34+
confidently. The concepts overlap but the
35+
behaviors diverge:
36+
37+
- `{{.title}}` in a catalog row *renders* a
38+
value; `{{.title}}` in a required-structure
39+
heading *matches* any text.
40+
- `<?require?>` is a single marker with no
41+
closing tag; `<?catalog?>` is a marker pair
42+
whose body is regenerated.
43+
- `<?allow-empty-section?>` takes no parameters;
44+
`<?catalog?>` takes up to seven.
45+
46+
## Goal
47+
48+
Give each directive a clear "if X then Y" rule
49+
so users can predict behavior on sight. Write
50+
one guide that covers all directives with
51+
examples.
52+
53+
## Analysis of current user model
54+
55+
### What a user sees today
56+
57+
| Marker | X (trigger) | Y (effect) |
58+
|--------------------------------|----------------------|---------------------------------------|
59+
| `<?catalog ...?>` | Marker pair in file | Body is regenerated from glob matches |
60+
| `<?include ...?>` | Marker pair in file | Body is replaced with included file |
61+
| `<?require ...?>` | Marker in template | Filename must match glob |
62+
| `<?allow-empty-section?>` | Marker after heading | Empty section is allowed |
63+
| `{{.field}}` in catalog row | Inside `row:` param | Replaced with front-matter value |
64+
| `{{.field}}` in template heading | Inside template `.md` | Heading must contain that value |
65+
66+
### Pain points
67+
68+
1. **Same syntax, different semantics** --
69+
`{{.field}}` means "insert value" in catalog
70+
but "match any text" in required-structure.
71+
2. **Marker pairs vs single markers** -- no
72+
visual cue tells the user whether a marker
73+
needs a closing tag.
74+
3. **Parameter count varies wildly** -- from
75+
zero (allow-empty-section) to seven (catalog).
76+
4. **No single reference** -- rules are
77+
documented per-rule; no unified walkthrough
78+
exists.
79+
80+
### What works well
81+
82+
- The `<?name ... ?>` syntax is visually
83+
distinct from Markdown content.
84+
- YAML inside markers is familiar to users who
85+
already write front matter.
86+
- Catalog and include share the same
87+
open/generate/close lifecycle via the
88+
`gensection` archetype.
89+
90+
## Proposed user model
91+
92+
### Principle: two kinds of markers
93+
94+
Collapse all directives into two categories a
95+
user can identify on sight:
96+
97+
| Kind | Shape | Rule | User prediction |
98+
|------------|-------------------------------|-----------------------------------------------|-----------------------------------------------------|
99+
| **Generator** | `<?name ...?>` ... `<?/name?>` | Content between markers is managed by mdsmith | "If I see a marker pair, `fix` regenerates the body" |
100+
| **Constraint** | `<?name ...?>` (no closing tag) | The marker asserts a condition | "If I see a lone marker, `check` validates something" |
101+
102+
The core rule: if a marker has a closing tag,
103+
the body is auto-generated; if it does not, it
104+
is a validation constraint.
105+
106+
This is already almost true today. The plan
107+
makes it explicit and documents it as the
108+
governing rule.
109+
110+
### Principle: one template language
111+
112+
Unify `{{.field}}` to always mean the same
113+
thing: "insert the value of `field`."
114+
115+
- **Catalog** already uses Go `text/template` --
116+
keep as-is.
117+
- **Required-structure** currently reuses the
118+
`{{.field}}` syntax for pattern matching, not
119+
insertion. This is the source of confusion.
120+
121+
**Proposal**: change required-structure to use a
122+
different sigil for wildcard matching. Two
123+
options:
124+
125+
| Option | Syntax | Meaning |
126+
|-----------------|-----------------------|------------------------------------------------------------|
127+
| A (recommended) | `{field}` single braces | "heading must contain the value of front-matter key `field`" |
128+
| B | `*` | "any text" (glob-style) |
129+
130+
Option A keeps the link to front matter explicit
131+
while removing the visual collision with Go
132+
templates. Option B is simpler but loses the
133+
field-name hint.
134+
135+
**Decision required from maintainer:** pick A
136+
or B before implementation.
137+
138+
### Principle: consistent YAML parameters
139+
140+
All directives already use YAML for parameters.
141+
No change needed, but the guide must present
142+
them with a uniform layout:
143+
144+
```markdown
145+
<?directive-name
146+
param1: value
147+
param2: value
148+
?>
149+
```
150+
151+
### What does NOT change
152+
153+
- The `<?...?>` marker syntax itself stays.
154+
- The YAML parameter format stays.
155+
- The `gensection` engine for generators stays.
156+
- The `fix` / `check` CLI commands stay.
157+
- `.mdsmith.yml` configuration stays.
158+
159+
This is intentionally conservative. The goal is
160+
a clearer mental model and a guide, not a
161+
rewrite.
162+
163+
## Tasks
164+
165+
### Phase 1: central directive reference (#70)
166+
167+
1. Write `docs/guides/directives.md` covering:
168+
169+
- The two-kind model (generator vs
170+
constraint)
171+
- Placement constraints: must be at document
172+
root, at most 3-space indent, ignored
173+
inside fenced code blocks and HTML blocks
174+
- Every directive with: purpose, parameters,
175+
one good example, one bad example, what
176+
`check` reports, what `fix` does
177+
- A quick-reference table at the top
178+
- Classification by role: "generated-section
179+
markers" vs "rule modifiers / escape
180+
hatches" (per #70)
181+
182+
2. Add cross-links from each rule README to the
183+
guide.
184+
3. Update `CLAUDE.md` catalog to include the new
185+
page.
186+
187+
### Phase 2: resolve `{{.field}}` ambiguity
188+
189+
4. Decide on Option A or B for
190+
required-structure patterns (needs maintainer
191+
input).
192+
5. Implement the chosen syntax in
193+
`requiredstructure/rule.go`:
194+
195+
- Update pattern extraction to use new sigil
196+
- Keep `{{.field}}` as a deprecated alias for
197+
one release cycle
198+
199+
6. Update `internal/rules/MDS020-required-structure/README.md`.
200+
7. Update the directive guide with the new
201+
syntax.
202+
8. Migrate existing template files
203+
(`plan/proto.md`,
204+
`internal/rules/proto.md`,
205+
`.claude/skills/proto.md`) to the new syntax.
206+
207+
### Phase 3: evaluate template engine (stretch)
208+
209+
9. Prototype replacing Go `text/template` with
210+
gonja or pongo2 in catalog rendering.
211+
212+
- Measure: does Jinja syntax reduce user
213+
confusion vs Go templates?
214+
- Measure: does it enable filters/conditionals
215+
that users actually need?
216+
217+
10. If the prototype shows clear benefit, plan a
218+
migration. If not, keep Go `text/template` and
219+
document its quirks in the guide.
220+
221+
## Acceptance Criteria
222+
223+
- [ ] `docs/guides/directives.md` exists and
224+
covers every directive with examples
225+
- [ ] The guide passes `mdsmith check
226+
docs/guides/`
227+
- [ ] `{{.field}}` in required-structure
228+
templates uses a distinct syntax from
229+
catalog templates (Phase 2)
230+
- [ ] Existing template files are migrated
231+
(Phase 2)
232+
- [ ] All tests pass: `go test ./...`
233+
- [ ] `go tool golangci-lint run` reports no
234+
issues

0 commit comments

Comments
 (0)