Skip to content

Boards and Sub-Boards

Relevant source files

The following files were used as context for generating this wiki page:

This document explains the structure and organization of Kanban boards in KanStack, including columns, sections, sub-board hierarchies, and the discovery mechanism. For information about the workspace-level TODO/ directory structure, see Workspaces and TODO/ Structure. For details on individual card structure and content, see Cards. For the markdown syntax conventions used in board files, see Markdown Format.

Overview

A board in KanStack is represented by a single markdown file (todo.md) within a TODO/ directory. Each board organizes cards into columns and optional sections, and can reference child boards to create hierarchical project structures. Boards are identified by their filesystem path rather than their title, allowing boards to be renamed without breaking relationships.

Board File Structure

File Location and Identity

Every board exists as a TODO/todo.md file within its own project directory. The board's identity is derived from the normalized path to its TODO/ directory, not from its filename or title.

project-name/
├── TODO/
│   ├── todo.md          # Board definition file
│   ├── cards/           # Local card files
│   └── README.md        # Optional board notes
└── ...

Sources: docs/plans/2026-03-12-cross-workspace-boards-design.md:8-13, docs/plans/2026-03-10-markdown-kanban-design.md:8-12

Board Identity Functions

The boardIdFromBoardPath function converts a board file path to its stable identity:

src/utils/kanbanPath.ts:88-90

The boardTodoPathFromBoardPath function extracts the TODO/ directory path:

src/utils/kanbanPath.ts:84-86

Sources: src/utils/kanbanPath.ts:84-90

Board Structure Components

Columns

Columns are the primary organizational units of a board, defined using ## headings in the markdown file. Each column can contain cards directly or organize them into sections.

## Backlog
## In Progress
## Review
## Done

The parser represents columns using the KanbanBoardColumn type, which includes a name, slug, and array of sections:

typescript
interface KanbanBoardColumn {
  name: string
  slug: string
  sections: KanbanBoardSection[]
}

Sources: docs/plans/2026-03-10-markdown-kanban-design.md:15-20, TODO/todo.md:25-41

Sections

Sections are optional subdivisions within columns, defined using ### headings. They provide additional organization for grouping related cards within a column.

Board Markdown Structure Diagram

Sources: docs/plans/2026-03-10-markdown-kanban-design.md:26-32, src/utils/boardMarkdown.test.ts:18-40

Example with sections:

## Todo

### High Priority
- [[cards/critical-bug]]

### Routine
- [[cards/minor-fix]]

The parser preserves sections throughout operations. The DEFAULT_SECTION_KEY constant ("__default__") is used internally for cards not under an explicit section:

src/utils/kanbanPath.ts:7

Sources: src/utils/kanbanPath.ts:7, src/utils/boardMarkdown.test.ts:42-82

Archive Column

Boards can have a special Archive column for storing completed or deprioritized cards. The archive column is automatically created when archiving a card if it doesn't exist, and is always placed last in column order:

src/utils/boardMarkdown.test.ts:84-105

Sources: src/utils/boardMarkdown.test.ts:84-105, src/utils/boardMarkdown.test.ts:180-194

Settings Block

Boards can include a settings block to store preferences and view state. Settings are stored in a special comment block using Obsidian-style syntax with a JSON payload:

%% kanban:settings
```json
{
  "sort-order": "manual",
  "group-by": "none",
  "show-empty-columns": true,
  "card-preview": "metadata",
  "show-sub-boards": false,
  "show-archive-column": false
}

%%


**Sources:** [docs/plans/2026-03-10-markdown-kanban-design.md:34-40](../docs/plans/2026-03-10-markdown-kanban-design.md), [TODO/todo.md:5-23](../TODO/todo.md)

## Board Data Types

The `KanbanBoardDocument` type represents a fully parsed board:

```typescript
interface KanbanBoardDocument {
  slug: string              // Path-based identity
  path: string              // File path
  title: string             // Display name
  frontmatter: Record<string, unknown>
  columns: KanbanBoardColumn[]
  subBoards: NormalizedWikiTarget[]
  settings?: Record<string, unknown>
}

Board Data Flow Diagram

Sources: src/types/workspace.ts:31-40

The LoadedWorkspace provides indexed access to boards:

src/types/workspace.ts:31-40

Sources: src/types/workspace.ts:31-40

Sub-Boards

Sub-Board Hierarchy Model

Sub-boards enable hierarchical project organization. A parent board can reference child boards, which can themselves reference their own child boards, creating a tree structure. Each sub-board maintains its own TODO/ directory with local cards and configuration.

Sub-Board Hierarchy Structure

Sources: docs/plans/2026-03-10-markdown-kanban-design.md:51-56, docs/plans/2026-03-12-cross-workspace-boards-design.md:8-13

Sub-Board Markdown Representation

Sub-boards are declared in a special ## Sub Boards section of the parent board. Each sub-board is represented as a bulleted wikilink pointing to the child board's TODO/ directory:

