<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Projects on mig5</title>
    <link>https://mig5.net/projects/</link>
    <description>Recent content from Projects on mig5</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-au</language><atom:link href="https://mig5.net/projects/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Bouquin</title>
      <link>https://mig5.net/projects/bouquin/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://mig5.net/projects/bouquin/</guid>
      <description><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-8">
        <div class="kicker mb-3"><i class="bi bi-journal-text"></i><span>Bouquin</span></div>
        <h1 class="display-6 fw-semibold mb-3">A local-first notebook & planner with encrypted storage</h1>
        <p class="lead mb-4">
          Bouquin ("Book-ahn") is a notebook and planner application written in Python/Qt, backed by SQLCipher so the
          notebook database is encrypted at rest.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://git.mig5.net/mig5/bouquin" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">Design goals</h2>
        <ul>
          <li>Encrypted-at-rest</li>
          <li>Every note is a calendar date</li>
          <li>All changes are version controlled, with a 'diff' viewer</li>
          <li> Revert to any previous version without losing newer versions</li>
          <li>Live markdown rendering as you type</li>
          <li>No syncing: deliberately offline-first</li>
          <li>Tagging and search</li>
          <li>One-off or recurring reminders with webhook support</li>
          <li>Time tracking, invoicing and document storage features</li>
          <li>Multi-lingual (English, French and Italian translations)</li>
        </ul>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://git.mig5.net/mig5/bouquin" target="_blank" rel="noopener noreferrer">Source repo</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need encryption & key management help?</div>
          <div class="smallprint mb-3">I do security-minded sysadmin work: hardening, secrets, and auditability.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></description>
      <content:encoded><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-8">
        <div class="kicker mb-3"><i class="bi bi-journal-text"></i><span>Bouquin</span></div>
        <h1 class="display-6 fw-semibold mb-3">A local-first notebook & planner with encrypted storage</h1>
        <p class="lead mb-4">
          Bouquin ("Book-ahn") is a notebook and planner application written in Python/Qt, backed by SQLCipher so the
          notebook database is encrypted at rest.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://git.mig5.net/mig5/bouquin" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">Design goals</h2>
        <ul>
          <li>Encrypted-at-rest</li>
          <li>Every note is a calendar date</li>
          <li>All changes are version controlled, with a 'diff' viewer</li>
          <li> Revert to any previous version without losing newer versions</li>
          <li>Live markdown rendering as you type</li>
          <li>No syncing: deliberately offline-first</li>
          <li>Tagging and search</li>
          <li>One-off or recurring reminders with webhook support</li>
          <li>Time tracking, invoicing and document storage features</li>
          <li>Multi-lingual (English, French and Italian translations)</li>
        </ul>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://git.mig5.net/mig5/bouquin" target="_blank" rel="noopener noreferrer">Source repo</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need encryption & key management help?</div>
          <div class="smallprint mb-3">I do security-minded sysadmin work: hardening, secrets, and auditability.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></content:encoded>
    </item>
    
    <item>
      <title>CSPresso</title>
      <link>https://mig5.net/projects/cspresso/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://mig5.net/projects/cspresso/</guid>
      <description><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-shield-check"></i><span>CSPresso</span></div>
        <h1 class="display-6 fw-semibold mb-3">Turn real page loads into a CSP you can ship</h1>
        <p class="lead mb-4">
          cspresso crawls same-origin pages with headless Chromium (Playwright), watches the assets that load,
          and emits a draft <code>Content-Security-Policy</code> header.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://cspresso.cafe" target="_blank" rel="noopener noreferrer">
            Visit cspresso.cafe <i class="bi bi-box-arrow-up-right"></i>
          </a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/cspresso" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#cspresso-snippet">Copy</button>
          <pre class="mb-0"><code id="cspresso-snippet">$ pipx install cspresso
