PlanWork
note

This rune is part of @refrakt-md/plan. Install with npm install @refrakt-md/plan and add "@refrakt-md/plan" to the plugins array in your refrakt.config.json.

Work

A discrete piece of implementation work with acceptance criteria, priority, complexity, and status tracking. Not a user story — a clear description of what needs to change. H2 headings create named sections for structured content like acceptance criteria, approach, and references.

Also available as {% task %}.

Ready work item

A work item ready for implementation with acceptance criteria and approach.

{% work id="RF-142" status="ready" priority="high" complexity="moderate" milestone="v0.5.0" tags="tint,theming" %}
# Implement tint rune dark mode support

The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.

## Acceptance Criteria
- [ ] Tint rune accepts light and dark content sections
- [ ] Identity transform emits data-tint-dark when dark values present
- [ ] Theme CSS swaps tokens in prefers-color-scheme: dark
- [ ] Inline tints without dark values fall back to page tokens
- [ ] Inspector audits contrast ratios for both variants

## Approach
The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as `--tint-dark-*` CSS custom properties alongside the light values.
{% /work %}
<article data-rune="work" data-rune-fields="{&quot;id&quot;:&quot;RF-142&quot;,&quot;status&quot;:&quot;ready&quot;,&quot;priority&quot;:&quot;high&quot;,&quot;complexity&quot;:&quot;moderate&quot;,&quot;assignee&quot;:&quot;&quot;,&quot;milestone&quot;:&quot;v0.5.0&quot;,&quot;source&quot;:&quot;&quot;,&quot;supersedes&quot;:&quot;&quot;,&quot;pr&quot;:&quot;&quot;,&quot;tags&quot;:&quot;tint,theming&quot;,&quot;created&quot;:&quot;2026-09-13&quot;,&quot;modified&quot;:&quot;2026-09-13&quot;}">
  <header data-name="title">
    <h1 id="implement-tint-rune-dark-mode-support">Implement tint rune dark mode support</h1>
  </header>
  <div data-name="blurb">
    <p>The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.</p>
  </div>
  <div data-name="body">
    <section data-name="acceptance-criteria">
      <h2 id="acceptance-criteria">Acceptance Criteria</h2>
      <ul>
        <li>[ ] Tint rune accepts light and dark content sections</li>
        <li>[ ] Identity transform emits data-tint-dark when dark values present</li>
        <li>[ ] Theme CSS swaps tokens in prefers-color-scheme: dark</li>
        <li>[ ] Inline tints without dark values fall back to page tokens</li>
        <li>[ ] Inspector audits contrast ratios for both variants</li>
      </ul>
    </section>
    <section data-name="approach">
      <h2 id="approach">Approach</h2>
      <p>
        The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as
        <code>--tint-dark-*</code>
        CSS custom properties alongside the light values.
      </p>
    </section>
  </div>
</article>
RF-142ready

Implement tint rune dark mode support

The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.

tinttheming

Acceptance Criteria

  • Tint rune accepts light and dark content sections
  • Identity transform emits data-tint-dark when dark values present
  • Theme CSS swaps tokens in prefers-color-scheme: dark
  • Inline tints without dark values fall back to page tokens
  • Inspector audits contrast ratios for both variants

Approach

The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as --tint-dark-* CSS custom properties alongside the light values.

