--- namespace: aiwg name: issue-list platforms: [all] description: List and filter tickets/issues from configured backend commandHint: argumentHint: [--status STATE --label LABEL --assignee USER --limit NUM --format table|json|markdown] allowedTools: Read, Write, Glob, Bash model: sonnet category: project-management --- > **Skill access pattern (post-kernel-pivot, 2026.5+)** > > Skill names referenced in this document are AIWG skills, **not slash commands**. Most are not kernel-listed and cannot be invoked as `/skill-name` by the platform. Reach them via: > > ```bash > aiwg discover "" > aiwg show skill > ``` > > Only kernel-listed skills (`aiwg-doctor`, `aiwg-refresh`, `aiwg-status`, `aiwg-help`, `use`, `steward`) are directly invokable as slash commands. See [skill-discovery rule](../../../addons/aiwg-utils/rules/skill-discovery.md). # Issue List ## Purpose List and filter tickets/issues from the configured ticketing provider (Gitea, GitHub, Jira, Linear) or local file-based tracking. Supports filtering by status, labels, assignee, and custom output formats. ## Task Given optional filter parameters: 1. **Load configuration** from `.aiwg/config.yaml` or project `CLAUDE.md` 2. **Fetch tickets** from provider or local files 3. **Apply filters** (status, labels, assignee) 4. **Format output** (table, JSON, or markdown) 5. **Display results** with summary statistics ## Parameters - **`--status STATE`** (optional): Filter by status (open|in_progress|closed|blocked|review|all) - Default: `open` (only show open tickets) - Use `all` to show all tickets regardless of status - **`--label LABEL`** (optional): Filter by label (can specify multiple: `--label bug --label high-priority`) - **`--assignee USER`** (optional): Filter by assignee (use `unassigned` for unassigned tickets) - **`--limit NUM`** (optional): Limit results to NUM tickets (default: 50) - **`--sort FIELD`** (optional): Sort by field (created|updated|priority|id) - Default: `created` (newest first) - **`--format FORMAT`** (optional): Output format (table|json|markdown|compact) - Default: `table` - **`--provider NAME`** (optional): Override configured provider ## Inputs **Configuration sources** (same as `issue-create` and `issue-update`): 1. `.aiwg/config.yaml` - Project-level configuration 2. `CLAUDE.md` - User-level configuration 3. Default: `local` provider ## Outputs **Table Format** (default): ``` ┌──────────┬────────────────────────┬────────────┬──────────┬──────────┬────────────┐ │ ID │ Title │ Status │ Priority │ Assignee │ Labels │ ├──────────┼────────────────────────┼────────────┼──────────┼──────────┼────────────┤ │ ISSUE-1 │ Implement user auth │ in_progress│ high │ johndoe │ feature,ui │ │ ISSUE-2 │ Add dark mode │ open │ medium │ janedoe │ feature │ │ ISSUE-3 │ Fix navigation bug │ closed │ critical │ johndoe │ bug │ └──────────┴────────────────────────┴────────────┴──────────┴──────────┴────────────┘ Summary: 3 tickets (1 open, 1 in_progress, 1 closed) ``` **Compact Format**: ``` ISSUE-1 [in_progress] [high] Implement user auth @johndoe [feature,ui] ISSUE-2 [open] [medium] Add dark mode @janedoe [feature] ISSUE-3 [closed] [critical] Fix navigation bug @johndoe [bug] Summary: 3 tickets (1 open, 1 in_progress, 1 closed) ``` **Markdown Format**: ```markdown # Issues ## ISSUE-1: Implement user auth **Status**: in_progress **Priority**: high **Assignee**: @johndoe **Labels**: feature, ui **Created**: 2026-01-10 **Updated**: 2026-01-13 --- ## ISSUE-2: Add dark mode **Status**: open **Priority**: medium **Assignee**: @janedoe **Labels**: feature **Created**: 2026-01-11 **Updated**: 2026-01-11 --- ## Summary 3 tickets (1 open, 1 in_progress, 1 closed) ``` **JSON Format**: ```json { "tickets": [ { "id": "ISSUE-1", "title": "Implement user auth", "status": "in_progress", "priority": "high", "assignee": "johndoe", "labels": ["feature", "ui"], "created": "2026-01-10", "updated": "2026-01-13", "url": "https://git.integrolabs.net/roctinam/ai-writing-guide/issues/1" }, { "id": "ISSUE-2", "title": "Add dark mode", "status": "open", "priority": "medium", "assignee": "janedoe", "labels": ["feature"], "created": "2026-01-11", "updated": "2026-01-11", "url": "https://git.integrolabs.net/roctinam/ai-writing-guide/issues/2" } ], "summary": { "total": 3, "open": 1, "in_progress": 1, "closed": 1 } } ``` ## Workflow ### Step 1: Parse Parameters Extract from command invocation: ```bash # List all open tickets (default) /issue-list # List all tickets (including closed) /issue-list --status all # Filter by status /issue-list --status in_progress /issue-list --status closed # Filter by label /issue-list --label bug /issue-list --label feature --label high-priority # Filter by assignee /issue-list --assignee johndoe /issue-list --assignee unassigned # Combine filters /issue-list --status open --label bug --assignee johndoe # Limit results /issue-list --limit 10 # Sort by field /issue-list --sort updated /issue-list --sort priority # Change format /issue-list --format compact /issue-list --format json /issue-list --format markdown ``` **Parameter extraction**: - All parameters optional - Default: `--status open --limit 50 --format table --sort created` ### Step 2: Load Configuration Same resolution rules as `issue-create` (preferred path): 1. **`--provider` flag** — explicit override always wins. 2. **`.aiwg/aiwg.config` `remotes.issue_tracker`** (#994) — derive provider via `resolveRemotes()` + `resolveRemoteProvider()` from `src/config/aiwg-config.ts`. 3. **Legacy `.aiwg/config.yaml`** (`ticketing` block) — back-compat. 4. **`CLAUDE.md` "Issueing Configuration"** — fallback. 5. **`local`** — default. When `resolveRemoteProvider(url)` returns `'unknown'` (self-hosted instances), the operator must pass `--provider` explicitly. Don't guess. ### Step 3: Fetch Issues (Provider-Specific) #### Gitea Use Gitea REST API: ```bash # Build query parameters STATE="open" # or "closed" or "all" LABELS="${LABEL:-}" ASSIGNEE="${ASSIGNEE:-}" LIMIT="${LIMIT:-50}" SORT="created" # or "updated" ORDER="desc" # Fetch issues curl -s -H "Authorization: token $(cat ~/.config/gitea/token)" \ "${URL}/api/v1/repos/${OWNER}/${REPO}/issues?state=${STATE}&labels=${LABELS}&assignee=${ASSIGNEE}&limit=${LIMIT}&sort=${SORT}&order=${ORDER}" ``` **Response mapping**: ```json [ { "number": 1, "title": "Implement user auth", "state": "open", "labels": [{"name": "feature"}, {"name": "ui"}], "assignee": {"login": "johndoe"}, "created_at": "2026-01-10T10:00:00Z", "updated_at": "2026-01-13T15:30:00Z", "html_url": "https://git.integrolabs.net/roctinam/ai-writing-guide/issues/1" } ] ``` **Map to internal format**: ```bash ID="ISSUE-${number}" TITLE="${title}" STATUS="${state}" # map to generic status PRIORITY="${extracted from body or labels}" ASSIGNEE="${assignee.login}" LABELS="${labels[].name joined by comma}" CREATED="${created_at}" UPDATED="${updated_at}" URL="${html_url}" ``` #### GitHub Use `gh` CLI: ```bash # Build query STATE="${STATUS:-open}" # or "closed" or "all" LABELS="${LABEL:-}" ASSIGNEE="${ASSIGNEE:-}" LIMIT="${LIMIT:-50}" # Fetch issues gh issue list \ --repo "${OWNER}/${REPO}" \ --state "${STATE}" \ --label "${LABELS}" \ --assignee "${ASSIGNEE}" \ --limit "${LIMIT}" \ --json number,title,state,labels,assignees,createdAt,updatedAt,url ``` **Response mapping**: ```json [ { "number": 42, "title": "Implement user auth", "state": "OPEN", "labels": [{"name": "feature"}, {"name": "ui"}], "assignees": [{"login": "johndoe"}], "createdAt": "2026-01-10T10:00:00Z", "updatedAt": "2026-01-13T15:30:00Z", "url": "https://github.com/jmagly/aiwg/issues/42" } ] ``` **Map to internal format**: ```bash ID="#${number}" TITLE="${title}" STATUS="${state}" # map OPEN → open, CLOSED → closed PRIORITY="${extracted from labels or body}" ASSIGNEE="${assignees[0].login}" LABELS="${labels[].name joined by comma}" CREATED="${createdAt}" UPDATED="${updatedAt}" URL="${url}" ``` #### Jira Use Jira REST API v3: ```bash # Build JQL query JQL="project = ${PROJECT_KEY}" # Add status filter if [ "${STATUS}" != "all" ]; then case "${STATUS}" in open) JQL="${JQL} AND status = 'To Do'" ;; in_progress) JQL="${JQL} AND status = 'In Progress'" ;; closed) JQL="${JQL} AND status = 'Done'" ;; blocked) JQL="${JQL} AND status = 'Blocked'" ;; review) JQL="${JQL} AND status = 'In Review'" ;; esac fi # Add label filter if [ -n "${LABEL}" ]; then JQL="${JQL} AND labels = '${LABEL}'" fi # Add assignee filter if [ -n "${ASSIGNEE}" ]; then if [ "${ASSIGNEE}" = "unassigned" ]; then JQL="${JQL} AND assignee is EMPTY" else JQL="${JQL} AND assignee = '${ASSIGNEE}'" fi fi # Fetch issues curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \ "${JIRA_URL}/rest/api/3/search?jql=${JQL}&maxResults=${LIMIT}&fields=summary,status,priority,assignee,labels,created,updated" ``` **Response mapping**: ```json { "issues": [ { "key": "PROJECT-123", "fields": { "summary": "Implement user auth", "status": {"name": "In Progress"}, "priority": {"name": "High"}, "assignee": {"displayName": "John Doe"}, "labels": ["feature", "ui"], "created": "2026-01-10T10:00:00.000+0000", "updated": "2026-01-13T15:30:00.000+0000" } } ] } ``` **Map to internal format**: ```bash ID="${key}" TITLE="${fields.summary}" STATUS="${fields.status.name}" # map to generic status PRIORITY="${fields.priority.name}" ASSIGNEE="${fields.assignee.displayName}" LABELS="${fields.labels joined by comma}" CREATED="${fields.created}" UPDATED="${fields.updated}" URL="${JIRA_URL}/browse/${key}" ``` #### Linear Use Linear GraphQL API: ```bash # Build GraphQL query cat > /tmp/linear-query.json <