Board View
The board view displays tasks in a column layout, giving an intuitive picture of each task's current status. You can change task status by dragging and dropping cards, without opening the task detail page.
Entering the Board Page
After starting the Web interface, click the "Board" tab in the top navigation bar to enter the board view. The page shows columns grouped by task status by default.
Asynchronous Loading Indicator
The board page uses a bind-first startup: the browser UI immediately shows a skeleton screen and loading-stage text (such as scanning tasks, building index), then renders real content after Core corpus initialization finishes in the background. If an error occurs during initialization, the page shows a retryable error panel; clicking it reloads. The sidebar stays mounted during loading; only the task count is in a loading state.
Hide Empty Status Columns
When a project uses 5+ statuses but most tasks are concentrated in a few, the board can become cluttered with empty columns. You can enable Hide empty status columns in the settings panel (or via hide_empty_columns in config.yml): after enabling, status columns that currently have no tasks are automatically hidden, so the board only shows columns with at least one task.
All status columns remain visible while dragging a task so it can be dropped into any target column. Empty columns are hidden again after the drag ends.
Drag-and-Drop to Change Task Status
The board page groups tasks by status. Common columns include:
- Todo — tasks to do
- In Progress — tasks in progress
- Done — completed tasks
Hover over a task card, hold the left mouse button, drag it to the target status column, and release. The task status is updated automatically, and the change is synced to the corresponding Markdown file in real time.
During dragging, the target column highlights to show the drop area.
Drag-and-Drop Behavior Details
- Preserves column order: if the current column has been manually sorted (for example by ID descending), the visual order stays stable during the drag and does not reorder under the cursor.
- Precise cross-column placement: when dropping a task into the target column, you can place it between any two existing cards. The system inserts the task at the visual position where you release the mouse, rather than simply appending it to the end.
- Cross-column sort recovery: after a task is placed across columns, the target column's manual sort is automatically cleared and restored to default ordinal ordering, ensuring the new task appears in the right place.
Milestone Swimlanes
If the project has milestones, the board page supports swimlanes grouped by milestone. Find the milestone filter or view-toggle control at the top of the page and click "Group by milestone".
Each milestone expands into a horizontal swimlane, with tasks inside the swimlane grouped by status columns. This view makes it easy to track the progress of a specific milestone.
Label Filtering
A label filter dropdown is provided at the top of the page. Click the dropdown, check the labels you want to filter by, and the board will show only tasks that have any of the selected labels.
- Supports multi-select labels; a task only needs to match one selected label to be shown.
- Uncheck labels or click "Clear filters" to restore the full task list.
Custom Label Colors
Each label has a small colored square (color swatch) on the right; click it to open a color picker and set a custom color for the label.
- Preset palette: 17 preset colors that adapt automatically to light/dark mode.
- Persistence: non-default color configurations are saved to the
label_colorsfield inbacklog/config.ymland remain effective after restarting the service. - Restore default: choose "Default" and save to revert to the system default gray.
- Card rendering: labels on board task cards show the configured background color; unconfigured labels keep the default gray.
Label color configuration is stored per project; different projects can have different label color schemes.
Task Card Labels
Each task card bottom shows that task's label list.
- Width adaptation: the card dynamically calculates how many labels fit in the available width, showing as many as possible; extras are collapsed as
+N. - Real-time response: when the window or sidebar width is adjusted, the number of displayed labels is recalculated automatically.
- Label colors: labels with custom colors are shown with the corresponding background color.
Task Card Acceptance Criteria Progress
For tasks in In Progress that contain acceptance criteria (AC), the card title row shows a rounded progress bar and a checked/total count (such as 2/4). The progress bar and task ID are laid out in the same flex row:
- Progress is calculated live from acceptance criteria and is not persisted as a separate field.
- Tasks without acceptance criteria show no progress indicator.
- After all acceptance criteria are checked, the task remains in In Progress and must be dragged to the Done column to complete.
- The progress bar uses emerald fill with a gray track; contrast against the card background is guaranteed in both light and dark themes.
The task list view shows the same progress indicator in the title column (a fixed 80px-wide progress bar for consistent row height).
Show Completed Tasks
The filter bar in both board and task list provides a "Show completed" checkbox:
- When checked, completed records in
backlog/completed/are shown alongside active tasks through the same filtering, sorting, and grouping pipeline; cards and list rows are marked with a "Completed" badge. - The checked state is synced to the address bar (
completed=1), so it can be shared via links and survives refresh. It counts as an active filter, so "Clear filters" also unchecks it. - Completed cards cannot be dragged (status cannot be written back to the completed directory). Clicking them opens a read-only popup: it shows all content but provides no edit, status-change, or other action buttons, and a read-only notice is shown below the title bar.
- When unchecked, no additional query overhead is incurred.
Multi-Select and Bulk Drag
The board supports moving multiple cards at once:
- Multi-select:
Ctrl/Cmd + clicktoggles the selected state of a single card;Shift + clickselects a range. After selecting, a selection toolbar appears at the top showing the count and a clear button. - Bulk drag: dragging any selected card moves the whole group; the drag ghost badge shows the actual number of cards being moved. Holding
Ctrl/Cmdwhile starting a drag on an unselected card adds it to the current selection. - Precise insertion: bulk placement supports inserting at any position between two cards in the target column; the drop order is submitted in board reading order. If the target column is in manual sort mode, it automatically reverts to default ordering on drop to ensure correct placement.
- Cross-branch cards do not participate in bulk writes; releasing on the original spot is a no-op and does not send a request.
Column Sorting
Each column has a "⋮" column action button in the upper-right corner; clicking it opens a sort menu:
Local Sort (6 Options)
The top half of the menu provides six display-only sort options:
- ID ↑ / ID ↓: sort by task ID ascending/descending
- Title ↑ / Title ↓: sort by task title alphabetically ascending/descending
- Priority ↑ / Priority ↓: sort by priority ascending/descending
Local sorting only affects the display order of the current board column and is not saved to the backend. When the menu is reopened, the active sort item is highlighted with a dark background and an × button appears on the right; click it to clear the sort and restore the original ordinal order.
Dragging a task card or executing "Apply Priority Order" below automatically clears local sorting.
Sort by Creation Date
In addition to local sorting, the column menu provides a Sort by creation date action (ascending/descending). The system compares each task's createdDate field using parseStoredUtcDate; tasks with missing or invalid dates are placed at the end, with task ID as tie-breaker. This sort applies to the current column, just like priority sorting.
Column Menu for Cross-Branch Tasks
When a column contains tasks from other branches (cross-branch tasks), the column action menu is still visible but some actions are restricted:
- Local sort options (ID / title / priority) still work, because they only affect view order and do not modify any persisted data.
- The Apply Priority Order button is hidden, because that operation modifies the
ordinalfield of all tasks in the current column, and cross-branch tasks should not be affected by the current branch's sort operation.
Cross-branch tasks show a branch-source indicator on the card. When all tasks in the column belong to the current branch, Apply Priority Order is shown normally.
Reorder by Priority (Save)
The bottom of the menu (separated by a divider) provides the "Reorder by priority (save)" option:
- One-click reorder all tasks in the current column by priority (high → medium → low).
- The new order is saved to the backend and persists after refreshing the page.
- The icon is a list with an up arrow, indicating a persistent operation.
Task Card Date Indicators
Each task card on the board shows date information when set:
- Header: calendar icon +
plannedStart ~ plannedEndplanned date range. The year is omitted when it matches the current year to reduce visual noise. - Footer: clock icon +
dueDatedue date, shown next to the relative creation time. - Completion time: cards in a terminal status (such as Done) with an
actualEndshow the actual completion time in local time (M/D HH:mm, full year if across years; hover shows the stored UTC value) to the right of the assignee in the footer. - Overdue highlight: when a task is not in a terminal status (Done / Cancelled) and the due date has passed,
dueDateis highlighted in red (text-red-600 dark:text-red-400 font-semibold).
Opening Task Details
Click any task card on the board to open the task detail modal:
- The underlying board page stays visible, and the address bar updates to
/task/:id/:title. - Supports dependency drill-down navigation: clicking a dependency tag in the task detail opens the subtask details.
- The task detail includes a Comments area for viewing and adding comments (in edit mode).
- Acceptance criteria (AC) list items show sequence numbers (
#1,#2...) for easy reference and communication. - Closing the modal returns you to the original board view, preserving the current label filters and column sort state.
- When accessing
/task/:iddirectly, the system opens the corresponding task with the board as the background.
Task cards on the board do not support both drag and click at the same time; once you start dragging, releasing the mouse completes the status change and will not accidentally open task details.
Task Detail Keyboard Shortcuts
After opening task details, these shortcuts enable quick actions:
| Key | Action |
|---|---|
e / E |
Enter edit mode |
c |
Change status |
d |
Delete task |
p |
|
Escape |
Close modal / cancel editing |
Cmd/Ctrl + S |
Save changes |
When focus is inside an editable element such as input, textarea, select, or contenteditable, preview-state shortcuts (e/E/c/d/p) are suppressed so they do not intercept normal text input. Edit-state Escape and Cmd/Ctrl + S still work inside editable targets.
Real-Time Updates
The board view supports real-time sync in multi-user collaboration scenarios:
- When other users drag tasks in the Web interface, your page updates card positions automatically.
- After task files are modified in an external editor, card content and status in the board columns refresh automatically.
- After tasks are created or deleted, the board reflects the change immediately without manual refresh.
- Changes to milestones, documents, decisions, and Wiki are also broadcast by type via WebSocket, and the corresponding lists refresh incrementally in place.
Refresh uses an in-place reconcile strategy: unchanged data keeps its original object reference; open pages, scroll positions, and filter states are not affected by broadcasts. Full-page reload is only used for first load, configuration changes, or when incremental refresh fails.