Skip to content

Plan 52: user-supplied archetype templates with CLI - #152

Merged
jeduden merged 22 commits into
mainfrom
claude/plan-52-archetype-template-library
Apr 22, 2026
Merged

Plan 52: user-supplied archetype templates with CLI#152
jeduden merged 22 commits into
mainfrom
claude/plan-52-archetype-template-library

Conversation

@jeduden

@jeduden jeduden commented Apr 20, 2026

Copy link
Copy Markdown
Owner

Summary

Plan 52 was reworked mid-PR. The first pass shipped four embedded
built-in archetype schemas; the reworked plan drops embedded assets
and ships a user-supplied archetype system with CLI support instead.
This PR reflects the reworked scope.

No archetype templates are embedded in the binary. Users author
their own schema files under directories registered in
.mdsmith.yml, and mdsmith discovers, lists, shows, and locates
them via a new archetypes CLI verb.

Key Changes

  • internal/archetypes package: Resolver over a list of root
    directories and any fs.FS. Earlier roots shadow later ones. The
    package ships no .md assets of its own.
  • Config: new top-level archetypes.roots key. config.Merge
    copies it through; config.InjectArchetypeRoots pushes it into
    required-structure rule settings unless the rule sets its own
    archetype-roots.
  • required-structure rule:
    • archetype: <name> resolves against configured roots via
      f.RootFS / f.RootDir.
    • New archetype-roots rule setting (list, default
      [archetypes]).
    • archetype and schema are mutually exclusive. The guard
      applies both in ApplySettings and at Check time.
    • Archetype schema reads honor --max-input-size via
      lint.ReadFSFileLimited.
    • <?require?> in an archetype file no longer produces a
      "has no effect" warning when the file lives under an archetype
      root.
  • mdsmith archetypes CLI (four verbs):
    • init [dir] scaffolds the directory (default ./archetypes)
      with an example.md schema and a README.md. Safe to re-run;
      never mutates .mdsmith.yml, prints the snippet to add.
    • list prints discovered archetypes as
      <name>\t<path> lines.
    • show <name> prints the raw schema source.
    • path <name> prints the resolved filesystem path.
    • Error messages print the effective roots (with the default
      substituted) so users can diagnose empty list output.
  • Docs: MDS020 README, enforcing-structure guide, and CLI
    reference document the new rule setting, config key, and CLI.

Known limitation

<?include?> expansion inside archetype schemas still reads via
lint.ReadFileLimited against the process working directory.
Archetype includes therefore require running mdsmith from the
project root until include expansion is unified with RootFS.
Documented in the MDS020 README and in the loadSchema comment.

Notes for release notes

  • New CLI verbs under mdsmith archetypes.
  • New top-level archetypes.roots config key.
  • New required-structure settings: archetype, archetype-roots.
  • .mdsmith.yml edits from the first pass of this PR have been
    reverted; no repo-wide lint-config changes remain.

https://claude.ai/code/session_01MrAcoEEB4tGYMmUz8ErbTp

claude added 2 commits April 20, 2026 19:00
Ship four built-in required-structure schemas for common agentic
Markdown patterns (story-file, prd, agent-definition, claude-md) and
expose them through a new `archetype` setting on the required-structure
rule. The setting is mutually exclusive with `schema` and maps the
archetype name to an embedded schema loaded via go:embed.

Documented in MDS020 README and the enforcing-structure guide.

Config: .mdsmith.yml adds `internal/archetypes/**` to the
directory-structure allow-list and ignores `internal/archetypes/*.md`
so the embedded schema templates are not linted as normal docs.
Copilot AI review requested due to automatic review settings April 20, 2026 21:03
@codecov

codecov Bot commented Apr 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.98058% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.03%. Comparing base (3291efc) to head (9efb0dc).
⚠️ Report is 112 commits behind head on main.

Files with missing lines Patch % Lines
cmd/mdsmith/archetypes.go 84.78% 20 Missing and 8 partials ⚠️
internal/rules/requiredstructure/rule.go 98.51% 1 Missing and 1 partial ⚠️
internal/archetypes/archetypes.go 99.36% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #152      +/-   ##
==========================================
+ Coverage   86.76%   88.03%   +1.27%     
==========================================
  Files          96      110      +14     
  Lines       10446    14106    +3660     
==========================================
+ Hits         9063    12418    +3355     
- Misses        900     1228     +328     
+ Partials      483      460      -23     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Simplify List() to drop unreachable embed.FS defensive branches.
- Extract schemaSource() helper so the archetype-vs-schema label
  used in the invalid-schema diagnostic is covered by a direct unit
  test.

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

Adds first-class, built-in schema “archetypes” to the required-structure rule so users can validate common agentic Markdown document patterns without maintaining their own schema files.

