Taxonomy System
The taxonomy system manages the organizational structure of work items through three entity types: categories, tags, and collections. These are stored in the data repository as YAML files and managed through the WorkTaxonomyService.
Overview
Every work can organize its items using:
| Entity | Purpose | Example |
|---|---|---|
| Categories | Primary classification buckets | "Frontend Frameworks", "DevOps Tools" |
| Tags | Cross-cutting labels | "open-source", "typescript", "free-tier" |
| Collections | Curated item groupings | "Editor's Picks", "Getting Started" |
Categories and tags are the primary taxonomy mechanisms used during AI generation. Collections provide an additional manual curation layer.
Architecture
The taxonomy service is located at packages/agent/src/services/work-taxonomy.service.ts and depends on:
DataGeneratorService-- reads and writes taxonomy data to the Git data repository.WorkOwnershipService-- enforces access control (viewer for reads, editor for writes).UserRepository-- resolves user entities for Git commit authorship.
Categories
Categories are the primary organizational axis. Each item belongs to exactly one category.
Data Model
interface Category {
id: string; // URL-friendly slug (e.g., "frontend-frameworks")
name: string; // Display name (e.g., "Frontend Frameworks")
description?: string; // Optional description
icon_url?: string; // Optional category icon URL
priority?: number; // Optional sort priority
}
CRUD Operations
List Categories
async getCategories(workId: string, userId: string): Promise<Category[]>
Reads categories from the data repository. Requires viewer access.
Create Category
async createCategory(workId: string, dto: CreateCategoryDto, userId: string)
- Validates that no duplicate name exists (case-insensitive comparison).
- Auto-generates the
idby slugifying the name (e.g., "My Category" becomes "my-category"). - Appends the new category to the existing list.
- Saves all categories back to the data repository.
Requires editor access.
Update Category
async updateCategory(workId: string, categoryId: string, dto: UpdateCategoryDto, userId: string)
Updates name, description, icon URL, or priority. Validates uniqueness if the name is being changed. Requires editor access.
Delete Category
async deleteCategory(workId: string, categoryId: string, userId: string)
Removes the category from the list. Note: items referencing this category are not automatically reassigned. Requires editor access.
Tags
Tags provide a flexible labeling system. Each item can have zero or more tags.
Data Model
interface Tag {
id: string; // URL-friendly slug (e.g., "open-source")
name: string; // Display name (e.g., "Open Source")
}
CRUD Operations
List Tags
async getTags(workId: string, userId: string): Promise<Tag[]>
Create Tag
async createTag(workId: string, dto: CreateTagDto, userId: string)
Validates name uniqueness (case-insensitive) and auto-generates the slug ID.
Update Tag
async updateTag(workId: string, tagId: string, dto: UpdateTagDto, userId: string)
Delete Tag
async deleteTag(workId: string, tagId: string, userId: string)
Collections
Collections are curated groups of items, independent of the category/tag taxonomy. They enable editorial groupings like "Best of 2025" or "Getting Started Essentials".
Data Model
interface Collection {
id: string; // URL-friendly slug
name: string; // Display name
description?: string; // Optional description
icon_url?: string; // Optional collection icon
priority?: number; // Sort priority
}
CRUD Operations
Collections follow the same CRUD pattern as categories:
async getCollections(workId: string, userId: string): Promise<Collection[]>
async createCollection(workId: string, dto: CreateCollectionDto, userId: string)
async updateCollection(workId: string, collectionId: string, dto: UpdateCollectionDto, userId: string)
async deleteCollection(workId: string, collectionId: string, userId: string)
All operations include duplicate name validation and auto-generated slug IDs.
Storage Format
Taxonomy data is stored in the data repository as YAML files:
{work-slug}-data/
categories.yml # Array of category objects
tags.yml # Array of tag objects
collections.yml # Array of collection objects
.works/works.yml # Work configuration
data/
item-slug/
item.yml # References category and tags by ID
categories.yml Example
- id: frontend-frameworks
name: Frontend Frameworks
description: JavaScript frameworks for building user interfaces
priority: 1
- id: devops-tools
name: DevOps Tools
description: Tools for deployment, CI/CD, and infrastructure
priority: 2
Item Reference
Items reference categories and tags by their slug IDs:
# data/react/item.yml
name: React
slug: react
category: frontend-frameworks
tags:
- open-source
- typescript
- meta
Slug Generation
All taxonomy entity IDs are auto-generated using slugifyText():
const newCategory: Category = {
id: slugifyText(dto.name.trim()), // "My Category" -> "my-category"
name: dto.name.trim()
};
This ensures IDs are URL-friendly and consistent with item references.
Access Control
| Operation | Required Role |
|---|---|
| List (categories, tags, collections) | Viewer |
| Create | Editor |
| Update | Editor |
| Delete | Editor |
Access is checked via WorkOwnershipService:
ensureAccess(workId, userId)for read operations.ensureCanEdit(workId, userId)for write operations.
AI Integration
During AI-powered generation, the pipeline:
- Loads existing categories via the taxonomy service.
- Passes category names to the AI as context for item categorization.
- Uses the advanced prompts
categorizationfield (if set) to guide category assignment. - New categories may be suggested by the AI and created through the taxonomy service.
Tags are typically extracted by the AI from item descriptions and source content. The deduplication phase normalizes and merges tag values across items.