Core Concepts
Tack is built around seven primitives. They are deliberately minimal. If you have used a Kanban board, you already understand the model.
Workspaces
A Workspace is the top-level container. It represents a team, an organization, or a customer in a multi-tenant product. Every Project, Label, and piece of Activity lives inside exactly one Workspace.
Workspaces are fully isolated from each other at the database level. Data from one Workspace is invisible to another, even if they share the same API key. In multi-tenant setups, each Workspace maps to a Heimdall App for authentication.
Key properties
id- Unique identifier (prefixed withws_)name- URL-safe slug, unique across the accountdisplay_name- Human-readable labelmetadata- Arbitrary JSON for your application-specific datacreated_at- ISO 8601 timestamp
Projects
A Project is a named board within a Workspace. It contains Lists and Cards. Think of it as a single Kanban board dedicated to a particular initiative, team, or product area.
Projects can be created with a set of initial Lists, or you can add Lists later. A Workspace can contain any number of Projects, and each Project operates independently.
Key properties
id- Unique identifier (prefixed withproj_)workspace_id- Parent Workspacename- URL-safe slug, unique within the Workspacedisplay_name- Human-readable labelstatus- active or archivedmetadata- Arbitrary JSON
Lists
A List is a column within a Project. Lists have a position that determines their left-to-right ordering on a board. Cards live inside Lists.
Common patterns include "Backlog → In Progress → Review → Done" or "To Do → Doing → Done". Tack does not enforce any particular workflow. You define the columns that match how your team works.
Key properties
id- Unique identifier (prefixed withlist_)project_id- Parent Projectname- URL-safe slug, unique within the Projectdisplay_name- Human-readable labelposition- Integer position (0-based)
Cards
A Card is the fundamental unit of work. It lives in a List, has a title and a markdown-formatted body, and can carry assignees, labels, a priority level, and a due date.
Cards are ordered within their List by a position field. When you move a card between lists or reorder it within a list, Tack handles the position arithmetic. You can also batch-move multiple cards in a single API call.
Key properties
id- Unique identifier (prefixed withcard_)project_id- Parent Projectlist_id- Current Listtitle- Short summary of the work itembody- Markdown-formatted descriptionpriority- One of: critical, high, medium, low, noneposition- Integer position within the Listassignees- Array of user IDslabels- Array of label namesdue_at- Optional ISO 8601 deadlinecompleted_at- Set when the card is marked completemetadata- Arbitrary JSON for your domain data
Priority levels
"critical" — Production issues, blockers
"high" — Important work for the current cycle
"medium" — Default for most cards
"low" — Nice-to-have, backlog items
"none" — UnclassifiedLabels
Labels are workspace-level tags that you apply to Cards for categorization and filtering. Each label has a name and an optional hex color. A Card can carry any number of labels.
Because labels are scoped to the Workspace (not the Project), you can use consistent categories across all your boards. Filter cards by label to see all "backend" work across every project, or combine label and priority filters for a focused view.
Key properties
id- Unique identifier (prefixed withlbl_)workspace_id- Parent Workspacename- URL-safe slug, unique within the Workspacecolor- Hex color code (e.g., #3b82f6)
Comments
Every Card supports a threaded comment stream. Comments are markdown-formatted and carry the author's user ID and a timestamp. Humans leave context, AI agents post status updates, and CI pipelines report results.
Comments are append-only within the API (you can add, but not edit or delete). This keeps the conversation as a reliable log that both humans and machines can trust.
Key properties
id- Unique identifier (prefixed withcmt_)card_id- Parent Cardauthor_id- User or service that posted the commentbody- Markdown-formatted comment textcreated_at- ISO 8601 timestamp
Activity
Every state-changing operation in Tack produces an Activity entry. This includes card creation, moves between lists, field updates, label changes, assignments, and comments. The activity feed is immutable and queryable at the project or card level.
The activity feed is designed to serve as context for LLM agents. An agent can read the recent activity for a project and understand what happened without parsing a UI. It is also useful for building change logs, audit trails, and notification systems.
Example activity entry
{
"id": "act_01HQ3...",
"project_id": "proj_01HQ3...",
"card_id": "card_01HQ3...",
"actor_id": "usr_01HQ3...",
"action": "card.moved",
"changes": {
"list_id": {
"from": "list_01HQ3A...",
"to": "list_01HQ3B..."
},
"position": {
"from": 2,
"to": 0
}
},
"timestamp": "2026-02-20T10:05:00Z"
}Action types
card.created
card.updated
card.moved
card.completed
card.archived
card.assigned
card.unassigned
card.labeled
card.unlabeled
comment.addedHow it all fits together
Account (your ProductCraft account)
└── Workspace (team / org / customer)
├── Projects
│ ├── Lists (ordered columns)
│ │ └── Cards (units of work)
│ │ ├── Comments
│ │ └── Activity entries
│ └── Project-level Activity feed
└── Labels (shared across projects)