Note Taxonomy
Per-workspace tag vocabulary and folder routing rules for BlackOps notes. Defines the known tags, decides which folder a note's markdown lands in when written to your repo, and surfaces soft warnings when the AI uses a tag outside your vocabulary — without ever blocking a write.
Overview
Every note in BlackOps carries tags and a note_type. Note Taxonomy turns those into structured taxonomy you control: a named vocabulary of tags, and an ordered list of routing rules that decide where the markdown file lands when synced to your vault.
The system has three jobs: keep AI-generated tags consistent with your conventions, make folder layout deterministic and configurable, and make all of it discoverable by MCP-connected assistants before they call post_notes or post_notes_write.
Key Capabilities
Tag Vocabulary
Per-workspace list of known tags with name, description, and color. Drives soft warnings on writes — unknown tags get a Levenshtein fuzzy-match suggestion. Writes are never blocked.
Folder Routing
Ordered rules match a note's tags or note_type to a destination folder. First match wins. Used by post_notes_write when no explicit relative path is provided.
list_notes MCP Tool
Filtered, paginated note queries for AI assistants — by tags, note_type, status, or full-text search across title and excerpt. Mirrors list_reservoir_items.
Pre-flight Awareness
The get_note_taxonomy MCP tool lets an AI fetch your vocabulary + routing rules before writing, so it picks known tags and predicts where a file will land.
How It Works
1. Manage your vocabulary in Settings
Open Settings → Note Taxonomy to add, edit, reorder, or remove tags. Each tag has a name, description, and color chip used in admin views. Removing a tag only removes it from the vocabulary — existing notes that use it are not modified.
2. Define folder routing rules
On the same settings page, build the ordered list of routing rules. Each rule has a condition (tag_match or note_type_match), a value to match, and a destination folder. Drag-style up/down controls set priority — first match wins.
A live preview at the bottom of the page shows where common tag/type combinations would route, so you can sanity-check changes before saving.
3. AI writes a note via MCP
When an AI assistant calls post_notes or patch_notes with tags, the response includes a warnings array listing any tags outside your vocabulary, with a suggestion if a known tag is within Levenshtein distance ≤ 2:
"warnings": [
"Unknown tag: 'featurez' — did you mean 'feature'?",
"Unknown tag: 'totallyunknown'"
]The note is saved either way — warnings are advisory.
4. AI writes the file via post_notes_write
When the AI calls post_notes_write with a note_id + target_id and no explicit relative_path, the server:
- Loads the note's tags and note_type
- Walks the routing rules in priority order
- Picks the first matching rule's folder, or the default folder
- Writes the file to
{folder}{slug}.md - Returns
routing_rule_appliedin the response so the AI can confirm where it landed
Explicit relative_path always wins — auto-routing is opt-out.
Defaults
Every workspace is seeded with sensible defaults on creation (via a database trigger, so the seed never depends on app code paths). You can edit, reorder, or replace any of them at any time.
Default tags
inbox— unsorted notesfeature— feature requestsbug— bugs and defectsblackops— BlackOps-specific workdaily— daily journalproject— project notesreference— long-lived referencecap— capture session notes
Default routing rules
- tag
feature→features/ - tag
bug→bugs/ - type
daily→daily/ - type
project→projects/ - type
reference→reference/
Default folder for unmatched notes: inbox/
MCP Tools
Returns the active site's tag vocabulary, folder routing rules, and default folder. Call this before post_notes to pick known tags, or before post_notes_write to predict the destination folder.
Filtered, paginated note query. Use this when get_recent_notes isn't specific enough.
tags+tags_match(defaultall, alsoany)note_type,status(defaultactive)search— title + excerpt ILIKElimit(default 20, max 200),offsetsort(created_at | updated_at | title),order(asc | desc)
API Reference
Returns { tags, folder_routing, default_folder }. Drives get_note_taxonomy.
Filtered note query with full pagination. Drives list_notes.
Admin read of the full taxonomy and PUT for the default folder. Used by the settings page.
CRUD + reorder for tag vocabulary. POST with { order: [id, ...] } reorders, otherwise creates.
CRUD + reorder for routing rules. Same order contract as tags.
Database Schema
note_tags
Per-workspace tag vocabulary. Columns: id, workspace_id, name, description, color, sort_order. Unique on (workspace_id, name).
note_folder_rules
Per-workspace ordered routing rules. Columns: id, workspace_id, condition_type (tag_match | note_type_match), condition_value, folder_path, priority. Unique on (workspace_id, condition_type, condition_value).
workspace_note_settings
Single-row config per workspace. Columns: workspace_id (PK), default_folder.
Auto-seed trigger
seed_note_taxonomy_for_new_site() fires AFTER INSERT on sites, populating defaults so new workspaces never need manual setup. Existing workspaces were backfilled at migration time.
Things to Know
- Tag warnings are advisory only — writes always succeed. Do not gate workflows on the absence of warnings.
- Removing a tag from the vocabulary doesn't strip it from existing notes — they keep the tag and just become "unknown" until you re-add it or rename to a known tag.
- Auto-routing only fires when
post_notes_writegets anote_idwith norelative_pathor template. Brain-scoped writes still require an explicit relative_path under the brain's source folder. - Notes have
tagsstored asjsonb, nottext[]— direct DB queries should use jsonb containment (tags @> '["feature"]').