From 4dd866c9ad856836efdd42ef0dcc4a0a905af930 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sun, 5 Apr 2026 08:47:49 +0200 Subject: [PATCH] feat(skills): integrate start-sprint into sprint-start skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move start-sprint.sh into .claude/skills/sprint-start/scripts/ (was standalone at parent directory level). Sprint-start Case B now calls the script automatically after activating a sprint — creates ephemeral worktrees and opens Ptyxis tabs for each active team. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/settings.json | 2 + .claude/skills/sprint-start/SKILL.md | 16 +++- .../sprint-start/scripts/start-sprint.sh | 73 +++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100755 .claude/skills/sprint-start/scripts/start-sprint.sh diff --git a/.claude/settings.json b/.claude/settings.json index 93838af11..726e21aaf 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -64,6 +64,8 @@ "Bash(list *)", "Bash(tree *)", "Bash(sed -n *)", + "Bash(.claude/skills/sprint-start/scripts/start-sprint.sh *)", + "Bash(.claude/skills/sprint-start/scripts/sprint-teardown.sh *)", "Skill(git-commit)", "Skill(sprint-start)", diff --git a/.claude/skills/sprint-start/SKILL.md b/.claude/skills/sprint-start/SKILL.md index a28b500cc..d4b48067e 100644 --- a/.claude/skills/sprint-start/SKILL.md +++ b/.claude/skills/sprint-start/SKILL.md @@ -209,10 +209,20 @@ If everything looks ready, activate the sprint: tooling/db/sprint start ``` -Then report: +Then open team terminal tabs automatically: + +```bash +.claude/skills/sprint-start/scripts/start-sprint.sh +``` + +This creates ephemeral worktrees under `.sprint/sprint-{N}/{team}/` for +each team with open tickets, and opens Ptyxis windows with tmux + Claude +auto-starting in each tab. The user will have one tab per active team. + +Report: - Sprint activated (name, ticket count per team) -- Remind the user to switch to a team branch and run `/sprint-start` - there (or run `start-sprint` to open team tabs) +- Worktrees created and tabs opened +- Each team tab runs `/sprint-start` to load briefing and spawn agents --- diff --git a/.claude/skills/sprint-start/scripts/start-sprint.sh b/.claude/skills/sprint-start/scripts/start-sprint.sh new file mode 100755 index 000000000..996602831 --- /dev/null +++ b/.claude/skills/sprint-start/scripts/start-sprint.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# Opens Ptyxis windows for the active sprint teams. +# Auto-starts Claude Code in each tab via tmux. +# +# Usage: start-sprint.sh [sprint-number] +# If omitted, auto-detects the active sprint from the database. +# +# Window 1: main (always) +# Window 2: one tab per active team with open tickets +# +# Worktrees are created under .sprint/ (ephemeral, cleaned after sprint close). +# Can be called from any directory — resolves paths from the script location. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# Script lives at .claude/skills/sprint-start/scripts/ — repo root is 4 levels up +REPO_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)" +# Parent of repo root is where .sprint/ and the DB live +PARENT="$(dirname "$REPO_ROOT")" + +# Resolve sprint number — argument or active sprint from DB +if [ -n "${1:-}" ]; then + SPRINT="$1" +else + SPRINT=$(cd "$REPO_ROOT" && tooling/db/sqlite-query "SELECT id FROM sprints WHERE status='active'" 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin)['rows'][0]['id'])" 2>/dev/null || true) + if [ -z "$SPRINT" ]; then + echo "error: no active sprint found. Pass a sprint number or activate a sprint first." >&2 + exit 1 + fi +fi + +# Query teams with open tickets +TEAMS=$(cd "$REPO_ROOT" && tooling/db/sqlite-query "SELECT DISTINCT team FROM tickets WHERE sprint_id=$SPRINT AND status NOT IN ('done','cancelled')" 2>/dev/null | python3 -c "import sys,json; [print(r['team']) for r in json.load(sys.stdin)['rows']]" 2>/dev/null || true) + +if [ -z "$TEAMS" ]; then + echo "Sprint $SPRINT has no open tickets. Opening main only." +fi + +echo "Sprint $SPRINT — teams: ${TEAMS:-none}" + +# ── Window 1: main (always) ───────────────────────────────────────── +ptyxis --new-window -d "$REPO_ROOT" -x 'tmux new-session \; send-keys claude Enter' +sleep 0.5 + +# ── Window 2: one tab per active team ─────────────────────────────── +first=true +for team in $TEAMS; do + BRANCH="sprint-${SPRINT}/${team}" + WDIR="$PARENT/.sprint/sprint-${SPRINT}/${team}" + + # Create worktree if it doesn't exist + if [ ! -d "$WDIR" ]; then + echo "Creating worktree: $WDIR (branch: $BRANCH)" + mkdir -p "$(dirname "$WDIR")" + # Create branch from main if it doesn't exist remotely + if git -C "$REPO_ROOT" rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1; then + git -C "$REPO_ROOT" worktree add "$WDIR" "$BRANCH" + else + git -C "$REPO_ROOT" worktree add -b "$BRANCH" "$WDIR" HEAD + fi + fi + + if $first; then + ptyxis --new-window -d "$WDIR" -x 'tmux new-session \; send-keys claude Enter' + first=false + else + ptyxis --tab -d "$WDIR" -x 'tmux new-session \; send-keys claude Enter' + fi + sleep 0.3 +done + +echo "Session ready. Main + ${TEAMS:-(no teams)}"