SPEC-029
ID:SPEC-029Status:draft

File-Derived Timestamps for Runes

claude/align-sidenav-styling-4MuxV View source
Branches 2
claude/align-sidenav-styling-4MuxV current draft
claude/file-naming-convention-LJdwR draftmain draft
History 5
  1. cf0cfc0
    Content editedby Claude
    Revert "Fix plan site truncation by escaping Markdoc tags in code fences
  2. 703b85a
    Content editedby Claude
    Fix plan site truncation by escaping Markdoc tags in code fences
  3. c3f2b29
    Content editedby Claude
    Add broader impact section to SPEC-029
  4. 4cb48aa
    Content editedby Claude
    Add blog date alignment section to SPEC-029
  5. 1fd712e
    Created (draft)by Claude
    Add SPEC-029: 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.

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 %}