Categorization (1 blogmarks)
← BlogmarksDeveloping a tagging scheme for my posts using facets
My TIL posts have an extremely one-dimensional categorization scheme. There is a list technology buckets (directories) like "Rails", "Unix", "Python", "git", "workflow", etc. Each TIL that I write has to fit into exactly one of those. In some ways the simplicity has been golden because it has allowed me to write posts without overthinking how to categorize and tag them.
Well, it is now time to overthink how to categorize and tag them. The challenge has been figuring out what kind of tagging scheme makes sense. Stack Overflow is an initial source of inspiration because each post can have a couple tags which come from an evolving, but canonical list of tags with varying specificity.
Multiple tags is a step in the right direction. But what about a post that is using "Python" to work with an "LLM" model to classification and tagging of my "TIL" posts as part of a publishing "workflow" inspired by a post I saw from "Simon Willison"? What I'm getting at is that there are many facets of tags that I'd like to have in mind when categorizing these posts.
I'm still refining it, but here are the set of facets that I'm planning to work with so far.
Technology: the specific named thing used or discussed (language, framework, library, CLI tool, service). Hierarchical, so a child implies its parent.
- Cardinality: one or more
- Examples: git, qpdf, overmind, tmux,
Click → Python,GoodJob → Rails → Ruby, uv, numpy, PostgreSQL
Topic: what the post is about independent of the tool. The tag should still apply if the post were rewritten with a different tool.
- Cardinality: one or more
- Examples: version control, PDF manipulation, process management, dev environment, CLI design, background jobs, algorithms, data modeling
Concern (optional; could fold into Topic): a quality attribute that cuts across topics.
- Cardinality: zero or more
- Examples: performance, security, accessibility, reliability, ergonomics, observability
Task: what I was trying to get done, expressed as a verb from a small controlled vocabulary.
- Cardinality: one or more (usually one or two)
- Examples: inspect, summarize, transform, remove, rename, configure, connect, debug, automate, migrate
Genre: the shape the post takes.
- Cardinality: exactly one
- Examples: How-to (single technique), Survey of approaches (several ways to one goal), Gotcha (pitfall and fix), Workflow / setup (how tools fit together), Explainer (how something works), Experiment, Prototype, Puzzle
Platform: the environment where the post applies, when that matters.
- Cardinality: zero or more
- Examples: macOS, Linux, terminal, browser, CI, Docker
Source: where the knowledge came from (provenance, not things mentioned in the post).
- Cardinality: zero or more
- Examples: man pages, official docs, project README, Stack Overflow, Simon Willison, CSS Tricks, pairing session, trial and error
Project: what I was working on when the post came up.
- Cardinality: zero or more (usually zero or one)
- Examples: py-vmt, notes app, client work, dotfiles
Version (metadata, not a browsing facet): a marker for version-sensitive posts that may go stale; the publish date covers everything else.
- Cardinality: zero or one
- Examples:
Rails 8+,Python 3.12+,git 2.40+
I'm planning to use this faceted tagging scheme in the prompt that I use with an LLM to do first-pass tag "hallucination".
Here is a structured JSON object of this facet definition:
{
"scheme": "til-faceted-classification",
"version": 1,
"facet_order": [
"technology",
"topic",
"concern",
"task",
"genre",
"platform",
"source",
"project",
"version"
],
"facets": {
"technology": {
"label": "Technology",
"question": "What named thing did I use?",
"definition": "The specific named thing used or discussed: language, framework, library, CLI tool, or service. Hierarchical: a child implies its parent.",
"cardinality": { "min": 1, "max": null },
"hierarchical": true,
"optional_facet": false,
"kind": "tag",
"examples": [
{ "value": "git" },
{ "value": "qpdf" },
{ "value": "overmind" },
{ "value": "tmux" },
{ "value": "uv" },
{ "value": "numpy" },
{ "value": "PostgreSQL" },
{ "value": "Python" },
{ "value": "Click", "parent": "Python" },
{ "value": "Ruby" },
{ "value": "Rails", "parent": "Ruby" },
{ "value": "GoodJob", "parent": "Rails" }
]
},
"topic": {
"label": "Topic",
"question": "What is this about if you remove the tool?",
"definition": "What the post is about independent of the tool. The tag should still apply if the post were rewritten with a different tool.",
"cardinality": { "min": 1, "max": null },
"hierarchical": false,
"optional_facet": false,
"kind": "tag",
"examples": [
"version control",
"PDF manipulation",
"process management",
"dev environment",
"CLI design",
"background jobs",
"algorithms",
"data modeling"
]
},
"concern": {
"label": "Concern",
"question": "What quality attribute does this touch?",
"definition": "A quality attribute that cuts across topics.",
"cardinality": { "min": 0, "max": null },
"hierarchical": false,
"optional_facet": true,
"notes": "Could be folded into Topic.",
"kind": "tag",
"examples": [
"performance",
"security",
"accessibility",
"reliability",
"ergonomics",
"observability"
]
},
"task": {
"label": "Task",
"question": "What was I trying to get done?",
"definition": "What I was trying to get done, expressed as a verb from a small controlled vocabulary.",
"cardinality": { "min": 1, "max": null, "typical_max": 2 },
"hierarchical": false,
"optional_facet": false,
"kind": "tag",
"examples": [
"inspect",
"summarize",
"transform",
"remove",
"rename",
"configure",
"connect",
"debug",
"automate",
"migrate"
]
},
"genre": {
"label": "Genre",
"question": "What shape does the post take?",
"definition": "The shape the post takes.",
"cardinality": { "min": 1, "max": 1 },
"hierarchical": false,
"optional_facet": false,
"kind": "tag",
"examples": [
{ "value": "How-to", "scope_note": "A single technique for a single goal." },
{ "value": "Survey of approaches", "scope_note": "Several ways to reach the same goal." },
{ "value": "Gotcha", "scope_note": "A pitfall and how to avoid it." },
{ "value": "Workflow / setup", "scope_note": "How tools fit together in a routine." },
{ "value": "Explainer", "scope_note": "How something works, not how to do something." },
{ "value": "Experiment" },
{ "value": "Prototype" },
{ "value": "Puzzle" }
]
},
"platform": {
"label": "Platform",
"question": "Where does this apply?",
"definition": "The environment where the post applies, when that matters.",
"cardinality": { "min": 0, "max": null },
"hierarchical": false,
"optional_facet": false,
"kind": "tag",
"examples": ["macOS", "Linux", "terminal", "browser", "CI", "Docker"]
},
"source": {
"label": "Source",
"question": "Where did I learn this?",
"definition": "Where the knowledge came from (provenance, not things mentioned in the post).",
"cardinality": { "min": 0, "max": null },
"hierarchical": false,
"optional_facet": false,
"kind": "tag",
"examples": [
"man pages",
"official docs",
"project README",
"Stack Overflow",
"Simon Willison",
"CSS Tricks",
"pairing session",
"trial and error"
]
},
"project": {
"label": "Project",
"question": "What was I working on when this came up?",
"definition": "What I was working on when the post came up.",
"cardinality": { "min": 0, "max": null, "typical_max": 1 },
"hierarchical": false,
"optional_facet": false,
"kind": "tag",
"examples": ["py-vmt", "notes app", "client work", "dotfiles"]
},
"version": {
"label": "Version",
"question": "Is this likely to go stale with a version change?",
"definition": "A marker for version-sensitive posts that may go stale; the publish date covers everything else.",
"cardinality": { "min": 0, "max": 1 },
"hierarchical": false,
"optional_facet": true,
"kind": "metadata",
"notes": "Metadata, not a browsing facet.",
"examples": ["Rails 8+", "Python 3.12+", "git 2.40+"]
}
}
}