plugins/specweave/skills/jira-mapper/SKILL.md
Expert in mapping SpecWeave increments to JIRA structure (Increment → Epic + Stories + Subtasks) with bidirectional sync. Use when exporting increments to JIRA, importing JIRA epics as increments, or configuring field mapping. Maintains traceability across systems.
npx skillsauth add anton-abyzov/specweave plugins/specweave/skills/jira-mapperInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert in mapping SpecWeave concepts to JIRA and vice versa with precision and traceability.
| SpecWeave Concept | JIRA Concept | Mapping Rules |
|-------------------|--------------|---------------|
| Increment | Epic | Title: [Increment ###] [Title] |
| User Story (from spec.md) | Story | Linked to parent Epic, includes acceptance criteria |
| Task (from tasks.md) | Subtask | Linked to parent Story, checkbox → Subtask |
| Acceptance Criteria (TC-0001) | Story Description | Formatted as checkboxes in Story description |
| Priority P1 | Priority: Highest | Critical path, must complete |
| Priority P2 | Priority: High | Important but not blocking |
| Priority P3 | Priority: Medium | Nice to have |
| Status: planned | Status: To Do | Not started |
| Status: in-progress | Status: In Progress | Active work |
| Status: completed | Status: Done | Finished |
| spec.md | Epic Description | Summary + link to spec (if GitHub repo) |
| JIRA Concept | SpecWeave Concept | Import Rules | |--------------|-------------------|--------------| | Epic | Increment | Auto-number next available (e.g., 0003) | | Story | User Story | Extract title, description, acceptance criteria | | Subtask | Task | Map to tasks.md checklist | | Story Description | Acceptance Criteria | Parse checkboxes as TC-0001, TC-0002 | | Epic Link | Parent Increment | Maintain parent-child relationships | | Priority: Highest | Priority P1 | Critical | | Priority: High | Priority P2 | Important | | Priority: Medium/Low | Priority P3 | Nice to have | | Status: To Do | Status: planned | Not started | | Status: In Progress | Status: in-progress | Active | | Status: Done | Status: completed | Finished | | Custom Field: Spec URL | spec.md link | Cross-reference |
These rules apply to ALL JIRA and Confluence API operations in this skill.
.env only, never prompts the user.env themselves# 1. Validate presence FIRST (before reading any values)
for KEY in JIRA_API_TOKEN JIRA_EMAIL JIRA_DOMAIN; do
if ! grep -qE "^${KEY}=.+" .env; then
echo "Error: ${KEY} missing or empty in .env"
exit 1
fi
done
# 2. Load credentials ONLY after validation passes (never display values)
# head -1 ensures only first match used if .env has duplicate keys
JIRA_API_TOKEN="$(grep '^JIRA_API_TOKEN=' .env | head -1 | cut -d '=' -f2-)"
JIRA_EMAIL="$(grep '^JIRA_EMAIL=' .env | head -1 | cut -d '=' -f2-)"
JIRA_DOMAIN="$(grep '^JIRA_DOMAIN=' .env | head -1 | cut -d '=' -f2-)"
# Reject IP addresses FIRST — IPv4, IPv6 brackets, hex-encoded (SSRF prevention)
if [[ "$JIRA_DOMAIN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ ]] || [[ "$JIRA_DOMAIN" =~ ^\[.*\]$ ]] || [[ "$JIRA_DOMAIN" =~ ^0x ]]; then
echo "Error: IP addresses not allowed — use a hostname"
exit 1
fi
# Reject localhost and private networks
if [[ "$JIRA_DOMAIN" =~ ^(localhost|127\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.) ]]; then
echo "Error: Internal/localhost addresses not allowed"
exit 1
fi
# Must be a valid hostname — no special chars, no consecutive dots
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$ ]]; then
echo "Error: JIRA_DOMAIN contains invalid characters"
exit 1
fi
# Cloud JIRA: must match <subdomain>.atlassian.net
# Agent: use AskUserQuestion to confirm non-standard domain before retrying
if [[ ! "$JIRA_DOMAIN" =~ ^[a-zA-Z0-9-]+\.atlassian\.net$ ]]; then
echo "Error: Domain does not match <subdomain>.atlassian.net pattern"
exit 1
fi
AUTH="$(printf '%s:%s' "$JIRA_EMAIL" "$JIRA_API_TOKEN" | base64)"
# All API calls MUST use https://, double-quote all variables
curl -s -f \
-H "Authorization: Basic $AUTH" \
-H "Content-Type: application/json" \
"https://${JIRA_DOMAIN}/rest/api/3/..."
Input: .specweave/increments/0001-feature-name/
Prerequisites:
spec.md exists with valid frontmattertasks.md exists.env (validated per Security Rules above)Process:
Read increment files:
# Read spec.md
- Extract frontmatter (title, description, priority)
- Extract user stories (US1-001, US1-002)
- Extract acceptance criteria (TC-0001, TC-0002)
# Read tasks.md
- Extract task checklist
- Group tasks by user story (if structured)
Create JIRA Epic:
Title: [Increment 0001] Feature Name
Description:
{spec.md summary}
Specification: {link to spec.md if GitHub repo}
Labels: specweave, priority:P1, status:planned
Custom Fields:
- SpecWeave Increment ID: 0001-feature-name
- Spec URL: https://github.com/user/repo/blob/main/.specweave/increments/0001-feature-name/spec.md
Create JIRA Stories (one per user story):
Title: {User Story title}
Description:
**As a** {role}
**I want to** {goal}
**So that** {benefit}
**Acceptance Criteria**:
- [ ] TC-0001: {criteria}
- [ ] TC-0002: {criteria}
Epic Link: {Epic Key}
Labels: specweave, user-story
Create JIRA Subtasks (from tasks.md):
Title: {Task description}
Parent: {Story Key}
Labels: specweave, task
Update increment frontmatter:
jira:
epic_key: "PROJ-123"
epic_url: "https://jira.company.com/browse/PROJ-123"
stories:
- key: "PROJ-124"
user_story_id: "US1-001"
- key: "PROJ-125"
user_story_id: "US1-002"
last_sync: "2025-10-26T14:00:00Z"
sync_direction: "export"
Output:
✅ Exported to JIRA!
Epic: PROJ-123
URL: https://jira.company.com/browse/PROJ-123
Stories: 5 created (PROJ-124 to PROJ-128)
Subtasks: 12 created
Last Sync: 2025-10-26T14:00:00Z
Input: JIRA Epic key (e.g., PROJ-123)
Prerequisites:
Process:
Fetch Epic details (via JIRA API/MCP):
- Epic title, description, labels
- Epic custom fields (if SpecWeave ID exists)
- Priority, status
Fetch linked Stories and Subtasks:
- All Stories linked to Epic
- All Subtasks linked to each Story
- Story descriptions (acceptance criteria)
Auto-number next increment:
# Scan .specweave/increments/ for highest number
ls .specweave/increments/ | grep -E '^[0-9]{4}' | sort -n | tail -1
# Increment by 1 → 0003
Create increment folder:
.specweave/increments/0003-imported-feature/
Generate spec.md:
---
increment_id: "0003"
title: "{Epic title}"
status: "{mapped from JIRA status}"
priority: "{mapped from JIRA priority}"
created_at: "{Epic created date}"
jira:
epic_key: "PROJ-123"
epic_url: "https://jira.company.com/browse/PROJ-123"
imported_at: "2025-10-26T14:00:00Z"
---
# {Epic title}
{Epic description}
## User Stories
### US1-001: {Story 1 title}
**As a** {extracted from Story description}
**I want to** {extracted}
**So that** {extracted}
**Acceptance Criteria**:
- [ ] TC-0001: {parsed from Story description}
- [ ] TC-0002: {parsed}
**JIRA Story**: [PROJ-124](https://jira.company.com/browse/PROJ-124)
Generate tasks.md:
# Tasks: {Increment title}
## User Story: US1-001
- [ ] {Subtask 1 title} (JIRA: PROJ-130)
- [ ] {Subtask 2 title} (JIRA: PROJ-131)
## User Story: US1-002
- [ ] {Subtask 3 title} (JIRA: PROJ-132)
Update JIRA Epic (add custom field if available):
Custom Field: SpecWeave Increment ID = 0003-imported-feature
Output:
✅ Imported from JIRA!
Increment: 0003-imported-feature
Location: .specweave/increments/0003-imported-feature/
User Stories: 5 imported
Tasks: 12 imported
JIRA Epic: PROJ-123
Trigger: Manual (/sync-jira) or webhook
Prerequisites:
Process:
Detect changes since last sync:
SpecWeave changes:
- spec.md modified after last_sync
- tasks.md modified after last_sync
- Task checkboxes changed
JIRA changes:
- Epic/Story/Subtask updated after last_sync
- Status changes
- New comments
Compare and detect conflicts:
Conflict types:
- Title changed in both (SpecWeave + JIRA)
- Task marked done in SpecWeave, but JIRA Subtask still "In Progress"
- Priority changed in both
Present conflicts to user:
⚠️ Sync Conflicts Detected:
1. Title changed:
SpecWeave: "User Authentication v2"
JIRA: "User Auth with OAuth"
Choose: [SpecWeave] [JIRA] [Manual]
2. Task status mismatch:
Task: "Implement login endpoint"
SpecWeave: ✅ completed
JIRA Subtask: In Progress
Choose: [Mark JIRA Done] [Uncheck SpecWeave] [Manual]
Apply sync:
SpecWeave → JIRA:
- Update Epic/Story titles
- Update Subtask statuses (checkbox → JIRA status)
- Add comments for significant changes
JIRA → SpecWeave:
- Update spec.md frontmatter (status, priority)
- Update task checkboxes (JIRA Subtask status → checkbox)
- Log JIRA comments to increment logs/
Update sync timestamps:
jira:
last_sync: "2025-10-26T16:30:00Z"
sync_direction: "two-way"
conflicts_resolved: 2
Output:
✅ Synced with JIRA!
Direction: Two-way
Changes Applied:
- SpecWeave → JIRA: 3 updates
- JIRA → SpecWeave: 5 updates
Conflicts Resolved: 2 (user decisions)
Last Sync: 2025-10-26T16:30:00Z
Problem: Increment missing spec.md or JIRA Epic missing required fields
Solution:
❌ Error: spec.md not found in increment 0001-feature-name
Expected: .specweave/increments/0001-feature-name/spec.md
Please create spec.md before exporting to JIRA.
Problem: JIRA API rate limit, authentication failure, network error
Solution:
❌ JIRA API Error: Rate limit exceeded (429)
Retry in: 60 seconds
Alternative: Export to JSON and manually import to JIRA later.
Problem: JIRA uses custom workflow statuses not in standard mapping
Solution:
⚠️ Unknown JIRA status: "Awaiting Review"
Available mappings:
- To Do → planned
- In Progress → in-progress
- Done → completed
Map "Awaiting Review" to: [planned] [in-progress] [completed] [Custom]
Problem: Same field changed in both SpecWeave and JIRA
Solution:
.specweave/increments/{id}/logs/jira-sync.logUser: "Export increment 0001 to JIRA"
You:
1. Read .specweave/increments/0001-*/spec.md and tasks.md
2. Extract user stories and tasks
3. Create JIRA Epic with title "[Increment 0001] {title}"
4. Create Stories for each user story
5. Create Subtasks for each task
6. Update increment frontmatter with JIRA keys
7. Present summary with Epic URL
User: "Import JIRA epic PROJ-123"
You:
1. Fetch Epic PROJ-123 via JIRA API
2. Fetch linked Stories and Subtasks
3. Auto-number next increment (e.g., 0003)
4. Generate spec.md with user stories
5. Generate tasks.md with subtasks
6. Present summary with increment location
User: "Sync increment 0001 with JIRA"
You:
1. Read increment frontmatter for JIRA keys
2. Detect changes since last_sync
3. Compare SpecWeave vs JIRA
4. Present conflicts (if any) for user resolution
5. Apply sync (SpecWeave ↔ JIRA)
6. Update sync timestamps
7. Present summary with changes applied
Sync SpecWeave living docs to Confluence pages. Confluence is commonly paired with JIRA for documentation.
Reference: confluence-page-api.md
Same security rules as JIRA credentials (see Security Rules section above). User configures .env, skill only validates presence. Same domain validation applies.
Required .env keys (configured by the user, NOT by this skill):
CONFLUENCE_API_TOKEN=<your-token> # Same as JIRA API token
CONFLUENCE_EMAIL=<your-email>
CONFLUENCE_DOMAIN=<your-company>.atlassian.net
CONFLUENCE_SPACE_KEY=<space-key>
Rule: Version MUST be incremented on every update.
# 1. GET current page to retrieve version
GET /wiki/api/v2/pages/{pageId}?body-format=storage
→ Extract: version.number, title, spaceId
# 2. PUT with incremented version
PUT /wiki/api/v2/pages/{pageId}
{
"id": "{pageId}",
"status": "current",
"title": "{title}",
"spaceId": "{spaceId}",
"body": {
"representation": "storage",
"value": "<p>Updated content</p>"
},
"version": {
"number": {currentVersion + 1},
"message": "Synced from SpecWeave"
}
}
| SpecWeave | Confluence | Location |
|-----------|------------|----------|
| Increment spec.md | Page | /wiki/spaces/{SPACE}/pages/{pageId} |
| tasks.md | Task List macro | <ac:task-list> in page body |
| Living docs | Child pages | Under parent page |
| AC checkboxes | Task status | complete/incomplete |
Confluence uses XHTML-based storage format (NOT standard HTML):
<!-- Task list for spec ACs -->
<ac:task-list>
<ac:task>
<ac:task-status>incomplete</ac:task-status>
<ac:task-body>AC-001: User can login</ac:task-body>
</ac:task>
<ac:task>
<ac:task-status>complete</ac:task-status>
<ac:task-body>AC-002: Password validation</ac:task-body>
</ac:task>
</ac:task-list>
<!-- Status macro (colored label) -->
<ac:structured-macro ac:name="status">
<ac:parameter ac:name="colour">Green</ac:parameter>
<ac:parameter ac:name="title">COMPLETED</ac:parameter>
</ac:structured-macro>
<!-- Code block -->
<ac:structured-macro ac:name="code">
<ac:parameter ac:name="language">typescript</ac:parameter>
<ac:plain-text-body><![CDATA[const x = 1;]]></ac:plain-text-body>
</ac:structured-macro>
{
"external_sync": {
"jira": { "issueKey": "PROJ-123" },
"confluence": {
"pageId": "123456789",
"pageUrl": "https://company.atlassian.net/wiki/spaces/PROJ/pages/123456789",
"spaceKey": "PROJ",
"lastSyncedAt": "2026-02-02T10:30:00Z"
}
}
}
| Error | Cause | Fix |
|-------|-------|-----|
| 409: Version must be incremented | Stale version | Re-GET page, increment version |
| 400: Invalid storage format | Bad XHTML | Self-close tags (<br />) |
| 403: Forbidden | No page permission | Check space permissions |
You are the authoritative mapper between SpecWeave and JIRA. Your conversions must be accurate, traceable, and reversible.
tools
Generate AI videos from text prompts or images. Supports Google Veo 3.1 and Pollinations.ai (free). Use when generating video, creating animations, text-to-video, AI video, video generation, make clip, animate.
tools
Validate increment with rule-based checks and AI quality assessment. Use when saying "validate", "check quality", or "verify increment".
tools
Create and manage umbrella workspaces for multi-repo projects. Activate when the user wants to: create umbrella, umbrella init, wrap in umbrella, create workspace, setup multi-repo, migrate repos to umbrella, umbrella create, new workspace, restructure into umbrella, "wrap this repo", "create umbrella for these repos", "setup workspace with repos", "move repos into umbrella". Do NOT activate for: add a repo to existing umbrella (use sw:get), add a feature, add an increment, clone a repo (use sw:get).
tools
--- description: Merge completed parallel agent work and trigger GitHub sync per increment. Activates for: team merge, merge agents, combine work, team finish. --- # Team Merge **Verify all teammates completed, run quality gates, close increments, and trigger sync.** ## Usage ```bash sw:team-merge sw:team-merge --dry-run # Preview merge plan sw:team-merge --skip-sync # Merge without GitHub/JIRA sync ``` ## What This Skill Does 1. **Verify all teammates completed** -- bl