con un clic
speckit-taskstoissues
Convert tasks from tasks.md into GitHub issues.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Convert tasks from tasks.md into GitHub issues.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
| name | speckit-taskstoissues |
| description | Convert tasks from tasks.md into GitHub issues. |
| compatibility | Requires spec-kit project structure with .specify/ directory |
| metadata | {"author":"github-spec-kit","source":"preset:taskstoissues-jira"} |
| user-invocable | true |
| disable-model-invocation | false |
$ARGUMENTS
You MUST consider the user input before proceeding (if not empty).
Check for extension hooks (before tasks-to-issues conversion):
.specify/extensions.yml exists in the project root.hooks.before_taskstoissues keyenabled is explicitly false. Treat hooks without an enabled field as enabled by default.condition expressions:
condition field, or it is null/empty, treat the hook as executablecondition, skip the hook and leave condition evaluation to the HookExecutor implementation.) with hyphens (-). For example, speckit.git.commit → /speckit-git-commit.optional flag:
optional: true):
## Extension Hooks
**Optional Pre-Hook**: {extension}
Command: `/{command}`
Description: {description}
Prompt: {prompt}
To execute: `/{command}`
optional: false):
## Extension Hooks
**Automatic Pre-Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
Wait for the result of the hook command before proceeding to the Outline.
.specify/extensions.yml does not exist, skip silentlySetup: Run .specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. Extract the absolute path to tasks.md from FEATURE_DIR. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
Load project configuration:
Read the project-level Jira config from dev/jira.yml at the repo root. Required keys: cloud, default_project_key, default_issue_type, custom_fields.epic_link, custom_fields.team, team.name, labels_default. Optional: team.id (cached UUID; auto-populated on first run), additional custom_fields.* entries (e.g. sprint, story_points) for future use.
[!CAUTION] If
dev/jira.ymldoes not exist, abort with:> dev/jira.yml not found. Copy .specify/presets/taskstoissues-jira/templates/jira.example.yml to dev/jira.yml at the repo root, fill in every REQUIRED field, and commit before re-running.
[!CAUTION] If any required top-level key is missing from
dev/jira.yml, abort with:> dev/jira.yml is missing required key '<key>'. See .specify/presets/taskstoissues-jira/templates/jira.example.yml for the full schema.Do not silently default.
[!CAUTION] If
default_project_keystill equals the example placeholderPROJ, abort with:> dev/jira.yml still has placeholder default_project_key 'PROJ'. Set it to your repo's Jira project key before re-running.
[!CAUTION] If
custom_fields.epic_linkorcustom_fields.teamequalscustomfield_XXXXX, abort with:> dev/jira.yml still has placeholder custom field IDs. Resolve real IDs with mcp__claude_ai_Atlassian__getJiraIssueTypeMetaWithFields and update the file before re-running.Do not invent IDs.
Resolve Atlassian cloud id: Call mcp__claude_ai_Atlassian__getAccessibleAtlassianResources once and match cloud from dev/jira.yml against the returned site URLs to obtain cloudId.
[!CAUTION] If
cloudIdcannot be resolved, orgetAccessibleAtlassianResourcesreturns more than one site without a unique match to the configuredcloud, abort with:> Multiple Atlassian sites accessible — pin one in dev/jira.yml under 'cloud' before re-running.
Resolve the Epic key:
git rev-parse --abbrev-ref HEAD. Build a case-insensitive regex from default_project_key of the form <default_project_key>-\d+ and match it against the branch name; uppercase the project-key portion of the match (e.g. with default_project_key=IFC, pmi-ifc-2521-auto-create-groups → IFC-2521).$ARGUMENTS against the same pattern.> Provide the Jira Epic for these tasks (e.g. <default_project_key>-1234): and wait for input. Validate the input matches the same <default_project_key>-\d+ pattern (case-insensitive).mcp__claude_ai_Atlassian__getJiraIssue and confirming fields.issuetype.name == "Epic". Abort if it is not an Epic.Resolve assignee account id: Call mcp__claude_ai_Atlassian__atlassianUserInfo once and read account_id from the response. That is the accountId of the user currently authenticated to the Atlassian MCP — the same user running the command — and becomes the assignee for every issue created in this run. Cache it for the duration of this run.
[!CAUTION] If
atlassianUserInfofails or returns noaccount_id, abort with:> Atlassian MCP not authenticated. Authenticate the Atlassian MCP server before re-running.Do not create any issues.
Resolve team UUID: From dev/jira.yml read team.name and team.id. Jira's Atlassian Teams picker (custom_fields.team) only accepts a UUID — team.name is kept in dev/jira.yml as a human label, never sent to Jira.
team.id is set, use it as-is.team.id is empty or missing, resolve it once via Atlassian:
mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql with:
cloudId from step 3jql = 'project = <default_project_key> AND "Team[Team]" is not EMPTY ORDER BY created DESC'fields = ["<custom_fields.team>"]maxResults = 20<custom_fields.team>.name for an exact case-insensitive match to team.name from dev/jira.yml. Extract the matching <custom_fields.team>.id (the UUID).dev/jira.yml at team.id so future runs skip this lookup, and use that UUID for issue creation.> Team '<team.name>' not found in Atlassian (searched recent issues in <default_project_key>). Set team.id explicitly in dev/jira.yml before re-running. Do not create any issues.Pass the resolved value to createJiraIssue as a bare UUID string (e.g. "<custom_fields.team>": "079e72e1-..."). The object form {"id": "<uuid>"} and the name form (e.g. "Backend Team") are both rejected by Jira's Teams picker.
Parse tasks.md by phase: Walk the file top-to-bottom and split it into phases, where a phase starts at a ## Phase <N>: <title> header and ends at the next ## Phase header (or end of file). For each phase capture:
phase_number (<N>) and phase_title (<title>) from the header linegoal_block: the **Goal**: paragraph immediately under the header, if presentindependent_test_block: the **Independent Test**: paragraph, if presenttasks: every unchecked - [ ] T<NNN> … line inside the phase, preserved verbatim including its [P] and [US<N>] tags and trailing file paths. Skip tasks already checked (- [x]).story: if the phase header matches User Story <n> or every child task carries the same [US<n>] tag, capture <n> as the phase's user-story number; otherwise leave unset.files: the union of affected file paths across the phase's task lines (trailing the summary or on subsequent indented lines), deduplicated and sorted.exit_criteria: any trailing **Exit criteria** / **Checkpoint** paragraph in the phase, if present.Skip phases that contain zero unchecked tasks. Build an ordered list phases: [{phase_number, phase_title, story, goal_block, independent_test_block, tasks, files, exit_criteria}].
Create one Jira issue per phase: For each parsed phase, call mcp__claude_ai_Atlassian__createJiraIssue with:
cloudId from step 3.
projectKey from default_project_key.
issueTypeName from default_issue_type.
summary = phase_title from step 7, with spec-kit-internal taxonomy tags stripped:
US<N> tags — already captured as a US<N> label below.P<N> tags — already captured by the Blocks links in step 9.[…] decorations carrying the same data ([P], [US<N>]).Keep meaningful tier markers (MVP, Beta, Alpha, etc.) and the descriptive feature text. Drop surrounding parentheses if their only remaining content is itself dropped (e.g. (P1 MVP) → MVP, but (Beta) stays as (Beta)).
Examples:
Phase 3: US1 (P1 MVP) — Auto-create groups → "MVP — Auto-create groups"Phase 1: US2 — Bulk import → "Bulk import"Phase 2: (Beta) Pagination on lists → "(Beta) Pagination on lists"description composed in this order:
goal_block (if any).independent_test_block (if any).## Tasks section containing the phase's task lines as a markdown checklist — each entry is the verbatim - [ ] T<NNN> … line.## Files section listing each affected path from files as a bullet.## Exit criteria section reproducing exit_criteria (if any)._Source:_ <relative path from repo root to tasks.md>.additional_fields:
assignee: { accountId: <resolved accountId> }labels: labels_default (from dev/jira.yml) + US<story> if the phase has a story valuecustom_fields:
<custom_fields.epic_link>: <Epic key from step 4> (e.g. customfield_10014: "IFC-2521")<custom_fields.team>: the bare UUID string resolved in step 6 (e.g. customfield_10001: "079e72e1-..."). Never send the object form {"id": "<uuid>"} and never send team.name.Record phase_number -> issueKey in an in-memory map.
[!CAUTION] UNDER NO CIRCUMSTANCES CREATE ISSUES IN A PROJECT OTHER THAN
default_project_keyFROMdev/jira.yml.
[!CAUTION] If any
createJiraIssuecall fails mid-run, stop immediately. Print the partialphase_number -> issueKeymap and instruct:> Partial run — delete the issues listed above manually in Jira before re-running. This skill is not idempotent in v1.Do not retry, do not roll back automatically.
Create phase-level dependency links: After every phase issue exists, derive the phase dependency graph from T<NNN> mentions inside each phase's task bodies:
tid -> phase_number index from the parse in step 7 — every T<NNN> owned by a phase maps to that phase's phase_number.P, scan its task bodies for T<NNN> mentions whose owning phase is not P itself. For each such mention, emit a directed edge (phase_of_mentioned_tid) -> P (the phase that owns the cited task blocks P).A -> B, B -> C, and A -> C, drop A -> C.(blocker_phase) -> (blocked_phase), call mcp__claude_ai_Atlassian__createIssueLink with:
type = "Blocks"inwardIssue = the blocker phase's Jira key (from the phase_number -> issueKey map)outwardIssue = the blocked phase's Jira keyPhase headers and [P] markers remain sequencing hints only — they are not first-class dependencies and must not produce link edges. The link source is exclusively T<NNN> mentions.
Summary output: Print a markdown table mapping Phase → IssueKey → Summary. Do not edit tasks.md automatically; the user can paste the mapping back if they want.
Check for extension hooks (after tasks-to-issues conversion):
Check if .specify/extensions.yml exists in the project root.
hooks.after_taskstoissues keyenabled is explicitly false. Treat hooks without an enabled field as enabled by default.condition expressions:
condition field, or it is null/empty, treat the hook as executablecondition, skip the hook and leave condition evaluation to the HookExecutor implementation.) with hyphens (-). For example, speckit.git.commit → /speckit-git-commit.optional flag:
optional: true):
## Extension Hooks
**Optional Hook**: {extension}
Command: `/{command}`
Description: {description}
Prompt: {prompt}
To execute: `/{command}`
optional: false):
## Extension Hooks
**Automatic Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
.specify/extensions.yml does not exist, skip silently