/jira-close
Close JIRA issue when increment complete
> /plugin marketplace add anton-abyzov/specweave > /plugin install sw@specweave
How it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/jira-close
Context preview
What this command does when you run it.
Close JIRA issue when increment complete
Command definition
jira-close.mddescription: Close JIRA issue when increment complete
Close JIRA Issue Command
**Usage**: `sw-jira:close <increment-id>`
**Purpose**: Close JIRA issue and add completion summary
---
Command Behavior
When user runs this command, Claude should:
1. Check Permission Gate (MANDATORY FIRST STEP)
**Before ANY JIRA API calls**, check if status updates are allowed:
// Read .specweave/config.json
const config = JSON.parse(await fs.readFile('.specweave/config.json', 'utf-8'));
const canUpdateExternal = config?.sync?.settings?.canUpdateExternalItems ?? false;
const canUpdateStatus = config?.sync?.settings?.canUpdateStatus ?? false;
// Close requires both permissions (write to close, status to change state)
if (!canUpdateExternal || !canUpdateStatus) {
const missing = [];
if (!canUpdateExternal) missing.push('canUpdateExternalItems');
if (!canUpdateStatus) missing.push('canUpdateStatus');
console.log(`
❌ Permission Denied
Closing JIRA issues requires these permissions:
${missing.map(p => ` - sync.settings.${p} = false (required: true)`).join('\n')}
To enable, update .specweave/config.json:
{
"sync": {
"settings": {
"canUpdateExternalItems": true,
"canUpdateStatus": true
}
}
}
`);
return;
}2. Resolve JIRA Profile
Use the increment's stored profile or fall back to global defaultProfile/activeProfile:
// Load increment metadata
const metadataPath = `.specweave/increments/${incrementId}/metadata.json`;
const metadata = JSON.parse(await fs.readFile(metadataPath, 'utf-8'));
// Priority: increment profile > global defaultProfile > activeProfile
let profileName = metadata?.external_sync?.jira?.profile;
if (!profileName) {
profileName = config?.sync?.defaultProfile ?? config?.sync?.activeProfile;
}
// Validate profile exists
const profileConfig = config?.sync?.profiles?.[profileName];
if (!profileConfig || profileConfig.provider !== 'jira') {
console.log(`❌ JIRA profile "${profileName}" not found`);
return;
}
const { domain, projectKey } = profileConfig.config;3. Validate Increment Completion
Before closing, verify the increment is actually complete:
// Check tasks.md for completion
const tasksPath = `.specweave/increments/${incrementId}/tasks.md`;
const tasksContent = await fs.readFile(tasksPath, 'utf-8');
const totalTasks = (tasksContent.match(/### T-\d+/g) || []).length;
const completedTasks = (tasksContent.match(/\[x\] completed/gi) || []).length;
if (completedTasks < totalTasks) {
console.log(`
⚠️ Increment not complete
Tasks: ${completedTasks}/${totalTasks} completed
Cannot close JIRA issue until all tasks are done.
Complete remaining tasks first, then re-run this command.
`);
return;
}4. Validate Issue Is Linked
// Check for linked issue
const issueKey = metadata?.external_sync?.jira?.issueKey
|| metadata?.external_ids?.jira?.epic;
if (!issueKey) {
console.log(`
⚠️ No JIRA issue linked
This increment is not linked to a JIRA issue.
First create an issue with: sw-jira:create ${incrementId}
`);
return;
}5. Invoke JIRA Manager Skill
Use Skill tool: Skill({ skill: "sw-jira:jira-sync", args: "Close JIRA issue for completed increment {increment-id}.
IMPORTANT:
- Permission verified: canUpdateExternalItems=true, canUpdateStatus=true
- Using profile: {profileName} (domain: {domain}, project: {projectKey})
- Issue key: {issueKey}
Steps:
1. Validate: All tasks in tasks.md complete
2. Generate: Completion summary (duration, deliverables)
3. Load issue key from metadata.json
4. GET available transitions from /rest/api/3/issue/{issueKey}/transitions
5. Find transition to 'Done' or 'Closed' status
6. POST transition: /rest/api/3/issue/{issueKey}/transitions
7. POST final comment with summary
8. Display: Closure confirmation with profile used"6. Display Result
✅ Closed JIRA Issue
Issue: {issueKey}
Profile: {profileName}
Domain: {domain}
Project: {projectKey}
Increment: {increment-id}
Status: 100% complete ({total}/{total} tasks)
Duration: {days} days
Summary posted to JIRA issue
URL: https://{domain}/browse/{issueKey}---
Permission Requirements
This command requires **both** permissions:
| Permission | Required | Purpose | |------------|----------|---------| | canUpdateExternalItems | true | Write to JIRA issue | | canUpdateStatus | true | Transition issue state to Done/Closed |
---
Example Output
Success
User: sw-jira:close 0005-payment-integration
Claude:
Checking permissions...
canUpdateExternalItems: true
canUpdateStatus: true
Resolving JIRA profile...
Using: jira-my-project (from increment)
Domain: company.atlassian.net
Project: MYPROJ
Validating completion...
Tasks: 10/10 complete
Closing issue...
✅ Closed JIRA Issue MYPROJ-123
Profile: jira-my-project
Increment: 0005-payment-integration
Status: 100% complete (10/10 tasks)
Duration: 3 days
Summary posted to JIRA issue
URL: https://company.atlassian.net/browse/MYPROJ-123
Permission Denied
User: sw-jira:close 0005
Claude:
Checking permissions...
canUpdateExternalItems: false
canUpdateStatus: false
❌ Permission Denied
Closing JIRA issues requires:
- sync.settings.canUpdateExternalItems = true
- sync.settings.canUpdateStatus = true
Update .specweave/config.json to enable these permissions.
Incomplete Increment
User: sw-jira:close 0005
Claude:
Checking permissions...
canUpdateExternalItems: true
canUpdateStatus: true
Validating completion...
⚠️ Increment not complete
Tasks: 6/10 completed
Cannot close JIRA issue until all tasks are done.
Complete remaining tasks:
- T-007: Add refund functionality
- T-008: Implement subscriptions
- T-009: Add analytics
- T-010: Security audit
No Issue Linked
User: sw-jira:close 0005
Claude:
Checking linked issue...
⚠️ No JIRA issue linked
This increment is not linked to a JIRA issue.
First create an i
Read more
description: Close JIRA issue when increment complete
Close JIRA Issue Command
**Usage**: `sw-jira:close <increment-id>`
**Purpose**: Close JIRA issue and add completion summary
---
Command Behavior
When user runs this command, Claude should:
1. Check Permission Gate (MANDATORY FIRST STEP)
**Before ANY JIRA API calls**, check if status updates are allowed:
// Read .specweave/config.json
const config = JSON.parse(await fs.readFile('.specweave/config.json', 'utf-8'));
const canUpdateExternal = config?.sync?.settings?.canUpdateExternalItems ?? false;
const canUpdateStatus = config?.sync?.settings?.canUpdateStatus ?? false;
// Close requires both permissions (write to close, status to change state)
if (!canUpdateExternal || !canUpdateStatus) {
const missing = [];
if (!canUpdateExternal) missing.push('canUpdateExternalItems');
if (!canUpdateStatus) missing.push('canUpdateStatus');
console.log(`
❌ Permission Denied
Closing JIRA issues requires these permissions:
${missing.map(p => ` - sync.settings.${p} = false (required: true)`).join('\n')}
To enable, update .specweave/config.json:
{
"sync": {
"settings": {
"canUpdateExternalItems": true,
"canUpdateStatus": true
}
}
}
`);
return;
}2. Resolve JIRA Profile
Use the increment's stored profile or fall back to global defaultProfile/activeProfile:
// Load increment metadata
const metadataPath = `.specweave/increments/${incrementId}/metadata.json`;
const metadata = JSON.parse(await fs.readFile(metadataPath, 'utf-8'));
// Priority: increment profile > global defaultProfile > activeProfile
let profileName = metadata?.external_sync?.jira?.profile;
if (!profileName) {
profileName = config?.sync?.defaultProfile ?? config?.sync?.activeProfile;
}
// Validate profile exists
const profileConfig = config?.sync?.profiles?.[profileName];
if (!profileConfig || profileConfig.provider !== 'jira') {
console.log(`❌ JIRA profile "${profileName}" not found`);
return;
}
const { domain, projectKey } = profileConfig.config;3. Validate Increment Completion
Before closing, verify the increment is actually complete:
// Check tasks.md for completion
const tasksPath = `.specweave/increments/${incrementId}/tasks.md`;
const tasksContent = await fs.readFile(tasksPath, 'utf-8');
const totalTasks = (tasksContent.match(/### T-\d+/g) || []).length;
const completedTasks = (tasksContent.match(/\[x\] completed/gi) || []).length;
if (completedTasks < totalTasks) {
console.log(`
⚠️ Increment not complete
Tasks: ${completedTasks}/${totalTasks} completed
Cannot close JIRA issue until all tasks are done.
Complete remaining tasks first, then re-run this command.
`);
return;
}4. Validate Issue Is Linked
// Check for linked issue
const issueKey = metadata?.external_sync?.jira?.issueKey
|| metadata?.external_ids?.jira?.epic;
if (!issueKey) {
console.log(`
⚠️ No JIRA issue linked
This increment is not linked to a JIRA issue.
First create an issue with: sw-jira:create ${incrementId}
`);
return;
}5. Invoke JIRA Manager Skill
Use Skill tool: Skill({ skill: "sw-jira:jira-sync", args: "Close JIRA issue for completed increment {increment-id}.
IMPORTANT:
- Permission verified: canUpdateExternalItems=true, canUpdateStatus=true
- Using profile: {profileName} (domain: {domain}, project: {projectKey})
- Issue key: {issueKey}
Steps:
1. Validate: All tasks in tasks.md complete
2. Generate: Completion summary (duration, deliverables)
3. Load issue key from metadata.json
4. GET available transitions from /rest/api/3/issue/{issueKey}/transitions
5. Find transition to 'Done' or 'Closed' status
6. POST transition: /rest/api/3/issue/{issueKey}/transitions
7. POST final comment with summary
8. Display: Closure confirmation with profile used"6. Display Result
✅ Closed JIRA Issue
Issue: {issueKey}
Profile: {profileName}
Domain: {domain}
Project: {projectKey}
Increment: {increment-id}
Status: 100% complete ({total}/{total} tasks)
Duration: {days} days
Summary posted to JIRA issue
URL: https://{domain}/browse/{issueKey}---
Permission Requirements
This command requires **both** permissions:
| Permission | Required | Purpose | |------------|----------|---------| | canUpdateExternalItems | true | Write to JIRA issue | | canUpdateStatus | true | Transition issue state to Done/Closed |
---
Example Output
Success
User: sw-jira:close 0005-payment-integration Claude: Checking permissions... canUpdateExternalItems: true canUpdateStatus: true Resolving JIRA profile... Using: jira-my-project (from increment) Domain: company.atlassian.net Project: MYPROJ Validating completion... Tasks: 10/10 complete Closing issue... ✅ Closed JIRA Issue MYPROJ-123 Profile: jira-my-project Increment: 0005-payment-integration Status: 100% complete (10/10 tasks) Duration: 3 days Summary posted to JIRA issue URL: https://company.atlassian.net/browse/MYPROJ-123
Permission Denied
User: sw-jira:close 0005 Claude: Checking permissions... canUpdateExternalItems: false canUpdateStatus: false ❌ Permission Denied Closing JIRA issues requires: - sync.settings.canUpdateExternalItems = true - sync.settings.canUpdateStatus = true Update .specweave/config.json to enable these permissions.
Incomplete Increment
User: sw-jira:close 0005 Claude: Checking permissions... canUpdateExternalItems: true canUpdateStatus: true Validating completion... ⚠️ Increment not complete Tasks: 6/10 completed Cannot close JIRA issue until all tasks are done. Complete remaining tasks: - T-007: Add refund functionality - T-008: Implement subscriptions - T-009: Add analytics - T-010: Security audit
No Issue Linked
User: sw-jira:close 0005 Claude: Checking linked issue... ⚠️ No JIRA issue linked This increment is not linked to a JIRA issue. First create an i
Spec-first AI development: describe a feature → AI creates spec + plan + tasks, builds autonomously, syncs to GitHub/JIRA. Domain-expert skills for PM, Architect, Frontend, QA learn your patterns permanently. Claude Code, Codex, Cursor, Copilot & more.
Repo: anton-abyzov/specweave
Other commands on specweave.
- /abandon
Abandon an incomplete increment (requirements changed, obsolete)
Open command - /ado-cleanup-duplicates
Clean up duplicate Azure DevOps work items for a Feature. Finds work items with duplicate titles and closes all except the first created item.
Open command - /ado-clone
Clone Azure DevOps repositories to local workspace. Use after init if cloning was skipped, or to add repos later.
Open command - /ado-close
Close Azure DevOps work item when increment complete
Open command - /ado-create
Create Azure DevOps work item from SpecWeave increment
Open command - /ado-import-areas
Import Azure DevOps area paths from a project and map them to SpecWeave projects. Creates 2-level directory structure with area path-based organization.
Open command