$ cspresso https://example.com --max-pages 10</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">Why it exists</h2>
        <p>
          CSP is powerful but notoriously fiddly. cspresso automates the "observe what loads" part by letting a real browser
          execute the app and then distilling observed origins into CSP directives.
        </p>

        <h2 class="h4 mt-4">It can help with</h2>
        <ul>
          <li>Discovering which origins your app actually depends on</li>
          <li>Drafting a baseline policy for review</li>
          <li>Evaluating candidates as Report-Only and failing CI on violations</li>
        </ul>

      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://cspresso.cafe" target="_blank" rel="noopener noreferrer">Website / docs</a></li>
            <li><a href="https://git.mig5.net/mig5/cspresso" target="_blank" rel="noopener noreferrer">Source repo</a></li>
            <li><a href="https://pypi.org/project/cspresso/" target="_blank" rel="noopener noreferrer">PyPI</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need a CSP rollout?</div>
          <div class="smallprint mb-3">I can help you roll out CSP safely with monitoring, reporting, and staged enforcement.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></description>
      <content:encoded><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-shield-check"></i><span>CSPresso</span></div>
        <h1 class="display-6 fw-semibold mb-3">Turn real page loads into a CSP you can ship</h1>
        <p class="lead mb-4">
          cspresso crawls same-origin pages with headless Chromium (Playwright), watches the assets that load,
          and emits a draft <code>Content-Security-Policy</code> header.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://cspresso.cafe" target="_blank" rel="noopener noreferrer">
            Visit cspresso.cafe <i class="bi bi-box-arrow-up-right"></i>
          </a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/cspresso" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#cspresso-snippet">Copy</button>
          <pre class="mb-0"><code id="cspresso-snippet">$ pipx install cspresso
$ cspresso https://example.com --max-pages 10</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">Why it exists</h2>
        <p>
          CSP is powerful but notoriously fiddly. cspresso automates the "observe what loads" part by letting a real browser
          execute the app and then distilling observed origins into CSP directives.
        </p>

        <h2 class="h4 mt-4">It can help with</h2>
        <ul>
          <li>Discovering which origins your app actually depends on</li>
          <li>Drafting a baseline policy for review</li>
          <li>Evaluating candidates as Report-Only and failing CI on violations</li>
        </ul>

      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://cspresso.cafe" target="_blank" rel="noopener noreferrer">Website / docs</a></li>
            <li><a href="https://git.mig5.net/mig5/cspresso" target="_blank" rel="noopener noreferrer">Source repo</a></li>
            <li><a href="https://pypi.org/project/cspresso/" target="_blank" rel="noopener noreferrer">PyPI</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need a CSP rollout?</div>
          <div class="smallprint mb-3">I can help you roll out CSP safely with monitoring, reporting, and staged enforcement.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></content:encoded>
    </item>
    
    <item>
      <title>DumpTales</title>
      <link>https://mig5.net/projects/dumptales/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://mig5.net/projects/dumptales/</guid>
      <description><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-8">
        <div class="kicker mb-3"><i class="bi bi-database"></i><span>DumpTales</span></div>
        <h1 class="display-6 fw-semibold mb-3">Find the story between two database snapshots</h1>
        <p class="lead mb-4">DumpTales compares MySQL or MariaDB SQL dumps, experimental PostgreSQL COPY dumps, and native SQLite databases. See added, removed and modified rows by primary key without connecting to the database.</p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="/news/dumptales/">Read the example</a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/dumptales" target="_blank" rel="noopener noreferrer">Source and installation</a>
        </div>
      </div>
      <div class="col-12 col-lg-4"><img class="img-fluid" src="icon.png" alt="DumpTales duck and database logo" width="320" height="320"></div>
    </div>
  </div>
</section>
<section class="section"><div class="container"><h2 class="h4">A quick comparison</h2><div class="terminal codeblock p-4"><pre class="mb-0"><code>dumptales old.sql.gz new.sql.gz

