How this skill is triggered — by the user, by Claude, or both
Slash command
/two-node:create-rhel-storiesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
```bash
/two-node:create-rhel-stories [--dry-run] [RHEL-XXXXX ...] [jql:<JQL query>]
Create OCPEDGE stories for groups of related TNF RHEL verification tickets that don't already have a corresponding story on the OCPEDGE backlog. Link the RHEL tickets to the new story and add the required components.
$ARGUMENTS (optional): One of the following input formats, optionally preceded by --dry-run
RHEL-12345 RHEL-12346 RHEL-12347): Process these tickets directlyjql:project = RHEL AND component = "resource-agents"): Search for tickets matching the query--dry-run): Auto-discover untested TNF resource-agents tickets using the default JQL--dry-run (optional): Preview the plan without creating or modifying anything in JiraThis command requires the mcp-atlassian MCP server for Jira access. This plugin includes an .mcp.json that configures it automatically using a pinned container image. The user needs:
podman installedJIRA_USERNAME environment variable set with their Red Hat emailJIRA_API_TOKEN environment variable set with a Jira API tokenIf the mcp__mcp-atlassian__jira_search tool is not available when the command runs, stop and show these setup instructions instead of proceeding.
All scripts are run relative to the plugin directory:
SCRIPTS_DIR=${PLUGIN_DIR}/scripts
This command uses a helper script for deterministic operations. The script is at:
${SCRIPTS_DIR}/ocpedge_rhel_helper.py
Available subcommands:
parse-args <arguments> — Parse input into {mode, jql?, tickets?}group-tickets <tickets_json> — Group tickets by base summary, clone links, OCPBUGS refsgenerate-description <ticket_keys_json> — Generate story description markdowngenerate-summary <base_summary> — Generate story summary with prefixcheck-links <tickets_json> — Check which tickets already have OCPEDGE linksfind-missing-clones <tickets_json> — Find clone-linked tickets not in the current set (sibling clones to fetch)All subcommands accept/return JSON. Use Bash to call them.
Pass - as the argument to read JSON from stdin (avoids ARG_MAX limits with large payloads):
echo '<large_json>' | python3 "${SCRIPTS_DIR}/ocpedge_rhel_helper.py" group-tickets -
When no arguments are provided (or only --dry-run), automatically search for TNF resource-agents tickets that need testing using this default JQL:
project = RHEL AND summary ~ "\\[TNF\\]" AND component = "resource-agents" AND ("Preliminary Testing" = Requested AND "Test Coverage" is EMPTY) AND (fixVersion in unreleasedVersions() OR fixVersion is EMPTY) ORDER BY created DESC
This aligns with the OCPEDGE RHEL Verification board (board 11551) filter, which shows all [TNF] resource-agents RHEL tickets, but further narrows to only untested ones.
If $ARGUMENTS contains --dry-run, the command runs Steps 0–5 (read-only operations and plan presentation) but does NOT execute Steps 6–7 (no issues created, no links added, no subtasks created). Instead, after presenting the plan, it shows what would be created and exits. This is useful for testing the grouping logic and verifying the plan against real Jira data without modifying anything.
Run the helper to parse the input:
python3 "${SCRIPTS_DIR}/ocpedge_rhel_helper.py" parse-args $ARGUMENTS
This returns JSON with mode ("jql", "tickets", or "interactive"), dry_run (boolean), and the parsed values.
mode is "interactive", use auto-discover mode: search with the default JQL for untested resource-agents tickets (see Auto-Discover Default JQL above).mode is "jql", use the jql field in Step 1.mode is "tickets", use the tickets list in Step 2.dry_run is true, stop after Step 5 (the plan) — do not create or modify anything in Jira.If specific ticket keys given: Use those directly.
If JQL query given (user-provided or auto-discover default): Search for tickets:
mcp__mcp-atlassian__jira_search(
jql='<JQL query>',
fields="summary,status,fixVersions,issuelinks,components,priority,description,customfield_10879,customfield_10638",
limit=50
)
For auto-discover mode (no arguments), use:
project = RHEL AND summary ~ "\\[TNF\\]" AND component = "resource-agents" AND ("Preliminary Testing" = Requested AND "Test Coverage" is EMPTY) AND (fixVersion in unreleasedVersions() OR fixVersion is EMPTY) ORDER BY created DESC
The JQL filter may only return a subset of clones for a given issue (e.g. only the untested ones). The OCPEDGE story should link all clones, not just the ones matching the filter.
Run the helper to find missing clones:
python3 "${SCRIPTS_DIR}/ocpedge_rhel_helper.py" find-missing-clones '<tickets_json>'
This returns a JSON array of ticket keys that are referenced via clone links but weren't in the search results. For each missing key, fetch it with jira_get_issue and add it to the ticket set. Then run find-missing-clones again on the expanded set — repeat until no new clones are found (this walks the full clone tree via the parent).
Typically one round is enough (the search results link to their parent, and fetching the parent reveals all siblings). Limit to 5 iterations maximum to prevent infinite loops in case of circular clone references.
If tickets were already returned with full details from Step 1 (JQL search includes the required fields), skip re-fetching and use those results directly.
Otherwise, for each RHEL ticket, fetch full details:
mcp__mcp-atlassian__jira_get_issue(
issue_key="RHEL-XXXXX",
fields="summary,status,fixVersions,issuelinks,components,priority,description"
)
Fetch tickets in parallel where possible to minimize wait time.
Extract from each ticket:
rhel-9.6.z, rhel-9.8, rhel-9.9Run the helper script to group tickets deterministically:
python3 "${SCRIPTS_DIR}/ocpedge_rhel_helper.py" group-tickets '<tickets_json>'
Pass a JSON array of ticket objects (each with key, summary, issuelinks, and optionally description fields from Step 2).
The script groups tickets using a union-find algorithm based on:
[rhel-9.6.z]Returns a JSON array of groups, each with base_summary, tickets, ocpbugs_refs, and existing_ocpedge_links.
For each group of related RHEL tickets, check if an OCPEDGE story already exists.
Method 1 — The existing_ocpedge_links field from the group-tickets output already contains OCPEDGE links found in the tickets' issuelinks. If non-empty, those are existing stories.
Method 2 — Search OCPEDGE project directly: For each group, search using the base summary:
mcp__mcp-atlassian__jira_search(
jql='project = OCPEDGE AND summary ~ "<base summary keywords>" AND issuetype = Story ORDER BY created DESC',
fields="summary,status,issuelinks,components",
limit=5
)
Use key distinctive words from the base summary (not common words like "the", "a", "in"). If the summary references an OCPBUGS ticket, include that in the search:
mcp__mcp-atlassian__jira_search(
jql='project = OCPEDGE AND text ~ "OCPBUGS-XXXXX" AND issuetype = Story ORDER BY created DESC',
fields="summary,status,issuelinks,components",
limit=5
)
If an existing OCPEDGE story is found for a group:
If all tickets have Preliminary Testing = Pass (or are Closed), the work is done — skip, no action needed.
If some tickets are still untested (Preliminary Testing = Requested or empty), present the user with options in Step 5:
Do NOT decide automatically — always ask the user which action to take for each Closed story with untested tickets.
Before creating anything, present a summary table to the user and ask for confirmation:
## Plan
### Groups to Create OCPEDGE Stories For
| # | Base Summary | RHEL Tickets | Existing OCPEDGE |
|---|-------------|-------------|-----------------|
| 1 | <summary> | RHEL-111, RHEL-222, RHEL-333 | None — will create |
| 2 | <summary> | RHEL-444, RHEL-555 | OCPEDGE-789 (open) — will add missing links |
| 3 | <summary> | RHEL-666, RHEL-777 | OCPEDGE-101 (Closed) — has untested tickets: **create new / skip?** |
| 4 | <summary> | RHEL-888 | OCPEDGE-202 (Closed) — all tickets passed, no action needed |
| 5 | <summary> | RHEL-999 | OCPEDGE-303 (open) — fully linked, no action needed |
### Stories to Create: X
### Links to Add: Y
Proceed? (yes/no)
Use AskUserQuestion to get confirmation. Do NOT proceed without explicit user approval.
The user may also:
Accommodate any adjustments before proceeding.
If dry_run is true: After presenting the plan, also show the exact summaries and descriptions that would be created (using generate-summary and generate-description), then stop. Print 🏁 Dry run complete — no changes were made in Jira. and exit. Do NOT proceed to Step 6 or beyond.
For each group that needs a new story, use the helper to generate the summary and description:
python3 "${SCRIPTS_DIR}/ocpedge_rhel_helper.py" generate-summary "<base_summary>"
python3 "${SCRIPTS_DIR}/ocpedge_rhel_helper.py" generate-description '["RHEL-111", "RHEL-222"]'
Then create the issue:
mcp__mcp-atlassian__jira_create_issue(
project_key="OCPEDGE",
summary="<output of generate-summary>",
issue_type="Story",
description="<output of generate-description>",
components="Two Node Fencing,QE,RHEL-Verification"
)
For each newly created OCPEDGE story, create two subtasks:
Subtask 1 — Bug fix verification:
mcp__mcp-atlassian__jira_create_issue(
project_key="OCPEDGE",
summary="Bug fix verification",
issue_type="Sub-task",
additional_fields="{\"parent\": \"OCPEDGE-XXXX\"}"
)
Subtask 2 — Automation:
mcp__mcp-atlassian__jira_create_issue(
project_key="OCPEDGE",
summary="Automation: adding to Polarion + Origin (two node) repo",
issue_type="Sub-task",
additional_fields="{\"parent\": \"OCPEDGE-XXXX\"}"
)
Create both subtasks in parallel for each story. Replace OCPEDGE-XXXX with the key of the story created in Step 6.
For each RHEL ticket that needs to be linked to its OCPEDGE story (both newly created and existing stories with missing links):
mcp__mcp-atlassian__jira_create_issue_link(
link_type="Relates",
inward_issue_key="<OCPEDGE-XXXX>",
outward_issue_key="<RHEL-XXXXX>"
)
Create links in parallel where possible.
After all operations complete, present a summary:
## Results
### Created Stories
| OCPEDGE Story | Summary | RHEL Tickets Linked | Subtasks |
|--------------|---------|-------------------|----------|
| [OCPEDGE-XXX](https://issues.redhat.com/browse/OCPEDGE-XXX) | <summary> | RHEL-111, RHEL-222, RHEL-333 | OCPEDGE-AAA (verification), OCPEDGE-BBB (automation) |
### Added Links to Existing Stories
| OCPEDGE Story | New Links Added |
|--------------|----------------|
| [OCPEDGE-YYY](https://issues.redhat.com/browse/OCPEDGE-YYY) | RHEL-444, RHEL-555 |
### Skipped (Already Fully Linked)
| OCPEDGE Story | RHEL Tickets |
|--------------|-------------|
| [OCPEDGE-ZZZ](https://issues.redhat.com/browse/OCPEDGE-ZZZ) | RHEL-666 |
### Components Set on All New Stories
- Two Node Fencing
- QE
- RHEL-Verification
mcp__mcp-atlassian__jira_search_fields and ask the user/two-node:create-rhel-stories
Searches for untested TNF resource-agents RHEL tickets using the default JQL and creates OCPEDGE stories.
/two-node:create-rhel-stories --dry-run
Previews the plan without creating or modifying anything in Jira.
/two-node:create-rhel-stories RHEL-12345 RHEL-12346 RHEL-12347
Processes only the specified RHEL tickets.
/two-node:create-rhel-stories jql:project = RHEL AND component = "resource-agents" AND status != Closed ORDER BY created DESC
Searches for tickets matching the JQL query.
/two-node:create-rhel-stories --dry-run RHEL-12345 RHEL-12346
Previews what would be created for specific tickets without modifying Jira.
Two Node Fencing, QE, RHEL-VerificationGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub openshift-eng/edge-tooling --plugin two-node