epic_list
List epics for any project. Filter by status, priority, or git branch—auto-detect active branch or show only branch-agnostic epics. Includes task counts and completion statistics.
Instructions
List epics for a project with task counts and completion stats. Optionally filter by status, priority, or branch. Pass branch="current" to auto-detect the active git branch; pass empty string to list only branch-agnostic epics.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | Project ID | |
| status | No | ||
| priority | No | ||
| branch | No | Filter by git branch. Pass "current" to auto-detect; pass empty string to list only branch-agnostic epics. Omit to list all. |
Implementation Reference
- src/tools/epics.ts:107-148 (handler)The main handler function for the 'epic_list' tool. Builds a dynamic SQL query with LEFT JOIN on tasks to compute task_count, done_count, blocked_count, and completion_pct, filtering by project_id, status, priority, and branch (with support for 'current' auto-detection via resolveBranch).
function handleEpicList(args: Record<string, unknown>) { const db = getDb(); const projectId = args.project_id as number; const status = args.status as string | undefined; const priority = args.priority as string | undefined; const branchFilter = resolveBranch(args.branch); const whereClauses = ['e.project_id = ?']; const params: unknown[] = [projectId]; if (status) { whereClauses.push('e.status = ?'); params.push(status); } if (priority) { whereClauses.push('e.priority = ?'); params.push(priority); } if (branchFilter === null) { whereClauses.push('e.branch IS NULL'); } else if (branchFilter !== undefined) { whereClauses.push('e.branch = ?'); params.push(branchFilter); } const sql = ` SELECT e.*, COUNT(t.id) as task_count, SUM(CASE WHEN t.status = 'done' THEN 1 ELSE 0 END) as done_count, SUM(CASE WHEN t.status = 'blocked' THEN 1 ELSE 0 END) as blocked_count, CASE WHEN COUNT(t.id) > 0 THEN ROUND(SUM(CASE WHEN t.status = 'done' THEN 1 ELSE 0 END) * 100.0 / COUNT(t.id), 1) ELSE 0 END as completion_pct FROM epics e LEFT JOIN tasks t ON t.epic_id = e.id WHERE ${whereClauses.join(' AND ')} GROUP BY e.id ORDER BY e.sort_order, e.created_at `; return db.prepare(sql).all(...params); } - src/tools/epics.ts:39-57 (schema)Schema definition for epic_list: registers the tool with name 'epic_list', provides description, and defines inputSchema requiring project_id with optional filters for status, priority, and branch.
{ name: 'epic_list', description: 'List epics for a project with task counts and completion stats. Optionally filter by status, priority, or branch. Pass branch="current" to auto-detect the active git branch; pass empty string to list only branch-agnostic epics.', annotations: { title: 'List Epics', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }, inputSchema: { type: 'object', properties: { project_id: { type: 'integer', description: 'Project ID' }, status: { type: 'string', enum: ['planned', 'in_progress', 'completed', 'cancelled'] }, priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] }, branch: { type: 'string', description: 'Filter by git branch. Pass "current" to auto-detect; pass empty string to list only branch-agnostic epics. Omit to list all.', }, }, required: ['project_id'], }, }, - src/tools/epics.ts:175-179 (registration)Registration of epic_list handler in the handlers export map, mapping the string 'epic_list' to the handleEpicList function.
export const handlers: Record<string, ToolHandler> = { epic_create: handleEpicCreate, epic_list: handleEpicList, epic_update: handleEpicUpdate, }; - src/helpers/git.ts:26-32 (helper)The resolveBranch helper used by handleEpicList to resolve the 'branch' argument. Returns null for empty string (branch-agnostic), undefined if omitted, the current git branch for 'current', or the literal string value.
export function resolveBranch(input: unknown): string | null | undefined { if (input === undefined) return undefined; if (input === null || input === '') return null; if (typeof input !== 'string') return undefined; if (input === 'current') return getCurrentBranch(); return input; }