Skip to main content
Compendium / Pillars & Roles / Loops & Cycles / IRAF Loop
#020

IRAF Loop

Intent → Reasoning → Action → Feedback — the four-step civic procedure cycle that governs any AI-assisted task.

STABLE
#svg #real-content #dark-mode-tested
Live
Procedure № IRAF
Cyclic
CYCLE IRAF I INTENT DECLARE II REASONING DELIBERATE III ACTION EXECUTE IV FEEDBACK REVIEW
Spec

Intent

Visualise the IRAF loop (Intent · Reasoning · Action · Feedback) as a four-node cycle. Frame it like an institutional procedure diagram — clean, symmetric, every label fits its frame.

Acceptance Criteria

  • [ ] Renders all four IRAF stages in a 2×2 corner layout
  • [ ] Connecting arrows show clockwise progression
  • [ ] Each node has its civic ordinal (I-IV) and a verb
  • [ ] Every label fits inside its frame at the rendered size
  • [ ] Does not require JS — pure SVG render

Constraints

  • Pure SVG
  • Theme-aware via tokens
  • No hex literals in brand-colour slots
  • ≤ 150 lines body
// iraf-loop.astro
---
import type { CompendiumMeta } from '../../../data/types';

export const meta: CompendiumMeta = {
  id: 20,
  slug: 'iraf-loop',
  name: 'IRAF Loop',
  category: 'pillars-roles',
  subcategory: 'loops-cycles',
  description: 'Intent → Reasoning → Action → Feedback — the four-step civic procedure cycle that governs any AI-assisted task.',
  spec: `## Intent
Visualise the IRAF loop (Intent · Reasoning · Action · Feedback) as a four-node cycle. Frame it like an institutional procedure diagram — clean, symmetric, every label fits its frame.

## Acceptance Criteria
- [ ] Renders all four IRAF stages in a 2×2 corner layout
- [ ] Connecting arrows show clockwise progression
- [ ] Each node has its civic ordinal (I-IV) and a verb
- [ ] Every label fits inside its frame at the rendered size
- [ ] Does not require JS — pure SVG render

## Constraints
- Pure SVG
- Theme-aware via tokens
- No hex literals in brand-colour slots
- ≤ 150 lines body`,
  tags: ['svg', 'real-content', 'dark-mode-tested'],
  status: 'stable',
  health: { ics: 100, a11y: 'aa', themed: true, animated: false },
};

// 2×2 corner layout. Each box is generous enough for the longest
// label ("REASONING", 9 chars at 14px Inter-Black ≈ 95px). Arrows
// run along the perimeter, never through the boxes.
const nodes = [
  { id: 'TL', x: 20,  y: 20,  c: 'var(--color-do)', k: 'I',   t: 'INTENT',    sub: 'DECLARE'    },
  { id: 'TR', x: 180, y: 20,  c: 'var(--color-co)', k: 'II',  t: 'REASONING', sub: 'DELIBERATE' },
  { id: 'BR', x: 180, y: 140, c: 'var(--color-de)', k: 'III', t: 'ACTION',    sub: 'EXECUTE'    },
  { id: 'BL', x: 20,  y: 140, c: 'var(--color-go)', k: 'IV',  t: 'FEEDBACK',  sub: 'REVIEW'     },
];
const boxW = 120;
const boxH = 50;
---

<div data-this-component class="w-full bg-paper text-black border-4 border-black shadow-nb-sm p-3 overflow-hidden">
  <div class="flex items-center justify-between mb-2 gap-2">
    <div class="font-mono text-[9px] uppercase tracking-[0.25em] opacity-60 truncate">Procedure № IRAF</div>
    <div class="font-mono text-[9px] uppercase tracking-[0.25em] opacity-60 shrink-0">Cyclic</div>
  </div>

  <svg viewBox="0 0 320 210" class="w-full block" aria-label="IRAF cycle: Intent, Reasoning, Action, Feedback" role="img">
    <defs>
      <marker id="iraf-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
        <path d="M 0 0 L 10 5 L 0 10 z" fill="var(--color-ink)" />
      </marker>
    </defs>

    <!-- Perimeter arrows (clockwise: TL → TR → BR → BL → TL).
         Each arrow runs along the gutter between boxes; never crosses
         a box. End-points stop 8px shy of the next box for a clean
         arrowhead landing. -->
    <path d="M 144 45 L 176 45"  stroke="var(--color-ink)" stroke-width="3" fill="none" marker-end="url(#iraf-arrow)" />
    <path d="M 240 74 L 240 136" stroke="var(--color-ink)" stroke-width="3" fill="none" marker-end="url(#iraf-arrow)" />
    <path d="M 176 165 L 144 165" stroke="var(--color-ink)" stroke-width="3" fill="none" marker-end="url(#iraf-arrow)" />
    <path d="M 80  136 L 80  74"  stroke="var(--color-ink)" stroke-width="3" fill="none" marker-end="url(#iraf-arrow)" />

    <!-- Centre stamp -->
    <text x="160" y="100" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="9" letter-spacing="3" fill="var(--color-ink)" opacity="0.45">CYCLE</text>
    <text x="160" y="118" text-anchor="middle" font-family="Inter, sans-serif" font-weight="900" font-size="20" letter-spacing="2" fill="var(--color-ink)">IRAF</text>

    <!-- Four corner nodes -->
    {nodes.map((n) => (
      <g>
        <rect
          x={n.x} y={n.y} width={boxW} height={boxH}
          fill={n.c} stroke="var(--color-ink)" stroke-width="3"
        />
        <!-- Civic ordinal in the top-left of the tile -->
        <text x={n.x + 8} y={n.y + 14} font-family="JetBrains Mono, monospace" font-size="9" font-weight="700" fill="var(--color-ink)" opacity="0.7">{n.k}</text>
        <!-- Main label, centred -->
        <text x={n.x + boxW / 2} y={n.y + 30} text-anchor="middle" font-family="Inter, sans-serif" font-weight="900" font-size="16" fill="var(--color-ink)">{n.t}</text>
        <!-- Verb sub-label -->
        <text x={n.x + boxW / 2} y={n.y + 43} text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="8" letter-spacing="1.5" fill="var(--color-ink)" opacity="0.7">{n.sub}</text>
      </g>
    ))}
  </svg>
</div>