dumptales old.sql new.sql --format json &gt; changes.json</code></pre></div><p class="mt-4">DumpTales runs locally and reads snapshots without executing their SQL. MySQL dumps in compatible primary-key order stream through; unordered data uses temporary compressed partitions. SQL dialect and gzip, bzip2 or single-file ZIP compression are detected automatically. Schema coverage varies by dialect. Read the <a href="/news/dumptales/">worked example and limitations</a> before using it with your own dumps.</p></div></section>
]]></description>
      <content:encoded><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-8">
        <div class="kicker mb-3"><i class="bi bi-database"></i><span>DumpTales</span></div>
        <h1 class="display-6 fw-semibold mb-3">Find the story between two database snapshots</h1>
        <p class="lead mb-4">DumpTales compares MySQL or MariaDB SQL dumps, experimental PostgreSQL COPY dumps, and native SQLite databases. See added, removed and modified rows by primary key without connecting to the database.</p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="/news/dumptales/">Read the example</a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/dumptales" target="_blank" rel="noopener noreferrer">Source and installation</a>
        </div>
      </div>
      <div class="col-12 col-lg-4"><img class="img-fluid" src="icon.png" alt="DumpTales duck and database logo" width="320" height="320"></div>
    </div>
  </div>
</section>
<section class="section"><div class="container"><h2 class="h4">A quick comparison</h2><div class="terminal codeblock p-4"><pre class="mb-0"><code>dumptales old.sql.gz new.sql.gz

dumptales old.sql new.sql --format json &gt; changes.json</code></pre></div><p class="mt-4">DumpTales runs locally and reads snapshots without executing their SQL. MySQL dumps in compatible primary-key order stream through; unordered data uses temporary compressed partitions. SQL dialect and gzip, bzip2 or single-file ZIP compression are detected automatically. Schema coverage varies by dialect. Read the <a href="/news/dumptales/">worked example and limitations</a> before using it with your own dumps.</p></div></section>
]]></content:encoded>
    </item>
    
    <item>
      <title>Enroll</title>
      <link>https://mig5.net/projects/enroll/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://mig5.net/projects/enroll/</guid>
      <description><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-terminal"></i><span>Enroll</span></div>
        <h1 class="display-6 fw-semibold mb-3">Get an existing Linux host into Ansible in seconds</h1>
        <p class="lead mb-4">
          Enroll inspects a Debian-like or RedHat-like system, harvests the state that matters,
          and generates Ansible roles/playbooks so you can bring snowflakes under management fast.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://enroll.sh" target="_blank" rel="noopener noreferrer">
            Visit enroll.sh <i class="bi bi-box-arrow-up-right"></i>
          </a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/enroll" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#enroll-snippet">Copy</button>
          <pre class="mb-0"><code id="enroll-snippet">$ enroll single-shot --harvest ./harvest --out ./ansible
$ cd ./ansible && tree -L 2</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">What it's for</h2>
        <ul>
          <li>Hosts with no config management</li>
          <li>Fast DR snapshots you can turn into playbooks</li>
          <li>Detecting drift over time (diff mode + notifications)</li>
        </ul>

        <h2 class="h4 mt-4">Highlights</h2>
        <div class="row g-3">
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-lightning-charge"></i></div>
              <div class="fw-semibold">Fast</div>
              <div class="smallprint">Harvest state, then render playbooks locally.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-shield-lock"></i></div>
              <div class="fw-semibold">Safe-by-default harvesting</div>
              <div class="smallprint">Heuristics to avoid likely secrets; opt-in for more.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-hdd-network"></i></div>
              <div class="fw-semibold">Remote over SSH</div>
              <div class="smallprint">Harvest from your workstation; generate output locally.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-lock"></i></div>
              <div class="fw-semibold">Optional encryption</div>
              <div class="smallprint">Store harvests/manifests encrypted at rest (SOPS/GPG).</div>
            </div>
          </div>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://enroll.sh" target="_blank" rel="noopener noreferrer">Website / docs</a></li>
            <li><a href="https://git.mig5.net/mig5/enroll" target="_blank" rel="noopener noreferrer">Source repo</a></li>
            <li><a href="https://pypi.org/project/enroll/" target="_blank" rel="noopener noreferrer">PyPI</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need help enrolling infra?</div>
          <div class="smallprint mb-3">I do contract sysadmin work and can help you adopt tooling like this safely.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></description>
      <content:encoded><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-terminal"></i><span>Enroll</span></div>
        <h1 class="display-6 fw-semibold mb-3">Get an existing Linux host into Ansible in seconds</h1>
        <p class="lead mb-4">
          Enroll inspects a Debian-like or RedHat-like system, harvests the state that matters,
          and generates Ansible roles/playbooks so you can bring snowflakes under management fast.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://enroll.sh" target="_blank" rel="noopener noreferrer">
            Visit enroll.sh <i class="bi bi-box-arrow-up-right"></i>
          </a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/enroll" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#enroll-snippet">Copy</button>
          <pre class="mb-0"><code id="enroll-snippet">$ enroll single-shot --harvest ./harvest --out ./ansible