<article class="rf-work rf-work--RF-142 rf-work--ready rf-work--high rf-work--moderate" data-id="RF-142" data-status="ready" data-priority="high" data-complexity="moderate" data-assignee="" data-milestone="v0.5.0" data-source="" data-supersedes="" data-pr="" data-tags="tint,theming" data-created="2026-09-13" data-modified="2026-09-13" data-rune="work" data-density="full">
  <div data-name="eyebrow" data-zone="eyebrow" data-zone-layout="bar" class="rf-work__eyebrow">
    <span data-meta-type="id">RF-142</span>
    <span class="rf-badge" data-meta-type="status" data-meta-sentiment="neutral" data-align="end">ready</span>
  </div>
  <header data-name="title" class="rf-work__title" data-section="title">
    <h1 id="implement-tint-rune-dark-mode-support">Implement tint rune dark mode support</h1>
  </header>
  <div data-name="blurb" class="rf-work__blurb" data-section="description">
    <p>The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.</p>
  </div>
  <dl data-name="metadata" data-zone="metadata" data-zone-layout="definition-list" class="rf-work__metadata">
    <div data-name="row" data-field="priority" class="rf-work__row">
      <dt data-meta-label="">Priority</dt>
      <dd>
        <span class="rf-badge" data-meta-type="category" data-meta-sentiment="caution">high</span>
      </dd>
    </div>
    <div data-name="row" data-field="complexity" class="rf-work__row">
      <dt data-meta-label="">Complexity</dt>
      <dd data-meta-type="quantity">moderate</dd>
    </div>
    <div data-name="row" data-field="milestone" class="rf-work__row">
      <dt data-meta-label="">Milestone</dt>
      <dd>
        <span class="rf-badge" data-meta-type="tag">v0.5.0</span>
      </dd>
    </div>
    <div data-name="row" data-field="created" class="rf-work__row">
      <dt data-meta-label="">Created</dt>
      <dd data-meta-type="temporal">
        <time datetime="2026-09-13">2026-09-13</time>
      </dd>
    </div>
    <div data-name="row" data-field="modified" class="rf-work__row">
      <dt data-meta-label="">Modified</dt>
      <dd data-meta-type="temporal">
        <time datetime="2026-09-13">2026-09-13</time>
      </dd>
    </div>
  </dl>
  <div data-name="tags" data-zone="tags" data-zone-layout="bar" class="rf-work__tags">
    <span class="rf-badge" data-meta-type="tag">tint</span>
    <span class="rf-badge" data-meta-type="tag">theming</span>
  </div>
  <div data-name="body" class="rf-work__body" data-section="body">
    <section data-name="acceptance-criteria" class="rf-work__acceptance-criteria">
      <h2 id="acceptance-criteria">Acceptance Criteria</h2>
      <ul>
        <li data-checked="unchecked">Tint rune accepts light and dark content sections</li>
        <li data-checked="unchecked">Identity transform emits data-tint-dark when dark values present</li>
        <li data-checked="unchecked">Theme CSS swaps tokens in prefers-color-scheme: dark</li>
        <li data-checked="unchecked">Inline tints without dark values fall back to page tokens</li>
        <li data-checked="unchecked">Inspector audits contrast ratios for both variants</li>
      </ul>
    </section>
    <section data-name="approach" class="rf-work__approach">
      <h2 id="approach">Approach</h2>
      <p>
        The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as 
        <code>--tint-dark-*</code>
         CSS custom properties alongside the light values.
      </p>
    </section>
  </div>
</article>

Blocked work item

A work item blocked by a dependency.

{% work id="RF-215" status="blocked" priority="medium" complexity="complex" assignee="alice" %}
# Alignment system migration

Migrate all runes from manual alignment classes to the new alignment system.

## Acceptance Criteria
- [ ] All runes use alignment utilities instead of manual classes
- [ ] No visual regressions in existing content
- [ ] Migration guide published
{% /work %}
<article data-rune="work" data-rune-fields="{&quot;id&quot;:&quot;RF-215&quot;,&quot;status&quot;:&quot;blocked&quot;,&quot;priority&quot;:&quot;medium&quot;,&quot;complexity&quot;:&quot;complex&quot;,&quot;assignee&quot;:&quot;alice&quot;,&quot;milestone&quot;:&quot;&quot;,&quot;source&quot;:&quot;&quot;,&quot;supersedes&quot;:&quot;&quot;,&quot;pr&quot;:&quot;&quot;,&quot;tags&quot;:&quot;&quot;,&quot;created&quot;:&quot;2026-09-13&quot;,&quot;modified&quot;:&quot;2026-09-13&quot;}">
  <header data-name="title">
    <h1 id="alignment-system-migration">Alignment system migration</h1>
  </header>
  <div data-name="blurb">
    <p>Migrate all runes from manual alignment classes to the new alignment system.</p>
  </div>
  <div data-name="body">
    <section data-name="acceptance-criteria">
      <h2 id="acceptance-criteria">Acceptance Criteria</h2>
      <ul>
        <li>[ ] All runes use alignment utilities instead of manual classes</li>
        <li>[ ] No visual regressions in existing content</li>
        <li>[ ] Migration guide published</li>
      </ul>
    </section>
  </div>
</article>
RF-215blocked

Alignment system migration

Migrate all runes from manual alignment classes to the new alignment system.

Acceptance Criteria

  • All runes use alignment utilities instead of manual classes
  • No visual regressions in existing content
  • Migration guide published
