Learn-skills.dev jira-issues
Create, read, update, and delete Jira issues. Use when managing Stories, Tasks, Bugs, or Epics - includes field updates and metadata.
install
source · Clone the upstream repo
git clone https://github.com/NeverSight/learn-skills.dev
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/01000001-01001110/agent-jira-skills/jira-issues" ~/.claude/skills/neversight-learn-skills-dev-jira-issues && rm -rf "$T"
manifest:
data/skills-md/01000001-01001110/agent-jira-skills/jira-issues/SKILL.mdsource content
Jira Issues Skill
Purpose
Create, read, update, and delete issues in Jira Cloud. Manage issue fields, transitions, and metadata.
When to Use
- Creating new issues (Story, Task, Bug, Epic)
- Updating issue fields (summary, description, assignee, etc.)
- Reading issue details
- Deleting issues
Prerequisites
- Authenticated JiraClient (see jira-auth skill)
- Project access permissions
- Issue type IDs for the target project
Implementation Pattern
Step 1: Define Issue Types
interface JiraIssue { id: string; key: string; self: string; fields: { summary: string; description?: { type: 'doc'; version: 1; content: Array<{ type: string; content?: Array<{ type: string; text: string; }>; }>; }; status: { name: string; id: string }; assignee?: { accountId: string; displayName: string }; reporter?: { accountId: string; displayName: string }; priority?: { name: string; id: string }; issuetype: { name: string; id: string }; project: { key: string; id: string }; created: string; updated: string; labels?: string[]; components?: Array<{ id: string; name: string }>; }; } interface CreateIssueInput { projectKey: string; summary: string; issueType: 'Story' | 'Task' | 'Bug' | 'Epic' | string; description?: string; assigneeAccountId?: string; labels?: string[]; priority?: string; }
Step 2: Create Issue
async function createIssue( client: JiraClient, input: CreateIssueInput ): Promise<{ id: string; key: string; self: string }> { const body: any = { fields: { project: { key: input.projectKey }, summary: input.summary, issuetype: { name: input.issueType }, }, }; // Add description in Atlassian Document Format (ADF) if (input.description) { body.fields.description = { type: 'doc', version: 1, content: [ { type: 'paragraph', content: [ { type: 'text', text: input.description, }, ], }, ], }; } if (input.assigneeAccountId) { body.fields.assignee = { id: input.assigneeAccountId }; } if (input.labels) { body.fields.labels = input.labels; } if (input.priority) { body.fields.priority = { name: input.priority }; } return client.request<{ id: string; key: string; self: string }>('/issue', { method: 'POST', body: JSON.stringify(body), }); }
Step 3: Get Issue
async function getIssue( client: JiraClient, issueKeyOrId: string, options: { fields?: string[]; expand?: string[]; } = {} ): Promise<JiraIssue> { const params = new URLSearchParams(); if (options.fields) params.set('fields', options.fields.join(',')); if (options.expand) params.set('expand', options.expand.join(',')); const query = params.toString() ? `?${params.toString()}` : ''; return client.request<JiraIssue>(`/issue/${issueKeyOrId}${query}`); }
Step 4: Update Issue
interface UpdateIssueInput { summary?: string; description?: string; assigneeAccountId?: string | null; labels?: string[]; priority?: string; } async function updateIssue( client: JiraClient, issueKeyOrId: string, input: UpdateIssueInput ): Promise<void> { const body: any = { fields: {} }; if (input.summary) { body.fields.summary = input.summary; } if (input.description !== undefined) { body.fields.description = input.description ? { type: 'doc', version: 1, content: [ { type: 'paragraph', content: [{ type: 'text', text: input.description }], }, ], } : null; } if (input.assigneeAccountId !== undefined) { body.fields.assignee = input.assigneeAccountId ? { id: input.assigneeAccountId } : null; } if (input.labels) { body.fields.labels = input.labels; } if (input.priority) { body.fields.priority = { name: input.priority }; } await client.request(`/issue/${issueKeyOrId}`, { method: 'PUT', body: JSON.stringify(body), }); }
Step 5: Delete Issue
async function deleteIssue( client: JiraClient, issueKeyOrId: string, deleteSubtasks: boolean = false ): Promise<void> { const query = deleteSubtasks ? '?deleteSubtasks=true' : ''; await client.request(`/issue/${issueKeyOrId}${query}`, { method: 'DELETE', }); }
Step 6: Bulk Create Issues
async function bulkCreateIssues( client: JiraClient, issues: CreateIssueInput[] ): Promise<Array<{ id: string; key: string; self: string }>> { const results: Array<{ id: string; key: string; self: string }> = []; // Jira doesn't have a native bulk create, so we batch with Promise.all const batches = []; const batchSize = 10; for (let i = 0; i < issues.length; i += batchSize) { batches.push(issues.slice(i, i + batchSize)); } for (const batch of batches) { const batchResults = await Promise.all( batch.map((issue) => createIssue(client, issue)) ); results.push(...batchResults); } return results; }
curl Examples
Create Issue
curl -X POST "$JIRA_BASE_URL/rest/api/3/issue" \ -H "Authorization: Basic $(echo -n 'email:token' | base64)" \ -H "Content-Type: application/json" \ -d '{ "fields": { "project": { "key": "SCRUM" }, "summary": "New feature implementation", "issuetype": { "name": "Story" }, "description": { "type": "doc", "version": 1, "content": [ { "type": "paragraph", "content": [{ "type": "text", "text": "Description here" }] } ] } } }'
Get Issue
curl -X GET "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123" \ -H "Authorization: Basic $(echo -n 'email:token' | base64)" \ -H "Accept: application/json"
Update Issue
curl -X PUT "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123" \ -H "Authorization: Basic $(echo -n 'email:token' | base64)" \ -H "Content-Type: application/json" \ -d '{ "fields": { "summary": "Updated summary" } }'
Delete Issue
curl -X DELETE "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123" \ -H "Authorization: Basic $(echo -n 'email:token' | base64)"
API Endpoints Summary
| Operation | Method | Path |
|---|---|---|
| Create issue | POST | |
| Get issue | GET | |
| Update issue | PUT | |
| Delete issue | DELETE | |
Required Fields by Issue Type
Story
(required)project.key
(required)summary
= "Story" (required)issuetype.name
Task
(required)project.key
(required)summary
= "Task" (required)issuetype.name
Bug
(required)project.key
(required)summary
= "Bug" (required)issuetype.name
(recommended)description
Description Format (ADF)
Jira uses Atlassian Document Format for rich text:
{ "type": "doc", "version": 1, "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Normal text" } ] }, { "type": "paragraph", "content": [ { "type": "text", "text": "Bold text", "marks": [{ "type": "strong" }] } ] } ] }
Common Mistakes
- Using plain text for description instead of ADF format
- Not using account ID for assignee (email doesn't work)
- Forgetting project key in create request
- Using issue type name that doesn't exist in project
References
Version History
- 2025-12-10: Created