$ cd ./ansible && tree -L 2</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">What it's for</h2>
        <ul>
          <li>Hosts with no config management</li>
          <li>Fast DR snapshots you can turn into playbooks</li>
          <li>Detecting drift over time (diff mode + notifications)</li>
        </ul>

        <h2 class="h4 mt-4">Highlights</h2>
        <div class="row g-3">
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-lightning-charge"></i></div>
              <div class="fw-semibold">Fast</div>
              <div class="smallprint">Harvest state, then render playbooks locally.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-shield-lock"></i></div>
              <div class="fw-semibold">Safe-by-default harvesting</div>
              <div class="smallprint">Heuristics to avoid likely secrets; opt-in for more.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-hdd-network"></i></div>
              <div class="fw-semibold">Remote over SSH</div>
              <div class="smallprint">Harvest from your workstation; generate output locally.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-lock"></i></div>
              <div class="fw-semibold">Optional encryption</div>
              <div class="smallprint">Store harvests/manifests encrypted at rest (SOPS/GPG).</div>
            </div>
          </div>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://enroll.sh" target="_blank" rel="noopener noreferrer">Website / docs</a></li>
            <li><a href="https://git.mig5.net/mig5/enroll" target="_blank" rel="noopener noreferrer">Source repo</a></li>
            <li><a href="https://pypi.org/project/enroll/" target="_blank" rel="noopener noreferrer">PyPI</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need help enrolling infra?</div>
          <div class="smallprint mb-3">I do contract sysadmin work and can help you adopt tooling like this safely.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></content:encoded>
    </item>
    
    <item>
      <title>Heckle</title>
      <link>https://mig5.net/projects/heckle/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://mig5.net/projects/heckle/</guid>
      <description><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-diagram-3"></i><span>Heckle</span></div>
        <h1 class="display-6 fw-semibold mb-3">Bring an existing git forge under Infrastructure as Code</h1>
        <p class="lead mb-4">
          Heckle inventories a GitHub, GitLab, Gitea or Forgejo namespace, maps supported objects to provider
          import contracts, and emits an editable project of <code>.tf</code> files and local modules you can
          adopt with Terraform or OpenTofu. The name is a play on HCL.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://heckle.tf" target="_blank" rel="noopener noreferrer">
            Visit heckle.tf <i class="bi bi-box-arrow-up-right"></i>
          </a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/heckle" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#heckle-snippet">Copy</button>
          <pre class="mb-0"><code id="heckle-snippet">$ export GITHUB_TOKEN='...'