<article class="rf-work rf-work--RF-215 rf-work--blocked rf-work--medium rf-work--complex" data-id="RF-215" data-status="blocked" data-priority="medium" data-complexity="complex" data-assignee="alice" data-milestone="" data-source="" data-supersedes="" data-pr="" data-tags="" data-created="2026-09-13" data-modified="2026-09-13" data-rune="work" data-density="full">
  <div data-name="eyebrow" data-zone="eyebrow" data-zone-layout="bar" class="rf-work__eyebrow">
    <span data-meta-type="id">RF-215</span>
    <span class="rf-badge" data-meta-type="status" data-meta-sentiment="negative" data-align="end">blocked</span>
  </div>
  <header data-name="title" class="rf-work__title" data-section="title">
    <h1 id="alignment-system-migration">Alignment system migration</h1>
  </header>
  <div data-name="blurb" class="rf-work__blurb" data-section="description">
    <p>Migrate all runes from manual alignment classes to the new alignment system.</p>
  </div>
  <dl data-name="metadata" data-zone="metadata" data-zone-layout="definition-list" class="rf-work__metadata">
    <div data-name="row" data-field="priority" class="rf-work__row">
      <dt data-meta-label="">Priority</dt>
      <dd>
        <span class="rf-badge" data-meta-type="category" data-meta-sentiment="neutral">medium</span>
      </dd>
    </div>
    <div data-name="row" data-field="complexity" class="rf-work__row">
      <dt data-meta-label="">Complexity</dt>
      <dd data-meta-type="quantity">complex</dd>
    </div>
    <div data-name="row" data-field="assignee" class="rf-work__row">
      <dt data-meta-label="">Assignee</dt>
      <dd>
        <span class="rf-badge" data-meta-type="tag">alice</span>
      </dd>
    </div>
    <div data-name="row" data-field="created" class="rf-work__row">
      <dt data-meta-label="">Created</dt>
      <dd data-meta-type="temporal">
        <time datetime="2026-09-13">2026-09-13</time>
      </dd>
    </div>
    <div data-name="row" data-field="modified" class="rf-work__row">
      <dt data-meta-label="">Modified</dt>
      <dd data-meta-type="temporal">
        <time datetime="2026-09-13">2026-09-13</time>
      </dd>
    </div>
  </dl>
  <div data-name="body" class="rf-work__body" data-section="body">
    <section data-name="acceptance-criteria" class="rf-work__acceptance-criteria">
      <h2 id="acceptance-criteria">Acceptance Criteria</h2>
      <ul>
        <li data-checked="unchecked">All runes use alignment utilities instead of manual classes</li>
        <li data-checked="unchecked">No visual regressions in existing content</li>
        <li data-checked="unchecked">Migration guide published</li>
      </ul>
    </section>
  </div>
</article>

Attributes

AttributeTypeRequiredDescription
idstringUnique identifier (e.g., "RF-142").
status"draft" | "ready" | "in-progress" | "review" | "done" | "blocked" | "pending" | "cancelled" | "superseded"Current status: draft, ready, in-progress, review, done, blocked, pending, cancelled, or superseded.
priority"critical" | "high" | "medium" | "low"Priority level: critical, high, medium, or low.
complexity"trivial" | "simple" | "moderate" | "complex" | "unknown"Complexity signal: trivial, simple, moderate, complex, or unknown.
assigneestringPerson or agent working on this.
milestonestringMilestone this belongs to.
sourcestringComma-separated IDs of specs or decisions this item implements.
supersedesstringID of the work item this replaces (set when status="superseded").
prstringComma-separated PR references that implemented this item (e.g. "refrakt-md/refrakt#142").
tagsstringComma-separated labels.
createdstringCreation date (ISO 8601). Defaults to file creation date from git.
modifiedstringLast modified date (ISO 8601). Defaults to file modification date from git.

Universal attributes

bg

The background layer (SPEC-088): image, video, gradient, flat overlay wash and legibility scrim, in a single injected layer behind the rune's content.

