Blog Post Template
The shape of an Abukix blog post. Pattern-first. Tied to a specific moment. ~800-2000 words. ~36 posts across Y3-Y5 (monthly cadence). The biggest voice-drift risk in the program — this template anchors it.
One post per month from Y3 onward. ~36 by graduation. Tied to a specific moment — an incident, a phase ship, a pattern reaching DEEP. Not a tutorial. Not a survey. Voice anchors live in brand/identity. This template makes them mechanical.
What an Abukix blog post is (and isn’t)
Is:
- 800-2,000 words. Reads in 5-10 minutes.
- Tied to one specific event that happened in your /root work that month.
- Pattern-first: names the pattern explicitly, links to its Pattern Library entry, shows the pattern operating in the event.
- Honest: includes what surprised you, what you got wrong, what’s still open.
- Carries receipts: links to the commit, the runbook, the ADR, the postmortem, the dashboard.
- Voice consistent with the brand pillar (“Building an AI Platform in Public”). See brand/identity — voice anchors.
Isn’t:
- A tutorial walkthrough (“here’s how to install Iceberg”). The internet has those.
- A vendor-style overview (“everything you need to know about service mesh”). That’s a survey paper.
- A career advice post in disguise. The post is about the technical thing, not about you-as-author.
- A first draft of AI-generated prose. The voice anchors fail; readers detect it within 2 paragraphs.
When to write one
Monthly cadence. Pick the post topic during the Sunday weekly log of the third week of each month.
Draft during week 4. Publish on the first weekend of the next month.
Skip a month at most twice per year — more is the canary that the rhythm is broken.
The natural source is your weekly log corpus. Re-read the past 4 weekly logs. Pick the section 3 or section 4 entry (what surprised me / what was stuck) that has the strongest pattern-naming opportunity. That’s the post.
The template — copy this verbatim
---
title: "<verb-noun-modifier short title; e.g., 'Why Flux reconciles faster than I expected'>"
slug: 2026-mm-flux-reconcile-perf
date: 2026-MM-DD
phase: "Y3 Phase 22" # current /root phase
pattern: control-loops # the load-bearing pattern of this post
related_patterns: [gitops, operator-pattern]
related_artifacts:
- commit: <SHA on basecamp>
- adr: 0014
- runbook: recover-flux-stuck-kustomization
- postmortem: 2026-04-12-flux-source-unreachable
reading_time: 7 # minutes
tags: [blog, year-3, flux, gitops, control-loops]
draft: false
---
# <Title>
## The moment
(One paragraph, 100-150 words. The specific event that prompted this post. A real day, a real terminal session, a real surprise. Anchor in time.)
I was watching `flux get kustomizations -A` scroll past at 11pm last Tuesday when something didn't add up: the reconcile loop had completed an apparent 47-resource diff in under 800ms. I'd assumed Flux was doing what I'd seen Terraform do — refresh every resource, diff each one, apply changes serially. The numbers said it wasn't. The patterns I'd internalized about declarative tooling were about to get refined.
## The pattern
The thing underneath is **[control-loops](/patterns/foundations/control-loops/)** — the same pattern Kubernetes itself uses at the workload level, and the pattern Flux applies one layer up at the cluster-state level. Worth naming explicitly because the post that follows is really about *what I learned by watching the pattern operate in a specific implementation I hadn't yet internalized*.
(2-3 sentences. Name the pattern. Link to its Pattern Library entry. Sketch what the pattern *should* look like before the post complicates it.)
## What I expected (and where it broke down)
(The mental model going in. 1-2 paragraphs.)
I expected Flux to behave like Terraform: read desired state from Git, list every resource the controller manages, diff each against actual cluster state, apply differences. My mental model said diff is O(N) where N is the number of managed resources. 47 resources × any non-trivial round-trip latency would be far more than 800ms.
## What's actually happening
(The corrected mental model. Where the surprise came from. 2-3 paragraphs.)
Flux doesn't refresh every resource on every reconcile. It maintains a content-hash of the rendered manifests AND a content-hash of the cluster state observed at last successful apply. The "diff" on a hot path is two hash comparisons — sub-millisecond. The full-resource refresh happens on a slower interval (default 10 minutes) AND on explicit `flux reconcile` invocation. The 800ms number was the optimistic path; the slow path I was *not* observing in that moment.
(If there's a code snippet, runbook excerpt, or kubectl output, paste it here. Brevity. The receipt, not the full transcript.)
$ flux get kustomizations -A | head -3 NAMESPACE NAME REVISION READY … flux-system flux-system sha1:abc123 True … flux-system basecamp-apps sha1:def456 True …
## What I'd missed about the pattern
(The transferable lesson. This is the load-bearing section of the post. 2-3 paragraphs.)
The control-loop pattern doesn't dictate *how often* the loop runs — just that it runs continuously. Implementations have wide latitude on caching, on optimistic-vs-pessimistic refresh, on event-driven vs interval-driven triggers. Flux uses an event-driven hot path with an interval-based slow path. Kubernetes' kubelet does the same. ArgoCD's choice is different in interesting ways (it leans harder on explicit refresh by default).
The senior-IC pattern recognition isn't "Flux uses event-driven reconciliation." It's: *every control-loop implementation lives somewhere in the trade-off space between optimistic-fresh-cached-fast and conservative-stale-refreshed-correct, and that position shapes everything downstream about how the system behaves under load.*
## What this opens up
(One paragraph. What's the next question this post leaves open? Don't tie it up in a bow — the open question is honest.)
The next thing I want to understand: how does this behavior degrade when the Git source goes unreachable for >2 minutes? The optimistic hot path won't notice; the slow path will. That's a class of incident I haven't seen yet on basecamp. The relevant runbook ([recover-flux-source-unreachable](/projects/ops-handbook/runbooks/kubernetes/recover-flux-source-unreachable.md)) is theoretical until I've actually run it.
## Receipts
- The commit that triggered this reconcile: [basecamp@abc1234](https://github.com/.../basecamp/commit/abc1234)
- ADR 0014: Why Flux over ArgoCD ([link](/adrs/0014-flux-over-argocd))
- The runbook this work spawned: `recover-flux-stuck-kustomization`
- Related Pattern Library entries: [control-loops](/patterns/foundations/control-loops/), [gitops](/patterns/infrastructure-and-platform/gitops/), [operator-pattern](/patterns/infrastructure-and-platform/operator-pattern/)
---
*This post is part of [Abukix — Building an AI Platform in Public](/). It documents a moment from [Year 3 Phase 22](/program/year-3/phase-22/) of the [/root program](/program/). The platform is `basecamp`; the cluster reconciles against [github.com/<user>/basecamp](https://github.com/<user>/basecamp).*
What good looks like
- The hook is specific. A real day, a real terminal, a real surprise. Not “you might be wondering about Flux.”
- One pattern named. Not three. The post has one load-bearing pattern; supporting patterns are linked but don’t compete for attention.
- The corrected mental model is the load-bearing section. Posts that are all-setup-no-payoff are common; posts that re-frame the reader’s mental model are rare and valuable.
- Receipts make the post unfalsifiable. Commit SHAs, runbook filenames, dashboard screenshots. The reader can verify.
- Open questions are honest. A post that ends “and I now understand everything” reads as performance. A post that ends “this opens up the question of X” reads as a working engineer.
- The footer ties to the brand. One sentence linking back to /root and basecamp.
Anti-patterns
| Anti-pattern | Why |
|---|---|
| Tutorial walkthrough (“how to install X”) | The internet has those. /root’s posts are about what operating something taught me, not how to set it up. |
| AI-generated draft | Voice anchors fail. Reader detects it. Per AI Learning Protocol: AI iterates your draft; doesn’t author the first one. |
| Three patterns at once | The reader can hold one. Pick the load-bearing one; reference the others. |
| No receipts | Without commits / runbooks / dashboards, the post is vibes. Add them or skip the post. |
| Tying it up in a bow | Real operational learning is open-ended. End with the next question, not “and so we triumphed.” |
| Posting on a tool you haven’t operated for 30+ days | The post lacks the operational evidence that makes it credible. Wait until you have the corpus. |
| 4,000-word post | Split it. /root posts target 800-2,000 words. Anything longer becomes the Pattern Paper preview. |
| No frontmatter pattern field | Y5’s RAG over the blog corpus indexes on pattern:. Posts without it are invisible to AIOps queries. |
Cadence rhythm
Sunday week 1 of month: Review past 4 weekly logs.
Sunday week 2: Pick the post candidate; rough title + pattern.
Sunday week 3: Outline in this template's structure.
Week 4 evenings: Draft. 1-2 hr per session.
First weekend of next mo: Edit + publish.
Don’t draft-and-publish in one session. The 2-week gap between outline and publish is what catches the bad takes — re-reading your own draft after a week is the cheapest editor you have.
Cross-references
- brand/identity — voice anchors + the brand pillar
- AI Learning Protocol — the rule for AI’s role in drafting
- weekly log template — the source material every blog post draws from
- pattern template — the artifact each post links into
- Writing Templates index