Tag Governance
Scale tagging from a handful of pages to hundreds by curating a vocabulary and enforcing it at build time.
Why Governance
A free-form tag list is fine for the first ten pages. By the hundredth, you will have deployment, Deployment, deploy, and deploys all pointing at the same topic — splitting your tag index into useless near-duplicates and making discovery worse, not better.
Tag governance fixes this by promoting the project’s tag set to a canonical vocabulary defined in src/. Every tag used in frontmatter is validated against this file. Typos and drift surface as audit findings; legitimate additions are intentional edits to the vocabulary.
The goal is to keep discovery sharp as the doc base grows. Start loose; tighten as you scale.
The Vocabulary File
src/ is an array of TagVocabularyEntry objects. Each entry declares a canonical tag id, an optional display label, a group, and any aliases content is allowed to use:
{
id: "deployment",
label: "Deployment",
description: "Hosting, CI, and release workflows.",
group: "topic",
aliases: ["deploy", "deploys"],
}
To phase out a tag without breaking existing pages, either mark it deprecated or redirect it to a replacement. Never silently delete an entry — see the inline comments in src/ for the full phase-out contract.
Extending the Vocabulary in Your Project
After scaffolding with create-zudo-doc, tag-vocabulary.ts belongs to your project. It is a normal source file, not a framework internal. Edit it directly — no forking or monkey-patching required. A typical addition looks like this:
export const tagVocabulary: readonly TagVocabularyEntry[] = [
// ...existing entries
{
id: "topic:auth",
label: "Auth",
description: "Authentication, sessions, SSO.",
group: "topic",
},
{
id: "type:runbook",
label: "Runbook",
description: "Incident response and on-call procedures.",
group: "type",
},
];
After editing, run <code>pnpm tags:audit</code> to verify nothing unexpected broke, and add tags to pages the usual way:
---
title: OAuth 2.0 Setup
tags: [topic:auth, type:runbook]
---
Two Orthogonal Settings
Governance is controlled by two independent settings in src/:
| Setting | Type | Purpose |
|---|---|---|
tagVocabulary | boolean | Whether the vocabulary file is consulted at all (alias resolution, deprecation, grouping). |
tagGovernance | "off" | "warn" | "strict" | Enforcement level when the vocabulary is consulted. |
They are orthogonal. tagVocabulary: false disables vocabulary entirely, regardless of tagGovernance. Leave tagVocabulary: true (the default) and tune enforcement via tagGovernance.
The Three Modes
"off"— vocabulary-aware enforcement is skipped. Tags stay completely loose. Useful for legacy migrations or prototypes."warn"(default) —pnpm tags:auditreports unknown tags, deprecations, and near-duplicates, butpnpm buildstill passes. Fixes can land at your own pace."strict"— unknown tags fail Zod validation atpnpm check/pnpm buildtime. The vocabulary becomes the single source of truth.
Recommended Escalation Path
- Seed the vocabulary from the tags you already use —
tag-vocabulary.tsships pre-filled with every tag that appears in the default showcase content. - Run
warnuntil the audit is clean. Fix unknowns, resolve aliases withpnpm tags:audit --fix, and retire near-duplicates by adding them as aliases of the canonical id. - Flip to
strictonce the audit is green. From that point on, new tags require a matching vocabulary entry — which is exactly the friction you want to prevent drift.
Adopt strict as soon as the backlog is empty; the earlier the constraint is in place, the cheaper it stays.
Faceted Tag Pattern
Flat tag soups (deployment, advanced, tutorial, i18n, …) scale poorly because the reader cannot tell what a tag answers. A faceted prefix names the axis:
type:— what kind of page is it?type:guide,type:reference,type:tutorial,type:runbook.level:— who is it for?level:beginner,level:advanced.topic:— what subject does it cover?topic:auth,topic:ai,topic:search.
The default vocabulary uses this pattern for type:* and level:* facets. You can extend it with your own topic:* entries, or introduce new facets (product:*, team:*) as your doc base grows. Facets stay separate in the grouped footer taglist — see Footer taglist.
Next Steps
- Tag audit — what
pnpm tags:auditreports and how to read it. - Tag suggestions — opt-in local LLM suggester for new pages.
- Footer taglist — surface the vocabulary to readers.