AttributeTypeRequiredDescription
bgstringBackground preset applied to this block
bg-fromstringGradient start colour — a semantic token name (→ var(--rf-color-*))
bg-gradient"to-t" | "to-b" | "to-l" | "to-r" | "to-tr" | "to-br" | "to-bl" | "to-tl"Gradient direction (bounded named set)
bg-gradient-type"linear" | "radial" | "conic"Gradient type
bg-tostringGradient end colour — a semantic token name
bg-viastringOptional middle gradient stop — a semantic token name
scrim"top" | "bottom" | "left" | "right" | "none"Scrim direction (heaviest edge); presence turns the scrim on, "none" opts out of the default cover scrim
scrim-blur"none" | "sm" | "md" | "lg"Frost scrim blur amount
scrim-strength"sm" | "md" | "lg"Gradient scrim strength
scrim-tone"dark" | "light"Whether the scrim darkens (for light text) or lightens (for dark text)
scrim-type"gradient" | "frost"Scrim treatment: gradient (default) or frost (backdrop blur)
dropcap

Per-instance drop-cap opt-in (SPEC-108).

AttributeTypeRequiredDescription
dropcapbooleanStyle the opening letter of a prose body as a drop cap (SPEC-108). Honoured only when the body reads as prose; ignored otherwise.
elevation

The chrome/depth ladder (SPEC-107). The skin maps each rung to a chrome bundle by attribute, so there is no BEM class.

AttributeTypeRequiredDescription
elevation"sunken" | "flush" | "flat" | "raised" | "floating" | "overlay" | "none" | "sm" | "md" | "lg"Surface depth on the SPEC-107 ladder (sunken→overlay); none/sm/md/lg are deprecated aliases
inset

Internal padding override.

AttributeTypeRequiredDescription
inset"flush" | "tight" | "default" | "loose" | "breathe"Inner padding of this block
motion

Scroll-reveal entrance (SPEC-105). The author declares the character, the theme owns the choreography, a behaviour owns the timing.

AttributeTypeRequiredDescription
reveal"none" | "fade" | "slide" | "scale" | "blur"Scroll-reveal entrance character (none|fade|slide|scale|blur); the theme owns the choreography
staggerbooleanCascade this block's items in as it reveals (no-op on single-child runes)
prominence

Header emphasis (SPEC-107). Scales a rune's page-section header; the skin maps it to a type register by attribute, so there is no BEM class.

AttributeTypeRequiredDescription
prominence"quiet" | "normal" | "prominent" | "display"Section-header emphasis (only on page-section-header family runes)
reading

Editorial register for body text (SPEC-108). The author picks the register; the theme owns the magnitude.

AttributeTypeRequiredDescription
reading"fine" | "ui" | "prose"Reading register for this block’s body (SPEC-108): fine | ui | prose. The theme owns the editorial treatment.
spacing

Block-level rhythm override.

AttributeTypeRequiredDescription
spacing"flush" | "tight" | "default" | "loose" | "breathe"Vertical spacing above and below this block
substrate

Generated pattern fills (SPEC-087). Markers only — the engine sets the attributes and cell/opacity custom properties, CSS draws the pattern.

AttributeTypeRequiredDescription
substrate"dots" | "grid" | "lines" | "cross" | "checker" | "none"Generated surface pattern
substrate-fill"inherit" | "inset"Surface fill the pattern sits on (full colour stays with tint)
substrate-opacity"sm" | "md" | "lg"Pattern ink strength
substrate-size"sm" | "md" | "lg"Pattern cell size
substrate-target"self" | "media"Which surface the pattern fills (overrides the rune/theme default)
tint

Per-rune colour override (SPEC-053): a named tint from the theme registry, with inline per-token overrides layered on top.

AttributeTypeRequiredDescription
tintstringColor tint preset applied to this block
tint-mode"auto" | "dark" | "light"Whether the tint adapts to auto, dark, or light mode
width

The track a block rune occupies.

AttributeTypeRequiredDescription
width"compact" | "narrow" | "content" | "wide" | "full"Maximum width constraint for this block
Not availableWhy
framethis rune declares neither a `frameTarget` nor a media section

Retiring a work item

Not every work item ships. Rather than deleting the file (which loses the reasoning trail) or marking it done (which lies to progress rollups), use one of the two terminal-but-non-achieving states:

  • cancelled — the work is deliberately dropped and no longer wanted. Record the reason in the body or a ## Resolution.
  • superseded — the work is replaced by a different item. Pair it with supersedes="WORK-xxx" pointing at the replacement.

Both statuses end the item's lifecycle without counting as completion — they are excluded from plan next, from milestone progress, and from plan-progress achieved counts. A ## Resolution explaining the retirement is allowed on either. | created | string | $file.created | Creation date (ISO 8601). Auto-populated from git history | | modified | string | $file.modified | Last modified date (ISO 8601). Auto-populated from git history |