plugins/specweave/skills/jira-resource-validator/SKILL.md
Validates JIRA projects and boards exist, auto-creates missing resources. Use when setting up JIRA integration, validating .env configuration, or troubleshooting missing projects/boards. Supports per-project board configuration with JIRA_BOARDS_{ProjectKey} pattern.
npx skillsauth add anton-abyzov/specweave plugins/specweave/skills/jira-resource-validatorInstall 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.
Purpose: Validate and auto-create Jira projects and boards, ensuring .env configuration is correct.
Auto-Activation: Triggers when Jira setup or validation is needed.
These rules apply to ALL JIRA API operations in this skill.
.env only, never prompts the user.env themselves (this skill may update non-secret keys like JIRA_BOARDS and JIRA_PROJECT)# 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 (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
# JIRA Cloud and Server/DC are both supported.
# Cloud domains match <subdomain>.atlassian.net; self-hosted use custom domains.
# No hard-block — deployment type is auto-detected at runtime.
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/..."
This skill ensures your Jira configuration in .env is valid and all resources exist. It's smart enough to:
JIRA_PROJECT exists✅ Automatically activates when:
sw-jira:sync and resources are missing.env has invalid Jira configurationJIRA_API_TOKEN=<your-token>
JIRA_EMAIL=<your-email>
JIRA_DOMAIN=<your-company>.atlassian.net
JIRA_STRATEGY=board-based
JIRA_PROJECT=PROJECTKEY
JIRA_BOARDS=1,2,3 # IDs (if exist) OR names (if creating)
The system is smart enough to handle ANY combination of IDs and names:
All IDs (validate existing boards):
JIRA_BOARDS=1,2,3
→ Validates boards 1, 2, 3 exist
All Names (create new boards):
JIRA_BOARDS=Frontend,Backend,Mobile
→ Creates 3 boards, updates .env with IDs: JIRA_BOARDS=101,102,103
Mixed IDs and Names (smart handling!):
JIRA_BOARDS=101,102,QA,Dashboard
→ Validates 101, 102 exist
→ Creates "QA" and "Dashboard" boards
→ Updates .env: JIRA_BOARDS=101,102,103,104 (all IDs!)
How it works: Each entry is checked individually:
Multiple JIRA projects with their own boards:
# Multiple projects with their own boards
JIRA_STRATEGY=project-per-team
JIRA_PROJECTS=BACKEND,FRONTEND,MOBILE
# Per-project boards (hierarchical naming)
JIRA_BOARDS_BACKEND=123,456 # Sprint + Kanban (IDs)
JIRA_BOARDS_FRONTEND=Sprint,Bug # Create these boards
JIRA_BOARDS_MOBILE=789,012,345 # iOS + Android + Release (IDs)
→ Validates 3 projects exist: BACKEND, FRONTEND, MOBILE → Validates/creates boards per project:
Naming Convention: {PROVIDER}_{RESOURCE_TYPE}_{PROJECT_KEY}
Mixed IDs and Names Per Project:
JIRA_BOARDS_BACKEND=123,NewBoard,456
→ Validates 123, 456 exist
→ Creates "NewBoard"
→ Updates .env: JIRA_BOARDS_BACKEND=123,789,456 (all IDs!)
Check if project exists:
# API call to Jira
GET /rest/api/3/project/PROJECTKEY
If project exists:
✅ Project "PROJECTKEY" exists
ID: 10001
Name: My Project
If project doesn't exist:
⚠️ Project "PROJECTKEY" not found
What would you like to do?
1. Select an existing project
2. Create a new project
3. Cancel
Your choice [1]:
Option 1: Select Existing:
Available projects:
1. PROJ1 - Project One
2. PROJ2 - Project Two
3. PROJ3 - Project Three
Select a project [1]:
✅ Updated .env: JIRA_PROJECT=PROJ1
Option 2: Create New:
Enter project name: My New Project
📦 Creating Jira project: PROJECTKEY (My New Project)...
✅ Project created: PROJECTKEY (ID: 10005)
Scenario A: All Board IDs (all numeric):
JIRA_BOARDS=1,2,3
Validation:
Checking boards: 1,2,3...
✅ Board 1: Frontend Board (exists)
✅ Board 2: Backend Board (exists)
⚠️ Board 3: Not found
⚠️ Issues found: 1 board(s)
Scenario B: All Board Names (all non-numeric):
JIRA_BOARDS=Frontend,Backend,Mobile
Auto-creation:
Checking boards: Frontend,Backend,Mobile...
📦 Creating board: Frontend...
✅ Created: Frontend (ID: 101)
📦 Creating board: Backend...
✅ Created: Backend (ID: 102)
📦 Creating board: Mobile...
✅ Created: Mobile (ID: 103)
📝 Updating .env with board IDs...
✅ Updated JIRA_BOARDS: 101,102,103
✅ All boards validated/created successfully
Scenario C: Mixed IDs and Names (SMART!):
JIRA_BOARDS=101,102,QA,Dashboard
Smart handling:
Checking boards: 101,102,QA,Dashboard...
✅ Board 101: Frontend Board (exists)
✅ Board 102: Backend Board (exists)
📦 Creating board: QA...
✅ Created: QA (ID: 103)
📦 Creating board: Dashboard...
✅ Created: Dashboard (ID: 104)
📝 Updating .env with board IDs...
✅ Updated JIRA_BOARDS: 101,102,103,104
✅ All boards validated/created successfully
Scenario: New project, no Jira resources exist yet
Action: Run sw-jira:sync
What Happens:
🔍 Validating Jira configuration...
Checking project: MINIDOOM...
⚠️ Project "MINIDOOM" not found
What would you like to do?
1. Select an existing project
2. Create a new project
3. Cancel
Your choice [2]: 2
Enter project name: Mini DOOM Tournament
📦 Creating Jira project: MINIDOOM (Mini DOOM Tournament)...
✅ Project created: MINIDOOM (ID: 10005)
Checking boards: Frontend,Backend,Mobile...
📦 Creating boards from names...
Creating board: Frontend in project MINIDOOM...
✅ Board created: Frontend (ID: 101)
Creating board: Backend in project MINIDOOM...
✅ Board created: Backend (ID: 102)
Creating board: Mobile in project MINIDOOM...
✅ Board created: Mobile (ID: 103)
✅ Updated .env: JIRA_BOARDS=101,102,103
🎉 Jira configuration complete! All resources ready.
Result: .env now has correct project and board IDs
Scenario: Project already exists in Jira
Action: Run validation
What Happens:
🔍 Validating Jira configuration...
Checking project: PROJ...
⚠️ Project "PROJ" not found
What would you like to do?
1. Select an existing project
2. Create a new project
3. Cancel
Your choice [1]: 1
Available projects:
1. FRONTEND - Frontend Team
2. BACKEND - Backend Team
3. MOBILE - Mobile Team
Select a project [1]: 2
✅ Updated .env: JIRA_PROJECT=BACKEND
✅ Project "BACKEND" exists
Checking boards: 45,46...
✅ All boards exist
Scenario: Some board IDs are invalid
Action: Run validation
What Happens:
🔍 Validating Jira configuration...
Checking project: PROJECTKEY...
✅ Project "PROJECTKEY" exists
Checking boards: 1,2,999...
Board 1: ✅ Exists (Frontend Board)
Board 2: ✅ Exists (Backend Board)
Board 999: ❌ Not found
⚠️ Boards not found: 999
Available boards in project PROJECTKEY:
1. Frontend Board (ID: 1)
2. Backend Board (ID: 2)
3. QA Board (ID: 3)
4. DevOps Board (ID: 4)
Would you like to:
1. Remove invalid board (999) from configuration
2. Replace with correct board ID
3. Create new board
Your choice [2]: 2
Enter correct board ID or name: 3
✅ Updated .env: JIRA_BOARDS=1,2,3
Manual validation:
# Via CLI
specweave validate-jira
# Or via skill activation
"Can you validate my Jira configuration?"
Validation output:
{
valid: true,
project: {
exists: true,
key: 'PROJECTKEY',
id: '10001',
name: 'My Project'
},
boards: {
valid: true,
existing: [1, 2, 3],
missing: [],
created: []
},
envUpdated: false
}
// Parse JIRA_BOARDS from .env
const boardsConfig = "101,102,QA,Dashboard"; // Mixed!
const boardEntries = boardsConfig.split(',').map(b => b.trim());
const finalBoardIds = [];
// Check EACH board individually
for (const entry of boardEntries) {
const isNumeric = /^\d+$/.test(entry);
if (isNumeric) {
// Entry is a board ID - validate it exists
const boardId = parseInt(entry);
const board = await checkBoard(boardId);
if (board) {
console.log(`✅ Board ${boardId}: ${board.name} (exists)`);
finalBoardIds.push(boardId);
} else {
console.error(`⚠️ Board ${boardId}: Not found`);
}
} else {
// Entry is a board name - create it
console.log(`📦 Creating board: ${entry}...`);
const board = await createBoard(entry, projectKey);
console.log(`✅ Created: ${entry} (ID: ${board.id})`);
finalBoardIds.push(board.id);
}
}
// Update .env if any boards were created
if (createdBoardIds.length > 0) {
updateEnv({ JIRA_BOARDS: finalBoardIds.join(',') });
}
Key improvement: Per-board detection instead of all-or-nothing!
JIRA_BOARDS=1,2,3 → Validates all IDsJIRA_BOARDS=A,B,C → Creates all boardsJIRA_BOARDS=1,2,C → Validates 1,2, creates C (mixed!)Jira REST API (v3):
POST /rest/api/3/board
Content-Type: application/json
{
"name": "Frontend Board",
"type": "scrum",
"filterId": 10000, # Filter for project issues
"location": {
"type": "project",
"projectKeyOrId": "PROJECTKEY" # CRITICAL: Associates board with project
}
}
Response:
{
"id": 101,
"name": "Frontend Board",
"type": "scrum"
}
IMPORTANT: The location field is MANDATORY to associate the board with a project. Without it, Jira creates the board but leaves it detached, requiring manual connection via the UI.
Filter creation (required for board):
POST /rest/api/3/filter
Content-Type: application/json
{
"name": "PROJECTKEY Issues",
"jql": "project = PROJECTKEY"
}
Response:
{
"id": 10000
}
Before (.env):
JIRA_PROJECT=PROJ
JIRA_BOARDS=Frontend,Backend,QA,DevOps
After validation:
JIRA_PROJECT=PROJ
JIRA_BOARDS=101,102,103,104
What happened:
Before (.env):
JIRA_PROJECT=PROJ
JIRA_BOARDS=1,2,3
After validation:
JIRA_PROJECT=PROJ
JIRA_BOARDS=1,2,3
What happened:
Before (.env):
JIRA_PROJECT=PROJ
JIRA_BOARDS=101,102,QA,Dashboard
After validation:
JIRA_PROJECT=PROJ
JIRA_BOARDS=101,102,103,104
What happened:
Before (.env):
JIRA_PROJECT=NONEXISTENT
JIRA_BOARDS=1,2
After validation (user selected existing project):
JIRA_PROJECT=EXISTINGPROJ
JIRA_BOARDS=1,2
What happened:
Symptom: API calls fail with 401 Unauthorized
Solution:
❌ Jira API authentication failed
Please check:
1. JIRA_API_TOKEN is correct
2. JIRA_EMAIL matches your Jira account
3. JIRA_DOMAIN is correct (yourcompany.atlassian.net)
Generate new token at:
https://id.atlassian.com/manage-profile/security/api-tokens
Symptom: Cannot create projects/boards (403 Forbidden)
Solution:
❌ Insufficient permissions to create resources
You need:
- Project Creator permission (for projects)
- Board Creator permission (for boards)
Contact your Jira administrator to request permissions.
Symptom: Project creation fails (key exists)
Solution:
❌ Project key "PROJ" already exists
Options:
1. Use a different project key
2. Select the existing project
3. Cancel
Your choice [2]:
Symptom: API calls timeout or fail
Solution:
❌ Jira API error: Request timeout
Please check:
1. Internet connection
2. Jira domain is correct
3. Jira is not down (check status.atlassian.com)
Retry? [Y/n]:
When using sw-jira:sync, validation runs automatically:
sw-jira:sync 0014
# Internally calls:
1. validateJiraResources()
2. Fix missing project/boards
3. Proceed with sync
Run validation independently:
# Via skill
"Validate my Jira configuration"
# Via CLI
specweave validate-jira
✅ Use board names for initial setup:
JIRA_BOARDS=Sprint-1,Sprint-2,Backlog
✅ Use board IDs after creation:
JIRA_BOARDS=101,102,103
✅ Keep .env in version control (gitignored tokens):
# Commit project/board structure
JIRA_PROJECT=PROJ
JIRA_BOARDS=101,102,103
# Don't commit sensitive data
JIRA_API_TOKEN=<redacted>
JIRA_EMAIL=<redacted>
✅ Document board mapping (in README):
## Jira Boards
- Board 101: Frontend Team
- Board 102: Backend Team
- Board 103: QA Team
This skill ensures your Jira configuration is always valid by:
Result: Zero manual Jira setup - system handles everything!
Skill Version: 1.0.0 Introduced: SpecWeave v0.9.5 Last Updated: 2025-11-09
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