Plan: Server-Side Template Rendering
Plan: Server-Side Template Rendering
Vision
Any agent or client can create structured notes (plans, phases, issues) by providing structured data instead of hand-writing HTML. Templates are stored in pal-e-docs, rendered server-side via Jinja2, and exposed through the full stack (API → SDK → MCP → commands). Token cost for plan creation drops from ~3000 to ~500.
Projects & Repos Touched
| Project/Repo | Platform | Role in this plan |
|---|---|---|
| pal-e-docs | Forgejo | API endpoint + Jinja2 rendering engine. Template storage (code blocks with <code>language: "jinja2"</code>). |
| pal-e-docs-sdk | Forgejo | New <code>create_note_from_template()</code> method. |
| pal-e-docs-mcp | Forgejo | New <code>create_note_from_template</code> MCP tool (thin SDK wrapper). |
| claude-custom | Forgejo | <code>/plan</code> command that guides agent to provide structured data → calls MCP tool. |
Context
Plan creation currently requires agents to hand-write ~3000 tokens of repetitive HTML. The
template-plan note documents the structure, and hooks enforce required sections, but agents still produce the full HTML by hand. Every phase repeats the same boilerplate (Slug/Goal/Owner/Repo/Issue). This is wasteful and error-prone.Discovered during basketball project session when Betty Sue created
plan-2026-03-08-tryout-prep without using the template skill (which doesn't exist yet). The hook caught compliance but couldn't prevent the token waste.What's already done:
- [x] Template notes exist in pal-e-docs (
template-plan,template-phase, etc.) - [x] Hooks enforce template compliance (
check-note-template.sh,check-phase-template.sh) - [x] Full stack exists: API → SDK → MCP → commands (Phase 8 architecture)
- [x] Block API with anchor_ids works for all block types (PR #120, #125, #127)
- [ ] No Jinja2 templates exist yet
- [ ] No
/plancommand exists yet - [ ] No server-side rendering endpoint exists
Previous Plan
plan-2026-02-26-tf-modularize-postgres — Epilogue item 10 identified the need. The block API fixes (Epilogue item 9) unblocked surgical template editing.Depends On
None. All prerequisites are met (Phase 8 stack, block API fixes).
Decisions Made
| Decision | Rationale |
|---|---|
| Server-side rendering in pal-e-docs API, not MCP server | API is the service layer. MCP is a client. SvelteKit frontend will need the same rendering — put it where all clients can use it. |
| Jinja2 templates stored as code blocks (<code>language: "jinja2"</code>) in existing template notes | No schema changes needed. Template notes already have a human-readable pseudo-template in a code block — add a second code block with the machine-renderable Jinja2. Both live together. |
| Start with <code>template-plan</code> only, extend to phases/issues later | Plans have the highest token waste (~3000 per plan). Phases and issues are smaller. Prove the pattern on the biggest win first. |
| Full stack: API → SDK → MCP → <code>/plan</code> command | Same Phase 8 pattern. Proven architecture. |
| <strong>DEFERRED (2026-03-09):</strong> Phases 3-4 paused after Phase 2 completion | The MCP tool is live — Betty Sue can call <code>create_note_from_template</code> directly. The <code>/plan</code> command (Phase 3) would just be a prompt wrapper around something she already knows how to do. Questionable ROI. The tool exists, the ceremony doesn't need automation yet. Revisit if plan creation becomes frequent enough to justify it. |
Phases
Phase 1: Jinja2 plan template + API endpoint
- Slug:
phase-2026-03-09-1-jinja2-api - Goal: Add a
POST /notes/from-templateendpoint that accepts structured JSON + template slug and returns a created note with rendered HTML - Owner: Dev agent
- Repo:
forgejo_admin/pal-e-docs - Forgejo Issue: #128 (closed), #132 QA nits (closed)
- PR: #131 (merged, squash)
- Status: COMPLETED
Scope
- Add
jinja2to dependencies - Write the Jinja2 HTML template for plans and add it to the
template-plannote as a code block withlanguage: "jinja2" - New route:
POST /notes/from-template— accepts{"template_slug": "template-plan", "slug": "...", "title": "...", "tags": "...", "project": "...", "data": {...}} - Route fetches template note → finds Jinja2 code block → renders with data → calls existing
create_notelogic - Define the data schema for plans (vision, repos, context, phases, decisions, key_files, verification, next_plan_seeds, related)
- Tests: unit test for Jinja2 rendering, integration test for the endpoint
Phase 2: SDK + MCP tool
- Slug:
phase-2026-03-09-2-sdk-mcp - Goal: Expose template rendering through the SDK and MCP tool so agents can use it
- Owner: Dev agent
- Repo:
forgejo_admin/pal-e-docs-sdk+forgejo_admin/pal-e-docs-mcp - Forgejo Issue: pal-e-docs-sdk #19 (closed), pal-e-docs-mcp #28 (closed)
- PR: pal-e-docs-sdk #21 (merged), pal-e-docs-mcp #31 (merged)
- Status: COMPLETED. Subphase 2a test hygiene also completed (PR #25, issue #24).
Scope
- SDK: new method
create_note_from_template(template_slug, slug, title, data, tags=None, project=None) - MCP: new tool
create_note_from_templatewrapping the SDK method. Tool description documents the data schema for each template type. - Tests: SDK integration test, MCP tool unit test
Phase 3: /plan command
- Slug:
phase-2026-03-09-3-plan-command - Goal: Create a
/planslash command that guides agents to provide structured data and calls the MCP tool - Owner: Dev agent
- Repo:
forgejo_admin/claude-custom - Forgejo Issue: TBD
Scope
- Create
commands/plan.md— structured prompt that: - Deploy: copy to
~/.claude/commands/ - Update
template-plannote to reference the command
Phase 4: Extend to phase + issue templates
- Slug:
phase-2026-03-09-4-extend-templates - Goal: Add Jinja2 templates for
template-phaseandtemplate-issue, proving the system is extensible - Owner: Dev agent
- Repo:
forgejo_admin/pal-e-docs+forgejo_admin/pal-e-docs-mcp - Forgejo Issue: TBD
Scope
- Write Jinja2 templates for phases and issues
- Add to existing template notes as code blocks
- MCP tool already supports any template_slug — just document the data schemas for phases and issues in the tool description
- Optional:
/phaseand/issuecommands
Key Files
| Phase | File | Repo | Change |
|---|---|---|---|
| 1 | <code>src/pal_e_docs/routes/notes.py</code> | pal-e-docs | New <code>POST /notes/from-template</code> endpoint |
| 1 | <code>src/pal_e_docs/services/template_renderer.py</code> | pal-e-docs | Jinja2 rendering service (new file) |
| 1 | <code>pyproject.toml</code> | pal-e-docs | Add jinja2 dependency |
| 2 | <code>src/pal_e_docs_sdk/client.py</code> | pal-e-docs-sdk | New <code>create_note_from_template()</code> method |
| 2 | <code>src/pal_e_docs_mcp/tools/notes.py</code> | pal-e-docs-mcp | New MCP tool |
| 3 | <code>commands/plan.md</code> | claude-custom | New command (new file) |
Verification
- [ ] Phase 1:
curl POST /notes/from-templatewith plan data creates a note with correct HTML structure, all required sections present - [ ] Phase 1: Hook
check-note-template.shwould pass on the rendered output (all ### headings present) - [ ] Phase 2:
create_note_from_templateMCP tool creates a plan with ~500 tokens of input instead of ~3000 - [ ] Phase 3:
/plancommand walks agent through structured data collection and creates the note - [ ] Phase 4: Phase and issue templates render correctly via the same endpoint
Next Plan Seeds
- Template versioning — what happens when a Jinja2 template changes? Notes created from v1 vs v2 will differ. May need a
template_versionfield. - SvelteKit template UI — web form that maps to the same API endpoint. Deferred to the frontend migration plan.
- Template validation — Pydantic models for each template's data schema, validated at the API layer. Would give better error messages than Jinja2 rendering failures.
Related
todo-jinja2-plan-templates— the TODO that spawned this plantemplate-plan— the existing plan template (will gain a Jinja2 code block)template-phase— Phase 4 targettemplate-issue— Phase 4 targetphase-postgres-epilogue-cleanup— Epilogue item 10plan-2026-02-26-tf-modularize-postgres— parent plan (Epilogue)check-note-template.sh— existing enforcement hook (should still pass on rendered output)