Changes:

  • Introduces internal/archetypes with embedded .md schema assets plus Lookup()/List().
  • Extends required-structure (MDS020) with an archetype setting (mutually exclusive with schema) and refactors schema loading.
  • Updates unit tests, rule documentation, structure guide docs, and plan tracking; adjusts .mdsmith.yml to allow/ignore the new archetype assets.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
plan/52_archetype-template-library.md Marks the archetype library plan as complete and checks off tasks/criteria.
PLAN.md Updates the plan index to show plan 52 as complete.
internal/archetypes/archetypes.go Adds embedded archetype registry with lookup + listing utilities.
internal/archetypes/archetypes_test.go Adds tests for listing, ordering, and lookup error behavior.
internal/archetypes/story-file.md Adds the built-in “story-file” schema template.
internal/archetypes/prd.md Adds the built-in “prd” schema template.
internal/archetypes/agent-definition.md Adds the built-in “agent-definition” schema template.
internal/archetypes/claude-md.md Adds the built-in “claude-md” schema template.
internal/rules/requiredstructure/rule.go Adds Archetype support, schema loading abstraction, and mutual exclusivity enforcement.
internal/rules/requiredstructure/rule_test.go Adds unit tests for archetype selection, type checks, exclusivity, and basic archetype validation.
internal/rules/MDS020-required-structure/README.md Documents the new archetype setting and lists available built-ins.
docs/guides/directives/enforcing-structure.md Adds user-facing guide section for configuring built-in archetypes.
.mdsmith.yml Allows internal/archetypes/** under directory-structure and ignores embedded archetype .md assets from linting.

Comment thread internal/archetypes/story-file.md Outdated
Comment thread internal/rules/requiredstructure/rule.go
Comment thread internal/archetypes/archetypes.go Outdated
claude added 2 commits April 20, 2026 21:10
- Add defensive mutual-exclusivity check in loadSchema so the rule
  behaves consistently when constructed directly (bypassing
  ApplySettings).
- Make story-file i-want and so-that required; the "as / i-want /
  so-that" trio is the defining shape of the archetype.
- Distinguish fs.ErrNotExist from unexpected embed read errors in
  Lookup via a unit-tested classifyLookupError helper.
Drop shipping built-in archetype templates. Add config-driven
archetype discovery (archetypes.roots) and CLI verbs
(init/list/show/path). Reverts implementation direction of the
first pass; task 1 calls out removal of the go:embed registry and
bundled story-file/prd/agent-definition/claude-md assets.
Copilot AI review requested due to automatic review settings April 21, 2026 06:13

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

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Comment thread PLAN.md Outdated
Comment thread plan/52_archetype-template-library.md
Comment thread plan/52_archetype-template-library.md Outdated
Comment thread .mdsmith.yml Outdated
claude added 2 commits April 21, 2026 06:26
Removes the go:embed archetype assets (story-file, prd,
agent-definition, claude-md) and reworks the feature around
user-supplied schema directories.

- internal/archetypes exposes a Resolver over a list of root
  directories backed by any fs.FS; earlier roots shadow later ones.
- Top-level config gains `archetypes.roots`. Merge copies the value
  through; InjectArchetypeRoots pushes it into required-structure
  rule settings when the rule doesn't set its own roots.
- required-structure accepts `archetype-roots` (list, default
  `[archetypes]`) and resolves `archetype: <name>` against the
  project RootFS.
- `mdsmith archetypes` CLI with init/list/show/path verbs. init
  scaffolds the directory with example.md + README.md, never
  mutates .mdsmith.yml. list prints "<name>\t<path>" lines; show
  prints the schema source; path prints the filesystem path.
- Docs: MDS020 README, enforcing-structure guide, and CLI reference
  cover the new config key, rule setting, and CLI verbs.
- Revert the .mdsmith.yml changes from the first pass: no more
  embedded .md files under internal/archetypes to allow or ignore.
Add unit tests for:
- InjectArchetypeRoots / injectRoots helpers (top-level rule,
  override, no-op cases)
- Merge copying archetypes from loaded and defaults
- Resolver.Lookup non-ErrNotExist Stat error path
- Resolver.AbsPath missing-name error
- asStringList typed []string and scalar inputs
- loadArchetype read-after-lookup error path (via a wrapping fs.FS
  that implements StatFS but errors on Open)

Refactored archetype read into loadArchetype helper for clarity.
Copilot AI review requested due to automatic review settings April 21, 2026 06:33
Add tests for:
- --help flag on archetypes and each verb
- Arg-validation exits: too many, wrong count
- Kept-existing README on init
- Bad config propagates through list/show/path
- MkdirAll failure when target is a regular file

Refactor loadConfig into a thin wrapper around loadConfigRaw so
the InjectArchetypeRoots call sits in a single tested location
instead of four per-branch call sites.

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

Copilot reviewed 15 out of 15 changed files in this pull request and generated 7 comments.

Comment thread plan/52_archetype-template-library.md
Comment thread internal/rules/requiredstructure/rule.go Outdated
Comment thread internal/rules/requiredstructure/rule.go
Comment thread internal/rules/MDS020-required-structure/README.md Outdated
Comment thread internal/rules/requiredstructure/rule.go Outdated
Comment thread cmd/mdsmith/archetypes.go Outdated
Comment thread docs/guides/directives/enforcing-structure.md Outdated
@jeduden jeduden changed the title Add built-in archetype schemas for common agentic documents Plan 52: user-supplied archetype templates with CLI Apr 21, 2026
claude added 2 commits April 21, 2026 06:48
- Size-bound archetype reads via lint.ReadFSFileLimited so
  --max-input-size applies uniformly.
- Suppress the <?require?> has-no-effect warning when the file
  itself lives under an archetype root (isSchemaOrArchetypeFile
  consolidates the skip/schema-file logic).
- List verb prints resolver.EffectiveRoots() so users see the
  defaulted './archetypes' root in the error when nothing was
  configured.
- Docs: enforcing-structure guide clarifies that 'archetypes init
  <dir>' creates '<dir>' exactly, and the MDS020 README no longer
  claims <?include?> resolves via RootFS — includes still read via
  the OS filesystem.
- loadSchema comment calls out the include-resolution limitation.
Review findings taking the user's perspective through the CLI and
fixture coverage:

- **Bug**: README.md inside an archetype directory was indexed as an
  archetype. `archetypes list` returned "README, example" after
  `init`; `archetypes show README` and `archetypes path README`
  worked on it. Fixed via `isArchetypeName` — reserves
  README/LICENSE/CONTRIBUTING/CODEOWNERS (case-insensitive) and
  rejects any `_`-prefixed or `.`-prefixed basename. Applied in both
  `List` and `Lookup`.

- **Inconsistency**: the "unknown archetype" and "no archetypes
  found" errors formatted roots differently — one relative, one
  absolute. Both now call `EffectiveRoots()`.

- **Missing fixtures**: MDS020 had fixture tests only for the
  `schema:` path. Added `good/archetype.md`,
  `bad/archetype-missing-section.md`, `bad/archetype-unknown.md`
  with supporting archetype files under `data/archetypes/`.

- **Resolver portability**: `os.DirFS` rejects `..` path segments,
  which broke the fixture setup. Resolver now falls back to raw
  `os.*` operations (joined with `RootDir`) when `FS` is nil, so
  fixture-style paths like `../../internal/rules/...` resolve the
  same way as schema paths. `loadArchetype` mirrors the distinction
  and uses `lint.ReadFileLimited` vs `lint.ReadFSFileLimited`.

- **Tests**: added `TestResolver_ListFiltersReservedNames`,
  `TestResolver_LookupRejectsReservedNames`, `TestIsArchetypeName`,
  and `TestEffectiveRoots_DefaultsAndRootDirJoin`.

- **Docs**: MDS020 README and the `init`-scaffolded README both
  document the reserved-name convention.
Copilot AI review requested due to automatic review settings April 21, 2026 20:25
Add unit tests that exercise loadArchetype when the archetype
resolver has no RootFS (fs-less mode), covering both the successful
read via lint.ReadFileLimited and the size-limit error path.

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

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Comment thread docs/guides/directives/enforcing-structure.md Outdated
Comment thread internal/archetypes/archetypes.go Outdated
Comment thread internal/rules/requiredstructure/rule.go
- Validate archetype-roots when RootFS is set: absolute paths and
  parent-traversal roots produce a clear diagnostic instead of a
  low-level "invalid path" error. This aligns with the constraints
  readSchemaFile already enforces for disk-based schemas.
- Clarify the Resolver comment: the os.* fallback allowing ".." is
  looser than RootFS-backed resolution; callers in
  required-structure reject parent-traversal roots when RootFS is
  set, so the looseness only surfaces in tests and fs-less callers.
- Fix enforcing-structure guide: <?include?> inside an archetype
  still resolves via OS paths relative to the process working
  directory, not the archetype's directory. Keep archetypes
  self-contained or run from project root.
- Tests: validate-archetype-root table; integration-style tests
  for root-escapes and absolute-root diagnostics.

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

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

Comment thread cmd/mdsmith/archetypes.go Outdated
- Move ValidateRoot/ValidateRoots into the archetypes package so
  both the rule and the CLI share one implementation.
- CLI archetypesResolver now validates archetypes.roots and scopes
  FS to os.DirFS(rootDir) when a project root is known, so
  archetype-roots cannot escape the project (matches the rule's
  RootFS-backed constraint).
- Keep the rule's pre-validation in loadArchetype for RootFS-backed
  invocations.
- Tests: moved TestValidateArchetypeRoot into the archetypes
  package, added ValidateRoots tests, plus CLI e2e tests for
  escaping-root and absolute-root rejections.
@jeduden
jeduden requested a review from Copilot April 21, 2026 21:04
Comment thread cmd/mdsmith/archetypes_e2e_test.go
Comment thread docs/reference/cli.md Outdated
…able

- Rename cmd/mdsmith/e2e_archetypes_test.go to archetypes_e2e_test.go
  so the feature stays the prefix and _test.go remains the conventional
  postfix, matching unit-test naming across the repo.
- Add a Default column to the check/fix flag reference table in
  docs/reference/cli.md and include the previously missing
  --no-follow-symlinks flag.

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

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

Comment thread internal/rules/requiredstructure/rule.go Outdated
isSchemaOrArchetypeFile matched any *.md under or below a
configured archetype root. With archetype-roots: ["."] it matched
the whole repo, disabling required-structure validation and
suppressing the misplaced <?require?> warning for every document.

Now the check accepts only files that are direct children of the
root: archetype discovery only finds <root>/<name>.md, so the
schema-source check should match that exact shape. Files in
subdirectories get treated as normal documents again.

Added tests for both cases: archetype-roots "." with a nested
doc, and a nested file under "archetypes/sub/" with the default
root.
Copilot AI review requested due to automatic review settings April 22, 2026 08:32

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

Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.

Comment thread internal/rules/requiredstructure/rule.go Outdated
Comment thread internal/archetypes/archetypes.go
- Drop the duplicate DefaultArchetypeRoot constant in the
  required-structure rule and reuse archetypes.DefaultRoot.
  Single source of truth for the default root name.
- Add Resolver.ListWithErrors that returns both the successfully
  discovered archetypes and the non-ErrNotExist errors from each
  readDir. List keeps its old signature for callers that do not
  care about errors.
- mdsmith archetypes list now surfaces read errors on stderr and
  exits 2 when a root errored with no discoverable archetypes.
- Tests: injected fs.FS that errors on ReadDir for a specific root
  to verify both the error-surfacing and not-exist-is-silent
  branches.

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

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

Comment thread internal/archetypes/archetypes.go
isArchetypeName now rejects names with path separators (/ or \)
and the literal ".." segment, so Lookup cannot be coerced into
reading outside the configured archetype roots (via raw os
fallback when RootFS is nil). Names rejected here surface as the
regular 'unknown archetype' diagnostic.

Tests: extended isArchetypeName table with separator/traversal
cases and added a disk-backed Lookup test that tries "../secret",
"sub/story", "a/../../etc/passwd", and ".." against a tempdir
where a secret.md sits next to the archetype root.

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

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Comment thread cmd/mdsmith/main_unit_test.go
Comment thread internal/rules/requiredstructure/rule_test.go Outdated
Comment thread cmd/mdsmith/archetypes.go
Comment thread cmd/mdsmith/main_unit_test.go
- Validate the target of 'mdsmith archetypes init' with
  archetypes.ValidateRoot so absolute and parent-traversal
  directories are rejected with a clear diagnostic instead of
  scaffolding successfully and printing a config snippet that the
  rule will later reject.
- Update existing unit tests that passed absolute paths to chdir
  into a tempdir and pass relative names.
- Add e2e tests for init rejecting '/abs/path' and '../outside'.
- cmd/mdsmith/main_unit_test.go captureStderr/captureStdout now
  'defer r.Close()' after os.Pipe so the read end is released
  even if f() panics.
- Fix stale writeArchetype comment that claimed a return value.
@jeduden jeduden added queue Add to a PR to enqueue it queue:active Applied automatically when a PR is in an active batch labels Apr 22, 2026
@jeduden

jeduden commented Apr 22, 2026

Copy link
Copy Markdown
Owner Author

🟢 Merge Queue — picked up

This PR is in the queue and will be batched with other queue-labelled PRs.

Next: No action needed — you'll get another comment when CI starts on the batch. View merge queue run.

@jeduden jeduden removed the queue Add to a PR to enqueue it label Apr 22, 2026
@jeduden

jeduden commented Apr 22, 2026

Copy link
Copy Markdown
Owner Author

🔵 Merge Queue — CI running

Merged into batch branch merge-queue/batch-152-1776880087. View CI run.

Next: No action needed — you'll be notified when CI completes.

@jeduden jeduden removed the queue:active Applied automatically when a PR is in an active batch label Apr 22, 2026
@jeduden
jeduden merged commit 6554d91 into main Apr 22, 2026
12 checks passed
@jeduden

jeduden commented Apr 22, 2026

Copy link
Copy Markdown
Owner Author

Merge Queue — merged

This PR landed on main via commit 6554d91. CI run that validated the merge.

Next: Done — nothing more to do here.

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.

4 participants