brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
jiraManage projects, issues, and workflows with Jira Cloud. Use when a user asks to set up Jira projects, create and manage issues, configure workflows, build Jira integrations, automate issue transitions, set up boards (Scrum/Kanban), manage sprints, use Jira REST API v3, create webhooks, build custom JQL queries, configure permissions and schemes, set up auto…
Independent GitHub snapshot · Automated classification · Original documentation governs
Automate and extend Jira Cloud — the most widely used issue tracker and project management tool. This skill covers project setup, issue CRUD, workflow configuration, Scrum and Kanban boards, sprint management, JQL (Jira Query Language) for advanced searches, REST API v3 for automation, webhooks, and building Atlassian Forge apps.
// Basic auth with API token — simplest for scripts and integrations.
// Generate token at: https://id.atlassian.com/manage-profile/security/api-tokens
const JIRA_BASE = "https://your-domain.atlassian.net";
const AUTH = Buffer.from(`your-email@company.com:${process.env.JIRA_API_TOKEN}`).toString("base64");
async function jira(method: string, path: string, body?: any) {
const res = await fetch(`${JIRA_BASE}/rest/api/3${path}`, {
method,
headers: { Authorization: `Basic ${AUTH}`, "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
if (!res.ok) throw new Error(`Jira ${method} ${path}: ${res.status} ${await res.text()}`);
return res.status === 204 ? null : res.json();
}
// For Marketplace apps, use OAuth 2.0 (3LO) — register at developer.atlassian.com
// Create a project: projectTypeKey = "software" | "business" | "service_desk"
const project = await jira("POST", "/project", {
key: "ENG", // 2-10 char uppercase key (ENG-1, ENG-2)
name: "Engineering",
projectTypeKey: "software",
leadAccountId: "5f1234abc...",
description: "Core product engineering",
});
// Default software issue types: Epic, Story, Task, Bug, Sub-task
// Custom issue type (requires admin)
const customType = await jira("POST", "/issuetype", {
name: "Tech Debt", type: "standard", hierarchyLevel: 0,
});
// Create an issue (descriptions use Atlassian Document Format, not plain text)
const issue = await jira("POST", "/issue", {
fields: {
project: { key: "ENG" },
issuetype: { name: "Story" },
summary: "Implement user authentication flow",
description: {
type: "doc", version: 1,
content: [{ type: "paragraph", content: [{ type: "text", text: "Build OAuth2 login with MFA support." }] }],
},
priority: { name: "High" }, // Highest, High, Medium, Low, Lowest
labels: ["auth", "security"],
assignee: { accountId: "5f1234abc..." },
customfield_10016: 8, // Story points (custom field ID varies)
components: [{ name: "Backend" }],
},
});
// Transition through workflow (e.g., To Do → In Progress)
const transitions = await jira("GET", `/issue/${issue.key}/transitions`);
const target = transitions.transitions.find((t: any) => t.name === "In Progress");
await jira("POST", `/issue/${issue.key}/transitions`, {
transition: { id: target.id },
});
// Bulk create (up to 50 per request)
const bulkResult = await jira("POST", "/issue/bulk", {
issueUpdates: [
{ fields: { project: { key: "ENG" }, issuetype: { name: "Task" }, summary: "Set up CI pipeline" } },
{ fields: { project: { key: "ENG" }, issuetype: { name: "Bug" }, summary: "Fix login timeout", priority: { name: "High" } } },
],
});
// JQL search — paginated via startAt/maxResults
const myBugs = await jira("POST", "/search", {
jql: `project = ENG AND issuetype = Bug AND priority in (High, Highest)
AND assignee = currentUser() AND sprint in openSprints()
ORDER BY priority DESC`,
maxResults: 50, fields: ["summary", "status", "priority", "assignee"],
});
// Stale work detection
const staleIssues = await jira("POST", "/search", {
jql: `project = ENG AND status != Done AND updated <= -14d ORDER BY updated ASC`,
maxResults: 100, fields: ["summary", "status", "assignee", "updated"],
});
// Key JQL functions: currentUser(), membersOf("team"), openSprints(),
// futureSprints(), startOfDay(), endOfWeek(), startOfMonth(-1)
// Agile API uses a separate base path: /rest/agile/1.0
async function agile(method: string, path: string, body?: any) {
const res = await fetch(`${JIRA_BASE}/rest/agile/1.0${path}`, {
method,
headers: { Authorization: `Basic ${AUTH}`, "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
if (!res.ok) throw new Error(`Agile ${method} ${path}: ${res.status}`);
return res.json();
}
// Boards, sprints, sprint issues
const boards = await agile("GET", "/board?type=scrum");
const sprints = await agile("GET", `/board/${boardId}/sprint?state=active`);
const sprintIssues = await agile("GET", `/sprint/${sprints.values[0].id}/issue?fields=summary,status,assignee`);
// Create sprint, move issues, close sprint
const newSprint = await agile("POST", "/sprint", {
name: "Sprint 24", startDate: "2026-02-24T09:00:00.000Z",
endDate: "2026-03-07T17:00:00.000Z", originBoardId: boardId,
goal: "Complete auth module and API v2 migration",
});
await agile("POST", `/sprint/${newSprint.id}/issue`, { issues: ["ENG-142", "ENG-143"] });
await agile("POST", `/sprint/${newSprint.id}`, { state: "closed", completeDate: new Date().toISOString() });
// Register a webhook for issue events
const webhook = await jira("POST", "/webhook", {
name: "Epic completion handler",
url: "https://your-app.com/webhook/jira",
events: ["jira:issue_updated"],
filters: { "issue-related-events-section": `project = ENG AND issuetype = Epic` },
});
// Webhook handler: auto-transition Epic children when Epic is marked Done
app.post("/webhook/jira", async (req, res) => {
res.sendStatus(200);
const { issue, changelog } = req.body;
const statusChange = changelog?.items?.find((i: any) => i.field === "status" && i.toString === "Done");
if (!statusChange || issue.fields.issuetype.name !== "Epic") return;
const children = await jira("POST", "/search", {
jql: `"Epic Link" = ${issue.key} AND status != Done`, fields: ["status"],
});
for (const child of children.issues) {
const tr = await jira("GET", `/issue/${child.key}/transitions`);
const done = tr.transitions.find((t: any) => t.name === "Done");
if (done) await jira("POST", `/issue/${child.key}/transitions`, { transition: { id: done.id } });
}
});
// Calculate velocity from closed sprints
async function getVelocity(boardId: number, sprintCount = 5) {
const closedSprints = await agile("GET", `/board/${boardId}/sprint?state=closed&maxResults=${sprintCount}`);
return Promise.all(closedSprints.values.map(async (sprint: any) => {
const issues = await agile("GET", `/sprint/${sprint.id}/issue?fields=customfield_10016,status`);
const points = issues.issues
.filter((i: any) => i.fields.status.statusCategory.key === "done")
.reduce((sum: number, i: any) => sum + (i.fields.customfield_10016 || 0), 0);
return { sprint: sprint.name, points };
}));
}
// Create a shared filter (saved JQL query)
const filter = await jira("POST", "/filter", {
name: "Sprint Burndown - ENG",
jql: "project = ENG AND sprint in openSprints() ORDER BY rank ASC",
sharePermissions: [{ type: "project", project: { id: project.id } }],
});
// Check permissions and add users to project roles
const permission = await jira("GET", `/mypermissions?projectKey=ENG&permissions=EDIT_ISSUES,ASSIGN_ISSUES`);
await jira("POST", `/project/${projectKey}/role/${roleId}`, {
user: ["accountId1", "accountId2"],
});
// Common roles: 10002=Administrators, 10001=Developers, 10000=Users
User prompt: "Create a Jira project called 'Payments' with key PAY. Set up a two-week sprint starting next Monday. Create 5 stories for building a Stripe integration: webhook handler, checkout flow, subscription management, refund processing, and payment dashboard. Assign them all to the new sprint with story points."
The agent will:
POST /project with projectTypeKey: "software" and key PAY.payments and stripe.POST /sprint/{id}/issue.User prompt: "Find all unresolved ENG issues that haven't been updated in over 14 days. Group them by assignee and tell me who has the most stale work."
The agent will:
project = ENG AND status != Done AND updated <= -14d ORDER BY assignee ASC, updated ASC with fields for summary, status, assignee, and updated date.{ type: "doc", version: 1, content: [...] } structure.customfield_10016 for story points) vary between Jira instances; use GET /issue/createmeta to discover the correct field IDs for your project./rest/agile/1.0) is separate from the core API (/rest/api/3); use it for boards, sprints, backlog, and ranking operations.startAt and maxResults to iterate through large result sets.GET /issue/{key}/transitions; transition IDs are not stable across different workflow configurations.