SPEC-029
ID:SPEC-029Status:draft

File-Derived Timestamps for Runes

Expose file-level created and modified timestamps as Markdoc variables so any rune can consume them as attribute defaults, with explicit attribute values taking precedence.

claude/file-naming-convention-LJdwR View source
Branches 2
claude/file-naming-convention-LJdwR current draft
main draftclaude/align-sidenav-styling-4MuxV draft
History 1
  1. f2b3512
    Created (draft)by Claude
    Add {ID}-{slug}.md filename convention + migrate filenames subcommand

Problem

Plan runes (and potentially other runes) benefit from knowing when content was created and last modified. The plan-activity rune already derives mtime from git via a standalone scanner (runes/plan/src/scanner.ts), but this is package-specific, runs outside the content pipeline, and only provides modification time — not creation time.

There is no general-purpose mechanism for runes to access file timestamps. Authors who want timestamps must manually maintain them in frontmatter, which is tedious and error-prone.

Design

Markdoc Variables

Inject two new variables into every page's Markdoc transform config:

VariableTypeDescription
$file.createdstring (ISO 8601 date)When the file was first committed
$file.modifiedstring (ISO 8601 date)When the file was last committed

These join the existing $page and $frontmatter variables already injected in packages/content/src/site.ts.

Timestamp Resolution Order

A three-tier fallback chain, consistent with the approach already proven in the plan scanner:

  1. Frontmatter override (highest priority) — if created or modified appear in frontmatter, use those values directly. This gives authors full control.
  2. Git history — derive timestamps from git log. This is the expected default for any content in a repository.
  3. Filesystem stat (lowest priority) — fall back to fs.stat().birthtimeMs / fs.stat().mtimeMs. Only meaningful for local-only content that has never been committed.

When none of the above produce a value, the variable is undefined and runes that consume it should handle the absence gracefully (e.g., omit a date display).

Rune Consumption

Runes opt in by declaring created and/or modified attributes with variable defaults:

{% spec id="SPEC-001" created=$file.created modified=$file.modified %}