Initial commit
This commit is contained in:
0
sprint-planner/.gitkeep
Normal file
0
sprint-planner/.gitkeep
Normal file
104
sprint-planner/SKILL.md
Normal file
104
sprint-planner/SKILL.md
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
name: sprint-planner
|
||||
description: Use this skill to plan a new sprint. It uses the Gemini CLI to intelligently decompose approved specs into atomic GitHub issues for the development team. Triggers include "plan sprint", "create sprint", or "start new sprint".
|
||||
---
|
||||
|
||||
# Sprint Planner Skill
|
||||
|
||||
## Purpose
|
||||
|
||||
To plan and initialize a new sprint by intelligently decomposing approved specifications into a comprehensive set of atomic GitHub issues. This skill bridges the gap between high-level specs and executable work items by using the **Gemini CLI** to analyze the spec's content and generate a thoughtful task breakdown. It then automates the creation of these tasks as GitHub issues within a new sprint milestone.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill in the following situations:
|
||||
|
||||
- Starting a new sprint or development cycle.
|
||||
- Converting an approved spec into actionable GitHub issues.
|
||||
- When you want an AI-assisted breakdown of an epic into atomic implementation tasks.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Project board configured with an "Approved Backlog" status column.
|
||||
- Approved spec files exist in the `docs/specs/` directory.
|
||||
- An Epic issue exists on GitHub that links to the spec file in its body.
|
||||
- `gh` CLI tool installed and authenticated.
|
||||
- `jq` tool installed for JSON parsing.
|
||||
- `gemini` CLI tool installed and authenticated.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Review Project Board
|
||||
|
||||
Check the project board for approved specs (represented as Epics) ready to be planned.
|
||||
|
||||
### Step 2: Discuss Sprint Scope with User
|
||||
|
||||
Engage the user to determine which epic(s) from the "Approved Backlog" to include in the sprint.
|
||||
|
||||
### Step 3: Define Sprint Metadata
|
||||
|
||||
Work with the user to establish the sprint name (e.g., "Sprint 4").
|
||||
|
||||
### Step 4: Run the Helper Script
|
||||
|
||||
Execute the sprint planning script to automate GitHub issue creation:
|
||||
|
||||
```bash
|
||||
bash scripts/create-sprint-issues.sh
|
||||
```
|
||||
|
||||
### Step 5: Understand What the Script Does
|
||||
|
||||
The helper script automates these steps:
|
||||
|
||||
1. **Queries Project Board**: Fetches all items from the "Approved Backlog" and prompts you to select an Epic to plan.
|
||||
2. **Extracts Spec File**: Parses the selected Epic's body to find the associated spec file path.
|
||||
3. **Creates Milestone**: Prompts you for a sprint name and creates the corresponding GitHub milestone.
|
||||
4. **Decomposes Spec with AI**: Instead of relying on a rigid format, the script sends the full content of the spec file and the parent Epic to the **Gemini CLI**. It asks the AI to generate a list of atomic, actionable tasks based on its understanding of the document.
|
||||
5. **Creates GitHub Issues**: The script parses the structured task list from Gemini's response and creates a GitHub issue for each task. Each issue is automatically titled, assigned to the new milestone, and includes a description and references to the parent Epic and spec file.
|
||||
|
||||
### Step 6: Verify Issue Creation
|
||||
|
||||
After the script completes, review the newly created issues in your milestone.
|
||||
|
||||
```bash
|
||||
gh issue list --milestone "Your Sprint Name"
|
||||
```
|
||||
|
||||
### Step 7: Review Created Issues with User
|
||||
|
||||
Walk through the AI-generated issues with your team. The generated tasks provide a strong baseline, but you should review them to confirm completeness, adjust priorities, and make any necessary refinements.
|
||||
|
||||
## Error Handling
|
||||
|
||||
### jq or Gemini Not Installed
|
||||
|
||||
**Symptom**: Script reports that `jq` or `gemini` command is not found.
|
||||
**Solution**: Install the required tool and ensure it's in your system's PATH.
|
||||
|
||||
### No Approved Epics Found
|
||||
|
||||
**Symptom**: Script reports no epics in the approved backlog.
|
||||
**Solution**: Ensure your Epics are in the correct status column on your project board.
|
||||
|
||||
### Epic Body Missing Spec Reference
|
||||
|
||||
**Symptom**: Script cannot find a spec file path in the Epic's body.
|
||||
**Solution**: Edit the Epic's issue body on GitHub to include a valid path to a spec file (e.g., `docs/specs/my-feature.md`).
|
||||
|
||||
### Gemini CLI Issues
|
||||
|
||||
**Symptom**: The script fails during the task decomposition step with an error from the `gemini` command.
|
||||
**Solution**:
|
||||
- Ensure the `gemini` CLI is installed and authenticated (`gemini auth`).
|
||||
- Check for API outages or network issues.
|
||||
- The quality of the task breakdown depends on a functional Gemini CLI.
|
||||
|
||||
## Notes
|
||||
|
||||
- **Intelligent Decomposition**: The skill no longer relies on a rigid task format in spec files. Gemini reads and understands the document to create tasks.
|
||||
- **LLM guides strategy, script executes**: You decide which spec to plan; the script uses AI to handle the tedious decomposition and issue creation.
|
||||
- **One epic per run**: Run the script once for each Epic you want to plan for the sprint.
|
||||
- **Traceability is built-in**: Each created task issue automatically references the parent Epic and the source spec file.
|
||||
- **Manual refinement is expected**: The AI-generated task list is a starting point. Review and adjust it with your team.
|
||||
188
sprint-planner/scripts/create-sprint-issues.sh
Executable file
188
sprint-planner/scripts/create-sprint-issues.sh
Executable file
@@ -0,0 +1,188 @@
|
||||
#!/bin/bash
|
||||
# This script plans a new sprint by creating a milestone and generating task issues from a tasks.yml file.
|
||||
|
||||
set -e
|
||||
|
||||
# --- USAGE ---
|
||||
usage() {
|
||||
echo "Usage: $0 [TASKS_FILE]"
|
||||
echo " TASKS_FILE: Path to the tasks.yml file (default: docs/changes/sprint-7-framework-improvements/tasks.yml)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
TASKS_FILE="${1:-docs/changes/sprint-7-framework-improvements/tasks.yml}"
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
# In a real scenario, this should be detected dynamically from the git remote URL
|
||||
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
||||
|
||||
# --- VALIDATION ---
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "Error: gh CLI is not installed. Please install it to continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v yq &> /dev/null; then
|
||||
echo "Error: yq is not installed. Please install it to continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$TASKS_FILE" ]; then
|
||||
echo "Error: Tasks file not found at $TASKS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate YAML structure
|
||||
echo "Validating tasks.yml structure..."
|
||||
if ! yq '.' "$TASKS_FILE" > /dev/null 2>&1; then
|
||||
echo "Error: Invalid YAML syntax in $TASKS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for required root-level 'epic' field
|
||||
if ! yq '.epic' "$TASKS_FILE" > /dev/null 2>&1; then
|
||||
echo "Error: Missing required 'epic' field in $TASKS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for required root-level 'tasks' array
|
||||
if ! yq '.tasks' "$TASKS_FILE" > /dev/null 2>&1; then
|
||||
echo "Error: Missing required 'tasks' array in $TASKS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TASK_COUNT=$(yq '.tasks | length' "$TASKS_FILE")
|
||||
if [ "$TASK_COUNT" -eq 0 ]; then
|
||||
echo "Error: No tasks found in $TASKS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ Validated YAML structure with $TASK_COUNT tasks"
|
||||
|
||||
# --- SCRIPT LOGIC ---
|
||||
|
||||
echo "Planning new sprint from $TASKS_FILE..."
|
||||
|
||||
# 1. Get Epic title from the tasks file
|
||||
EPIC_TITLE=$(yq -r '.epic' "$TASKS_FILE")
|
||||
echo "Found Epic: $EPIC_TITLE"
|
||||
|
||||
# 2. Create or verify the Sprint milestone
|
||||
read -p "Enter the name for the new sprint milestone (e.g., 'Sprint 1: Framework Improvements'): " SPRINT_NAME
|
||||
if [ -z "$SPRINT_NAME" ]; then
|
||||
echo "Error: Milestone name cannot be empty." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking for milestone: $SPRINT_NAME"
|
||||
EXISTING_MILESTONE=$(gh api "/repos/$REPO/milestones" | jq -r --arg name "$SPRINT_NAME" '.[] | select(.title == $name) | .title')
|
||||
|
||||
if [ "$EXISTING_MILESTONE" == "$SPRINT_NAME" ]; then
|
||||
echo "Milestone '$SPRINT_NAME' already exists. Using existing milestone."
|
||||
else
|
||||
echo "Creating new milestone: $SPRINT_NAME"
|
||||
gh api --method POST -H "Accept: application/vnd.github.v3+json" "/repos/$REPO/milestones" -f title="$SPRINT_NAME"
|
||||
echo "Milestone '$SPRINT_NAME' created."
|
||||
fi
|
||||
|
||||
# 3. Create an Epic Issue for the entire sprint
|
||||
echo "Creating parent Epic issue..."
|
||||
EPIC_BODY="This Epic tracks all work for the '$SPRINT_NAME' sprint. All tasks below are part of this epic."
|
||||
EPIC_ISSUE_URL=$(gh issue create --title "$EPIC_TITLE" --body "$EPIC_BODY" --milestone "$SPRINT_NAME")
|
||||
EPIC_ISSUE_NUMBER=$(echo "$EPIC_ISSUE_URL" | awk -F'/' '{print $NF}')
|
||||
echo "Parent Epic issue #$EPIC_ISSUE_NUMBER created."
|
||||
|
||||
# 4. Ensure all labels exist
|
||||
echo "Ensuring all necessary labels exist..."
|
||||
ALL_LABELS=$(yq -r '.tasks[].labels | .type + "\n" + .component + "\n" + (.priority // "")' "$TASKS_FILE" | sort -u | grep -v '^$')
|
||||
|
||||
while IFS= read -r label; do
|
||||
if [ -n "$label" ]; then
|
||||
echo " - Ensuring label '$label' exists..."
|
||||
# Assign a color based on the label type for better visual organization
|
||||
color="D4C5F9" # default purple
|
||||
if [[ "$label" == P* ]]; then color="B60205"; fi # red for priority
|
||||
if [[ "$label" == "feature" ]]; then color="0E8A16"; fi # green
|
||||
if [[ "$label" == "enhancement" ]]; then color="5319E7"; fi # purple
|
||||
if [[ "$label" == "bug" ]]; then color="B60205"; fi # red
|
||||
if [[ "$label" == "docs" ]]; then color="0075CA"; fi # blue
|
||||
if [[ "$label" == "refactor" || "$label" == "chore" ]]; then color="FBCA04"; fi # yellow
|
||||
|
||||
gh label create "$label" --color "$color" --description "Auto-created for sprint planning" || true
|
||||
fi
|
||||
done <<< "$ALL_LABELS"
|
||||
echo "Label setup complete."
|
||||
|
||||
# 5. Load context from RETROSPECTIVE.md to inform better task creation
|
||||
echo "Loading context from RETROSPECTIVE.md..."
|
||||
RETROSPECTIVE_FILE="RETROSPECTIVE.md"
|
||||
if [ -f "$RETROSPECTIVE_FILE" ]; then
|
||||
echo "✓ Found RETROSPECTIVE.md with past learnings"
|
||||
# Count recent learnings to inform user about context
|
||||
RECENT_LEARNINGS=$(grep -c "^### #[0-9]" "$RETROSPECTIVE_FILE" 2>/dev/null || echo "0")
|
||||
echo " - Contains $RECENT_LEARNINGS completed issues with learnings"
|
||||
else
|
||||
echo "⚠ RETROSPECTIVE.md not found - no historical context available"
|
||||
fi
|
||||
|
||||
# 6. Parse the tasks.yml file and create an issue for each task
|
||||
echo "Creating issues for all tasks..."
|
||||
|
||||
# Use yq to output each task's fields separated by a pipe for safe reading
|
||||
yq -r '.tasks[] | .title +"|" + .description +"|" + .labels.type +"|" + .labels.component +"|" + (.labels.priority // "")' "$TASKS_FILE" | while IFS='|' read -r title description type component priority;
|
||||
|
||||
do
|
||||
|
||||
echo "---"
|
||||
echo "Processing task: $title"
|
||||
|
||||
# Validate required fields
|
||||
if [ -z "$title" ]; then
|
||||
echo "Error: Task missing required 'title' field. Skipping." >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -z "$description" ]; then
|
||||
echo "Error: Task '$title' missing required 'description' field. Skipping." >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -z "$type" ]; then
|
||||
echo "Error: Task '$title' missing required 'labels.type' field. Skipping." >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -z "$component" ]; then
|
||||
echo "Error: Task '$title' missing required 'labels.component' field. Skipping." >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# Construct the issue body
|
||||
BODY=$(printf "%s\n\n**Parent Epic:** #%s" "$description" "$EPIC_ISSUE_NUMBER")
|
||||
|
||||
# Construct the labels string (priority is optional)
|
||||
if [ -n "$priority" ]; then
|
||||
LABELS="$type,$component,$priority"
|
||||
else
|
||||
LABELS="$type,$component"
|
||||
fi
|
||||
|
||||
# --- DEBUGGING ---
|
||||
echo " - Title: $title"
|
||||
echo " - Body: $BODY"
|
||||
echo " - Milestone: $SPRINT_NAME"
|
||||
echo " - Labels: $LABELS"
|
||||
# --- END DEBUGGING ---
|
||||
|
||||
# Create the GitHub issue
|
||||
gh issue create --title "$title" --body "$BODY" --milestone "$SPRINT_NAME" --label "$LABELS"
|
||||
|
||||
done
|
||||
|
||||
echo "-------------------------------------------------"
|
||||
echo "Sprint planning complete!"
|
||||
echo "All tasks from $TASKS_FILE have been created as GitHub issues in the '$SPRINT_NAME' milestone."
|
||||
echo "View the milestone here: https://github.com/$REPO/milestones"
|
||||
Reference in New Issue
Block a user