Agent Skills: Jira Transitions Skill

Move Jira issues through workflow states. Use when transitioning issues (To Do, In Progress, Done) or setting resolutions.

UncategorizedID: 01000001-01001110/agent-jira-skills/jira-transitions

Install this agent skill to your local

pnpm dlx add-skill https://github.com/01000001-01001110/agent-jira-skills/tree/HEAD/jira-transitions

Skill Files

Browse the full folder contents for jira-transitions.

Download Skill

Loading file tree…

jira-transitions/SKILL.md

Skill Metadata

Name
jira-transitions
Description
Move Jira issues through workflow states. Use when transitioning issues (To Do, In Progress, Done) or setting resolutions.

Jira Transitions Skill

Purpose

Move issues through workflow states. Get available transitions and execute status changes.

When to Use

  • Moving issues to different statuses (To Do → In Progress → Done)
  • Getting available transitions for an issue
  • Bulk transitioning issues
  • Setting resolution when closing issues

Prerequisites

  • Authenticated JiraClient (see jira-auth skill)
  • Issue transition permissions
  • Knowledge of workflow structure

Important Notes

Transition IDs are NOT standardized - they vary by:

  • Jira instance
  • Project
  • Workflow configuration

Always query available transitions first before attempting to transition.

Implementation Pattern

Step 1: Define Types

interface Transition {
  id: string;
  name: string;
  to: {
    id: string;
    name: string;
    statusCategory: {
      id: number;
      key: string;
      name: string;
    };
  };
  fields?: Record<string, {
    required: boolean;
    name: string;
    allowedValues?: Array<{ id: string; name: string }>;
  }>;
}

interface TransitionsResponse {
  transitions: Transition[];
}

Step 2: Get Available Transitions

async function getTransitions(
  client: JiraClient,
  issueKeyOrId: string
): Promise<Transition[]> {
  const response = await client.request<TransitionsResponse>(
    `/issue/${issueKeyOrId}/transitions?expand=transitions.fields`
  );
  return response.transitions;
}

Step 3: Find Transition by Name

async function findTransitionByName(
  client: JiraClient,
  issueKeyOrId: string,
  targetStatusName: string
): Promise<Transition | null> {
  const transitions = await getTransitions(client, issueKeyOrId);
  return transitions.find(
    t => t.name.toLowerCase() === targetStatusName.toLowerCase() ||
         t.to.name.toLowerCase() === targetStatusName.toLowerCase()
  ) || null;
}

Step 4: Execute Transition

interface TransitionOptions {
  resolution?: { name: string } | { id: string };
  comment?: string;
  fields?: Record<string, any>;
}

async function transitionIssue(
  client: JiraClient,
  issueKeyOrId: string,
  transitionId: string,
  options: TransitionOptions = {}
): Promise<void> {
  const body: any = {
    transition: { id: transitionId },
  };

  if (options.resolution || options.fields) {
    body.fields = { ...options.fields };
    if (options.resolution) {
      body.fields.resolution = options.resolution;
    }
  }

  if (options.comment) {
    body.update = {
      comment: [
        {
          add: {
            body: {
              type: 'doc',
              version: 1,
              content: [
                {
                  type: 'paragraph',
                  content: [{ type: 'text', text: options.comment }],
                },
              ],
            },
          },
        },
      ],
    };
  }

  await client.request(`/issue/${issueKeyOrId}/transitions`, {
    method: 'POST',
    body: JSON.stringify(body),
  });
}

Step 5: High-Level Transition Helper

async function moveIssueTo(
  client: JiraClient,
  issueKeyOrId: string,
  targetStatus: string,
  options: TransitionOptions = {}
): Promise<boolean> {
  const transition = await findTransitionByName(client, issueKeyOrId, targetStatus);

  if (!transition) {
    console.error(`No transition found to status: ${targetStatus}`);
    return false;
  }

  // Check if resolution is required
  if (transition.fields?.resolution?.required && !options.resolution) {
    // Default to "Done" resolution
    options.resolution = { name: 'Done' };
  }

  await transitionIssue(client, issueKeyOrId, transition.id, options);
  return true;
}

Step 6: Bulk Transition

async function bulkTransition(
  client: JiraClient,
  issueKeys: string[],
  targetStatus: string,
  options: TransitionOptions = {}
): Promise<{ success: string[]; failed: string[] }> {
  const results = { success: [] as string[], failed: [] as string[] };

  for (const issueKey of issueKeys) {
    try {
      const success = await moveIssueTo(client, issueKey, targetStatus, options);
      if (success) {
        results.success.push(issueKey);
      } else {
        results.failed.push(issueKey);
      }
    } catch (error) {
      results.failed.push(issueKey);
    }
  }

  return results;
}

Common Transitions

Most Jira projects have these standard transitions:

| From Status | Transition Name | To Status | |-------------|-----------------|-----------| | To Do | Start Progress | In Progress | | In Progress | Done | Done | | In Progress | Stop Progress | To Do | | Done | Reopen | To Do |

Note: These names vary by workflow configuration.

Resolution Values

When transitioning to "Done", you often need a resolution:

| Resolution | Description | |------------|-------------| | Done | Work completed | | Won't Do | Not planning to do | | Duplicate | Already exists | | Cannot Reproduce | Cannot reproduce issue |

curl Examples

Get Available Transitions

curl -X GET "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions?expand=transitions.fields" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Accept: application/json"

Execute Transition (Simple)

curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "transition": { "id": "21" }
  }'

Transition with Resolution (for Done)

curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "transition": { "id": "31" },
    "fields": {
      "resolution": { "name": "Done" }
    }
  }'

Transition with Comment

curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "transition": { "id": "21" },
    "update": {
      "comment": [
        {
          "add": {
            "body": {
              "type": "doc",
              "version": 1,
              "content": [
                {
                  "type": "paragraph",
                  "content": [{ "type": "text", "text": "Moving to In Progress" }]
                }
              ]
            }
          }
        }
      ]
    }
  }'

API Response (204 No Content)

A successful transition returns 204 No Content with an empty body.

Error Handling

Common Errors

| Error | Cause | Solution | |-------|-------|----------| | 400 Bad Request | Invalid transition ID | Query transitions first | | 400 Bad Request | Missing required resolution | Add resolution field | | 403 Forbidden | No permission to transition | Check workflow permissions | | 404 Not Found | Issue doesn't exist | Verify issue key |

Error Response Example

{
  "errorMessages": [
    "You must specify a resolution when transitioning issues to the 'Done' status."
  ],
  "errors": {
    "resolution": "Resolution is required."
  }
}

Workflow Discovery Pattern

async function discoverWorkflow(
  client: JiraClient,
  issueKeyOrId: string
): Promise<Map<string, Transition[]>> {
  // Get transitions from current state
  const transitions = await getTransitions(client, issueKeyOrId);

  console.log(`Available transitions from current state:`);
  for (const t of transitions) {
    console.log(`  ${t.id}: ${t.name} → ${t.to.name}`);
    if (t.fields?.resolution?.required) {
      console.log(`    (requires resolution)`);
    }
  }

  return new Map([
    ['current', transitions]
  ]);
}

Common Mistakes

  • Using transition ID without querying first
  • Forgetting resolution when moving to Done
  • Assuming transition IDs are same across projects
  • Not handling 204 response (empty body is success)

References

Version History

  • 2025-12-10: Created
Jira Transitions Skill Skill | Agent Skills