Skip to content

refactor: migrate mintlify codegen to Metalsmith plugin architecture#1231

Draft
razor-x wants to merge 6 commits into
mainfrom
claude/mintlify-migration-arch-zzext7
Draft

refactor: migrate mintlify codegen to Metalsmith plugin architecture#1231
razor-x wants to merge 6 commits into
mainfrom
claude/mintlify-migration-arch-zzext7

Conversation

@razor-x

@razor-x razor-x commented Jul 6, 2026

Copy link
Copy Markdown
Member

Summary

Refactored the mintlify codegen pipeline from a standalone script-based approach to a modular Metalsmith plugin architecture. This improves maintainability, testability, and aligns with the existing @seamapi/smith infrastructure.

Key Changes

  • Restructured codegen entry point: Replaced generate.ts with smith.ts as the new Metalsmith-based entry point that orchestrates the entire pipeline
  • Modularized core logic: Extracted errors and events generation into dedicated layout modules (lib/layout/errors-page.ts, lib/layout/events-page.ts, lib/layout/object-page.ts) with clear separation of concerns
  • Created plugin system: Implemented Metalsmith plugins for each pipeline phase:
    • lib/openapi.ts - OpenAPI spec transformation and metadata injection
    • lib/reference.ts - Object/events/errors page generation
    • lib/postprocess.ts - Link canonicalization
    • lib/ingest.ts - docs.json ingestion
    • lib/report.ts - End-of-run statistics
  • Refactored utilities: Consolidated property formatting and sample value generation into lib/format-type.ts and lib/sample-value.ts for reuse across layout modules
  • Added Handlebars templates: Created layout templates (layouts/*.hbs) and partials for rendering object, events, and errors pages with consistent formatting
  • Introduced configuration: Created lib/config.ts for centralized pipeline configuration and data/object-pages.yaml for per-route metadata
  • Updated build workflow: Modified package.json and GitHub Actions to use the new Metalsmith-based generation pipeline
  • Generated initial content: Created comprehensive API reference pages for locks, thermostats, ACS, pagination, authentication, and other core resources

Implementation Details

  • The new architecture uses Metalsmith's file-based pipeline, making it easier to debug and extend
  • Layout context objects are built incrementally and passed to Handlebars templates for rendering
  • Error and event code grouping logic is preserved but now lives in dedicated layout modules
  • The pipeline maintains backward compatibility with existing OpenAPI spec transformations while adding new capabilities for object/events/errors documentation
  • All generated pages include proper frontmatter, examples, and property documentation

Notes

  • Generated pages are now in mintlify-codegen/source/api/ (added to .prettierignore)
  • The refactoring maintains feature parity with the previous implementation while improving code organization

https://claude.ai/code/session_01P1YTCN8DidaFWzvLYyge3N

claude added 6 commits July 6, 2026 21:03
… + hbs pattern

Port the Mintlify codegen from ad-hoc string-building scripts onto the
repo's established codegen architecture (codegen/smith.ts):

- mintlify-codegen/smith.ts: Metalsmith entry point — @metalsmith/metadata
  over the shared codegen/data YAML, @seamapi/smith's blueprint() plugin
  (replacing the hand-rolled load-data.ts), then plugins for spec
  enrichment (openapi), page creation (reference), docs.json nav surgery
  (docs-json), Handlebars rendering (@metalsmith/layouts), and link
  canonicalization (postprocess).
- All MDX rendering moves to layouts/*.hbs + partials with pure
  layout-context builders in lib/layout/ (object-page, events-page,
  errors-page). Duplicated helpers (formatType x2, sampleValue x3,
  indent x2, readFileOrNull x2, title derivation x2) are consolidated
  under lib/.
- Object pages are now fully generated — the indexOf/regex splicing into
  hand-written api/**/object.mdx is gone. Page frontmatter comes from the
  new Zod-validated mintlify-codegen/data/object-pages.yaml (the
  codegen/data/paths.yaml pattern).
- The api/ tree is wholly pipeline-owned: smith.ts pre-cleans
  mintlify-docs/api/** (like codegen/smith.ts pre-cleans
  docs/api-reference), static pages (index, installation, ...) and the
  16 authored object pages move to mintlify-codegen/source/ and flow
  through the build; stale generated pages can no longer linger.
- Endpoint pages keep the enriched openapi.json + x-codeSamples approach
  rendered natively by Mintlify; transform-spec.ts survives unchanged as
  a lib module.
- generate:mintlify now runs tsx mintlify-codegen/smith.ts; generate.yml
  step names call out each codegen entry point; automerge.yml watches
  mintlify-docs/api/** now that the whole folder is generated.

Output parity: regenerated output is byte-identical to the old pipeline
except one whitespace normalization (api/workspaces/object.mdx had a
stray double blank line after its frontmatter). Verified by snapshot
diff of api/**, openapi.json, and docs.json across both pipelines, plus
a double-run idempotency check.

Reproduced inconsistencies flagged with TODOs for follow-up (kept to
avoid output changes in this refactor):
- record-format properties render type="object" on object pages but
  type="Object" on events/errors pages (lib/format-type.ts).
- nested property children indent 6 spaces on events pages vs 4 on
  object pages (layouts/partials/event-property.hbs).
- the 16 handwritten object pages (notably /locks and /thermostats,
  which duplicate drifted blueprint property data) should converge onto
  blueprint sourcing with group filtering (data/object-pages.yaml).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1YTCN8DidaFWzvLYyge3N
Convert the 16 formerly hand-written object pages to generated pages,
completing the rule that everything under mintlify-docs/api comes from
the OpenAPI spec/blueprint or authored data in object-pages.yaml:

- /locks, /thermostats, /noise_sensors: filtered views of the shared
  device resource using the include_groups idiom from
  codegen/data/paths.yaml (group-filtered properties, sub-group
  sections, and resource samples), with authored intros in
  object-pages.yaml replacing their stale migrated property dumps.
- /action_attempts: synthesized resource section mirroring
  processActionAttemptResource in codegen/lib/layout/api-route.ts,
  with the action_type enum built from blueprint.actionAttempts.
- simulate/ and unmanaged/ routes (11 pages): endpoint-listing pages
  generated from the blueprint route's documented endpoints.
- /acs: namespace overview page — authored intro plus every documented
  acs resource with its blueprint description, linking to its object
  page.

Supporting changes:
- object-pages.yaml schema v2: endpoints/namespace page kinds,
  resource_type, include_groups/exclude_groups, heading, and intro
  fields; the handwritten flag is gone.
- Object-property rendering gains a general `Enum values` accordion
  (previously special-cased for the Event object's event_type).
- mintlify-codegen/source/ now holds only the 6 truly static pages;
  prettier ignores it so authored MDX bytes pass through unchanged.
- Suppress the missing-entry warning for routes whose resources are all
  undocumented.

Unlike the preceding architecture port, this change intentionally
updates the content of those 16 pages: stale hand-authored property
data is replaced by blueprint truth, and endpoint listings pick up the
current upstream descriptions. The other 26 object pages and all
events/errors pages are byte-identical; the pipeline remains idempotent
and passes validate:mintlify and validate:mintlify-anchors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1YTCN8DidaFWzvLYyge3N
…pages

Corrections to keep generated-page diffs limited to unavoidable content
changes (blueprint truth vs drifted authored text):

- Endpoint-listing pages link relatively (./get) again, matching the
  original pages, instead of absolute /api paths.
- /noise_sensors returns to its original shape — heading, authored
  intro, and an endpoint listing — instead of a full device property
  view (endpoint listing pages now support an optional heading+intro
  section); a TODO in object-pages.yaml records the option to expand it
  later.
- /acs restores the authored "The Access Control Systems (ACS)
  namespace contains the following resources:" line (new
  resources_intro field) and its self-anchor resource links, with a
  template TODO suggesting object-page links as a future improvement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1YTCN8DidaFWzvLYyge3N
…cy format

Regenerate the three GitBook-migrated object pages from the blueprint in
their original presentation instead of the modern ResponseField format,
so the PR diff shows only content-level changes (blueprint truth vs
drifted authored data):

- New legacy-object.hbs layout + legacy-* partials reproduce the
  migrated GitBook dialect: `**`name`** _Boolean_` property blocks with
  `---` separators, <Accordion> enum values with <code> items, variant
  accordions for errors/warnings properties, Child Properties /
  Child Object Properties blocks, on-page Errors/Warnings sections, and
  a relative-linked Endpoints section. TODO comments flag each legacy
  construct for a future modernization decision.
- lib/layout/legacy-object-page.ts ports the GitBook composition
  algorithms verbatim from codegen/lib/layout/api-route.ts (bugs
  included — e.g. the non-total groupVariants comparator) so section
  composition and ordering match the GitBook source of truth: flat
  alphabetical group-filtered Properties and device.properties,
  unsorted-variant Errors/Warnings, first-paragraph endpoint listings,
  the <Tabs> sample block (seam_cli resource_data) alongside
  ResponseExample, and the 80-column <Warning> deprecation wrap rule.
- object-pages.yaml: legacy: true marks these three routes; the
  thermostats intro carries its trailing `---` divider.

Known intentional cleanups (flagged in the templates): converter
glitches in the old pages are not reproduced — mis-nested fields after
list-of-objects children (assa_abloy endpoints, dormakaba
predefined_time_slots) now render flat, and a stray `</Warning>-`
artifact is gone. Remaining page diffs are blueprint-content drift:
capability-flag descriptions the old pages lacked, new/removed enum
values, new error/warning variants, and new endpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1YTCN8DidaFWzvLYyge3N
Rewrite absolute https://docs.seam.co/<path> links in generated output
(openapi.json + api/**/*.mdx) to root-relative /<path> links in the
canonicalize postprocess step, matching the hand-written content's link
convention. Upstream @seamapi/types descriptions use the absolute form,
which also hid these links from broken-link validation.

Relativizing exposed GitBook-era anchors that no longer match Mintlify's
heading slugs, so the postprocess step now also heals anchors on
internal links against the actual headings (and explicit id="..."
markers) of the target pages: it rewrites dotted GitBook anchors to
Mintlify slugs (acs_system.errors.x -> acs_system-errors-x), completes
GitBook-truncated slugs by prefix match, redirects section anchors that
became child pages (access-codes#backup-access-codes ->
access-codes/backup-access-codes), and drops anchors whose sections no
longer exist anywhere on the target page (with a generate-time warning
for content follow-up).

Mechanical result: a line-for-line link swap across the generated pages
and spec; validate:mintlify and the broken-links/anchors check pass
clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1YTCN8DidaFWzvLYyge3N
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.

2 participants