$ heckle generate github --org example --out ./iac
$ cd ./iac && tofu plan</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">What it's for</h2>
        <ul>
          <li>Forges with repos, teams, protections and webhooks but no IaC</li>
          <li>Bringing org/group/repo setup into Terraform or OpenTofu</li>
          <li>Auditing and reproducing forge configuration as code</li>
        </ul>

        <h2 class="h4 mt-4">Highlights</h2>
        <div class="row g-3">
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-eye"></i></div>
              <div class="fw-semibold">Safe, no-op discovery</div>
              <div class="smallprint">Reads the forge and generates HCL; never runs <code>apply</code> and never persists disposable validation state.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-git"></i></div>
              <div class="fw-semibold">Four forges</div>
              <div class="smallprint">GitHub, GitLab, Gitea and Forgejo, including orgs, groups and personal accounts.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-clipboard-check"></i></div>
              <div class="fw-semibold">Rehearsed adoption</div>
              <div class="smallprint">Classifies known provider behaviour and stops on unrecognised plan changes.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-tools"></i></div>
              <div class="fw-semibold">Terraform or OpenTofu</div>
              <div class="smallprint">OpenTofu is the default; pass <code>--tf terraform</code> to choose otherwise. Heckle itself is not required after adoption.</div>
            </div>
          </div>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://heckle.tf" target="_blank" rel="noopener noreferrer">Website / docs</a></li>
            <li><a href="https://git.mig5.net/mig5/heckle" target="_blank" rel="noopener noreferrer">Source repo</a></li>
          </ul>
          <div class="smallprint mt-2 mb-0">Heckle is currently alpha software.</div>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need help adopting IaC?</div>
          <div class="smallprint mb-3">I can help you bring existing forges and infrastructure under Terraform or OpenTofu safely.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></description>
      <content:encoded><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-diagram-3"></i><span>Heckle</span></div>
        <h1 class="display-6 fw-semibold mb-3">Bring an existing git forge under Infrastructure as Code</h1>
        <p class="lead mb-4">
          Heckle inventories a GitHub, GitLab, Gitea or Forgejo namespace, maps supported objects to provider
          import contracts, and emits an editable project of <code>.tf</code> files and local modules you can
          adopt with Terraform or OpenTofu. The name is a play on HCL.
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://heckle.tf" target="_blank" rel="noopener noreferrer">
            Visit heckle.tf <i class="bi bi-box-arrow-up-right"></i>
          </a>
          <a class="btn btn-outline-primary btn-lg" href="https://git.mig5.net/mig5/heckle" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#heckle-snippet">Copy</button>
          <pre class="mb-0"><code id="heckle-snippet">$ export GITHUB_TOKEN='...'
$ heckle generate github --org example --out ./iac
$ cd ./iac && tofu plan</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">What it's for</h2>
        <ul>
          <li>Forges with repos, teams, protections and webhooks but no IaC</li>
          <li>Bringing org/group/repo setup into Terraform or OpenTofu</li>
          <li>Auditing and reproducing forge configuration as code</li>
        </ul>

        <h2 class="h4 mt-4">Highlights</h2>
        <div class="row g-3">
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-eye"></i></div>
              <div class="fw-semibold">Safe, no-op discovery</div>
              <div class="smallprint">Reads the forge and generates HCL; never runs <code>apply</code> and never persists disposable validation state.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-git"></i></div>
              <div class="fw-semibold">Four forges</div>
              <div class="smallprint">GitHub, GitLab, Gitea and Forgejo, including orgs, groups and personal accounts.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-clipboard-check"></i></div>
              <div class="fw-semibold">Rehearsed adoption</div>
              <div class="smallprint">Classifies known provider behaviour and stops on unrecognised plan changes.</div>
            </div>
          </div>
          <div class="col-12 col-md-6">
            <div class="feature-card p-4 h-100">
              <div class="icon-pill mb-3"><i class="bi bi-tools"></i></div>
              <div class="fw-semibold">Terraform or OpenTofu</div>
              <div class="smallprint">OpenTofu is the default; pass <code>--tf terraform</code> to choose otherwise. Heckle itself is not required after adoption.</div>
            </div>
          </div>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://heckle.tf" target="_blank" rel="noopener noreferrer">Website / docs</a></li>
            <li><a href="https://git.mig5.net/mig5/heckle" target="_blank" rel="noopener noreferrer">Source repo</a></li>
          </ul>
          <div class="smallprint mt-2 mb-0">Heckle is currently alpha software.</div>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Need help adopting IaC?</div>
          <div class="smallprint mb-3">I can help you bring existing forges and infrastructure under Terraform or OpenTofu safely.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></content:encoded>
    </item>
    
    <item>
      <title>JinjaTurtle</title>
      <link>https://mig5.net/projects/jinjaturtle/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://mig5.net/projects/jinjaturtle/</guid>
      <description><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-braces"></i><span>JinjaTurtle</span></div>
        <h1 class="display-6 fw-semibold mb-3">Convert real config files into templates you can manage</h1>
        <p class="lead mb-4">
          JinjaTurtle is a CLI tool that helps you generate Jinja2 templates and Ansible inventory/vars from native config
          files (toml/yaml/json/ini/xml and friends).
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://git.mig5.net/mig5/jinjaturtle" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#jt-snippet">Copy</button>
          <pre class="mb-0"><code id="jt-snippet">$ jinjaturtle /etc/myapp/config.toml
