Skip to content

feat: surface agent_description README frontmatter to agent template tools#26212

Open
johnstcn wants to merge 21 commits into
mainfrom
cj/codagt-447-readme-frontmatter
Open

feat: surface agent_description README frontmatter to agent template tools#26212
johnstcn wants to merge 21 commits into
mainfrom
cj/codagt-447-readme-frontmatter

Conversation

@johnstcn

@johnstcn johnstcn commented Jun 10, 2026

Copy link
Copy Markdown
Member

Implements CODAGT-447 without a database migration, so it can be backported to a patch release.

Agents pick templates from templates.description (VARCHAR(128)), which is too short. Rather than add a column (#25978, needs a migration), this surfaces a new agent_description README frontmatter key from the existing template_versions.readme column to the agent template-detail tools.

  • Add coderd/util/frontmatter: a lightweight, hugo-free parser with a typed, locked key set and an AgentDescription helper (trims, truncates to 2048 runes).
  • Surface agent_description to the agent template tools, best-effort so a missing or unreadable version never fails the tool: read_template and list_templates on the Coder Agents (chatd) surface, and coder_get_template on the public MCP surface. The chatd list_templates fetches each page template's active version with the template-scoped GetTemplateVersionByID (same access path as read_template, bounded by the page size of 10) and returns the full description so an agent can choose in a single call.
  • Migrate scripts/examplegen to the shared parser; examples.gen.json is byte-identical and the hugo dependency is dropped (go.sum -117 lines).
  • Add agent_description to the Docker, Kubernetes, AWS, and GCP example templates and document it under docs/ai-coder/.

The longer text (up to 2048 runes) is agent-only and never shown in the dashboard.

Decision log
  • Migration-free over the abstract column (feat: add template abstracts for agents #25978): the column approach needs a migration and cannot be backported to a patch; the customer issue warrants a backport.
  • Dedicated agent_description key, not reused description: the dashboard starter-import flow prefills CreateTemplateRequest.Description from frontmatter description (bound by lt=128); overloading it would break that path.
  • Locked, typed schema shared by examplegen and the agent tools: unknown keys are ignored, not rejected, so existing templates keep working.
  • Lightweight parser, not hugo: keeps hugo out of the server/agent binaries; mirrors the separateFrontmatter pattern in coder/registry.
  • Why not an off-the-shelf frontmatter library: evaluated goldmark-frontmatter and adrg/frontmatter; both cost more dependency weight than the ~50 lines they would replace, and neither cleanly returns the verbatim body the byte-identical examples.gen.json guard needs. goldmark-frontmatter is a goldmark block parser that exposes only the parsed frontmatter (not the body), pulls in yuin/goldmark plus a new BurntSushi/toml, and its fence handling would regress cases we hardened (trailing-whitespace fences, leading blank lines, BOM). adrg/frontmatter adds a new BurntSushi/toml dependency and parses with yaml.v2, a second YAML implementation alongside the yaml.v3 used elsewhere. (goldmark-frontmatter is also not what Hugo uses for frontmatter; Hugo uses its own parser/pageparser.)
  • List + detail on the chatd surface: the Coder Agents list_templates and read_template both surface the full agent_description; list_templates reads each page template's active version via the template-scoped GetTemplateVersionByID (the same RBAC path as read_template, bounded by the page size of 10), enabling single-call template selection. A batched GetTemplateVersionsByIDs was avoided because it requires ResourceSystem and would silently drop agent_description for every non-owner user. It is returned untruncated on purpose, truncating the rich description would defeat its purpose, and the maxed-out-descriptions-at-scale case is addressed by template scoping rather than truncation. The public coder_list_templates is left unchanged to avoid adding a field to the codersdk API in this patch; it can be added later if requested.
  • Cross-repo safe: coder/registry and coder/registry-server use non-strict yaml.Unmarshal, so the new key is ignored there.
  • Out of scope: the CLI not populating metadata from frontmatter is a separate bug, CODAGT-578.
  • Backport branch/version: still to be decided.

Generated with Coder Agents on behalf of @johnstcn.

@linear-code

linear-code Bot commented Jun 10, 2026

Copy link
Copy Markdown

CODAGT-447

@github-actions

Copy link
Copy Markdown

Docs preview

📖 View docs preview for docs/ai-coder/agents/getting-started.md

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Chat: Spend limit reached | View chat
Requested: 2026-06-11 19:00 UTC by @johnstcn
Spend: $103.53 / $100.00 (limit reached)

deep-review v0.7.1 | Round 5 | 78a6ec2..f5197a4

Last posted: Round 5, 17 findings (1 P1, 2 P2, 9 P3, 5 Nit), REQUEST_CHANGES. Review

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P2 Author fixed (d6f3360) codersdk/toolsdk/toolsdk.go:782 TemplateVersion fetch returns hard error, making coder_get_template fail for supplementary agent_description data R1 Netero Yes
CRF-2 P2 Author fixed (adcf6f4) coderd/util/frontmatter/frontmatter.go:92 Fence comparison only strips \r; trailing whitespace on fence line causes silent data loss of agent_description R2 Hisoka Yes
CRF-3 P3 Author fixed (adcf6f4) coderd/util/frontmatter/frontmatter_test.go:101 Error test cases assert require.Error without checking which error; four error paths indistinguishable R2 Chopper Yes
CRF-4 P3 Author fixed (adcf6f4) codersdk/toolsdk/toolsdk.go:795 CRF-1 fix (best-effort version fetch) has no regression test R2 Chopper Yes
CRF-5 P3 Author fixed (adcf6f4) coderd/util/frontmatter/frontmatter.go:58 "Single entry point" doc comment claim will go stale when a third caller appears R2 Gon Yes
CRF-6 P3 Author fixed (adcf6f4) codersdk/toolsdk/toolsdk.go:694 AgentDescription doc comment inaccurately restates omitempty behavior; field is also omitted for blank/whitespace values R2 Gon Yes
CRF-7 P3 Author fixed (adcf6f4) coderd/x/chatd/chattool/readtemplate.go:92 Five-line comment carries product framing around one line of invariant; same pattern at toolsdk.go:790 R2 Gon Yes
CRF-8 P3 Author contested; panel closed R3 (7/7 accept) coderd/util/frontmatter/frontmatter.go:68 Second fence-splitter implementation alongside codersdk/workspacesdk/frontmatter.go R2 Robin Yes
CRF-9 Nit Author fixed (adcf6f4) coderd/util/frontmatter/frontmatter_test.go:116 TestParseDoesNotPanic bare loop without subtests; failure output does not identify which input R2 Bisky, Chopper Yes
CRF-10 Nit Author fixed (adcf6f4) examples/templates/docker/README.md:8 Example templates use single-line agent_description; docs prescribe >- folded block scalars R2 Leorio Yes
CRF-11 Nit Author fixed (adcf6f4) coderd/util/frontmatter/frontmatter.go:72 Named return frontmatter shadows the package name R2 Gon Yes
CRF-12 Nit Author fixed (adcf6f4) coderd/util/frontmatter/frontmatter.go:17 "Matches the cap" is circular; the constant IS the cap R2 Gon, Razor Yes
CRF-13 Nit Author fixed (adcf6f4) docs/ai-coder/agents/platform-controls/template-optimization.md:91 "limited to 128 characters" but validation is lt=128 (effective max 127) R2 Razor Yes
CRF-14 P3 Author fixed (5d11c97) coderd/x/chatd/chattool/readtemplate_test.go:256 Test comment references "CRF-1", a review artifact meaningless to future readers R3 Gon Yes
CRF-15 P3 Author fixed (5d11c97) examples/templates/gcp-linux/README.md:10 YAML >- fold inserts space inside "region-specific", producing "region- specific" at runtime R3 Leorio Yes
CRF-16 P1 Open coderd/x/chatd/chattool/listtemplates.go:129 GetTemplateVersionsByIDs requires ResourceSystem RBAC; silently fails for all non-owner users, agent_description never surfaced in list_templates R5 Hisoka Yes
CRF-17 P3 Open coderd/x/chatd/chattool/listtemplates_test.go:302 Test uses raw database.Store with no dbauthz wrapper; cannot catch the RBAC failure above R5 Hisoka Yes

Contested and acknowledged

CRF-8 (P3, coderd/util/frontmatter/frontmatter.go:68) - Second fence-splitter implementation

  • Finding: Two fence-splitter implementations in the codebase. Both find two --- fences, extract YAML between them, and return the body after the closing fence.
  • Author defense: Different schemas (typed struct vs map[string]any), different body semantics (byte-offset verbatim slice for examplegen), separate test suites; consolidating would couple unrelated consumers. Trailing-whitespace gap closed via CRF-2.
  • Panel closure (R3, 7/7 accept): All 7 evaluating reviewers verified the behavioral differences justify separate implementations. The ~15 shared lines of fence-finding logic would require parameterizing body handling, error format, and whitespace tolerance to abstract, adding more complexity than the duplication costs.

Round log

Round 1

Netero-only. 1 P2. Reviewed against aba9407..c8a2b29.

Round 2

Panel (15 reviewers). CRF-1 addressed. 1 P2, 6 P3, 5 Nit new. Reviewed against aba9407..d6f3360.

Round 3

Panel (10 reviewers). CRF-2 through CRF-13 addressed. CRF-8 contested, panel closed (7/7). 2 P3 new. Reviewed against aba9407..adcf6f4.

Round 4

Churn guard: PROCEED. CRF-14 and CRF-15 addressed. Netero: clean. 0 open findings. All 15 findings resolved. APPROVE.

Round 5

Panel (9 reviewers). Post-approval re-review after scope expansion (list_templates surfacing). 1 P1, 1 P3 new. Reviewed against 78a6ec2..f5197a4.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First-pass review (Netero). This is a mechanical-checks-only round; the full review panel has not yet reviewed this PR. One P2 finding below. The panel will review after this is addressed.

The approach is clean: a lightweight frontmatter parser that replaces hugo, good test coverage (1.4:1 test-to-production ratio), correct reuse of existing coderstrings.Truncate, and the chatd surface handles the version fetch best-effort as it should.

"The chatd surface handles the same fetch best-effort, and its comment explicitly states 'a missing or unreadable version must not fail read_template.' The same reasoning applies here."

🤖 This review was automatically generated with Coder Agents.

Comment thread codersdk/toolsdk/toolsdk.go Outdated

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panel review (15 reviewers). CRF-1 addressed cleanly in d6f3360; both surfaces now use the best-effort pattern. 1 P2, 6 P3, 5 Nit.

The overall design is solid: a lightweight frontmatter parser that replaces Hugo, shared typed schema across three consumers, correct reuse of coderstrings.Truncate, strong test coverage (1.4:1 test-to-production ratio), and no scope drift. The examplegen refactor produces byte-identical output. Authorization paths are correct in both surfaces. The approach is proportional to the problem.

"This is Texture Surprise: the parser presents a tolerant face (handles CRLF, leading blank lines, unknown keys) but hides a strict fence match that rejects a common real-world variation." (Hisoka)

Notes from the panel worth preserving: the extra TemplateVersion API round-trip per coder_get_template is acceptable for the detail path but worth watching if more version data is needed later. The detail-path-only placement means list_templates still has limited routing signal when many templates share similar short descriptions; this is an explicit, reasonable tradeoff.

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/util/frontmatter/frontmatter.go
Comment thread coderd/util/frontmatter/frontmatter_test.go
Comment thread codersdk/toolsdk/toolsdk.go
Comment thread coderd/util/frontmatter/frontmatter.go Outdated
Comment thread codersdk/toolsdk/toolsdk.go Outdated
Comment thread coderd/util/frontmatter/frontmatter_test.go Outdated
Comment thread examples/templates/docker/README.md Outdated
Comment thread coderd/util/frontmatter/frontmatter.go Outdated
Comment thread coderd/util/frontmatter/frontmatter.go Outdated
Comment thread docs/ai-coder/agents/platform-controls/template-optimization.md Outdated

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review (10 reviewers). All 12 prior findings addressed or resolved. CRF-8 (second fence-splitter) closed by panel vote (7/7 accept the author's defense). 2 new P3 findings.

All R2 fixes verified: fence matching handles trailing whitespace and BOM (CRF-2), error assertions now distinguish paths (CRF-3), missing-version regression test added for chattool (CRF-4), comments trimmed to invariants (CRF-5/6/7), subtests added (CRF-9), examples use >- format (CRF-10), naming and doc fixes (CRF-11/12/13). The fixup commits are clean and introduce no regressions.

"The maintenance cost of two simple, well-tested implementations is lower than the coupling cost of a shared abstraction." (Netero, on CRF-8)

Dropped from R3 panel: Gon P2 on Parse doc comment (frontmatter.go:34) dropped because Leorio praised this exact comment in R2 as exemplary; the caller-side error-handling guidance is actionable, not bloat. Bisky P3 on missing >- test dropped because it would test yaml.Unmarshal, not PR code. Bisky P3 on toolsdk CRF-4 gap dropped to Note; the author's explanation (concrete client, not an interface) is valid and the guard pattern is verified via the chattool test.

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/x/chatd/chattool/readtemplate_test.go Outdated
Comment thread examples/templates/gcp-linux/README.md Outdated

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All 15 findings resolved across 4 rounds (2 P2, 8 P3, 5 Nit; 1 contested and closed by panel vote 7/7).

The PR delivers a clean, migration-free solution for agent template routing. A lightweight frontmatter parser replaces the Hugo dependency (117 fewer go.sum lines), a shared typed schema serves three consumers without drift, and both agent tool surfaces degrade gracefully on version-fetch failure. Test coverage is strong at 1.6:1 test-to-production ratio, including regression tests for the best-effort error path and hostile-input panic protection.

Dropped from R4: Bisky P3 re-raising CRF-4 on the toolsdk best-effort path. Verified against the code: TemplateVersionRichParameters (line 770) and TemplateVersionPresets (line 774) return hard errors before the best-effort TemplateVersion fetch is reached. Any test using a non-existent ActiveVersionID would fail at the parameters step, not test the best-effort path. The author's R2 explanation is correct; testing this path requires either an interface refactor or a partial-failure mock, both out of scope.

"I tried to build a case against this and could not." (Pariston, R2 and R4)

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/util/frontmatter/frontmatter.go Outdated
Comment thread coderd/util/frontmatter/frontmatter.go Outdated
Comment thread coderd/util/frontmatter/frontmatter.go
Comment thread coderd/util/frontmatter/frontmatter.go
Comment thread coderd/util/frontmatter/frontmatter.go
Comment thread coderd/util/frontmatter/frontmatter.go
@johnstcn johnstcn marked this pull request as ready for review June 11, 2026 08:10
Copilot AI review requested due to automatic review settings June 11, 2026 08:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements CODAGT-447 by surfacing a new agent_description README frontmatter field (stored in template_versions.readme) to agent-facing template detail tools, enabling longer agent-only template routing context without a DB migration.

Changes:

  • Added a lightweight coderd/util/frontmatter parser and AgentDescription helper that trims and truncates to 2048 runes.
  • Surfaced agent_description (best-effort) in agent detail tools: coder_get_template (toolsdk) and read_template (chattool), with tests.
  • Migrated scripts/examplegen off Hugo frontmatter parsing, removed Hugo from dependencies, and updated example template READMEs + docs to describe agent_description.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
scripts/examplegen/main.go Switches example parsing to the shared frontmatter parser and removes Hugo frontmatter usage.
go.mod Drops github.com/gohugoio/hugo and related indirect deps; updates indirect dependency set after migration.
go.sum Removes Hugo-related transitive sums consistent with the dependency removal.
examples/templates/kubernetes/README.md Adds agent_description frontmatter for agent routing context.
examples/templates/gcp-linux/README.md Adds agent_description frontmatter for agent routing context.
examples/templates/docker/README.md Adds agent_description frontmatter for agent routing context.
examples/templates/aws-linux/README.md Adds agent_description frontmatter for agent routing context.
docs/ai-coder/agents/platform-controls/template-optimization.md Documents agent_description, its purpose, and an example snippet.
docs/ai-coder/agents/getting-started.md Links to and recommends using agent_description when 128 chars isn’t sufficient.
codersdk/toolsdk/toolsdk.go Extends template detail tool response with agent_description fetched from active version README (best-effort).
codersdk/toolsdk/toolsdk_test.go Adds coverage for surfaced/absent/truncated agent_description behavior and JSON omission.
coderd/x/chatd/chattool/readtemplate.go Adds best-effort agent_description inclusion in read_template output.
coderd/x/chatd/chattool/readtemplate_test.go Adds coverage for surfaced/absent/truncated/missing-version behavior in read_template.
coderd/util/frontmatter/frontmatter.go Introduces the shared frontmatter parser + AgentDescription truncation helper.
coderd/util/frontmatter/frontmatter_test.go Adds comprehensive parsing and truncation tests (CRLF/BOM/whitespace/fence variations).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread coderd/util/frontmatter/frontmatter.go Outdated

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the biggest question mark to me. I get the reason for removing the Hugo dependency, but it might be worth investigating a lighter-weight alternative?

@DanielleMaywood DanielleMaywood left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm definitely open for this approach. I'm not the biggest fan of the hand-rolled frontmatter extraction (from an edge case point of view) but maybe I'm too used to the JS ecosystem where you just pull a dependency in for everything

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post-approval re-review (9 reviewers) after scope expansion: chatd list_templates now surfaces agent_description. 1 P1, 1 P3.

The new list_templates surfacing has a blocking RBAC issue (CRF-16): the batched GetTemplateVersionsByIDs call requires ResourceSystem, which only the site-level owner role grants. All other users (members, org admins, template admins) silently get no agent_description in list_templates. The feature works in read_template (which uses template-scoped GetTemplateVersionByID), so there is a behavioral split between the two tools.

The rest of the PR remains solid. All 15 prior findings stay resolved. The frontmatter parser, toolsdk surface, readtemplate surface, examplegen refactor, docs, and example templates are clean.

"It looks correct at a glance, and the test passes. But the test uses a raw database.Store from dbtestutil.NewDB, which has no dbauthz wrapper." (Hisoka)

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/x/chatd/chattool/listtemplates.go Outdated
Comment thread coderd/x/chatd/chattool/listtemplates_test.go

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review

Copy link
Copy Markdown
Contributor

@johnstcn ⛔ This review has reached its per-chat spend limit ($103.53 / $100.00). Further review rounds are paused.

To raise the limit and continue, comment:

/coder-agents-review set-spend-limit:150

This is a per-chat budget, separate from any account-level usage limit.

🤖 Managed by Coder Agents.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants