Claude
Skills
Sign in
Back

issue-update

Included with Lifetime
$97 forever

Update existing ticket/issue with status changes, comments, or field updates

General

What this skill does


<!-- AIWG-SKILL-CALLOUT -->
> **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 "<capability>"
> aiwg show skill <name>
> ```
>
> 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 Update

## Purpose

Update an existing ticket/issue with status transitions, progress comments, assignee changes, or metadata updates. Automatically uses the configured ticketing provider (Gitea, GitHub, Jira, Linear) or local file-based tracking.

## Task

Given a ticket ID and update parameters:

1. **Load configuration** from `.aiwg/config.yaml` or project `CLAUDE.md`
2. **Validate ticket exists** on provider or in local files
3. **Apply updates** (status, comment, assignee, labels, priority)
4. **Return confirmation** with updated ticket details

## Parameters

- **`<ticket-id>`** (required): Issue identifier (e.g., `ISSUE-001`, `#42`, `PROJECT-123`, `ENG-456`)
- **`--status STATE`** (optional): Update ticket status
  - Valid states: `open`, `in_progress`, `closed`, `blocked`, `review`
  - Provider-specific mappings applied automatically
- **`--comment "text"`** (optional): Add progress comment or note
- **`--assignee USER`** (optional): Assign to user (or `unassigned` to clear)
- **`--labels "label1,label2"`** (optional): Replace labels (comma-separated)
- **`--add-labels "label1,label2"`** (optional): Add labels without replacing existing
- **`--remove-labels "label1,label2"`** (optional): Remove specific labels
- **`--priority LEVEL`** (optional): Update priority (low|medium|high|critical)
- **`--milestone NAME`** (optional): Associate with milestone (provider-dependent)
- **`--provider NAME`** (optional): Override configured provider

## Inputs

**Configuration sources** (same as `issue-create`):
1. `.aiwg/config.yaml` - Project-level configuration
2. `CLAUDE.md` - User-level configuration
3. Default: `local` provider

## Outputs

**All Providers**:
- Confirmation of update
- Updated ticket details
- URL or file path to view changes

## Workflow

### Step 1: Parse Parameters

Extract from command invocation:

```bash
# Update status
/issue-update ISSUE-001 --status in_progress

# Add comment
/issue-update ISSUE-001 --comment "Completed authentication module, working on authorization next"

# Update status with comment
/issue-update ISSUE-001 --status closed --comment "Fixed in commit abc123"

# Assign ticket
/issue-update ISSUE-001 --assignee johndoe

# Update multiple fields
/issue-update ISSUE-001 --status in_progress --assignee johndoe --priority high --comment "Started implementation"

# Add labels without replacing
/issue-update ISSUE-001 --add-labels "urgent,needs-review"

# Remove labels
/issue-update ISSUE-001 --remove-labels "wip,blocked"

# Replace all labels
/issue-update ISSUE-001 --labels "completed,tested"
```

**Parameter extraction**:
- Issue ID: First argument (required)
- Flags: Parse `--flag value` pairs
- At least one update flag required (status, comment, assignee, labels, priority)

### Step 2: Load Configuration

Same as `issue-create` command:

1. Check `.aiwg/config.yaml`
2. Fallback to `CLAUDE.md`
3. Default to `local` provider

Override with `--provider` if specified.

### Step 3: Validate Issue Exists

**Gitea**:
```bash
# Fetch issue to verify existence
curl -s -H "Authorization: token $(cat ~/.config/gitea/token)" \
  "${URL}/api/v1/repos/${OWNER}/${REPO}/issues/${TICKET_NUM}"

# Check HTTP status: 200 = exists, 404 = not found
```

**GitHub**:
```bash
# Fetch issue via gh CLI
gh issue view "${TICKET_NUM}" --repo "${OWNER}/${REPO}"

# Exit code 0 = exists, non-zero = not found
```

**Jira**:
```bash
# Fetch issue via REST API
curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
  "${JIRA_URL}/rest/api/3/issue/${ISSUE_KEY}"

# Check HTTP status: 200 = exists, 404 = not found
```

**Linear**:
```bash
# Fetch issue via GraphQL
curl -s -X POST https://api.linear.app/graphql \
  -H "Authorization: ${LINEAR_API_TOKEN}" \
  -d '{"query": "query { issue(id: \"'${ISSUE_ID}'\") { id identifier title } }"}'

# Check if issue returned in response
```

