<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Architecture - Tag - arleo.eu</title><link>https://www.arleo.eu/en/tags/architecture/</link><description>Architecture - Tag - arleo.eu</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sat, 09 May 2026 23:52:28 +0200</lastBuildDate><atom:link href="https://www.arleo.eu/en/tags/architecture/" rel="self" type="application/rss+xml"/><item><title>hugo-mcp v2.0: a Python plugin-system in 200 lines</title><link>https://www.arleo.eu/en/posts/hugo-mcp-plugins-architecture/</link><pubDate>Sat, 09 May 2026 23:52:28 +0200</pubDate><author>Jmr</author><guid>https://www.arleo.eu/en/posts/hugo-mcp-plugins-architecture/</guid><description><![CDATA[<div class="featured-image">
                <img src="/images/hugo-mcp-plugins-architecture-featured.jpg" referrerpolicy="no-referrer">
            </div><h2 id="tldr">TL;DR</h2>
<p><a href="https://github.com/jmrGrav/hugo-mcp/releases/tag/v2.0.0" target="_blank" rel="noopener noreffer ">hugo-mcp v2.0.0</a> introduces a <strong>Python plugin-system</strong> that lets anyone add hooks after each <code>create_page</code> / <code>update_page</code> / <code>delete_page</code> operation. 200 lines of code for the core, 3 production plugins shipped (IndexNow, Google Indexing, Cloudflare). This post explains the design, the trade-offs, the security posture, and shows how to write your own plugin in 5 minutes.</p>]]></description></item><item><title>Roadmap: should we migrate the 16 articles to content/posts/?</title><link>https://www.arleo.eu/en/posts/roadmap-migration-content-posts/</link><pubDate>Sat, 09 May 2026 13:09:37 +0200</pubDate><author>Jmr</author><guid>https://www.arleo.eu/en/posts/roadmap-migration-content-posts/</guid><description><![CDATA[<div class="featured-image">
                <img src="/images/roadmap-migration-content-posts-featured.jpg" referrerpolicy="no-referrer">
            </div><h2 id="status-thinking-decision-pending">Status: thinking, decision pending</h2>
<p>This page documents a Hugo content architecture question I have not yet decided.</p>
<h2 id="context">Context</h2>
<p>The LoveIt theme used by arleo.eu follows the recommended Hugo convention: blog articles go in content/posts/. The home filters where Site.RegularPages Type posts.</p>
<p>But due to Grav migration history, my 16 editorial articles are at the root of content/, not in content/posts/. Hugo by default treats all these folders as Type page, not Type posts. So the LoveIt home filter does not see them, and I have to either override layouts/index.html or filter manually.</p>
<h2 id="the-question">The question</h2>
<p>Should I migrate the 16 articles to content/posts/ to follow LoveIt convention, or leave them at the root?</p>
<h2 id="option-a-migrate-to-contentposts">Option A: Migrate to content/posts/</h2>
<p>Pros:</p>
<ul>
<li>Theme conformity, no layout override needed</li>
<li>Repo readability, instantly see which folders are articles vs reference pages</li>
<li>Future-proof, if LoveIt evolves with new features on Type posts they apply for free</li>
<li>Standard mental model for any Hugo dev discovering the repo</li>
</ul>
<p>Cons:</p>
<ul>
<li>URL change. /csp-nonce/ would become /posts/csp-nonce/ by default. Breaks all inbound links.</li>
<li>Possible mitigation via explicit url in front matter to preserve URLs</li>
<li>Migration friction, 16 folders to move, 16 files to edit</li>
<li>Internal links: many articles cite each other, must audit</li>
</ul>
<h2 id="option-b-keep-the-root">Option B: Keep the root</h2>
<p>Pros:</p>
<ul>
<li>Identical URLs without doing anything</li>
<li>No migration, 0 files touched</li>
<li>Internal links intact by definition</li>
<li>layouts/home.html override already in place, 1 line diff</li>
</ul>
<p>Cons:</p>
<ul>
<li>Custom override to maintain if LoveIt evolves</li>
<li>Repo readability: reference pages and articles mixed at root</li>
<li>Weird convention, a Hugo dev wonders why no posts folder</li>
</ul>
<h2 id="seo-considerations">SEO considerations</h2>
<p>SEO fears URL change. With url override on Option A, no URL change. But then what is the migration&rsquo;s purpose? Just internal repo readability. Cost vs benefit, probably not worth it.</p>
<h2 id="hugo-mcp-considerations">Hugo MCP considerations</h2>
<p>The MCP tools accept a route parameter. With url override, MCP workflow is unchanged for the user.</p>
<h2 id="the-provisional-decision">The provisional decision</h2>]]></description></item><item><title>Strategy 4: separating content (MCP) from structure (Git)</title><link>https://www.arleo.eu/en/posts/strategie-4-mcp-vs-git/</link><pubDate>Sat, 09 May 2026 13:03:25 +0200</pubDate><author>Jmr</author><guid>https://www.arleo.eu/en/posts/strategie-4-mcp-vs-git/</guid><description><![CDATA[<div class="featured-image">
                <img src="/images/strategie-4-mcp-vs-git-featured.jpg" referrerpolicy="no-referrer">
            </div><h2 id="the-problem">The problem</h2>
