From dx-core
Create or close child Task work items under an Azure DevOps/Jira User Story. Use to break down a story into FE/BE/Authoring tasks with hour estimates, or use "close" argument to close all child tasks after development is done.
npx claudepluginhub easingthemes/dx-aem-flow --plugin dx-coreThis skill is limited to using the following tools:
You create child Task work items under a parent User Story in Azure DevOps or Jira. You read the story, infer which work groups apply (BE, FE, Authoring), plan tasks with hour estimates that match the Story Points budget, present the plan for user approval, then create the tasks via ADO or Jira MCP.
Creates Azure DevOps Tasks to log completed work on User Stories with pre-set hours. Validates CLAUDE.md config and gathers details via interactive prompts. Ideal for frequent daily logging.
Converts Confluence spec pages into Jira backlogs with Epics and linked tickets. Use for generating backlogs from specs, breaking down requirements, or creating issues from Confluence.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
You create child Task work items under a parent User Story in Azure DevOps or Jira. You read the story, infer which work groups apply (BE, FE, Authoring), plan tasks with hour estimates that match the Story Points budget, present the plan for user approval, then create the tasks via ADO or Jira MCP.
Read shared/provider-config.md for provider detection and field mapping.
.ai/config.yamltracker.provider (preferred) or scm.provider (legacy fallback):
ado → Azure DevOps (default if not set)jira → Atlassian Jiraprovider variable for branching in subsequent steps..ai/config.yaml scm.org.ai/config.yaml scm.project.ai/config.yaml jira.url.ai/config.yaml jira.project-key.ai/config.yaml jira.child-issue-type (default: Sub-task)The first token of $ARGUMENTS is the work item ID (numeric for ADO, KEY-123 for Jira) or a full URL.
If the user provides a URL, extract the ID/key from it. Supported formats:
https://dev.azure.com/{org}/{project}/_workitems/edit/{id}https://{org}.visualstudio.com/{project}/_workitems/edit/{id}https://{instance}/browse/{KEY-123}Input detection (see shared/provider-config.md):
/^[A-Z]+-\d+$/ → Jira issue key/^\d+$/ → numeric ID; check tracker.providerdev.azure.com or visualstudio.com → ADO/browse/ → JiraRemaining tokens are optional group filters: BE, FE, Authoring (case-insensitive). If provided, only create tasks for those groups.
/dx-req-tasks 2416553 → all groups (inferred)
/dx-req-tasks 2416553 BE → only BE tasks
/dx-req-tasks 2416553 FE BE → only FE + BE tasks
/dx-req-tasks 2416553 Authoring → only Authoring tasks
/dx-req-tasks 2416553 close → close all child tasks
If no argument is provided, ask the user for the work item ID.
If close is in the arguments: Skip steps 2-10. Jump to Close Mode (at the end of this skill).
Before making any ADO calls, load the required tools:
ToolSearch("+ado wit")
mcp__ado__wit_get_work_item
project: "<ADO project from config>"
id: <work item ID>
expand: "relations"
Extract:
Microsoft.VSTS.Scheduling.StoryPoints (number)System.AreaPathSystem.IterationPathSystem.AssignedTo (the person assigned to the parent story — used to assign child tasks)System.Description (HTML)Microsoft.VSTS.Common.AcceptanceCriteria (HTML)System.StateSystem.LinkTypes.Hierarchy-Forward)mcp__atlassian__jira_get_issue
issue_key: "<issue key>"
Map fields:
fields.story_points or fields.<jira.custom-fields.story-points> (read from config)fields.components[].name (ADO equivalent: Area Path)fields.sprint.name (ADO equivalent: Iteration Path)fields.assignee.displayNamemcp__atlassian__jira_search with parent = <issue_key> AND issuetype = Sub-taskIf Story Points is missing or 0, ask the user: "Story has no Story Points set. How many SP should I use for budget?"
Calculate total budget hours = Story Points × 8.
Always check for existing children from the relations extracted in step 3. If child IDs exist, fetch their details:
mcp__ado__wit_get_work_items_batch_by_ids
project: "<ADO project from config>"
ids: [<child IDs>]
fields: ["System.Title", "System.WorkItemType", "System.State",
"Microsoft.VSTS.Scheduling.OriginalEstimate",
"Microsoft.VSTS.Scheduling.RemainingWork"]
Filter to only Task type work items (ignore Bugs, Test Cases, etc.).
Children are fetched in Step 3 via JQL search. For each child sub-task returned:
PROJ-124)fields.summaryfields.status.namefields.timeoriginalestimate (in seconds — divide by 3600 for hours)fields.timeestimate (in seconds — divide by 3600 for hours)For each existing Task, record:
BE -, FE -, Authoring -)If an existing Task has no OriginalEstimate (null or 0), infer an estimate based on the task title and parent story content:
| Title pattern | Inferred hours |
|---|---|
BE - PR Review or FE - PR Review | 1 |
* - Unit Tests | 3 |
* - Testing | 2 |
* - Planning | 1 |
* - Implement * or other implementation tasks | 8 |
Authoring - * (any authoring task) | 4 |
| Anything else unclear | 4 (default) |
Mark inferred estimates with (inferred) in the display so the user can see which ones were guessed. These inferred values are used for budget calculation and will be proposed for update in the confirmation step.
existing_hours = sum of OriginalEstimate (actual or inferred) across all existing Tasks
remaining_budget = (story_points × 8) - existing_hours
If existing Tasks are found, print them:
### Existing Tasks (<existing_count> tasks, <existing_hours>h allocated)
| ID | Title | Hours | State |
|----|-------|-------|-------|
| #12345 | BE - Implement Sling Model | 8 | Active |
| #12346 | FE - PR Review | 1 (inferred) | New |
**Budget:** <budget>h total, <existing_hours>h allocated, **<remaining_budget>h remaining**
Tasks with (inferred) hours will have their estimates set in ADO after user confirmation (step 9).
remaining_budget > 0 → plan new tasks for the remaining hoursremaining_budget = 0 → print "Budget fully allocated. No new tasks needed." and stop (unless user requests specific additions)remaining_budget < 0 → warn: "Existing tasks exceed budget by Xh. Proceed with planning additional tasks anyway?" Wait for confirmation.When planning new tasks (step 6), skip any task that already exists by matching title prefix patterns:
BE - PR Review already exists → don't create anotherFE - Testing already exists → don't create anotherBE - Implement model changes covers the BE - Implement slot)If all groups already have tasks but some tasks have no estimates (OriginalEstimate is null/0), switch to estimate-only mode:
(inferred)wit_update_work_items_batch (step 9)If there are both existing tasks without estimates and remaining budget for new tasks:
Reference .claude/rules/ for domain-specific naming conventions and group signals.
Parse square bracket tags from the title: [BE], [FE], [Authoring].
[BE] → include BE group[FE] → include FE group[Authoring] → include Authoring groupIf the title has no recognizable tags, analyze the Description and Acceptance Criteria:
| Signal | Group |
|---|---|
| Mentions model, exporter, Java, service, backend, API, servlet, controller | BE |
| Mentions frontend, rendering, template, CSS, JavaScript, UI, design, component markup | FE |
| Mentions dialog, authoring, content author, configuration, CMS | Authoring |
If nothing is clear from content, default to all three groups.
If the user passed group filters in the arguments, override the inferred groups. Only create tasks for the specified groups.
If the story title or description mentions a specific component name and a component index exists (.ai/project/component-index.md or .ai/component-index.md), grep it for the component:
Grep(".ai/project/component-index.md", "<component-name>")
This helps generate more specific implementation task titles (e.g., "BE - Update StarterKitExporter" instead of generic "BE - Implement exporter").
For each active group, generate tasks. Follow these constraints:
| Group | Max Tasks | Permanent Tasks | Nature |
|---|---|---|---|
| BE | 5 | BE - PR Review (1h), BE - Unit Tests (2-4h) | Development (models, services) |
| FE | 5 | FE - PR Review (1h), FE - Testing (1-2h) | Development (templates, CSS, JS) |
| Authoring | 2 | (none — no PR or testing) | Content authoring (non-development) |
Authoring is NOT development. Authoring tasks are for content authors who configure components — editing dialogs, setting up content, verifying pages. There is no code, no PR, no unit tests. Authoring tasks are purely CMS authoring work.
Based on story content, create implementation tasks. Examples:
BE:
BE - Implement model (6-10h)BE - Update exporter (6-10h)BE - Implement service logic (6-10h)FE:
FE - Implement component rendering (6-10h)FE - Implement responsive styles (6-10h)FE - Update component template (6-10h)Authoring:
Authoring - Configure component dialog (2-4h)Authoring - Verify authored content (1-2h)BE - Planning or FE - Planning (1-2h) — only if story is complex (3+ SP)total_budget = story_points × 8
existing_hours = sum of OriginalEstimate from existing child Tasks (step 4)
remaining_budget = total_budget - existing_hours
groups = active groups (1-3), minus groups fully covered by existing tasks
# Split remaining_budget proportionally across groups that need new tasks
if all 3 groups need tasks:
BE gets ~45%, FE gets ~40%, Authoring gets ~15%
if BE + FE only:
BE gets ~50%, FE gets ~50%
if single group:
that group gets 100%
# Within each group:
1. Skip permanent tasks that already exist (matched in step 4)
2. Allocate remaining permanent tasks first (PR Review 1h, Testing/Unit Tests)
3. Fill remaining group budget with implementation tasks
4. Adjust implementation task hours to consume exact remaining_budget
Print the task breakdown table. If existing tasks were found, show both sections:
## Task Breakdown — Story #<id> (<story_points> SP = <budget>h)
**<Story Title>**
**Groups:** BE, FE, Authoring
**Area Path:** <area_path>
**Iteration:** <iteration_path>
### Existing Tasks (already in ADO)
| ID | Group | Title | Hours | State |
|----|-------|-------|-------|-------|
| #12345 | BE | BE - Implement model | 8 | Active |
| #12346 | FE | FE - PR Review | 1 | New |
| | | **Subtotal** | **9** | |
### New Tasks (to be created)
| # | Group | Task Title | Hours |
|---|-------|-----------|-------|
| 1 | BE | BE - Unit Tests | 3 |
| 2 | BE | BE - PR Review | 1 |
| 3 | FE | FE - Implement component rendering | 8 |
| 4 | FE | FE - Testing | 2 |
| 5 | Authoring | Authoring - Configure dialog | 4 |
| 6 | Authoring | Authoring - PR Review | 1 |
| | | **Subtotal** | **19** |
> **Budget:** 28h (3.5 SP × 8h) = 9h existing + 19h new ✓ Balanced
Want to adjust? You can:
- Remove a task: "remove #5"
- Add a task: "add FE - Update styles 4h"
- Change hours: "#4 to 6h"
- Change title: "#1 title BE - Update model"
- Or say **"go"** to create all tasks in ADO
If no existing tasks, omit the "Existing Tasks" section and show only "New Tasks".
If the user requests changes:
Repeat until the user says "go", "create", "yes", "looks good", or similar affirmation.
Once approved, create all tasks as children of the parent story:
mcp__ado__wit_add_child_work_items
parentId: <story ID>
project: "<ADO project from config>"
workItemType: "Task"
items: [
{
"title": "<task title>",
"description": "",
"areaPath": "<from parent>",
"iterationPath": "<from parent>"
},
...for each task
]
The response returns the created work item IDs.
Create each task as a Sub-task (one at a time — no batch creation with parent linking):
mcp__atlassian__jira_create_issue
project_key: "<jira.project-key>"
issue_type: "<jira.child-issue-type>" # default: "Sub-task"
summary: "<task title>"
parent_key: "<parent issue key>"
description: ""
Repeat for each task. The response returns the created issue key.
After creation, set Original Estimate, Remaining Work, and Assigned To on all newly created tasks. Also set estimates on existing tasks that had missing estimates (marked (inferred) in step 4).
Assignment rule: All newly created tasks are assigned to the same person as the parent story (System.AssignedTo). If the parent has no assignee, leave tasks unassigned.
mcp__ado__wit_update_work_items_batch
updates: [
{
"id": <task ID>,
"path": "/fields/Microsoft.VSTS.Scheduling.OriginalEstimate",
"value": "<hours>"
},
{
"id": <task ID>,
"path": "/fields/Microsoft.VSTS.Scheduling.RemainingWork",
"value": "<hours>"
},
{
"id": <task ID>,
"path": "/fields/System.AssignedTo",
"value": "<parent story assignee email or display name>"
},
...for each new task AND each existing task with inferred estimates
]
Note: Only set System.AssignedTo on newly created tasks. Do NOT reassign existing tasks — they may have been intentionally assigned to someone else.
For each created sub-task, set estimates and assignee:
mcp__atlassian__jira_update_issue
issue_key: "<created sub-task key>"
fields: {
"timeoriginalestimate": <hours * 3600>,
"timeestimate": <hours * 3600>,
"assignee": {"name": "<parent assignee username>"}
}
Note: Jira stores time estimates in seconds, not hours. Multiply by 3600.
In estimate-only mode (no new tasks), this is the only ADO write operation — skip step 8 entirely. Do NOT change assignment on existing tasks in estimate-only mode.
## Created <N> Tasks under Story #<id>
| # | ID | Title | Hours | Link |
|---|-----|-------|-------|------|
| 1 | #<id> | BE - Implement model | 8 | [Open]({scm.org}/{scm.project_url_encoded}/_workitems/edit/<id>) |
| 2 | #<id> | BE - Unit Tests | 3 | [Open](...) |
| ... | | | | |
| | | **Total** | **<budget>h** | |
All tasks linked as children of [#<story_id>]({scm.org}/{scm.project_url_encoded}/_workitems/edit/<story_id>).
Where {scm.org} and {scm.project_url_encoded} are read from .ai/config.yaml.
If provider = jira:
| # | Key | Title | Hours | Link |
|---|---|---|---|---|
| 1 | PROJ-124 | BE - Implement model | 8 | Open |
When the argument contains close, this skill closes all open child tasks under the story.
ToolSearch("+ado wit")
mcp__ado__wit_get_work_item
project: "<ADO project from config>"
id: <work item ID>
expand: "relations"
Extract child Task IDs from relations (System.LinkTypes.Hierarchy-Forward).
If no children found, print "No child tasks found." and STOP.
Fetch child details:
mcp__ado__wit_get_work_items_batch_by_ids
project: "<ADO project from config>"
ids: [<child IDs>]
fields: ["System.Title", "System.WorkItemType", "System.State",
"Microsoft.VSTS.Scheduling.OriginalEstimate",
"Microsoft.VSTS.Scheduling.RemainingWork",
"Microsoft.VSTS.Scheduling.CompletedWork"]
Filter to Task type only.
Closeable: Tasks in state New, Active, or In Progress (not already Closed, Removed, or Resolved).
If no closeable tasks, print "All tasks already closed." and STOP.
Check that development is actually complete before closing:
bash .ai/lib/dx-common.sh find-spec-dir <work-item-id>implement.md exists, check that all steps are donedone, warn:
⚠ implement.md has <N> incomplete steps. Close tasks anyway? (y/n)
Wait for confirmation.If no spec dir or no implement.md, skip this check (user may be closing manually).
For each closeable task, compute the time fields:
completed_work_new = (existing CompletedWork or 0) + (existing RemainingWork or 0)
remaining_work_new = 0
This moves whatever time was remaining into completed work — the task used its full budget.
## Close Tasks — Story #<id>
| ID | Title | State | Original | Completed → | Remaining → |
|----|-------|-------|----------|-------------|-------------|
| #12345 | BE - Implement model | Active | 8h | 0 → 8h | 8 → 0h |
| #12346 | FE - PR Review | New | 1h | 0 → 1h | 1 → 0h |
| #12347 | BE - Unit Tests | Closed | 3h | (already closed) | |
**<N> tasks will be closed.** Proceed? (y/n)
Wait for user confirmation.
For each closeable task, update in this order:
mcp__ado__wit_update_work_items_batch
updates: [
{
"id": <task ID>,
"path": "/fields/Microsoft.VSTS.Scheduling.CompletedWork",
"value": <completed_work_new>
},
{
"id": <task ID>,
"path": "/fields/Microsoft.VSTS.Scheduling.RemainingWork",
"value": 0
},
{
"id": <task ID>,
"path": "/fields/System.State",
"value": "Closed"
},
...for each closeable task
]
mcp__atlassian__jira_update_issue
issue_key: "<sub-task key>"
fields: {
"timespent": <completed_work_new * 3600>,
"timeestimate": 0
}
transition: "Done"
Note: Jira transitions vary by workflow. Use mcp__atlassian__jira_get_transitions to find the "Done" transition ID if "Done" doesn't work by name. Jira stores time in seconds — multiply hours by 3600.
## Closed <N> Tasks under Story #<id>
| ID | Title | Completed | Previous State |
|----|-------|-----------|---------------|
| #12345 | BE - Implement model | 8h | Active |
| #12346 | FE - PR Review | 1h | New |
**Total completed:** <sum>h
All child tasks closed. Remaining work zeroed, time moved to Completed Work.
/dx-req-tasks 2416553 — Fetches story #2416553, infers BE+FE+Authoring groups from the title and description, plans tasks with hours totaling Story Points x 8, presents the breakdown for approval, then creates child Tasks in ADO.
/dx-req-tasks 2416553 FE — Creates only Frontend tasks (FE - Implement component rendering, FE - Testing, FE - PR Review) under the story, skipping BE and Authoring groups.
/dx-req-tasks 2416553 (with existing tasks) — Detects 3 existing child Tasks already consuming 24h of the 40h budget, plans new tasks for the remaining 16h, and fills in missing hour estimates on existing tasks marked (inferred).
/dx-req-tasks 2416553 close — Fetches child tasks, checks implement.md steps are all done, shows close plan with time updates (Remaining Work → Completed Work), and after confirmation closes all tasks. Sprint burndown and capacity tracking stay accurate.
"Story has no Story Points set" Cause: The parent story lacks a Story Points value, which is needed to calculate the hour budget. Fix: Set Story Points on the ADO work item first, or answer the prompt with the SP value to use.
Budget exceeds or doesn't match total hours Cause: Existing child tasks already exceed the SP x 8 budget, or manual adjustments shifted the total. Fix: The skill warns about the mismatch. You can say "proceed anyway" or adjust individual task hours in the interactive table before confirming.
"MCP tool not found" or ADO call fails
Cause: ADO MCP tools were not loaded, or the PAT lacks Work Items write permissions.
Fix: Ensure .mcp.json has the ADO server configured (run /dx-init if not). Verify your ADO PAT has "Work Items: Read & Write" scope.