**Local**:
```bash
# Check if file exists
if [ -f ".aiwg/issues/${TICKET_ID}.md" ]; then
  echo "Issue exists"
else
  echo "Issue not found"
fi
```

**Error if not found**:
```
❌ Issue not found: ISSUE-001

Available tickets:
- ISSUE-002: Add dark mode
- ISSUE-003: Fix navigation bug

List all tickets: /issue-list
```

### Step 4: Map Status to Provider-Specific Values

**Status mapping table**:

| Generic | Gitea | GitHub | Jira | Linear | Local |
|---------|-------|--------|------|--------|-------|
| `open` | open | open | To Do | Backlog | open |
| `in_progress` | open | open | In Progress | In Progress | in_progress |
| `closed` | closed | closed | Done | Done | closed |
| `blocked` | open | open | Blocked | Blocked | blocked |
| `review` | open | open | In Review | In Review | review |

**Implementation**:
```bash
case "${PROVIDER}" in
  gitea|github)
    case "${STATUS}" in
      closed) PROVIDER_STATUS="closed" ;;
      *) PROVIDER_STATUS="open" ;;
    esac
    ;;
  jira)
    case "${STATUS}" in
      open) PROVIDER_STATUS="To Do" ;;
      in_progress) PROVIDER_STATUS="In Progress" ;;
      closed) PROVIDER_STATUS="Done" ;;
      blocked) PROVIDER_STATUS="Blocked" ;;
      review) PROVIDER_STATUS="In Review" ;;
    esac
    ;;
  linear)
    case "${STATUS}" in
      open) PROVIDER_STATUS="Backlog" ;;
      in_progress) PROVIDER_STATUS="In Progress" ;;
      closed) PROVIDER_STATUS="Done" ;;
      blocked) PROVIDER_STATUS="Blocked" ;;
      review) PROVIDER_STATUS="In Review" ;;
    esac
    ;;
  local)
    PROVIDER_STATUS="${STATUS}"
    ;;
esac
```

**Note**: Gitea and GitHub don't have separate "in_progress" state - use labels instead (e.g., add "in-progress" label when status changes to `in_progress`)

### Step 5: Update Issue (Provider-Specific)

#### Gitea

Use MCP tools `mcp__gitea__edit_issue` and `mcp__gitea__create_issue_comment`:

**Edit issue metadata**:
```bash
# Update status (state)
# Use mcp__gitea__edit_issue
# Parameters:
#   owner: ${OWNER}
#   repo: ${REPO}
#   issue_number: ${TICKET_NUM}
#   state: "open" | "closed"
#   assignee: ${ASSIGNEE} (optional)
#   labels: [${LABELS}] (optional)
```

**Add comment**:
```bash
# Use mcp__gitea__create_issue_comment
# Parameters:
#   owner: ${OWNER}
#   repo: ${REPO}
#   issue_number: ${TICKET_NUM}
#   body: ${COMMENT}
```

**Combined workflow**:
1. If status/assignee/labels specified → use `mcp__gitea__edit_issue`
2. If comment specified → use `mcp__gitea__create_issue_comment`
3. Both can be called in sequence if needed

#### GitHub

Use `gh` CLI:

**Update status**:
```bash
# Open issue
gh issue reopen "${TICKET_NUM}" --repo "${OWNER}/${REPO}"

# Close issue
gh issue close "${TICKET_NUM}" --repo "${OWNER}/${REPO}"
```

**Add comment**:
```bash
gh issue comment "${TICKET_NUM}" \
  --repo "${OWNER}/${REPO}" \
  --body "${COMMENT}"
```

**Update assignee**:
```bash
# Assign
gh issue edit "${TICKET_NUM}" \
  --repo "${OWNER}/${REPO}" \
  --add-assignee "${ASSIGNEE}"

# Unassign
gh issue edit "${TICKET_NUM}" \
  --repo "${OWNER}/${REPO}" \
  --remove-assignee "${ASSIGNEE}"
```

**Update labels**:
```bash
# Add labels
gh issue edit "${TICKET_NUM}" \
  --repo "${OWNER}/${REPO}" \
  --add-label "label1,label2"

# Remove labels
gh issue edit "${TICKET_NUM}" \
  --repo "${OWNER}/${REPO}" \
  --remove-label "label1,label2"
```

#### Jira

Use Jira REST API v3:

**Update issue fields**:
```bash
cat > /tmp/jira-update.json <<EOF
{
  "fields": {
    "status": {
      "name": "${PROVIDER_STATUS}"
    },
    "assignee": {
      "name": "${ASSIGNEE}"
    },

Related in General