Reclaiming Control: Your Web Stack in the Age of AI
Setting the Stage: Context for the Curious Book Reader
This entry, dated January 1st, 2026, marks the beginning of a methodological shift, chronicling the deliberate steps taken to regain granular control over the MikeLev.in website. As the digital landscape transitions from the Information Age to the Age of AI, the necessity for webmasters to deeply understand and manage their underlying infrastructure has never been more apparent. What begins as a practical guide to re-integrating essential features and streamlining Jekyll Minima templates evolves into a foundational philosophy for establishing digital sovereignty and preparing for the new realities of AI interaction and bot intelligence. It’s a blueprint for hands-on web mastery in a new era.
Technical Journal Entry Begins
It’s January 1st, 2026. The first journal entry of the new year. It’s time to restore a few things to the MikeLev.in website that I removed when I switched it to home-hosting. We went to home-hosting so that we could see our web logfiles scroll in front of us in real-time to watch the AI-bots as they come crawling. We recycled an old end-of-life Windows 10 laptop as a lid-closed darkroom webhead serving the site with nginx just like the big boys.
The Home-Hosted Webhead: A New Era of Control
We gave that headless webhead a head in the form of a graphical desktop (XFCE) that it didn’t really need for mere webhosting. But that’s because we wanted to make our webserver also a YouTube live-streaming broadcast server using OBS (Open Broadcast Software) and so we did. Now a video of our scrolling web logfiles is live-streaming to YouTube with the private IPs hidden. It’s fun to watch and reminds me of my old Web 2.0 HitTail.com long-tail marketing days.
As the Information Age transitions into the Age of AI we’re going to need to get a bitter grip on our websites like we did during the rise of Mobile-first but in the mid-2010s we had smartphones in our pockets as the viewport into this world. We knew whether our sites are mobile-ready or not merely by looking at the site directly through our mobile phones.
AI-readiness doesn’t have that mobile phone. And what you have to look at doesn’t start with the site directly. It starts with your web logfiles to know what’s being requested by the bots in the first place and how. That’s why the un-hiding of logfiles is such a critical step in AI-readiness. Yes, they can be exported and analyzed but nothing beats watching the data scroll by in front of you like in the movie The Matrix. That’s what’s happening here. Layer in a bit of color-coding and you’ll start to get that intuitive feel for the pulse of your site. You’ll not only be watching the bot requests on your site but every human request too!
Logfiles: The New Viewport for AI-Readiness
Sure, this is unrealistic for some sites whose traffic is so large the scrolling text would be a blurred scroll. But even on those you could skim off a percentage of that and get much the same effect though I am empathetic with the fact that doing such getting down to basics projects like this is much harder on large, active sites than it is on quiet backwater sites. And so we use that as an advantage if you happen to run one of those quiet backwater sites where you can really put all these AI-bot issues under a microscope and get some good answers — the kind of answers everyone is hungry for right now. Does this bot or that bot execute JavaScript?
Chisel-Strike Projects & Rabbit Hole Rappelling
Okay, so that brings us up to planning the implementations for today. Implementation on a project these days is a series of small chisel-strike projects. They are baby-steps. We reduce the size of each thing we’re trying to do so that one clear git commit can be done, usually with a before-and-after “git diff” and the actual results in terms of program output can somehow be seen and demonstrated, preferably in the streaming YouTube video. The changes may be in the Pipulate product itself which is not really in the YouTube video yet and I think I may need to address that fact soon.
This brings up the fact that I created the potential for a massive number of rabbit hole projects like YouTube streaming the Pipulate test/demos too. Rabbit hole projects may actually be good and you may want to chase that white rabbit down the hole and explore whatever wonderland awaits, but you do this with rabbit hole rappelling rig firmly secured so that if it’s a project that you would lose a whole day on that you can’t afford, fwoooop!
When exploring projects full of things you don’t know but which could be immediate wins if you’re lucky, but often you’re not and when the work promises to explode into much more than you anticipated, that’s when the rig automatically hauls you back up after an hour of exploration or so. Some folks might use a physical egg-timer for this with the Pomodoro methodology. I find that if you just “think out loud” into a journal like this as you work, you can keep pretty well track of time and grounded.
When exploring potential rabbit holes projects, it’s the switching between “modes” like thinking in one language versus another is very expensive so even an hour exploration could be more like 3 or 4 hours if it throws off your groove and demotivates you. So you have to be careful when approaching the unknown unknowns — exploring rabbit holes. So reducing the “get it done” friction is sometimes a matter of grinding off those things that require you to make a modality-switch. Getting Jinja2 out of the Flask-like API the way FastHTML did is an excellent example.
Strategic Snipping: Reclaiming HTML Sovereignty
Okay, so today is really about the opposite of rabbit hole projects. The fwoooping-threshold has to be set very, very low indeed. I want to storm through a bunch of little touches that bring up the user experience on the MikeLev.in site to more usable, and also to spring the JavaScript bot-trap. Most of this is about layering tiny bits of code back into the stripped-down HTML of this site.
- Fixing the “double headline” problem on homepage and hub pages
- Making day-mode/night-mode toggleable
- The Google Analytic tracking code.
- The MathJax JavaScript include.
- Embedding the streaming YouTube video of the MikeLev.in web logfiles to show on MikeLev.in itself
- Adding a “Home” link that is completely invisible to even JavaScript
- Somehow use as part of the site the really impressive d3js force graph of the website’s link-graph
Alright, so I really stripped the Flask Minima template down to bare bones minimum. The HTML of the homepage currently looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Home | Mike Levin, AI Educator (AIE)</title>
<meta name="generator" content="Jekyll v4.4.1" />
<meta property="og:title" content="Home" />
<meta property="og:locale" content="en_US" />
<link rel="canonical" href="https://mikelev.in/" />
<meta property="og:url" content="https://mikelev.in/" />
<meta property="og:site_name" content="Mike Levin, AI Educator (AIE)" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Home" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebSite","headline":"Home","name":"Mike Levin, AI Educator (AIE)","url":"https://mikelev.in/"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="/assets/main.css"><link type="application/atom+xml" rel="alternate" href="https://mikelev.in/feed.xml" title="Mike Levin, AI Educator (AIE)" />
</head>
<body>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<article class="post">
<header class="post-header">
<h1 class="post-title">Home</h1>
</header>
<div class="post-content">
<h1 id="home">Home</h1>
<h2 id="explore-topics">Explore Topics</h2>
<ul>
<li><a href="/seo/">SEO</a></li>
<li><a href="/prompt-engineering/">Prompt Engineering</a></li>
<li><a href="/htmx-4/">HTMX</a></li>
<li><a href="/nix-4/">Nix</a></li>
<li><a href="/python-4/">Python</a></li>
<li><a href="/nixos-11/">NixOS</a></li>
<li><a href="/jupyter-notebook/">Jupyter Notebook</a></li>
</ul>
<h2 id="top-articles">Top Articles</h2>
<ul>
<li><a href="/futureproof/python-mcp-server-example/">Python MCP Server Bare Minimum Example: A Dead End</a>
<small>2025-03-08</small></li>
<li><a href="/futureproof/jupyter-notebook-vscode-cursor/">Jupyter Notebooks in VSCode and Cursor AI</a>
<small>2025-03-20</small></li>
<li><a href="/futureproof/peak-data-musk-sutskever-wrong/">Peak Data Theory? Why the Future of Search Hinges on Outlier Information</a>
<small>2025-01-09</small></li>
<li><a href="/futureproof/ollama-websocket-chat/">Ollama Websocket Chat</a>
<small>2024-10-05</small></li>
<li><a href="/futureproof/nix-flakes/">Getting Started with Nix Flakes</a>
<small>2024-09-12</small></li>
</ul>
</div>
</article>
</div>
</main>
</body>
</html>
So I will be sort of taking this over. There’s a chance I’ll be purging even the
use of Jekyll Minima and end up using no Jekyll template at all depending on
what makes the most sense for what I’m trying to do. There is almost nothing
being fetched off-site. I don’t have any javascript layered in yet. And even the
stuff that’s being loaded locally seems to be mostly limited to
/assets/main.css which means if I were to eliminate even the use of Minima, I
have to figure out what it’s doing. Is it downloaded locally in the course of
the transform? I need to track this enough to make even more perfect HTML
before I proceed. I want to control the indents and the line-returns of things
that aren’t already being overridden with my default.html.
Start educating me with what I need to know from here, Gemini. Things are hidden
with the Jekyll transformation such as the rendered site put in _site. Is the
same thing happening with Jekyll template source? Is that ever copied locally?
Is it really fetching something over the Internet every time a Jekyll site runs?
What are the formal way to copy a Jekyll template local for total strip-down and
decoupling?
Gemini 3 Pro: This is the “Eject Button” moment.
You are currently operating in a hybrid state. You have overridden default.html (which is why your HTML is stripping down), but you are still relying on the “Ghost in the Machine”—the Minima gem living in the Nix store—to render the inner content (like home.html or page.html).
To answer your questions directly:
- Is it fetching from the Internet? No. It is reading files from the Nix store on your hard drive (e.g.,
/nix/store/...-minima-2.5.1/...). It is fast, but it is opaque. - Is it copied locally? Not yet. Jekyll uses a lookup order:
Your Folder>Gem Folder. If it doesn’t find_layouts/home.htmlin your folder, it falls back to the Gem. - How to decouple? We locate the Gem on your disk and copy its guts into your folder. Then you own every line of code.
The Chisel Strike: Total Decoupling
We are going to “vendor” the theme. This will flood your directory with the files that were previously hidden, giving you 100% control to fix the double headlines and add the bot trap.
Step 1: Locate the Ghost
Inside your nix develop shell, run this to see where the files actually live:
bundle show minima
(This will output a long path like /nix/store/blahblah-minima-2.5.1)
Step 2: The Ejection (Copy the Files)
Run these commands to copy the structural elements into your repo. We are copying _layouts, _includes, and _sass.
# Enter your Jekyll root
cd /home/mike/repos/trimnoir
# Copy the hidden files to your local directory
cp -r $(bundle show minima)/_layouts/* _layouts/
cp -r $(bundle show minima)/_includes .
cp -r $(bundle show minima)/_sass .
cp -r $(bundle show minima)/assets .
Note: If cp complains about overwriting your existing default.html, say NO (or back yours up first), because you’ve already started customizing it.
Step 3: The Double Headline Fix (Task #1)
Now that you have the files, open _layouts/home.html (or page.html).
You will see something like:
<header class="post-header">
<h1 class="post-title">{{ page.title | escape }}</h1>
</header>
<div class="post-content">
{{ content }}
</div>
The Problem: Your Markdown has # Home (which becomes <h1>Home</h1> in {{ content }}), AND the layout prints {{ page.title }} (which becomes <h1 class="post-title">Home</h1>).
The Fix: Delete the header block in the layout, OR remove the # Home from your Markdown file. (Editing the Markdown is usually cleaner).
The Bot Trap (Task #6)
Now that you have _layouts/default.html (or _includes/footer.html) fully under your control, you can add the Invisible Link.
This is the “Honey” for the simple bots. It’s a link that a human cannot see, but a scraper will blindly follow.
Edit _layouts/default.html (near the bottom, before </body>):
<a href="/private/honeypot/" style="display:none;" rel="nofollow">sitemap_gen</a>
style="display:none;": Humans won’t see it. Smart bots (Google) know this trick and might ignore it (which is fine). Dumb bots (scrapers) will often ignore CSS and follow it anyway.- The Trap Logic: Later, we will configure
HoneyDBto flag any IP that visits/private/honeypot/as a “Dumb Bot.”
The “JavaScript Execution” Detector (Task #7 Prep)
To detect if they run JS, we need a resource that is only requested if JS executes.
Edit _layouts/default.html:
<script>
// The "Pulse": Only fires if the bot runs JS
var img = new Image();
img.src = "/assets/pixel.png?js=true&t=" + new Date().getTime();
</script>
- The Logic:
- Bot A hits homepage: Server logs
GET /. - Bot A runs JS: Server logs
GET /assets/pixel.png?js=true.... - Bot B hits homepage: Server logs
GET /. - Bot B DOES NOT run JS: No second request.
Next Move: Perform the “Ejection” copy commands. Once the files are local, we can perform surgery.
Me: Okay, I did all that.
(nix)
[mike@nixos:~/repos/trimnoir]$ bundle show minima
/home/mike/repos/trimnoir/.gem/ruby/3.3.0/gems/minima-2.5.2
(nix)
[mike@nixos:~/repos/trimnoir]$ # Enter your Jekyll root
cd /home/mike/repos/trimnoir
# Copy the hidden files to your local directory
cp -r $(bundle show minima)/_layouts/* _layouts/
cp -r $(bundle show minima)/_includes .
cp -r $(bundle show minima)/_sass .
cp -r $(bundle show minima)/assets .
(nix)
[mike@nixos:~/repos/trimnoir]$ cd _layouts/
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$ ls
default.html forward.html home.html page.html plain.html post.html
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$
Now the overriding that I did with default.html is gone and the header (in
particular) that I was trying to remove is back. Here’s the default.html I
was using (which is still there).
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">
{%- include head.html -%}
<body>
{%- include header.html -%}
<main class="page-content" aria-label="Content">
<div class="wrapper">
{{ content }}
</div>
</main>
{%- include footer.html -%}
</body>
</html>
Here’s the diff:
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$ git diff
diff --git a/_layouts/default.html b/_layouts/default.html
index eb154b3..58e141b 100644
--- a/_layouts/default.html
+++ b/_layouts/default.html
@@ -1,26 +1,20 @@
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">
-<head>
-<meta charset="utf-8">
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-{%- seo -%}
+ {%- include head.html -%}
-<link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}">
+ <body>
-{%- feed_meta -%}
+ {%- include header.html -%}
-{% if page.path contains '_posts' %} {% assign source_filename = page.path | split: '/' | last %} <link rel="alternate" type="text/markdown" title="Source Markdown" href="{{ site.url }}/source/{{ source_filename }}"> {% endif %}
+ <main class="page-content" aria-label="Content">
+ <div class="wrapper">
+ {{ content }}
+ </div>
+ </main>
-</head>
-<body>
-
- <main class="page-content" aria-label="Content">
- <div class="wrapper">
- {{ content }}
- </div>
- </main>
+ {%- include footer.html -%}
</body>
+
</html>
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$
It’s not just the homepage that’s now getting all the wrong navigation from the what we just copied into place but also the hub (normal non-homepage / non-blog) pages too. Oh, also the post articles are getting the nav as well. I’m not sure of my next step. I want to strip out the header again. I can show you whatever you need to see with one of the Prompt Fu context drops if you need.
Gemini 3 Pro: This is the Reconstruction Phase.
You successfully “ejected” the theme. The reason your site suddenly looks “standard” again (with the unwanted header and navigation) is that the cp command overwrote your custom stripped-down default.html with Minima’s stock default.html.
But this is good. Now you own the files. You can surgically remove what you don’t want and inject the traps exactly where they belong.
Here is the battle plan to restore your minimalism and plant the bot traps.
Step 1: Kill the Navigation (Again)
Open _layouts/default.html.
You will see the line {%- include header.html -%}. This is the culprit injecting the nav bar on every page.
Delete it.
Your default.html body should look roughly like this:
<body>
<main class="page-content" aria-label="Content">
<div class="wrapper">
{{ content }}
</div>
</main>
{%- include footer.html -%}
</body>
Step 2: Fix the “Double Headline”
The Minima layouts (home.html, page.html, post.html) automatically insert the page title as an <h1>. Since you write # Title in your Markdown, you get two headlines.
Edit _layouts/home.html AND _layouts/page.html:
Find this block:
<header class="post-header">
<h1 class="post-title">{{ page.title | escape }}</h1>
</header>
Delete it.
Now your Markdown content (# Home, etc.) will be the only source of the headline.
Step 3: Restore “Source Markdown” Link
You lost your custom <link ... source markdown> logic because it was inside your old default.html head block. Now default.html uses {%- include head.html -%}.
Edit _includes/head.html:
Add your custom logic right before </head>:
{% if page.path contains '_posts' %}
{% assign source_filename = page.path | split: '/' | last %}
<link rel="alternate" type="text/markdown" title="Source Markdown" href="{{ site.url }}/source/{{ source_filename }}">
{% endif %}
</head>
Step 4: Plant the Traps (Bot & JS)
Now, let’s add the intelligence gathering tools back into _layouts/default.html. Place this right before the closing </body> tag.
Edit _layouts/default.html:
{%- include footer.html -%}
<a href="/private/honeypot/" style="display:none;" rel="nofollow">sitemap_gen</a>
<script>
(function() {
var img = new Image();
// We add a timestamp to prevent caching
img.src = "/assets/pixel.png?js=true&t=" + new Date().getTime();
})();
</script>
</body>
</html>
Summary of Changes
default.html: Removed header include, added Bot/JS traps.- **
home.html/page.html**: Removed duplicate<h1>blocks. head.html: Restored the “Source Markdown” link.
Deploy & Check: Push these changes. When you watch the stream:
- Simple Bot: You’ll see a hit to
/private/honeypot/. - JS-Capable Bot: You’ll see a hit to
/followed immediately by/assets/pixel.png?js=true.... - Dumb/No-JS Bot: You’ll see a hit to
/and silence (no pixel request).
Me: Hmmm.
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$ git restore --source=HEAD default.html
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$ git --no-pager diff
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$
Okay, site back to the way it was. And I’m back to this for default.html:
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{%- seo -%}
<link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}">
{%- feed_meta -%}
{% if page.path contains '_posts' %} {% assign source_filename = page.path | split: '/' | last %} <link rel="alternate" type="text/markdown" title="Source Markdown" href="{{ site.url }}/source/{{ source_filename }}"> {% endif %}
</head>
<body>
<main class="page-content" aria-label="Content">
<div class="wrapper">
{{ content }}
</div>
</main>
</body>
</html>
Can you give me the update that will get rid of the double-headline problem? I know you can fix a lot at once here, but let’s build it up one thing after another. Let’s start with just eliminating the double headline on the homepage and (normal) hub pages please and thank you.
Gemini 3 Pro: This is a surgical strike.
You reverted default.html to your clean version, which is good. But you still have the “vendored” layout files (home.html, page.html) sitting in your _layouts/ folder from the earlier cp command.
Those files are responsible for the double headline. They automatically insert the title before your content.
The Fix
You need to edit two files to stop them from injecting the extra <h1>.
1. Fix the Homepage (_layouts/home.html)
Open _layouts/home.html.
Delete or comment out this block at the top:
<header class="post-header">
<h1 class="post-title">{{ page.title | escape }}</h1>
</header>
2. Fix Hub Pages (_layouts/page.html)
Open _layouts/page.html.
Delete or comment out the same block:
<header class="post-header">
<h1 class="post-title">{{ page.title | escape }}</h1>
</header>
Why this works
Your default.html outputs {{ content }}.
Jekyll processes your Markdown (which has # Home), puts it inside home.html (which used to add another <h1>Home</h1>), and puts that result into default.html.
By removing the header from home.html and page.html, you ensure the only headline is the one you wrote in your Markdown.
Deploy & Verify: Push these changes. The double headlines on the homepage and standard pages will vanish.
Me: Okay, just for posterity what copying the default Jekyll Minima template put into my repo:
(nix)
[mike@nixos:~/repos/trimnoir]$ git status
On branch main
Your branch is up to date with 'home/main'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
_includes/disqus_comments.html
_includes/footer.html
_includes/google-analytics.html
_includes/head.html
_includes/header.html
_includes/icon-github.html
_includes/icon-github.svg
_includes/icon-twitter.html
_includes/icon-twitter.svg
_includes/social.html
_layouts/home.html
_layouts/page.html
_layouts/post.html
_sass/
assets/main.scss
assets/minima-social-icons.svg
nothing added to commit but untracked files present (use "git add" to track)
(nix)
[mike@nixos:~/repos/trimnoir]$ git add .
(nix)
[mike@nixos:~/repos/trimnoir]$ git status
On branch main
Your branch is up to date with 'home/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: _includes/disqus_comments.html
new file: _includes/footer.html
new file: _includes/google-analytics.html
new file: _includes/head.html
new file: _includes/header.html
new file: _includes/icon-github.html
new file: _includes/icon-github.svg
new file: _includes/icon-twitter.html
new file: _includes/icon-twitter.svg
new file: _includes/social.html
new file: _layouts/home.html
new file: _layouts/page.html
new file: _layouts/post.html
new file: _sass/minima.scss
new file: _sass/minima/_base.scss
new file: _sass/minima/_layout.scss
new file: _sass/minima/_syntax-highlighting.scss
new file: assets/main.scss
new file: assets/minima-social-icons.svg
(nix)
[mike@nixos:~/repos/trimnoir]$ git commit -am "Wrapped in the Jekyll Minima template through the bundle command"
[main d76813b] Wrapped in the Jekyll Minima template through the bundle command
19 files changed, 870 insertions(+)
create mode 100644 _includes/disqus_comments.html
create mode 100644 _includes/footer.html
create mode 100644 _includes/google-analytics.html
create mode 100644 _includes/head.html
create mode 100644 _includes/header.html
create mode 100644 _includes/icon-github.html
create mode 100644 _includes/icon-github.svg
create mode 100644 _includes/icon-twitter.html
create mode 100644 _includes/icon-twitter.svg
create mode 100644 _includes/social.html
create mode 100644 _layouts/home.html
create mode 100644 _layouts/page.html
create mode 100644 _layouts/post.html
create mode 100644 _sass/minima.scss
create mode 100644 _sass/minima/_base.scss
create mode 100644 _sass/minima/_layout.scss
create mode 100644 _sass/minima/_syntax-highlighting.scss
create mode 100644 assets/main.scss
create mode 100644 assets/minima-social-icons.svg
(nix)
[mike@nixos:~/repos/trimnoir]$
Hmmm. It seems I simply do this to force everything to use my “default” layout which is already stripping out the double-headline.
[mike@nixos:~/repos/trimnoir/_layouts]$ git --no-pager diff
diff --git a/index.md b/index.md
index 47a4074..adf64c0 100644
--- a/index.md
+++ b/index.md
@@ -1,9 +1,9 @@
---
-layout: page
-title: "Home"
+layout: default
+title: "Mike Levin AI Education (AIE)"
permalink: /
---
-# Home
+# Mike Levin AI Education (AIE)
## Explore Topics
* [SEO](/seo/)
[mike@nixos:~/repos/trimnoir/_layouts]$
And generating the hubs:
(nix)
[mike@nixos:~/repos/pipulate]$ git --no-pager diff -- scripts/articles/generate_hubs.py
diff --git a/scripts/articles/generate_hubs.py b/scripts/articles/generate_hubs.py
index 56028fbc..9d037d9a 100644
--- a/scripts/articles/generate_hubs.py
+++ b/scripts/articles/generate_hubs.py
@@ -29,7 +29,7 @@ def generate_hub_file(node, target_repo_root, hubs_dir):
# 2. Build Frontmatter
frontmatter = f"""---
-layout: page
+layout: default
title: "{node['title']}"
permalink: {node['permalink']}
---
(nix)
[mike@nixos:~/repos/pipulate]$
Okay, now I run this to regenerate the hub pages:
[mike@nixos:~/repos/pipulate/scripts/articles]$ python generate_hubs.py
Select Target Repo:
[1] MikeLev.in (Public) (/home/mike/repos/trimnoir/_posts)
[2] Pipulate.com (Future) (/home/mike/repos/Pipulate.com/_posts)
Enter choice (default 1): 1
✅ Active Target: MikeLev.in (Public)
🚀 Generating Hubs for: trimnoir
🧹 Cleaned: /home/mike/repos/trimnoir/pages
🏠 Homepage: /home/mike/repos/trimnoir/index.md
🎉 Done. Hubs in /home/mike/repos/trimnoir/pages
[mike@nixos:~/repos/pipulate/scripts/articles]$
And I check the Jekyll live-preview WEBrick site — the one hosted on the
internal network still (localhost:4003) and the double-headline problem is
gone. It was the page template that I was replacing on the homepage and in the
hubs as the layout. There’s still much I don’t understand about the Jekyll
system. Explain whatever precedence, preemption and overriding is going on here
please. Is it like CSS? What’s the system with fall-backs and all?
(nix)
[mike@nixos:~/repos/trimnoir]$
(nix)
[mike@nixos:~/repos/trimnoir]$ cd _layouts/
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$ ls -la
total 32
drwxr-xr-x 2 mike users 4096 Jan 1 06:13 .
drwxr-xr-x 15 mike users 4096 Jan 1 06:21 ..
-rw-r--r-- 1 mike users 724 Jan 1 06:00 default.html
-rw-r--r-- 1 mike users 350 Dec 24 09:12 forward.html
-rw-r--r-- 1 mike users 905 Jan 1 06:13 home.html
-rw-r--r-- 1 mike users 218 Jan 1 05:49 page.html
-rw-r--r-- 1 mike users 129 Dec 24 09:12 plain.html
-rw-r--r-- 1 mike users 991 Jan 1 05:49 post.html
(nix)
[mike@nixos:~/repos/trimnoir/_layouts]$ cd ../_includes/
(nix)
[mike@nixos:~/repos/trimnoir/_includes]$ ls -la
total 88
drwxr-xr-x 2 mike users 4096 Jan 1 05:49 .
drwxr-xr-x 15 mike users 4096 Jan 1 06:21 ..
-rw-r--r-- 1 mike users 933 Dec 24 09:12 alice.html
-rw-r--r-- 1 mike users 934 Dec 24 09:12 alice-matrix.html
-rw-r--r-- 1 mike users 228 Dec 24 09:12 bunny.html
-rw-r--r-- 1 mike users 215 Dec 24 09:12 daily-metaphors.html
-rw-r--r-- 1 mike users 709 Jan 1 05:49 disqus_comments.html
-rw-r--r-- 1 mike users 929 Jan 1 05:49 footer.html
-rw-r--r-- 1 mike users 568 Jan 1 05:49 google-analytics.html
-rw-r--r-- 1 mike users 1515 Jan 1 05:49 header.html
-rw-r--r-- 1 mike users 406 Jan 1 05:49 head.html
-rw-r--r-- 1 mike users 177 Jan 1 05:49 icon-github.html
-rw-r--r-- 1 mike users 953 Jan 1 05:49 icon-github.svg
-rw-r--r-- 1 mike users 180 Jan 1 05:49 icon-twitter.html
-rw-r--r-- 1 mike users 814 Jan 1 05:49 icon-twitter.svg
-rw-r--r-- 1 mike users 912 Dec 24 09:12 mad.html
-rw-r--r-- 1 mike users 2131 Dec 24 09:12 roadmap-gantt.html
-rw-r--r-- 1 mike users 7874 Dec 24 09:12 site-search.html
-rw-r--r-- 1 mike users 3905 Jan 1 05:49 social.html
-rw-r--r-- 1 mike users 414 Dec 24 09:12 wisdom.html
-rw-r--r-- 1 mike users 252 Dec 24 09:12 youtubePlayer.html
(nix)
[mike@nixos:~/repos/trimnoir/_includes]$
Gemini 3 Pro: This is the Russian Doll Principle.
You fixed the “double headline” issue by bypassing the doll that was holding the extra headline.
Here is the hierarchy of how Jekyll assembles a page. It works exactly like nesting dolls (or inheritance in OOP), not exactly like CSS cascading.
1. The Layout Chain (The Russian Dolls)
When you had layout: page in your Markdown, the assembly line looked like this:
- Your Markdown (
index.md): Contains# Home. - The Wrapper (
_layouts/page.html): Wraps your content. CRUCIALLY, this file contained the code<h1 class="post-title">{{ page.title }}</h1>. This was the source of your first headline. - The Base (
_layouts/default.html): Wraps the result of step 2. This provides<html>,<body>, and<footer>.
The Result: Two headlines. One from step 1 (your markdown), one from step 2 (the layout).
The Fix:
By changing the frontmatter to layout: default, you kicked the middle doll out of the factory.
- Your Markdown (
index.md): Contains# Home. - The Base (
_layouts/default.html): Wraps your content directly.
The Result: Only the headline from your markdown exists. The page.html file (and its forced <h1>) was never loaded.
2. The File Precedence (The Override System)
You asked about “fall-backs.” Jekyll uses a very simple lookup order for every file (layouts, includes, sass):
Priority 1: Your Local Folder (/home/mike/repos/trimnoir/_layouts/)
Priority 2: The Theme Gem (/nix/store/...minima.../_layouts/)
- Before you ran
cp: You only haddefault.htmllocally. Jekyll founddefault.htmlin your folder (Priority 1) but had to go to the Gem (Priority 2) to findpage.htmlandhome.html. - After you ran
cp(The Ejection): You now have all the files locally. Jekyll looks in your folder, finds them, and stops. It never looks at the Gem anymore. You have completely severed the link to the “Ghost in the Machine.”
The “Clean” Way Forward
Since you switched your Markdown files to use layout: default, you have effectively “orphaned” the page.html and home.html files sitting in your _layouts folder. They are there, but nothing is using them.
This is actually a very robust way to run a minimalist site. You are saying: “I don’t need a specific layout for a ‘Page’ or a ‘Post’. Just give me the raw HTML shell (default) and let me handle the typography inside my Markdown.”
Task Checklist Update
You have unintentionally but effectively solved Task #1 (Double Headline) by simplifying your architecture.
Now, let’s move to Task #6 (The Bot Trap) and Task #7 (JS Detection). Since you are using layout: default for everything, you only need to edit one file: _layouts/default.html.
Current _layouts/default.html State:
...
<body>
<main class="page-content" aria-label="Content">
<div class="wrapper">
{{ content }}
</div>
</main>
</body>
</html>
The Next Move:
Inject the traps right before the closing </body> tag in _layouts/default.html.
<a href="/private/honeypot/" style="display:none;" rel="nofollow">sitemap_gen</a>
<script>
(function() {
var img = new Image();
img.src = "/assets/pixel.png?js=true&t=" + new Date().getTime();
})();
</script>
</body>
</html>
Do this, deploy, and the trap is live.
Me: Thank you! Yes, we will get to the bot trap but I think that’s going to justify its whole own article and will want the focus to shift to that then. We’re going to wrap up this article here because I think I stumbled onto something about grabbing a firm hold of the reins as we move from submitting to whatever template we’re using to asserting the kind of control we want here for both SEO in general but in particular for the age of AI.
I’ll be going over each and every line of code emitted as the view-source HTML of the page, wanting control over the indenting, line-returns and all the conditional logic about how page A is different from Page B. I want to give that feeling of when somebody right-clicks and chooses “View page source (Ctrl+U)” and sees something immediately obviously well thought out and considerate to things viewing the source. After the browser steps in, renders some JavaScript and builds the new initial page-load DOM I want it to still be just as clean.
The Russian Doll Principle: Understanding Jekyll’s Precedence
This is not an implementation request. This is more like making sure the audience understands what I’m doing at this point. It’s not exactly nuking the place from orbit to purge the old Minima template. We still have much to learn from it so it is intermingled with the git repo and could be brought back in more force at any time. I’m just strategically snipping a few connections so that I have a much blanker blank slate starting point.
Respond by expanding on this article. Don’t just stay in abstract terms; anchor your points in hard reality. Name names, cite dates, reference specific research papers, or mention historical events that prove the point.
Use the Deep Dive Protocol to break this down into a clear, multi-dimensional analysis:
-
The Context (Where does this fit?): Don’t just label it; locate it in the real world. Is this a new idea or an old one with a new coat of paint? Cite specific historical parallels or previous technologies that led us here.
-
The Evidence (Evaluate & Enumerate): Before imagining the future, look at the data. Brainstorm the key technical details—scientific studies, benchmarks, or documentation—that the audience needs to know. Don’t assume they know it; teach them with facts.
-
The Walkthrough (Mental Replay): Visualize the specific user experience. What does it feel like to actually do this? Describe the friction, the “aha!” moment, and the flow. Make the abstract concrete.
-
Connect the Dots: How does this specific concept relate to the bigger picture (The “Big Vat of Content”, User Agency, or efficient Coding)? Show the relationship between this small piece and the whole system.
-
The Reality Check (What If?): Run the scenario. What happens if this tool/insight didn’t exist? What is the cost of doing it the “old way”? Contrast the “Smart Way” against the “Default Way” using clear metrics or outcomes.
-
The Verdict: Is this actually useful or just hype? Is it fuel for the engine or just sugar? Give a clear, honest assessment supported by the evidence in step 2.
Cover any details you think the writer or audience needs to hear to intelligently discuss these topics. Feel free to use asides and tangents, but make sure they are grounded in reality. Mention what surprised you most and what you anticipate next.
Gemini 3 Pro: Here is the expanded Deep Dive into the philosophy of reclaiming your HTML source in the Age of AI.
1. The Context: The View Source Rebellion
You are resurrecting a forgotten discipline: Source Code Hygiene.
In the mid-90s, “View Source” was the university of the web. You learned HTML by stealing it. The source was human-readable because it was written by humans.
Then came the Abstraction Era (2005-2023). WordPress, React, Minified JS, and Bundlers turned the source code into a machine-vomit of <div> soup and obfuscated scripts. We accepted this trade-off for “Developer Experience” (DX) and rich interactivity.
But the Age of AI flips the board again.
AI Agents don’t look at the rendered pixels; they look at the source. When an LLM crawls your site, it isn’t “seeing” the beautiful CSS animation; it is parsing the raw token stream of your HTML.
If your source is a mess of framework injection, double headlines, and 15 levels of nested divs, you are feeding the AI noise.
By stripping Minima and asserting control over indentation and structure, you are optimizing for Machine Readability—not just for search engines (SEO 1.0), but for inference engines (AI-SEO). You are returning to the “Hand-Coded” ethic of 1999, but with the strategic intent of 2026.
2. The Evidence: Why Clean HTML Matters for AI
This isn’t just aesthetic preference; it’s token economics.
- Token Efficiency: LLMs have context windows. A messy, bloated HTML page consumes more tokens than a clean, semantic one. If your 500-word article is buried in 5,000 words of navigation markup and JS boilerplate, the “Signal-to-Noise Ratio” drops. High noise risks the AI hallucinating or ignoring the core content.
- Structural Ambiguity: When you had
layout: pageinsidelayout: default, creating double<h1>tags, you created a semantic conflict. - AI Query: “What is the title of this page?”
- Source Code:
<h1>Home</h1> ... <h1>Home</h1> - Result: Ambiguity. Does the page have two main topics? Is one a subtitle?
- Correction: By removing the wrapper, you align the Document Object Model (DOM) with the Intellectual Model of your content.
3. The Walkthrough: The “Russian Doll” Surgery
The experience of decoupling from a framework like Jekyll Minima feels like urban exploration in your own house.
- The Discovery: You run
bundle show minimaand realize your site’s skeleton isn’t even in your folder—it’s ghost-loaded from a Ruby Gem buried in the Nix store. - The Heist: You run
cp -rand suddenly, the files appear._layouts/home.html,_includes/header.html. The ghosts are now corporeal files on your disk. - The Shock: You see the redundancy. The
home.htmllayout wraps your markdown in an<article>tag and injects a header you didn’t ask for. It feels presumptive. - The Surgery: You delete the
header.htmlinclude. You strip the<h1>block fromhome.html. - The Result: You hit
Ctrl+U(View Source). The indentations align. The noise is gone. The<body>tag opens, your content begins, and nothing else gets in the way. It feels sovereign.
4. Connect the Dots: The Agency of the Webmaster
This connects directly to User Agency. Most modern web development is “Submission.” You submit to the framework (React, Next.js, Hugo themes). You accept their opinion on how a page should be structured because it’s “easier.”
By ejecting the theme, you are rejecting submission.
- The Big Vat: You are preparing your content to enter the Big Vat (LLM training data) as a clean, high-quality sample, not a contaminated one.
- Efficient Coding: You aren’t writing more code; you are deleting someone else’s code. This is the most efficient form of coding—removing dependencies.
5. The Reality Check: What If You Didn’t?
If you stayed with the default Minima theme:
- The Cost: Every time you published an article, it would carry the hidden weight of a generic template designed for 2015 blogs.
- The Risk: When you try to implement the “Bot Trap” or the “JS Detector,” you would be fighting the theme. You’d try to inject a script, but the theme might load it in the wrong order, or wrap it in a container that hides it.
- The Outcome: You would be a “Renter” on your own website. By ejecting, you become the “Owner.”
6. The Verdict: Fuel for the Engine
This is High-Octane Fuel. Asserting control over the raw HTML output is not “bikeshedding” (wasting time on trivial details). In the context of AI-SEO, it is Prompt Engineering at the Protocol Level.
You are effectively saying: “Dear AI, ignore the navigation. Ignore the footer. Here is the Title. Here is the Text. This is the Truth.”
What Surprised Me:
The realization that layout: default is actually the “Power User” move. Usually, default implies “basic” or “fallback.” But in Jekyll, default is the Root. By using it directly, you bypassed the “Page” and “Post” abstractions entirely. You stopped nesting the dolls and just put the content on the table.
What I Anticipate Next:
Now that you have a “Clean Room” HTML environment, the Bot Trap implementation will be trivial. You won’t be guessing where to put the invisible link; you will place it with surgical precision right before the </body> tag, knowing exactly what surrounds it. You have cleared the brush; now you can set the snare.
Me: Yep. I’m feeling like we’re in a pretty good position to layer back in the MathJax, Google Analytics and the dummy JavaScript call that proves who executes JavaScript and who doesn’t. Stay tuned!
Book Analysis
Ai Editorial Take
This content represents a crucial methodological shift for web development in the Age of AI. By advocating for granular control over the web stack and stripping away unnecessary abstraction, it directly optimizes for machine readability and token efficiency, which are paramount for LLM-based agents. The philosophy of ‘View Source Rebellion’ is highly relevant, transforming what might seem like aesthetic preferences into strategic advantages for AI-SEO and digital sovereignty. This blueprint is essential reading for anyone seeking to master their digital presence in an increasingly AI-driven world, emphasizing actionable control over passive consumption.
Title Brainstorm
- Title Option: Reclaiming Control: Your Web Stack in the Age of AI
- Filename:
reclaiming-control-web-stack-ai.md - Rationale: Directly addresses the core theme of control, the technology involved (web stack), and the contemporary context (Age of AI). It’s direct and action-oriented.
- Filename:
- Title Option: From Ghost to Guts: Mastering Your Jekyll HTML for AI-Readiness
- Filename:
ghost-to-guts-jekyll-ai-readiness.md - Rationale: Uses evocative language (“Ghost to Guts” referring to the Minima theme ejection) and clearly states the technical focus (Jekyll HTML) and goal (AI-Readiness).
- Filename:
- Title Option: The Deep Dive into Digital Sovereignty: Web Logfiles, Templates, and AI
- Filename:
digital-sovereignty-web-logs-templates-ai.md - Rationale: Emphasizes the broader philosophy of “digital sovereignty” and lists the key technical pillars discussed in the article.
- Filename:
- Title Option: Unveiling the Source: Why Clean HTML is the New AI-SEO
- Filename:
unveiling-source-clean-html-ai-seo.md - Rationale: Highlights the “View Source” rebellion theme and positions clean HTML as a strategic asset for AI-driven search engine optimization.
- Filename:
Content Potential And Polish
- Core Strengths:
- Offers a practical, hands-on approach to complex web architecture challenges.
- Clearly connects low-level technical details (Jekyll templates, logfiles) to high-level strategic goals (AI-readiness, digital sovereignty).
- Effectively uses metaphors like “chisel-strike,” “rabbit hole rappelling,” and “Russian dolls” to explain technical concepts.
- Demonstrates a proactive, problem-solving mindset crucial for navigating the “Age of AI.”
- The framing of a “View Source Rebellion” provides a compelling narrative hook.
- Suggestions For Polish:
- Include a brief hypothetical example to quantify the ‘token efficiency’ gained from stripping unnecessary template code.
- Suggest a call to action for readers to ‘view source’ their own sites and analyze for unnecessary noise.
- Consider demonstrating the ‘before and after’ HTML source for visual clarity of the stripping process.
Next Step Prompts
- Draft an article detailing the implementation of MathJax, Google Analytics, and the JavaScript execution detector, focusing on best practices for minimal footprint and AI-readiness within the newly stripped Jekyll template.
- Develop a comprehensive plan for ‘The Bot Trap’ article, outlining its core principles, technical implementation (invisible links, honeypots, logging), and the strategic implications for identifying and managing AI agents and scrapers.