Guide to creating and using postfix templates for command output, and introspecting template data schemas.
Verb output templates enable you to append custom, structured output to docmgr commands after they complete their normal human-friendly output. This system decouples command logic from output formatting, allowing you to create LLM-friendly summaries, automation-friendly data structures, or custom reports without modifying the command code. Templates are optional and only render when present, making them perfect for team-specific workflows or integration with external tools.
Verb templates are Go text templates that render after a command finishes its normal output. They receive structured data from the command and can format it however you need—as YAML summaries, JSON snippets, markdown reports, or any other text format.
Key characteristics:
Template schema introspection lets you discover what data is available to templates without reading source code. Each command that supports templates can print its data structure using the --print-template-schema flag, showing field names, types, and nested structures in JSON or YAML format.
Use cases:
Templates are resolved from the docs root (ttmp/ by default) using a canonical path based on the command's verb structure:
Grouped verbs: templates/<group>/<verb>.templ
docmgr doc list → templates/doc/list.templdocmgr list tickets → templates/list/tickets.templSingle-level verbs: templates/<verb>.templ
docmgr doctor → templates/doctor.templdocmgr status → templates/status.templResolution order:
All verb templates receive a common envelope of data available to every template:
type CommonTemplateData struct {
Verbs []string // Full verb path, e.g., ["docmgr", "doc", "list"]
Root string // Absolute docs root used
Now time.Time // Rendering timestamp
Settings map[string]interface{} // Parsed layer values (flags, config)
}
In templates, access these as:
{{ .Verbs }} — Command path array{{ .Root }} — Docs root directory{{ .Now }} — Current timestamp{{ .Settings }} — Command settings mapEach command provides its own data structure in addition to the common envelope. For example, doc list provides:
type DocListTemplateData struct {
TotalDocs int
TotalTickets int
Tickets []struct {
Ticket string
Docs []struct {
DocType string
Title string
Status string
Topics []string
Updated string
Path string
}
}
}
Access verb-specific data directly in templates: {{ .TotalDocs }}, {{ range .Tickets }}, etc.
Before writing a template, discover what data is available using the --print-template-schema flag:
# Print schema for doc list command
docmgr doc list --print-template-schema
# Print schema in YAML format
docmgr doc list --print-template-schema --schema-format yaml
# Print schema for doctor command
docmgr doctor --print-template-schema
Example schema output:
{
"type": "object",
"properties": {
"TotalDocs": {
"type": "integer"
},
"TotalTickets": {
"type": "integer"
},
"Tickets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"Ticket": {
"type": "string"
},
"Docs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"DocType": {
"type": "string"
},
"Title": {
"type": "string"
},
"Status": {
"type": "string"
}
}
}
}
}
}
}
}
}
When to use schema introspection:
First, print the schema to understand what fields are available:
docmgr doc list --print-template-schema --schema-format yaml
Create the template file at the canonical path. For docmgr doc list, create:
ttmp/templates/doc/list.templ
Use Go text template syntax with the data structure from the schema:
{{- /* LLM-oriented summary of docs */ -}}
---
summary:
docs: {{ .TotalDocs }}
tickets: {{ .TotalTickets }}
guidance: |
Prefer the most recently updated docs per ticket when summarizing.
top_docs:
{{- range $t := .Tickets }}
{{- range $d := $t.Docs | slice 0 1 }}
- ticket: {{ $t.Ticket }}
title: {{ $d.Title }}
type: {{ $d.DocType }}
status: {{ $d.Status }}
path: {{ $d.Path }}
{{- end }}
{{- end }}
Run the command to see your template rendered:
docmgr doc list
# Normal output appears first...
# Then your template output appears
Verb templates have access to Go's standard template functions plus Sprig template functions for common operations:
Common functions:
slice — Extract sub-slices: {{ slice .Items 0 5 }}first, last — Get first/last element: {{ first .Items }}has, hasKey — Check existence: {{ if has "key" .Map }}default — Provide defaults: {{ .Value | default "unknown" }}upper, lower, title — String transformationsjoin — Join slices: {{ join .Topics ", " }}len — Get length: {{ len .Items }}Custom functions:
countBy — Count items matching a condition (used in doctor templates)See the Sprig documentation for the complete function list.
File: templates/doc/list.templ
{{- /* LLM-oriented summary of docs */ -}}
---
summary:
docs: {{ .TotalDocs }}
tickets: {{ .TotalTickets }}
guidance: |
Prefer the most recently updated docs per ticket when summarizing.
top_docs:
{{- range $t := .Tickets }}
{{- range $d := $t.Docs | slice 0 1 }}
- ticket: {{ $t.Ticket }}
title: {{ $d.Title }}
type: {{ $d.DocType }}
status: {{ $d.Status }}
path: {{ $d.Path }}
{{- end }}
{{- end }}
File: templates/doctor.templ
---
doctor_summary:
findings_total: {{ .TotalFindings }}
by_ticket:
{{- range .Tickets }}
- ticket: {{ .Ticket }}
errors: {{ countBy .Findings "ERROR" }}
warnings: {{ countBy .Findings "WARNING" }}
oks: {{ countBy .Findings "OK" }}
{{- end }}
guidance: |
Address ERRORs first. For WARNINGs, add owner and due date.
File: templates/status.templ
---
workspace_status:
total_tickets: {{ .TicketsTotal }}
stale_tickets: {{ .TicketsStale }}
total_docs: {{ .DocsTotal }}
doc_breakdown:
design: {{ .DesignDocs }}
reference: {{ .ReferenceDocs }}
playbooks: {{ .Playbooks }}
stale_after_days: {{ .StaleAfterDays }}
Templates should provide summary or structured data, not duplicate the command's normal output. Use them for:
YAML is more readable than JSON for human consumption and works well with LLMs:
---
summary:
total: {{ .Total }}
items:
{{- range .Items }}
- name: {{ .Name }}
status: {{ .Status }}
{{- end }}
Use default to handle missing or zero values:
{{ .Value | default "unknown" }}
{{ if .OptionalField }}{{ .OptionalField }}{{ end }}
Add comments explaining what the template produces:
{{- /* LLM-oriented summary for automation */ -}}
{{- /* Team-specific status report format */ -}}
Always check the schema before writing templates:
docmgr <verb> --print-template-schema
Store templates in your repository so they're versioned with your documentation:
ttmp/
├── templates/
│ ├── doc/
│ │ └── list.templ
│ └── doctor.templ
The following commands support verb output templates:
doc list / list docs — Lists all documentslist tickets — Lists all ticketsdoctor — Validation and health checksstatus — Workspace status summarysearch — Document search resultstasks list — Task listingsvocab list — Vocabulary listingsdoc guidelines — Guideline displayEach command provides its own data structure. Use --print-template-schema to discover the exact fields available.
Example templates are available in the codebase at examples/verb-templates/. Copy these to ttmp/templates/ in your workspace to use them, or use them as reference when creating your own:
# Copy example templates to your workspace
cp -r examples/verb-templates/* ttmp/templates/
Available examples:
examples/verb-templates/doc/list.templ — Document listing summaryexamples/verb-templates/list/tickets.templ — Ticket listing summaryexamples/verb-templates/doctor.templ — Doctor findings summaryexamples/verb-templates/status.templ — Status reportexamples/verb-templates/examples/*.templ — Advanced examplesCheck:
ttmp/templates/<group>/<verb>.templ--with-glaze-output)Debug:
# Check if template file exists
ls -la ttmp/templates/doc/list.templ
# Test template syntax (if using a Go template validator)
Template errors print warnings to stderr but don't fail the command. Check stderr for details:
docmgr doc list 2>&1 | grep -i "template\|warning"
Use schema introspection to see available fields:
docmgr doc list --print-template-schema
Ensure you're using valid Sprig functions. Check the Sprig documentation for available functions.
Verb templates are ideal for automation workflows:
CI/CD Integration:
# Generate LLM-friendly summary for ticket review
docmgr doc list --ticket MEN-1234 > summary.yaml
# Extract structured data for reporting
docmgr doctor --all | grep -A 100 "doctor_summary" > health-report.yaml
LLM Integration: Templates can format output specifically for LLM consumption, providing structured summaries that LLMs can easily parse and reason about.
Commands can provide custom template functions beyond Sprig. Check command documentation or source code for command-specific functions like countBy used in doctor templates.