I Have 41 Posts. I Audited Their Tags. 11 Survived.
I have 41 blog posts. They each have tags. Until last week, those tags were whatever I thought made sense when I wrote the post. Some recurred. Most didn't. The rest were categories I wanted to exist, or aspects I wanted to mention.
I had no system. I had vibes.
Then I ran the audit that wiped the registry.
The system I wanted
I wanted four content pillars, four primary niches that described the shape of my blog. Every published post had to declare a pillar. Tags had to map to pillars. A build-time validator had to fail if a published post declared a pillar that no tag supported.
Four pillars:
ai— AI tooling, agents, OpenCode, Claude Code, agentic coding workflowshomelab— self-hosting, hardware, Unraid, servers, OS setup on machinesrabbit-holes— broad technical pillar: shipping projects + debugging/learning while building thingsreflections— non-tech, opinion, career, expanded thoughts
The pillars themselves were the easy part.
The hard part was the tags.
The audit
I ran the audit as a wayfinder pass. One decision per tag.
The mechanics were dull. Every tag lives in a post's frontmatter, so I pulled the frontmatter from all 41 posts, listed every tag with its count, and sorted by that. The agent did the tallying. The judgment calls were all mine.
Some tags were obviously load-bearing. projex showed up on every post that mentioned my component library. velite showed up on every post about my content pipeline. homelab showed up on the server posts. github showed up on the recovery and the deprecation posts.
Some tags were obviously decorative. debugging showed up on three posts, all of which were about different kinds of debugging. workflow showed up on five posts, all of which were about different kinds of workflows. ai-assisted-development showed up on one post.
The first rule was: if it recurs, keep it. That got me a first registry with about 48 tags in it, more than the posts actually used. Some were categories I wanted to exist rather than categories I had. It took reading the five workflow posts back to back to see the problem: they had nothing in common. The rule was measuring the wrong thing.
A tag earns its place if there's evidence of a series. At least one other post has to anchor it. A tag that could be folded into a broader existing tag gets folded. A tag that's used once and not part of a series dies. The count gets a hearing, but the posts have to actually belong together.
apt died. Used once. Subsumed by ubuntu. No reason to keep it.
github stayed. Multiple posts: the Ubuntu apt deprecation post and the git corruption recovery post. A real series about GitHub-shaped problems.
workflow died. Five uses, zero series. The tag was a context label, not a topic.
claude-code stayed. Two posts already, more coming. Real series.
The death rate was high. Of 41 tags that appeared across the 41 posts (the equal counts were an accident), 30 died. 11 survived.
The 11:
ai:opencode,hermes,claude-codehomelab:docker,zerowork,obsidianrabbit-holes:projex,velite,nextjs,github,ubuntu
(The registry also carries the pillar names themselves as tags: ai, homelab, reflections. Those aren't series. They're just the pillars.)
Yes, I could tag any post with the bare pillar name and the validator would wave it through. The validator catches accidents. The coherent-series test is what catches lies. Tagging a post reflections just to get through a build is workflow all over again.
reflections is the only pillar with no series tags. The first genuinely reflective post has to bring its tag through the PR process.
Why the death rate was the point
A tag is a promise. When I tag a post workflow, if you click this tag, you'll find a series of posts about workflows. The reader lands on a tag page expecting a coherent collection.
If the tag delivers three posts about three different things, the tag lied. Anyone who clicked it got a pile of nothing. That's on me.
I keep going back and forth on whether the test is too strict. It's not, really. A tag with no series is just noise on a tag page.
The 30 tags that died weren't wrong. They were over-promised. They were:
- context labels (
debugging,thinking,meta,lessons-learned,retrospective,burnout) - aspect descriptions (
css,styling,build-time,production,ai-assisted-development) - single-use nouns (
apt,devto,router) that fit better as a broader existing tag
The 11 that survived are the tags I actually write in.
What the validator actually does
The build-time validator lives in velite.config.js, the config for Velite, my content pipeline. It runs on every build, for anything published. It checks: the declared pillar of a post must equal the pillar of at least one tag in tags[]. If it doesn't, the build fails.
This sounds bureaucratic. It isn't. It's the way I keep myself honest.
Say I write something about what two years of blogging taught me, and I mention in passing that the site runs in Docker. Tag: docker. Declared pillar: reflections. Build dead:
[content-pillars] post 'what-blogging-taught-me' declares pillar='reflections' but no tag in tags[] maps to that pillar. Either add a tag whose registered pillar is 'reflections' or change the declared pillar.
docker is registered as homelab. Nothing on the post maps to reflections. The validator won't let me silently have a post that doesn't belong to any tag series. If a post can't anchor any tag series, it shouldn't be published as a tag-anchored post. It should be published as something else, or it should get a tag that earns its place.
The validator also changes how I write. When I sit down to write a post and I want to tag it workflow, I have to ask: is this post part of a series I'm willing to commit to? If yes, fine. If no, the tag dies and I pick a real one.
I don't know if that counts as discipline or just an elaborate way to make my own builds fail. But the vibes never made me stop and ask.
The two ADRs that came out of this
The whole taxonomy lives in two architecture decision records, under docs/adr/ in this site's repo.
ADR 0001 — the four pillars, the tag registration rule, the coherent-series test. This is the constitution.
ADR 0002 — the SEO policy. How tag pages render, what metadata they expose, how they relate to pillar pages. This is the policy that turns the constitution into something Google can crawl.
The wayfinder pass gave me a rule I could encode in the validator.
I knew what the blog was about. I had been writing it for two years. I didn't have the taxonomy for what it was about until I counted the tags.
New tags go through me
There will be new tags. New tags require a PR to the registry (src/data/content-pillars.ts) with a one-line rationale that passes the coherent-series test. No agent mediates this. I'm the curator.
That's the right shape. Tags are mine. The agent can write the post, can audit the existing tags, can build the validator. The decision about whether a new tag earns its place is mine.
The death rate felt bad while I was doing it. Felt like I was throwing things away, or being too strict.
Then I read a tag page with three posts that actually belonged together, and I realized what the page would have looked like with seven tags on it, half of which lied. The page would have been unreadable. The reader would have clicked and bounced. The tag would have meant nothing.
Most of the work in this was deletion. 30 tags out of 41 went. The posts stayed. They're still about what they were about. The surviving tags earned their place.