# → Jinja2 template + Ansible defaults</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">When it's useful</h2>
        <ul>
          <li>You inherited a complex config file and need to make it data-driven</li>
          <li>You want clean diffs and repeatable rollouts</li>
          <li>You're gradually migrating manual changes into config management</li>
        </ul>

        <div class="callout p-4">
          <div class="fw-semibold mb-1">Pairs nicely with Enroll</div>
          <div class="smallprint">Enroll can detect structured configs and hand off to JinjaTurtle for templating.</div>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://git.mig5.net/mig5/jinjaturtle" target="_blank" rel="noopener noreferrer">Source repo</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Want to template infra safely?</div>
          <div class="smallprint mb-3">I can help you adopt config management without breaking prod.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></description>
      <content:encoded><![CDATA[
<section class="hero hero--compact">
  <div class="container">
    <div class="row g-4 align-items-center">
      <div class="col-12 col-lg-7">
        <div class="kicker mb-3"><i class="bi bi-braces"></i><span>JinjaTurtle</span></div>
        <h1 class="display-6 fw-semibold mb-3">Convert real config files into templates you can manage</h1>
        <p class="lead mb-4">
          JinjaTurtle is a CLI tool that helps you generate Jinja2 templates and Ansible inventory/vars from native config
          files (toml/yaml/json/ini/xml and friends).
        </p>
        <div class="d-flex flex-wrap gap-2">
          <a class="btn btn-primary btn-lg" href="https://git.mig5.net/mig5/jinjaturtle" target="_blank" rel="noopener noreferrer">
            Repo <i class="bi bi-git"></i>
          </a>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="terminal codeblock">
          <button class="btn btn-sm btn-outline-light copy-btn" data-copy-target="#jt-snippet">Copy</button>
          <pre class="mb-0"><code id="jt-snippet">$ jinjaturtle /etc/myapp/config.toml
# → Jinja2 template + Ansible defaults</code></pre>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section">
  <div class="container">
    <div class="row g-4">
      <div class="col-12 col-lg-7">
        <h2 class="h4">When it's useful</h2>
        <ul>
          <li>You inherited a complex config file and need to make it data-driven</li>
          <li>You want clean diffs and repeatable rollouts</li>
          <li>You're gradually migrating manual changes into config management</li>
        </ul>

        <div class="callout p-4">
          <div class="fw-semibold mb-1">Pairs nicely with Enroll</div>
          <div class="smallprint">Enroll can detect structured configs and hand off to JinjaTurtle for templating.</div>
        </div>
      </div>

      <div class="col-12 col-lg-5">
        <div class="callout p-4">
          <div class="fw-semibold mb-2">Links</div>
          <ul class="mb-0">
            <li><a href="https://git.mig5.net/mig5/jinjaturtle" target="_blank" rel="noopener noreferrer">Source repo</a></li>
          </ul>
        </div>

        <div class="mt-3 callout p-4">
          <div class="fw-semibold mb-1">Want to template infra safely?</div>
          <div class="smallprint mb-3">I can help you adopt config management without breaking prod.</div>
          <a class="btn btn-primary" href="/contact/">Contact me</a>
        </div>
      </div>
    </div>
  </div>
</section>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
