← Tack Docs

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 with ws_)
  • name - URL-safe slug, unique across the account
  • display_name - Human-readable label
  • metadata - Arbitrary JSON for your application-specific data
  • created_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 with proj_)
  • workspace_id - Parent Workspace
  • name - URL-safe slug, unique within the Workspace
  • display_name - Human-readable label
  • status - active or archived
  • metadata - 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 with list_)
  • project_id - Parent Project
  • name - URL-safe slug, unique within the Project
  • display_name - Human-readable label
  • position - 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 with card_)
  • project_id - Parent Project
  • list_id - Current List
  • title - Short summary of the work item
  • body - Markdown-formatted description
  • priority - One of: critical, high, medium, low, none
  • position - Integer position within the List
  • assignees - Array of user IDs
  • labels - Array of label names
  • due_at - Optional ISO 8601 deadline
  • completed_at - Set when the card is marked complete
  • metadata - 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"      — Unclassified

Labels

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 with lbl_)
  • workspace_id - Parent Workspace
  • name - URL-safe slug, unique within the Workspace
  • color - 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 with cmt_)
  • card_id - Parent Card
  • author_id - User or service that posted the comment
  • body - Markdown-formatted comment text
  • created_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.added

How 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)