project

Architecture

How the compiler pipeline and its packages fit together.

cmd/smill delegates process exit to internal/cli.Run, which can be tested with in-memory stdout/stderr. The CLI selects explicit inputs and performs bounded reads. It never walks recursively or resolves content URLs.

internal/frontmatter handles UTF-8, exact boundaries, a YAML node tree, duplicate keys and JSON-safe conversion. internal/validate checks known metadata types. internal/diagnostic indexes source bytes into line/rune positions and stable codes.

internal/markdown parses GFM using Goldmark, independently segments root headings, validates the limited heading attribute grammar and converts the AST to our IR. Goldmark types do not escape this package. internal/model owns the versioned serializable representation, stable IDs, ordered sections/cards and literal code.

Three direct dependencies are justified: Goldmark handles GFM parsing, a YAML node tree supports duplicate keys and source locations, and the user-selected Cobra v1.10.2 provides command/help/flag parsing. Other production operations use the Go standard library. Dependencies are pinned in go.mod/go.sum; no sibling project package is imported.

Future renderers consume IR and must establish their own layout and escaping contracts. The Hugo renderer consumes the semantic IR directly and exports a complete project; it never reparses original Markdown. See Hugo contracts. The navi renderer (internal/render/navi, navi export) likewise consumes the IR, preserving complete frontmatter in a versioned .navi.json companion for each exported sheet: a card is exported only when it carries .navi and an explicit ID, and the package can neither execute commands nor use the network.

Go 1.27.2 was selected after checking Go release support and sibling policy on 2026-10-13. BundleDock pins that toolchain; WorkHarbor tests it alongside 1.26.9. See provenance for inspected revisions.

internal/importer/reference is a pure adapter returning canonical Markdown plus a structured loss report. CLI owns bounded input and exclusive output creation. The adapter preserves provenance, archives legacy behavior and revalidates against the core. It never fetches or executes external content. See imports.