<p>You have a Hugo site. You want to:</p>
<ol>
<li><strong>Edit content via Claude.ai</strong> (publish an article, fix a typo, update a draft) without touching an SSH terminal.</li>
<li><strong>Version the structure</strong> (layouts, themes, hugo.toml, deploy scripts) in Git, like a serious dev.</li>
</ol>
<p>First instinct: &ldquo;everything in Git&rdquo;. Articles too. The MCP commits, pushes, GitHub webhook triggers a rebuild. Clean, GitOps-philosophy.</p>
<p>Except it doesn&rsquo;t work that well. Here&rsquo;s why, and the simple solution I call <strong>Strategy 4</strong>.</p>
<h2 id="why-everything-in-git-breaks-in-practice">Why &ldquo;everything in Git&rdquo; breaks in practice</h2>
<p>Imagine your MCP <code>git commit</code>s on every <code>create_page</code>. Naive strategy, often suggested. Here are the problems:</p>
<h3 id="problem-1--mcp--git-conflict">Problem 1 — MCP ↔ Git conflict</h3>
<p>You push a new layout from your laptop (<code>layouts/index.html</code> modified). At the same time, the MCP is committing a new article version. Race condition: the MCP might <code>git pull --rebase</code> and fail, or worse, overwrite your local commit.</p>
<h3 id="problem-2--mcps-git-identity">Problem 2 — MCP&rsquo;s Git identity</h3>
<p>Whose commits is the MCP making? With which GPG key? If you have a &ldquo;signed commits required&rdquo; policy, the MCP needs to manage a GPG key, which has to be secured, rotated, etc.</p>
<h3 id="problem-3--unwanted-auto-commits">Problem 3 — Unwanted auto-commits</h3>
<p>You&rsquo;re testing, you create a draft article to experiment, you delete it. But the MCP already committed. Now you have a &ldquo;wip test&rdquo; commit in history, to rebase or squash manually.</p>
<h3 id="problem-4--asymmetric-reversibility">Problem 4 — Asymmetric reversibility</h3>
<p>A <code>git revert</code> repo-side has no effect on files the MCP already created. You end up with a desynchronized repo and filesystem state.</p>
<h2 id="strategy-4-separate-the-zones">Strategy 4: separate the zones</h2>
<p>The idea: <strong>MCP and Git never write to the same files</strong>.</p>
<table>
  <thead>
      <tr>
          <th>Zone</th>
          <th>Who edits</th>
          <th>Versioned in Git?</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>content/**/*.md</code></td>
          <td><strong>MCP only</strong></td>
          <td>❌ NO (<code>.gitignore</code>)</td>
      </tr>
      <tr>
          <td><code>layouts/</code>, <code>themes/</code>, <code>static/</code>, <code>hugo.toml</code>, <code>deploy.sh</code></td>
          <td><strong>Git push only</strong></td>
          <td>✅ YES</td>
      </tr>
  </tbody>
</table>
<p>Repo-side <code>.gitignore</code>:</p>
<div class="code-block code-line-numbers open" data-start="0">
    <div class="code-header language-">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><pre tabindex="0"><code>content/
public/
resources/</code></pre></div>
<p>Implications:</p>
<ul>
<li>The MCP can write to <code>content/</code> whenever. No Git conflict possible.</li>
<li>You can <code>git reset --hard</code> repo-side with confidence — <code>content/</code> stays intact.</li>
<li>No need for the MCP to manage a Git identity.</li>
<li>No &ldquo;commit pollution&rdquo;.</li>
</ul>
<h2 id="trade-off-no-content-versioning">Trade-off: no content versioning</h2>
<p>You lose Git versioning of content. That&rsquo;s a real loss:</p>
<ul>
<li>No <code>git blame</code> on an article to see who wrote what.</li>
<li>No <code>git log content/csp-nonce/index.fr.md</code> for history.</li>
<li>No PR review for articles.</li>
</ul>
<p><strong>Mitigation</strong>: VM snapshots + daily encrypted <code>content/</code> backup to QNAP. That covers <strong>disaster recovery</strong>, but not fine-grained versioning (who-changed-what-when).</p>
<p>For my personal homelab (single author, technical articles, no editorial validation workflow), it&rsquo;s an acceptable trade-off. For a 10-contributor team blog, I&rsquo;d reconsider.</p>
<h2 id="final-architecture">Final architecture</h2>]]></description></item></channel></rss>