## Sub Boards

- [[services/api/TODO|API Service]]
- [[services/worker/TODO|Worker Service]]

The wikilink target points to the child's TODO/ directory, not directly to todo.md. The optional display text after the | provides a human-readable title.

Sources: docs/plans/2026-03-10-markdown-kanban-design.md:21-23, docs/plans/2026-03-12-cross-workspace-boards-design.md:27-30

Sub-Board Discovery Mechanism

Sub-board discovery is a manual, user-triggered process rather than automatic scanning. The "Find Sub Boards" action scans the filesystem tree for descendant TODO/ directories and persists discovered paths to markdown.

Discovery Process:

  1. User triggers "Find Sub Boards" from system menu
  2. Scanning starts from parent directory of current board's TODO/ folder
  3. Scanner recursively finds descendant directories named TODO
  4. Current board's own TODO/ is excluded from results
  5. Only nearest TODO/ folders are selected (no double-counting nested boards)
  6. Discovered paths are written to ## Sub Boards as relative wikilinks
  7. Workspace reloads from updated markdown

Sub-Board Discovery Flow

Sources: docs/plans/2026-03-12-cross-workspace-boards-design.md:15-23, TODO/cards/cross-workspace-boards.md:32-34

Sub-Board Path Resolution

Sub-board paths are stored as relative paths from the parent board's project directory. The resolveBoardTargetPath function resolves these relative paths to absolute board identities:

src/utils/kanbanPath.ts:111-119

The buildSubBoardTarget function constructs the relative path from parent to child:

src/utils/kanbanPath.ts:127-130

Sources: src/utils/kanbanPath.ts:111-130

Sub-Board Loading Model

When opening a board, the loader:

  1. Loads the selected board's todo.md and local cards/*.md
  2. Resolves ## Sub Boards links relative to the board's project root
  3. Recursively loads child boards and their cards
  4. Builds indexed maps keyed by path-based slugs

Missing child board paths remain visible as unresolved links rather than being silently removed.

Sources: docs/plans/2026-03-12-cross-workspace-boards-design.md:40-45

Board Operations

Column Management

Boards support several column operations, each serialized to markdown and persisted:

OperationFunctionDescription
Add ColumnaddBoardColumnMarkdown()Appends new column before archive
Rename ColumnrenameBoardColumnMarkdown()Updates column heading and slug
Delete ColumndeleteBoardColumnMarkdown()Removes column, orphaning cards
Reorder ColumnsreorderBoardColumnsMarkdown()Rearranges columns in specified order

Sources: src/utils/boardMarkdown.test.ts:157-178

Creating Sub-Boards

Creating a sub-board involves two operations:

  1. Add sub-board link to parent using addSubBoardMarkdown():

src/utils/boardMarkdown.test.ts:120-124

  1. Create child board file using createBoardMarkdown(), which inherits parent column structure:

src/utils/boardMarkdown.test.ts:125

The child board inherits the parent's column structure but starts with empty columns:

src/utils/boardMarkdown.test.ts:130-139

Sources: src/utils/boardMarkdown.test.ts:107-139

Board Renaming

Renaming a board updates only the title field in frontmatter without changing the board's identity or path:

src/utils/boardMarkdown.test.ts:141-155

Sources: src/utils/boardMarkdown.test.ts:141-155

Board Constraints and Rules

Structural Rules

  1. Column Headings: Must use ## for columns, never ### or other levels
  2. Section Headings: Must use ### for sections, only inside columns
  3. Card Links: Must be bulleted wikilinks, one per line
  4. Sub-Board Section: ## Sub Boards is reserved and must not contain ### sections
  5. Archive Position: Archive column always appears last if present

Sources: docs/plans/2026-03-10-markdown-kanban-design.md:14-32

Sub-Board Constraints

  1. Tree Structure: Sub-boards only exist under parent board's filesystem tree
  2. No External Links: Cannot link to arbitrary boards outside the tree
  3. Manual Discovery: Discovery is user-triggered, not automatic
  4. Path-Based Identity: Board identity derives from TODO/ path, not title
  5. Local Cards: Each board's cards live in its own TODO/cards/ directory

Sources: docs/plans/2026-03-12-cross-workspace-boards-design.md:15-23, docs/plans/2026-03-12-cross-workspace-boards-design.md:34-37

Summary Table: Board vs Sub-Board

AspectBoardSub-Board
File LocationTODO/todo.mdchild-dir/TODO/todo.md
IdentityPath to TODO/ directoryPath to child's TODO/ directory
CardsTODO/cards/*.mdchild-dir/TODO/cards/*.md
Parent ReferenceNoneListed in parent's ## Sub Boards
Column StructureDefined by ## headingsInherits parent columns on creation
DiscoveryRoot board opened by userFound via "Find Sub Boards" scan

Sources: docs/plans/2026-03-12-cross-workspace-boards-design.md:8-61