Skip to content

Schema Design

Tags in Thogits are more than labels — they carry structured field schemas that define what data a thogit stores. Good schema design makes filtering powerful, keeps data consistent, and lets your system evolve without breaking existing thogits.

Start small

Begin with the fields you need today. Schema versioning lets you add fields later without breaking existing data.

One tag per concern

Separate concerns into distinct tags. Use “Task” for workflow, “Priority” for priority, “Assignment” for ownership — not one mega-tag.

Name consistently

Use PascalCase for tag names (ProjectTask, SprintGoal) and snake_case for field names (due_date, story_points).

Use References for relationships

Link thogits together with Reference fields instead of duplicating data. This enables reference traversal in filters.

TypeUse forExample
StringFree-form textdescription, notes
NumberQuantities, priorities, scorespriority, story_points
BooleanBinary flagsis_billable, requires_review
DatePoints in timedue_date, started_at
SelectWorkflow states, enums (single choice)status, severity
MultiSelectLabels, categories (multiple choice)labels, skills
ReferenceLinks to other thogitsassignee, project, parent

Select fields are ordered — the position of each variant matters. This enables ordinal filters like select_gte (at least this far in the workflow) and select_lte.

{
"status": {
"type": "Select",
"variants": [
"Backlog",
"Todo",
"In Progress",
"In Review",
"Done"
]
}
}

With this ordering, {"Task.status": {"select_gte": "In Progress"}} matches thogits that are “In Progress”, “In Review”, or “Done” — anything at that stage or later.

Variants can carry additional fields that only apply when that variant is active. This is useful for conditional data — a “Blocked” status needs a reason, a “Deferred” status needs a target date.

{
"status": {
"type": "Select",
"variants": [
"Todo",
"In Progress",
{"name": "Blocked", "fields": {"reason": "String"}},
{"name": "Deferred", "fields": {"until": "Date"}},
"Done"
]
}
}

When setting field values, variant sub-fields are stored flat alongside other fields:

{
"status": {"variant": "Blocked"},
"reason": "Waiting on design review"
}

Use MultiSelect when a thogit can belong to multiple categories simultaneously. Unlike Select, MultiSelect has no ordering semantics.

{
"labels": {
"type": "MultiSelect",
"variants": ["Bug", "Feature", "Frontend", "Backend", "P1", "P2", "P3"]
}
}

Set values as an array:

{
"labels": ["Bug", "Frontend", "P1"]
}

Reference fields store a ULID pointing to another thogit. This creates a typed link that you can traverse in filters using the -> operator.

{
"assignee": "Reference",
"project": "Reference"
}

Set values by providing the target thogit’s ID:

{
"assignee": "01JQXYZ000PERSON00000ALICE",
"project": "01JQXYZ000PROJECT0000API"
}

When you update a tag’s fields (add, rename, or remove fields), the schema_version increments automatically. Existing thogits keep their old version and field values until explicitly updated.

This means:

  • Adding a field is always safe. Existing thogits just won’t have the new field yet.
  • Removing a field doesn’t delete data. Old thogits retain their values under the previous version.
  • Changing a field type creates a new version. Existing data stays valid under the old schema.

Use the get_outdated_thogit_tags MCP tool (or check schema_version on thogit tags) to find thogits that are behind the current schema version.

Complete example: project management system

Section titled “Complete example: project management system”

Here is a full schema design for a project management system with four interconnected tags.

  1. Terminal window
    curl -X POST https://app.thogits.com/api/tags \
    -H "Content-Type: application/json" \
    -b cookies.txt -c cookies.txt \
    -d '{
    "name": "Person",
    "fields": {
    "department": {
    "type": "Select",
    "variants": [
    "Engineering",
    "Design",
    "Product",
    "Marketing"
    ]
    },
    "role": "String"
    }
    }'
  2. The lead field is a Reference to a Person thogit.

    Terminal window
    curl -X POST https://app.thogits.com/api/tags \
    -H "Content-Type: application/json" \
    -b cookies.txt -c cookies.txt \
    -d '{
    "name": "Project",
    "fields": {
    "name": "String",
    "lead": "Reference",
    "status": {
    "type": "Select",
    "variants": [
    "Planning",
    "Active",
    "Paused",
    "Complete"
    ]
    },
    "start_date": "Date",
    "target_date": "Date"
    }
    }'
  3. Terminal window
    curl -X POST https://app.thogits.com/api/tags \
    -H "Content-Type: application/json" \
    -b cookies.txt -c cookies.txt \
    -d '{
    "name": "Sprint",
    "fields": {
    "project": "Reference",
    "number": "Number",
    "start_date": "Date",
    "end_date": "Date",
    "goal": "String"
    }
    }'
  4. References assignee (Person), project (Project), and sprint (Sprint).

    Terminal window
    curl -X POST https://app.thogits.com/api/tags \
    -H "Content-Type: application/json" \
    -b cookies.txt -c cookies.txt \
    -d '{
    "name": "Task",
    "fields": {
    "status": {
    "type": "Select",
    "variants": [
    "Backlog",
    "Todo",
    "In Progress",
    {"name": "Blocked", "fields": {"blocked_reason": "String"}},
    "In Review",
    "Done"
    ]
    },
    "priority": "Number",
    "story_points": "Number",
    "due_date": "Date",
    "assignee": "Reference",
    "project": "Reference",
    "sprint": "Reference",
    "labels": {
    "type": "MultiSelect",
    "variants": ["Bug", "Feature", "Tech Debt", "Frontend", "Backend", "Infra"]
    }
    }
    }'
  5. Create a person, a project referencing that person, and a task referencing both.

    Terminal window
    # Create a person
    curl -X POST https://app.thogits.com/api/thogits \
    -H "Content-Type: application/json" \
    -b cookies.txt -c cookies.txt \
    -d '{
    "name": "Alice Chen",
    "tags": [{
    "tag_ref": {"Existing": "PERSON_TAG_ID"},
    "field_values": {
    "department": {"variant": "Engineering"},
    "role": "Tech Lead"
    }
    }]
    }'
    # Create a project with Alice as lead
    curl -X POST https://app.thogits.com/api/thogits \
    -H "Content-Type: application/json" \
    -b cookies.txt -c cookies.txt \
    -d '{
    "name": "API Redesign",
    "tags": [{
    "tag_ref": {"Existing": "PROJECT_TAG_ID"},
    "field_values": {
    "name": "API Redesign",
    "lead": "ALICE_THOGIT_ID",
    "status": {"variant": "Active"},
    "start_date": "2026-04-01",
    "target_date": "2026-06-30"
    }
    }]
    }'
    # Create a task on that project assigned to Alice
    curl -X POST https://app.thogits.com/api/thogits \
    -H "Content-Type: application/json" \
    -b cookies.txt -c cookies.txt \
    -d '{
    "name": "Design new endpoint schema",
    "tags": [{
    "tag_ref": {"Existing": "TASK_TAG_ID"},
    "field_values": {
    "status": {"variant": "In Progress"},
    "priority": 1,
    "story_points": 5,
    "due_date": "2026-04-15",
    "assignee": "ALICE_THOGIT_ID",
    "project": "PROJECT_THOGIT_ID",
    "labels": ["Feature", "Backend"]
    }
    }]
    }'

With this structure in place, you can write powerful queries like “all high-priority tasks on active projects led by someone in Engineering” using reference traversal:

{
"and": [
{"has_tag": "Task"},
{"Task.priority": {"lte": 2}},
{"Task.project->Project.status": {"match": "Active"}},
{"Task.project->Project.lead->Person.department": {"match": "Engineering"}}
]
}