From edge-scrum
Use when analyzing the health of an OCP release cycle — evaluates Features, Initiatives, Epics, and Tasks from Jira to assess progress, identify risks, surface refinement gaps, and recommend actions to keep the team on track toward branch cut
How this skill is triggered — by the user, by Claude, or both
Slash command
/edge-scrum:release-healthThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are orchestrating a release health analysis for the OCPEDGE team. Data fetching runs inline using MCP tools and transform scripts. Analysis is delegated to a sub-agent.
You are orchestrating a release health analysis for the OCPEDGE team. Data fetching runs inline using MCP tools and transform scripts. Analysis is delegated to a sub-agent.
Before proceeding: Read
plugins/edge-scrum/references/Edge-Scrum-Laws.mdto find which law files apply to release health orchestration. For this skill, load:laws/00-team-roster.md,laws/01-jira-projects.md,laws/05-jira-features.md,laws/06-jira-fields.md,laws/09-sprint-policies.md,laws/14-agent-conventions.md. The configuration below is derived from the Laws — when in doubt, defer to the law files.
# Scrum Board (skill-specific; not in Laws)
board_id: "11479"
board_name: "OpenShift Edge Scrum"
sprint_prefix: ["OCPEDGE Sprint", "OpenShift Edge Sprint"]
# Custom Field IDs (Red Hat Jira instance-specific)
fields:
story_points: customfield_10028 # Numeric; Stories/Tasks/Spikes
epic_link: customfield_10014 # Story → Epic relationship
parent_link: customfield_10018 # Epic → Feature/Initiative relationship
qa_contact: customfield_10470 # User picker; QA owner
flagged: customfield_10021 # Array; non-empty = impediment
docs_approver: customfield_10473 # User picker; Doc Contact
sme: customfield_10475 # User picker; Subject Matter Expert
Rules:
plugins/edge-scrum/bin/) convert raw MCP data to structured JSONcheck-page.py to extract pagination info from persisted filesRead, Write, and jira_search — it consumes the structured JSONThe user may provide arguments: $ARGUMENTS
4.19, 5.0) → release version281-285) → first through last sprintbc:285 or branch-cut 285) → last sprint before feature freezeRead both files and hold in working memory:
Load these law files from plugins/edge-scrum/references/laws/:
00-team-roster.md — team capacity and .roster.json structure01-jira-projects.md — Jira projects and OCPBUGS components — authoritative project keys and component names05-jira-features.md — Feature/Initiative conventions and sizing06-jira-fields.md — custom field IDs09-sprint-policies.md — sprint capacity rules14-agent-conventions.md — agent orchestration conventionsplugins/edge-scrum/.roster.json — extract:
username, display_name, and sp_target per member.roster.json.example to .roster.json and populate it.The Laws are authoritative. Where this skill and the Laws conflict, the Laws win.
Parse arguments. Use AskUserQuestion for any missing values:
4.19, 5.0Compute and confirm:
FIRST = first sprint numberLAST = last sprint number (branch cut)TOTAL_SPRINTS = LAST − FIRST + 1REFINEMENT_SPRINT_NUM = FIRST (dedicated to spike creation, no delivery expected)TOTAL_DEV_SPRINTS = TOTAL_SPRINTS − 1TODAY = today's date (YYYY-MM-DD)Create the work directory:
WORKDIR=/tmp/release-health-$(date +%Y%m%d) && mkdir -p $WORKDIR && echo $WORKDIR
Record WORKDIR — substitute it into all agent prompts.
Fetch sprints and features in parallel using MCP tools, then transform with scripts.
Call jira_get_sprints_from_board for board_id "11479" three times:
state="active"state="closed" — paginate using page_token (see pagination protocol below); use limit=50state="future"After all pages are fetched, note all persisted file paths and run:
python3 plugins/edge-scrum/bin/transform-sprints.py \
--input <all_persisted_file_paths> \
--output {WORKDIR}/sprints.json \
--today {TODAY} \
--first-sprint {FIRST} \
--last-sprint {LAST} \
--total-dev-sprints {TOTAL_DEV_SPRINTS}
Call jira_search with:
project = OCPSTRAT AND issuetype in (Feature, Initiative) AND labels in ("ocpedge-plan", "microshift") AND "Target Version" = "openshift-{VERSION}" AND (resolution is EMPTY OR resolution not in (Duplicate, Obsolete)) ORDER BY Rank ASCkey, summary, status, issuetype, priority, assignee, fixVersions, labels, description, issuelinks, customfield_10795, customfield_10470, customfield_10473, customfield_1047550Paginate using page_token. If zero results, use fallback JQL (set fallback_used):
project = OCPSTRAT AND issuetype in (Feature, Initiative) AND labels in ("ocpedge-plan", "microshift") AND "Target Version" = "openshift-{VERSION}" AND status not in (Done, Closed) ORDER BY Rank ASC
After all pages fetched, run:
python3 plugins/edge-scrum/bin/transform-features.py \
--input <all_persisted_file_paths> \
--output {WORKDIR}/features.json
Append --fallback-used if fallback JQL was used.
Read and check:
{WORKDIR}/sprints.json — if "error" key is present or sprint_map is empty, warn the user and stop{WORKDIR}/features.json — if feature_keys is empty, warn the user about scope and stopRead {WORKDIR}/features.json. Extract feature_keys_csv.
If feature_keys has more than 50 entries, split into batches of 50. For each batch, call jira_search:
project in (OCPEDGE, USHIFT) AND "Parent Link" in ({feature_keys_batch_csv}) ORDER BY Rank ASCkey, summary, status, assignee, labels, description, parent, customfield_10028, customfield_10018, customfield_10470, customfield_10473, customfield_1047550Paginate using page_token. After all pages fetched, run:
python3 plugins/edge-scrum/bin/transform-epics.py \
--input <all_persisted_file_paths> \
--output {WORKDIR}/epics.json
Read {WORKDIR}/sprints.json. Extract refinement_sprint_id.
Call jira_search:
project in (OCPEDGE, USHIFT) AND issuetype = Spike AND sprint = {refinement_sprint_id}key, summary, status, assignee, issuelinks50Paginate using page_token. After all pages fetched, run:
python3 plugins/edge-scrum/bin/transform-spikes.py \
--input <all_persisted_file_paths> \
--features-file {WORKDIR}/features.json \
--epics-file {WORKDIR}/epics.json \
--sprints-file {WORKDIR}/sprints.json \
--output {WORKDIR}/spikes.json
Read {WORKDIR}/epics.json and verify: epic_keys is a non-empty array, feature_to_epics is an object, and epics is an array. If any check fails, warn the user with a descriptive error and stop.
This Jira instance uses page_token pagination, NOT start_at. Follow this protocol for all paginated MCP calls:
Make the first call without page_token
The response may be persisted to a file. Note the file path.
Run check-page.py to get pagination info:
python3 plugins/edge-scrum/bin/check-page.py <persisted_file_path>
Output: {"issues_count": N, "has_more": bool, "next_page_token": "..."}
If has_more is true: make the next call with page_token set to the next_page_token value. Repeat from step 2.
If has_more is false: pagination is complete.
For small responses that fit in context (not persisted), write them to {WORKDIR}/raw_<type>_<page>.json using Write, then run check-page.py on that file.
For jira_get_sprints_from_board: closed sprints may require multiple pages. Active and future typically fit in one page each.
Read plugins/edge-scrum/skills/release-health-analysis/SKILL.md. Substitute {WORKDIR}, {VERSION}, {TODAY}, {REFINEMENT_SPRINT_NUM}, then spawn as a sub-agent:
This agent reads all four data files, detects misplaced spikes, fetches child issues, builds the hierarchy, assesses all risks, and writes {WORKDIR}/analysis.md.
plugins/edge-scrum/references/release-health-report-template.md{WORKDIR}/analysis.md===ANALYSIS_META=== block for header values{placeholder} values in the template:
{executive_summary}: Write 3-5 sentences using top_risks, overall_health, feature counts, and sprint_recommendation from ANALYSIS_META. Cover: overall verdict, count on track vs. at risk, top 2-3 risks, one recommended priority this sprint.{DASHBOARD}, {FEATURE_DETAIL}, {EPIC_DETAIL}, {RISK_REGISTER}, {REFINEMENT_BACKLOG}, {SPRINT_FORECAST}, {ACTIONS}: paste the corresponding ===SECTION:*=== block content from analysis.md, stripping the sentinel lines[KEY](https://redhat.atlassian.net/browse/KEY) markdown links, skipping keys already inside link syntax.reports/release_health_{VERSION}_{TODAY}.mdtest -n "{WORKDIR}" && [[ "{WORKDIR}" == /tmp/release-health-* ]] && rm -rf -- "{WORKDIR}"4.19 vs 4.19.0): Analysis agent tries both in fixVersion queries."error" in JSON; main context stops before Phase 3.spike_keys[]; analysis agent uses worst-case status.all_ref_sprint_spikes cross-reference with epics.json.plugins/edge-scrum/bin/ — reusable data transformation (no LLM needed)plugins/edge-scrum/skills/release-health-analysis/SKILL.md — LLM-driven risk assessment and report generation{WORKDIR} persists across phases within a run. Rerunning on the same day overwrites prior files.plugins/edge-scrum/references/laws/ per the index at plugins/edge-scrum/references/Edge-Scrum-Laws.md — never hardcode roster, rules, or sizing in skill definitions.Guides 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 edge-scrum