From 121593b6706074a30907d8a7efd615e02450f9a7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:08:53 +0000 Subject: [PATCH 1/2] Initial plan From 427ae7994b95af8ced693eb7bf63e32dfd9043a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:13:14 +0000 Subject: [PATCH 2/2] fix: add missing YAML frontmatter to 6 skill files (closes #706) Agent-Logs-Url: https://github.com/jazz127/squaddev/sessions/dcd8d4ee-16de-42c7-8ba3-038b4275d7db Co-authored-by: jazz127 <61506018+jazz127@users.noreply.github.com> --- .squad-templates/skills/nap/SKILL.md | 8 + .../cross-machine-coordination/SKILL.md | 8 + .squad/skills/model-selection/SKILL.md | 8 + .squad/skills/personal-squad/SKILL.md | 8 + .squad/skills/release-process/SKILL.md | 8 + .../squad-cli/templates/casting-reference.md | 208 +++--- packages/squad-cli/templates/ceremonies.md | 28 + .../templates/skills/cli-wiring/SKILL.md | 8 + .../cross-machine-coordination/SKILL.md | 8 + .../templates/skills/external-comms/SKILL.md | 658 +++++++++--------- .../skills/gh-auth-isolation/SKILL.md | 366 +++++----- .../templates/skills/humanizer/SKILL.md | 210 +++--- .../templates/skills/model-selection/SKILL.md | 8 + .../squad-cli/templates/skills/nap/SKILL.md | 8 + .../templates/skills/personal-squad/SKILL.md | 8 + .../skills/pr-review-response/SKILL.md | 268 +++++++ .../templates/skills/pr-screenshots/SKILL.md | 298 ++++---- .../templates/skills/release-process/SKILL.md | 8 + .../skills/versioning-policy/SKILL.md | 119 ++++ .../squad-sdk/templates/casting-reference.md | 208 +++--- packages/squad-sdk/templates/ceremonies.md | 28 + .../squad-sdk/templates/orchestration-log.md | 54 +- .../templates/skills/cli-wiring/SKILL.md | 8 + .../cross-machine-coordination/SKILL.md | 8 + .../templates/skills/external-comms/SKILL.md | 658 +++++++++--------- .../skills/gh-auth-isolation/SKILL.md | 366 +++++----- .../templates/skills/humanizer/SKILL.md | 210 +++--- .../templates/skills/model-selection/SKILL.md | 8 + .../squad-sdk/templates/skills/nap/SKILL.md | 8 + .../templates/skills/personal-squad/SKILL.md | 8 + .../skills/pr-review-response/SKILL.md | 268 +++++++ .../templates/skills/pr-screenshots/SKILL.md | 298 ++++---- .../templates/skills/release-process/SKILL.md | 8 + .../skills/versioning-policy/SKILL.md | 119 ++++ .../templates/workflows/squad-heartbeat.yml | 334 ++++----- templates/ceremonies.md | 28 + templates/skills/nap/SKILL.md | 8 + templates/workflows/squad-heartbeat.yml | 334 ++++----- 38 files changed, 3103 insertions(+), 2101 deletions(-) create mode 100644 packages/squad-cli/templates/skills/pr-review-response/SKILL.md create mode 100644 packages/squad-cli/templates/skills/versioning-policy/SKILL.md create mode 100644 packages/squad-sdk/templates/skills/pr-review-response/SKILL.md create mode 100644 packages/squad-sdk/templates/skills/versioning-policy/SKILL.md diff --git a/.squad-templates/skills/nap/SKILL.md b/.squad-templates/skills/nap/SKILL.md index 5973b1cf2..5d3f7787c 100644 --- a/.squad-templates/skills/nap/SKILL.md +++ b/.squad-templates/skills/nap/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "nap" +description: "Context hygiene — compress, prune, archive .squad/ state to reclaim context window budget" +domain: "context-management" +confidence: "medium" +source: "extracted" +--- + # Skill: nap > Context hygiene — compress, prune, archive .squad/ state diff --git a/.squad/skills/cross-machine-coordination/SKILL.md b/.squad/skills/cross-machine-coordination/SKILL.md index 79c4bc7ea..229b62298 100644 --- a/.squad/skills/cross-machine-coordination/SKILL.md +++ b/.squad/skills/cross-machine-coordination/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "cross-machine-coordination" +description: "Git-based task queuing pattern for coordinating agents across multiple machines" +domain: "distributed-systems" +confidence: "medium" +source: "specification" +--- + # Skill: Cross-Machine Coordination Pattern **Skill ID:** `cross-machine-coordination` diff --git a/.squad/skills/model-selection/SKILL.md b/.squad/skills/model-selection/SKILL.md index 4c6866fd4..a00b0d6c8 100644 --- a/.squad/skills/model-selection/SKILL.md +++ b/.squad/skills/model-selection/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "model-selection" +description: "Determines which LLM model to use for each agent spawn using a 5-layer resolution hierarchy" +domain: "orchestration" +confidence: "high" +source: "extracted" +--- + # Model Selection > Determines which LLM model to use for each agent spawn. diff --git a/.squad/skills/personal-squad/SKILL.md b/.squad/skills/personal-squad/SKILL.md index f926821fa..d94b348eb 100644 --- a/.squad/skills/personal-squad/SKILL.md +++ b/.squad/skills/personal-squad/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "personal-squad" +description: "User-level agents that travel across projects via ambient discovery and ghost protocol" +domain: "agent-management" +confidence: "high" +source: "extracted" +--- + # Personal Squad — Skill Document ## What is a Personal Squad? diff --git a/.squad/skills/release-process/SKILL.md b/.squad/skills/release-process/SKILL.md index 28d62b5ed..9d5999fc0 100644 --- a/.squad/skills/release-process/SKILL.md +++ b/.squad/skills/release-process/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "release-process" +description: "Battle-tested release checklist and rules derived from the v0.9.0→v0.9.1 incident" +domain: "release-engineering" +confidence: "high" +source: "extracted" +--- + # Release Process > Earned knowledge from the v0.9.0→v0.9.1 incident. Every agent involved in releases MUST read this before starting release work. diff --git a/packages/squad-cli/templates/casting-reference.md b/packages/squad-cli/templates/casting-reference.md index ab2ffe56b..f0a72e094 100644 --- a/packages/squad-cli/templates/casting-reference.md +++ b/packages/squad-cli/templates/casting-reference.md @@ -1,104 +1,104 @@ -# Casting Reference - -On-demand reference for Squad's casting system. Loaded during Init Mode or when adding team members. - -## Universe Table - -| Universe | Capacity | Shape Tags | Resonance Signals | -|---|---|---|---| -| The Usual Suspects | 6 | small, noir, ensemble | crime, heist, mystery, deception | -| Reservoir Dogs | 8 | small, noir, ensemble | crime, heist, tension, loyalty | -| Alien | 8 | small, sci-fi, survival | space, isolation, threat, engineering | -| Ocean's Eleven | 14 | medium, heist, ensemble | planning, coordination, roles, charm | -| Arrested Development | 15 | medium, comedy, ensemble | dysfunction, business, family, satire | -| Star Wars | 12 | medium, sci-fi, epic | conflict, mentorship, legacy, rebellion | -| The Matrix | 10 | medium, sci-fi, cyberpunk | systems, reality, hacking, philosophy | -| Firefly | 10 | medium, sci-fi, western | frontier, crew, independence, smuggling | -| The Goonies | 8 | small, adventure, ensemble | exploration, treasure, kids, teamwork | -| The Simpsons | 20 | large, comedy, ensemble | satire, community, family, absurdity | -| Breaking Bad | 12 | medium, drama, tension | chemistry, transformation, consequence, power | -| Lost | 18 | large, mystery, ensemble | survival, mystery, groups, leadership | -| Marvel Cinematic Universe | 25 | large, action, ensemble | heroism, teamwork, powers, scale | -| DC Universe | 18 | large, action, ensemble | justice, duality, powers, mythology | -| Futurama | 12 | medium, sci-fi, comedy | future, robots, space, absurdity | - -**Total: 15 universes** — capacity range 6–25. - -## Selection Algorithm - -Universe selection is deterministic. Score each universe and pick the highest: - -``` -score = size_fit + shape_fit + resonance_fit + LRU -``` - -| Factor | Description | -|---|---| -| `size_fit` | How well the universe capacity matches the team size. Prefer universes where capacity ≥ agent_count with minimal waste. | -| `shape_fit` | Match universe shape tags against the assignment shape derived from the project description. | -| `resonance_fit` | Match universe resonance signals against session and repo context signals. | -| `LRU` | Least-recently-used bonus — prefer universes not used in recent assignments (from `history.json`). | - -Same inputs → same choice (unless LRU changes between assignments). - -## Casting State File Schemas - -### policy.json - -Source template: `.squad/templates/casting-policy.json` -Runtime location: `.squad/casting/policy.json` - -```json -{ - "casting_policy_version": "1.1", - "allowlist_universes": ["Universe Name", "..."], - "universe_capacity": { - "Universe Name": 10 - } -} -``` - -### registry.json - -Source template: `.squad/templates/casting-registry.json` -Runtime location: `.squad/casting/registry.json` - -```json -{ - "agents": { - "agent-role-id": { - "persistent_name": "CharacterName", - "universe": "Universe Name", - "created_at": "ISO-8601", - "legacy_named": false, - "status": "active" - } - } -} -``` - -### history.json - -Source template: `.squad/templates/casting-history.json` -Runtime location: `.squad/casting/history.json` - -```json -{ - "universe_usage_history": [ - { - "universe": "Universe Name", - "assignment_id": "unique-id", - "used_at": "ISO-8601" - } - ], - "assignment_cast_snapshots": { - "assignment-id": { - "universe": "Universe Name", - "agents": { - "role-id": "CharacterName" - }, - "created_at": "ISO-8601" - } - } -} -``` +# Casting Reference + +On-demand reference for Squad's casting system. Loaded during Init Mode or when adding team members. + +## Universe Table + +| Universe | Capacity | Shape Tags | Resonance Signals | +|---|---|---|---| +| The Usual Suspects | 6 | small, noir, ensemble | crime, heist, mystery, deception | +| Reservoir Dogs | 8 | small, noir, ensemble | crime, heist, tension, loyalty | +| Alien | 8 | small, sci-fi, survival | space, isolation, threat, engineering | +| Ocean's Eleven | 14 | medium, heist, ensemble | planning, coordination, roles, charm | +| Arrested Development | 15 | medium, comedy, ensemble | dysfunction, business, family, satire | +| Star Wars | 12 | medium, sci-fi, epic | conflict, mentorship, legacy, rebellion | +| The Matrix | 10 | medium, sci-fi, cyberpunk | systems, reality, hacking, philosophy | +| Firefly | 10 | medium, sci-fi, western | frontier, crew, independence, smuggling | +| The Goonies | 8 | small, adventure, ensemble | exploration, treasure, kids, teamwork | +| The Simpsons | 20 | large, comedy, ensemble | satire, community, family, absurdity | +| Breaking Bad | 12 | medium, drama, tension | chemistry, transformation, consequence, power | +| Lost | 18 | large, mystery, ensemble | survival, mystery, groups, leadership | +| Marvel Cinematic Universe | 25 | large, action, ensemble | heroism, teamwork, powers, scale | +| DC Universe | 18 | large, action, ensemble | justice, duality, powers, mythology | +| Futurama | 12 | medium, sci-fi, comedy | future, robots, space, absurdity | + +**Total: 15 universes** — capacity range 6–25. + +## Selection Algorithm + +Universe selection is deterministic. Score each universe and pick the highest: + +``` +score = size_fit + shape_fit + resonance_fit + LRU +``` + +| Factor | Description | +|---|---| +| `size_fit` | How well the universe capacity matches the team size. Prefer universes where capacity ≥ agent_count with minimal waste. | +| `shape_fit` | Match universe shape tags against the assignment shape derived from the project description. | +| `resonance_fit` | Match universe resonance signals against session and repo context signals. | +| `LRU` | Least-recently-used bonus — prefer universes not used in recent assignments (from `history.json`). | + +Same inputs → same choice (unless LRU changes between assignments). + +## Casting State File Schemas + +### policy.json + +Source template: `.squad/templates/casting-policy.json` +Runtime location: `.squad/casting/policy.json` + +```json +{ + "casting_policy_version": "1.1", + "allowlist_universes": ["Universe Name", "..."], + "universe_capacity": { + "Universe Name": 10 + } +} +``` + +### registry.json + +Source template: `.squad/templates/casting-registry.json` +Runtime location: `.squad/casting/registry.json` + +```json +{ + "agents": { + "agent-role-id": { + "persistent_name": "CharacterName", + "universe": "Universe Name", + "created_at": "ISO-8601", + "legacy_named": false, + "status": "active" + } + } +} +``` + +### history.json + +Source template: `.squad/templates/casting-history.json` +Runtime location: `.squad/casting/history.json` + +```json +{ + "universe_usage_history": [ + { + "universe": "Universe Name", + "assignment_id": "unique-id", + "used_at": "ISO-8601" + } + ], + "assignment_cast_snapshots": { + "assignment-id": { + "universe": "Universe Name", + "agents": { + "role-id": "CharacterName" + }, + "created_at": "ISO-8601" + } + } +} +``` diff --git a/packages/squad-cli/templates/ceremonies.md b/packages/squad-cli/templates/ceremonies.md index 45b4a581a..e50c151f3 100644 --- a/packages/squad-cli/templates/ceremonies.md +++ b/packages/squad-cli/templates/ceremonies.md @@ -39,3 +39,31 @@ 2. Root cause analysis 3. What should change? 4. Action items for next iteration + + +--- + +## Retrospective with Enforcement + +| Field | Value | +|-------|-------| +| **Trigger** | auto | +| **When** | weekly | +| **Condition** | No *retrospective* log in .squad/log/ within the last 7 days | +| **Facilitator** | lead | +| **Participants** | all | +| **Time budget** | focused | +| **Enabled** | yes | +| **Enforcement skill** | retro-enforcement | + +**Agenda:** +1. What shipped this week? (closed issues, merged PRs) +2. What did not ship? (open issues, blockers) +3. Root cause on any failures +4. Action items -- each MUST become a GitHub Issue labeled retro-action + +**Coordinator integration:** +At round start, call Test-RetroOverdue (see skill retro-enforcement). If overdue, run this ceremony before the work queue. + +**Why GitHub Issues, not markdown:** +Production data: 0% completion across 6 retros using markdown checklists, 100% after switching to GitHub Issues. diff --git a/packages/squad-cli/templates/skills/cli-wiring/SKILL.md b/packages/squad-cli/templates/skills/cli-wiring/SKILL.md index 03f7bf55f..9d60aa343 100644 --- a/packages/squad-cli/templates/skills/cli-wiring/SKILL.md +++ b/packages/squad-cli/templates/skills/cli-wiring/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "cli-wiring" +description: "Checklist for correctly wiring new CLI commands in cli-entry.ts" +domain: "cli-development" +confidence: "high" +source: "extracted" +--- + # Skill: CLI Command Wiring **Bug class:** Commands implemented in `packages/squad-cli/src/cli/commands/` but never routed in `cli-entry.ts`. diff --git a/packages/squad-cli/templates/skills/cross-machine-coordination/SKILL.md b/packages/squad-cli/templates/skills/cross-machine-coordination/SKILL.md index 79c4bc7ea..229b62298 100644 --- a/packages/squad-cli/templates/skills/cross-machine-coordination/SKILL.md +++ b/packages/squad-cli/templates/skills/cross-machine-coordination/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "cross-machine-coordination" +description: "Git-based task queuing pattern for coordinating agents across multiple machines" +domain: "distributed-systems" +confidence: "medium" +source: "specification" +--- + # Skill: Cross-Machine Coordination Pattern **Skill ID:** `cross-machine-coordination` diff --git a/packages/squad-cli/templates/skills/external-comms/SKILL.md b/packages/squad-cli/templates/skills/external-comms/SKILL.md index 045b993f1..9ac372dca 100644 --- a/packages/squad-cli/templates/skills/external-comms/SKILL.md +++ b/packages/squad-cli/templates/skills/external-comms/SKILL.md @@ -1,329 +1,329 @@ ---- -name: "external-comms" -description: "PAO workflow for scanning, drafting, and presenting community responses with human review gate" -domain: "community, communication, workflow" -confidence: "low" -source: "manual (RFC #426 — PAO External Communications)" -tools: - - name: "github-mcp-server-list_issues" - description: "List open issues for scan candidates and lightweight triage" - when: "Use for recent open issue scans before thread-level review" - - name: "github-mcp-server-issue_read" - description: "Read the full issue, comments, and labels before drafting" - when: "Use after selecting a candidate so PAO has complete thread context" - - name: "github-mcp-server-search_issues" - description: "Search for candidate issues or prior squad responses" - when: "Use when filtering by keywords, labels, or duplicate response checks" - - name: "gh CLI" - description: "Fallback for GitHub issue comments and discussions workflows" - when: "Use gh issue list/comment and gh api or gh api graphql when MCP coverage is incomplete" ---- - -## Context - -Phase 1 is **draft-only mode**. - -- PAO scans issues and discussions, drafts responses with the humanizer skill, and presents a review table for human approval. -- **Human review gate is mandatory** — PAO never posts autonomously. -- Every action is logged to `.squad/comms/audit/`. -- This workflow is triggered manually only ("PAO, check community") — no automated or Ralph-triggered activation in Phase 1. - -## Patterns - -### 1. Scan - -Find unanswered community items with GitHub MCP tools first, or `gh issue list` / `gh api` as fallback for issues and discussions. - -- Include **open** issues and discussions only. -- Filter for items with **no squad team response**. -- Limit to items created in the last 7 days. -- Exclude items labeled `squad:internal` or `wontfix`. -- Include discussions **and** issues in the same sweep. -- Phase 1 scope is **issues and discussions only** — do not draft PR replies. - -### Discussion Handling (Phase 1) - -Discussions use the GitHub Discussions API, which differs from issues: - -- **Scan:** `gh api /repos/{owner}/{repo}/discussions --jq '.[] | select(.answer_chosen_at == null)'` to find unanswered discussions -- **Categories:** Filter by Q&A and General categories only (skip Announcements, Show and Tell) -- **Answers vs comments:** In Q&A discussions, PAO drafts an "answer" (not a comment). The human marks it as accepted answer after posting. -- **Phase 1 scope:** Issues and Discussions ONLY. No PR comments. - -### 2. Classify - -Determine the response type before drafting. - -- Welcome (new contributor) -- Troubleshooting (bug/help) -- Feature guidance (feature request/how-to) -- Redirect (wrong repo/scope) -- Acknowledgment (confirmed, no fix) -- Closing (resolved) -- Technical uncertainty (unknown cause) -- Empathetic disagreement (pushback on a decision or design) -- Information request (need more reproduction details or context) - -### Template Selection Guide - -| Signal in Issue/Discussion | → Response Type | Template | -|---------------------------|-----------------|----------| -| New contributor (0 prior issues) | Welcome | T1 | -| Error message, stack trace, "doesn't work" | Troubleshooting | T2 | -| "How do I...?", "Can Squad...?", "Is there a way to...?" | Feature Guidance | T3 | -| Wrong repo, out of scope for Squad | Redirect | T4 | -| Confirmed bug, no fix available yet | Acknowledgment | T5 | -| Fix shipped, PR merged that resolves issue | Closing | T6 | -| Unclear cause, needs investigation | Technical Uncertainty | T7 | -| Author disagrees with a decision or design | Empathetic Disagreement | T8 | -| Need more reproduction info or context | Information Request | T9 | - -Use exactly one template as the base draft. Replace placeholders with issue-specific details, then apply the humanizer patterns. If the thread spans multiple signals, choose the highest-risk template and capture the nuance in the thread summary. - -### Confidence Classification - -| Confidence | Criteria | Example | -|-----------|----------|---------| -| 🟢 High | Answer exists in Squad docs or FAQ, similar question answered before, no technical ambiguity | "How do I install Squad?" | -| 🟡 Medium | Technical answer is sound but involves judgment calls, OR docs exist but don't perfectly match the question, OR tone is tricky | "Can Squad work with Azure DevOps?" (yes, but setup is nuanced) | -| 🔴 Needs Review | Technical uncertainty, policy/roadmap question, potential reputational risk, author is frustrated/angry, question about unreleased features | "When will Squad support Claude?" | - -**Auto-escalation rules:** -- Any mention of competitors → 🔴 -- Any mention of pricing/licensing → 🔴 -- Author has >3 follow-up comments without resolution → 🔴 -- Question references a closed-wontfix issue → 🔴 - -### 3. Draft - -Use the humanizer skill for every draft. - -- Complete **Thread-Read Verification** before writing. -- Read the **full thread**, including all comments, before writing. -- Select the matching template from the **Template Selection Guide** and record the template ID in the review notes. -- Treat templates as reusable drafting assets: keep the structure, replace placeholders, and only improvise when the thread truly requires it. -- Validate the draft against the humanizer anti-patterns. -- Flag long threads (`>10` comments) with `⚠️`. - -### Thread-Read Verification - -Before drafting, PAO MUST verify complete thread coverage: - -1. **Count verification:** Compare API comment count with actually-read comments. If mismatch, abort draft. -2. **Deleted comment check:** Use `gh api` timeline to detect deleted comments. If found, flag as ⚠️ in review table. -3. **Thread summary:** Include in every draft: "Thread: {N} comments, last activity {date}, {summary of key points}" -4. **Long thread flag:** If >10 comments, add ⚠️ to review table and include condensed thread summary -5. **Evidence line in review table:** Each draft row includes "Read: {N}/{total} comments" column - -### 4. Present - -Show drafts for review in this exact format: - -```text -📝 PAO — Community Response Drafts -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -| # | Item | Author | Type | Confidence | Read | Preview | -|---|------|--------|------|------------|------|---------| -| 1 | Issue #N | @user | Type | 🟢/🟡/🔴 | N/N | "First words..." | - -Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review - -Full drafts below ▼ -``` - -Each full draft must begin with the thread summary line: -`Thread: {N} comments, last activity {date}, {summary of key points}` - -### 5. Human Action - -Wait for explicit human direction before anything is posted. - -- `pao approve 1 3` — approve drafts 1 and 3 -- `pao edit 2` — edit draft 2 -- `pao skip` — skip all -- `banana` — freeze all pending (safe word) - -### Rollback — Bad Post Recovery - -If a posted response turns out to be wrong, inappropriate, or needs correction: - -1. **Delete the comment:** - - Issues: `gh api -X DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}` - - Discussions: `gh api graphql -f query='mutation { deleteDiscussionComment(input: {id: "{node_id}"}) { comment { id } } }'` -2. **Log the deletion:** Write audit entry with action `delete`, include reason and original content -3. **Draft replacement** (if needed): PAO drafts a corrected response, goes through normal review cycle -4. **Postmortem:** If the error reveals a pattern gap, update humanizer anti-patterns or add a new test case - -**Safe word — `banana`:** -- Immediately freezes all pending drafts in the review queue -- No new scans or drafts until `pao resume` is issued -- Audit entry logged with halter identity and reason - -### 6. Post - -After approval: - -- Human posts via `gh issue comment` for issues or `gh api` for discussion answers/comments. -- PAO helps by preparing the CLI command. -- Write the audit entry after the posting action. - -### 7. Audit - -Log every action. - -- Location: `.squad/comms/audit/{timestamp}.md` -- Required fields vary by action — see `.squad/comms/templates/audit-entry.md` Conditional Fields table -- Universal required fields: `timestamp`, `action` -- All other fields are conditional on the action type - -## Examples - -These are reusable templates. Keep the structure, replace placeholders, and adjust only where the thread requires it. - -### Example scan command - -```bash -gh issue list --state open --json number,title,author,labels,comments --limit 20 -``` - -### Example review table - -```text -📝 PAO — Community Response Drafts -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -| # | Item | Author | Type | Confidence | Read | Preview | -|---|------|--------|------|------------|------|---------| -| 1 | Issue #426 | @newdev | Welcome | 🟢 | 1/1 | "Hey @newdev! Welcome to Squad..." | -| 2 | Discussion #18 | @builder | Feature guidance | 🟡 | 4/4 | "Great question! Today the CLI..." | -| 3 | Issue #431 ⚠️ | @debugger | Technical uncertainty | 🔴 | 12/12 | "Interesting find, @debugger..." | - -Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review - -Full drafts below ▼ -``` - -### Example audit entry (post action) - -```markdown ---- -timestamp: "2026-03-16T21:30:00Z" -action: "post" -item_number: 426 -draft_id: 1 -reviewer: "@bradygaster" ---- - -## Context (draft, approve, edit, skip, post, delete actions) -- Thread depth: 3 -- Response type: welcome -- Confidence: 🟢 -- Long thread flag: false - -## Draft Content (draft, edit, post actions) -Thread: 3 comments, last activity 2026-03-16, reporter hit a preview-build regression after install. - -Hey @newdev! Welcome to Squad 👋 Thanks for opening this. -We reproduced the issue in preview builds and we're checking the regression point now. -Let us know if you can share the command you ran right before the failure. - -## Post Result (post, delete actions) -https://github.com/bradygaster/squad/issues/426#issuecomment-123456 -``` - -### T1 — Welcome - -```text -Hey {author}! Welcome to Squad 👋 Thanks for opening this. -{specific acknowledgment or first answer} -Let us know if you have questions — happy to help! -``` - -### T2 — Troubleshooting - -```text -Thanks for the detailed report, {author}! -Here's what we think is happening: {explanation} -{steps or workaround} -Let us know if that helps, or if you're seeing something different. -``` - -### T3 — Feature Guidance - -```text -Great question! {context on current state} -{guidance or workaround} -We've noted this as a potential improvement — {tracking info if applicable}. -``` - -### T4 — Redirect - -```text -Thanks for reaching out! This one is actually better suited for {correct location}. -{brief explanation of why} -Feel free to open it there — they'll be able to help! -``` - -### T5 — Acknowledgment - -```text -Good catch, {author}. We've confirmed this is a real issue. -{what we know so far} -We'll update this thread when we have a fix. Thanks for flagging it! -``` - -### T6 — Closing - -```text -This should be resolved in {version/PR}! 🎉 -{brief summary of what changed} -Thanks for reporting this, {author} — it made Squad better. -``` - -### T7 — Technical Uncertainty - -```text -Interesting find, {author}. We're not 100% sure what's causing this yet. -Here's what we've ruled out: {list} -We'd love more context if you have it — {specific ask}. -We'll dig deeper and update this thread. -``` - -### T8 — Empathetic Disagreement - -```text -We hear you, {author}. That's a fair concern. - -The current design choice was driven by {reason}. We know it's not ideal for every use case. - -{what alternatives exist or what trade-off was made} - -If you have ideas for how to make this work better for your scenario, we'd love to hear them — open a discussion or drop your thoughts here! -``` - -### T9 — Information Request - -```text -Thanks for reporting this, {author}! - -To help us dig into this, could you share: -- {specific ask 1} -- {specific ask 2} -- {specific ask 3, if applicable} - -That context will help us narrow down what's happening. Appreciate it! -``` - -## Anti-Patterns - -- ❌ Posting without human review (NEVER — this is the cardinal rule) -- ❌ Drafting without reading full thread (context is everything) -- ❌ Ignoring confidence flags (🔴 items need Flight/human review) -- ❌ Scanning closed issues (only open items) -- ❌ Responding to issues labeled `squad:internal` or `wontfix` -- ❌ Skipping audit logging (every action must be recorded) -- ❌ Drafting for issues where a squad member already responded (avoid duplicates) -- ❌ Drafting pull request responses in Phase 1 (issues/discussions only) -- ❌ Treating templates like loose examples instead of reusable drafting assets -- ❌ Asking for more info without specific requests +--- +name: "external-comms" +description: "PAO workflow for scanning, drafting, and presenting community responses with human review gate" +domain: "community, communication, workflow" +confidence: "low" +source: "manual (RFC #426 — PAO External Communications)" +tools: + - name: "github-mcp-server-list_issues" + description: "List open issues for scan candidates and lightweight triage" + when: "Use for recent open issue scans before thread-level review" + - name: "github-mcp-server-issue_read" + description: "Read the full issue, comments, and labels before drafting" + when: "Use after selecting a candidate so PAO has complete thread context" + - name: "github-mcp-server-search_issues" + description: "Search for candidate issues or prior squad responses" + when: "Use when filtering by keywords, labels, or duplicate response checks" + - name: "gh CLI" + description: "Fallback for GitHub issue comments and discussions workflows" + when: "Use gh issue list/comment and gh api or gh api graphql when MCP coverage is incomplete" +--- + +## Context + +Phase 1 is **draft-only mode**. + +- PAO scans issues and discussions, drafts responses with the humanizer skill, and presents a review table for human approval. +- **Human review gate is mandatory** — PAO never posts autonomously. +- Every action is logged to `.squad/comms/audit/`. +- This workflow is triggered manually only ("PAO, check community") — no automated or Ralph-triggered activation in Phase 1. + +## Patterns + +### 1. Scan + +Find unanswered community items with GitHub MCP tools first, or `gh issue list` / `gh api` as fallback for issues and discussions. + +- Include **open** issues and discussions only. +- Filter for items with **no squad team response**. +- Limit to items created in the last 7 days. +- Exclude items labeled `squad:internal` or `wontfix`. +- Include discussions **and** issues in the same sweep. +- Phase 1 scope is **issues and discussions only** — do not draft PR replies. + +### Discussion Handling (Phase 1) + +Discussions use the GitHub Discussions API, which differs from issues: + +- **Scan:** `gh api /repos/{owner}/{repo}/discussions --jq '.[] | select(.answer_chosen_at == null)'` to find unanswered discussions +- **Categories:** Filter by Q&A and General categories only (skip Announcements, Show and Tell) +- **Answers vs comments:** In Q&A discussions, PAO drafts an "answer" (not a comment). The human marks it as accepted answer after posting. +- **Phase 1 scope:** Issues and Discussions ONLY. No PR comments. + +### 2. Classify + +Determine the response type before drafting. + +- Welcome (new contributor) +- Troubleshooting (bug/help) +- Feature guidance (feature request/how-to) +- Redirect (wrong repo/scope) +- Acknowledgment (confirmed, no fix) +- Closing (resolved) +- Technical uncertainty (unknown cause) +- Empathetic disagreement (pushback on a decision or design) +- Information request (need more reproduction details or context) + +### Template Selection Guide + +| Signal in Issue/Discussion | → Response Type | Template | +|---------------------------|-----------------|----------| +| New contributor (0 prior issues) | Welcome | T1 | +| Error message, stack trace, "doesn't work" | Troubleshooting | T2 | +| "How do I...?", "Can Squad...?", "Is there a way to...?" | Feature Guidance | T3 | +| Wrong repo, out of scope for Squad | Redirect | T4 | +| Confirmed bug, no fix available yet | Acknowledgment | T5 | +| Fix shipped, PR merged that resolves issue | Closing | T6 | +| Unclear cause, needs investigation | Technical Uncertainty | T7 | +| Author disagrees with a decision or design | Empathetic Disagreement | T8 | +| Need more reproduction info or context | Information Request | T9 | + +Use exactly one template as the base draft. Replace placeholders with issue-specific details, then apply the humanizer patterns. If the thread spans multiple signals, choose the highest-risk template and capture the nuance in the thread summary. + +### Confidence Classification + +| Confidence | Criteria | Example | +|-----------|----------|---------| +| 🟢 High | Answer exists in Squad docs or FAQ, similar question answered before, no technical ambiguity | "How do I install Squad?" | +| 🟡 Medium | Technical answer is sound but involves judgment calls, OR docs exist but don't perfectly match the question, OR tone is tricky | "Can Squad work with Azure DevOps?" (yes, but setup is nuanced) | +| 🔴 Needs Review | Technical uncertainty, policy/roadmap question, potential reputational risk, author is frustrated/angry, question about unreleased features | "When will Squad support Claude?" | + +**Auto-escalation rules:** +- Any mention of competitors → 🔴 +- Any mention of pricing/licensing → 🔴 +- Author has >3 follow-up comments without resolution → 🔴 +- Question references a closed-wontfix issue → 🔴 + +### 3. Draft + +Use the humanizer skill for every draft. + +- Complete **Thread-Read Verification** before writing. +- Read the **full thread**, including all comments, before writing. +- Select the matching template from the **Template Selection Guide** and record the template ID in the review notes. +- Treat templates as reusable drafting assets: keep the structure, replace placeholders, and only improvise when the thread truly requires it. +- Validate the draft against the humanizer anti-patterns. +- Flag long threads (`>10` comments) with `⚠️`. + +### Thread-Read Verification + +Before drafting, PAO MUST verify complete thread coverage: + +1. **Count verification:** Compare API comment count with actually-read comments. If mismatch, abort draft. +2. **Deleted comment check:** Use `gh api` timeline to detect deleted comments. If found, flag as ⚠️ in review table. +3. **Thread summary:** Include in every draft: "Thread: {N} comments, last activity {date}, {summary of key points}" +4. **Long thread flag:** If >10 comments, add ⚠️ to review table and include condensed thread summary +5. **Evidence line in review table:** Each draft row includes "Read: {N}/{total} comments" column + +### 4. Present + +Show drafts for review in this exact format: + +```text +📝 PAO — Community Response Drafts +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +| # | Item | Author | Type | Confidence | Read | Preview | +|---|------|--------|------|------------|------|---------| +| 1 | Issue #N | @user | Type | 🟢/🟡/🔴 | N/N | "First words..." | + +Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review + +Full drafts below ▼ +``` + +Each full draft must begin with the thread summary line: +`Thread: {N} comments, last activity {date}, {summary of key points}` + +### 5. Human Action + +Wait for explicit human direction before anything is posted. + +- `pao approve 1 3` — approve drafts 1 and 3 +- `pao edit 2` — edit draft 2 +- `pao skip` — skip all +- `banana` — freeze all pending (safe word) + +### Rollback — Bad Post Recovery + +If a posted response turns out to be wrong, inappropriate, or needs correction: + +1. **Delete the comment:** + - Issues: `gh api -X DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}` + - Discussions: `gh api graphql -f query='mutation { deleteDiscussionComment(input: {id: "{node_id}"}) { comment { id } } }'` +2. **Log the deletion:** Write audit entry with action `delete`, include reason and original content +3. **Draft replacement** (if needed): PAO drafts a corrected response, goes through normal review cycle +4. **Postmortem:** If the error reveals a pattern gap, update humanizer anti-patterns or add a new test case + +**Safe word — `banana`:** +- Immediately freezes all pending drafts in the review queue +- No new scans or drafts until `pao resume` is issued +- Audit entry logged with halter identity and reason + +### 6. Post + +After approval: + +- Human posts via `gh issue comment` for issues or `gh api` for discussion answers/comments. +- PAO helps by preparing the CLI command. +- Write the audit entry after the posting action. + +### 7. Audit + +Log every action. + +- Location: `.squad/comms/audit/{timestamp}.md` +- Required fields vary by action — see `.squad/comms/templates/audit-entry.md` Conditional Fields table +- Universal required fields: `timestamp`, `action` +- All other fields are conditional on the action type + +## Examples + +These are reusable templates. Keep the structure, replace placeholders, and adjust only where the thread requires it. + +### Example scan command + +```bash +gh issue list --state open --json number,title,author,labels,comments --limit 20 +``` + +### Example review table + +```text +📝 PAO — Community Response Drafts +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +| # | Item | Author | Type | Confidence | Read | Preview | +|---|------|--------|------|------------|------|---------| +| 1 | Issue #426 | @newdev | Welcome | 🟢 | 1/1 | "Hey @newdev! Welcome to Squad..." | +| 2 | Discussion #18 | @builder | Feature guidance | 🟡 | 4/4 | "Great question! Today the CLI..." | +| 3 | Issue #431 ⚠️ | @debugger | Technical uncertainty | 🔴 | 12/12 | "Interesting find, @debugger..." | + +Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review + +Full drafts below ▼ +``` + +### Example audit entry (post action) + +```markdown +--- +timestamp: "2026-03-16T21:30:00Z" +action: "post" +item_number: 426 +draft_id: 1 +reviewer: "@bradygaster" +--- + +## Context (draft, approve, edit, skip, post, delete actions) +- Thread depth: 3 +- Response type: welcome +- Confidence: 🟢 +- Long thread flag: false + +## Draft Content (draft, edit, post actions) +Thread: 3 comments, last activity 2026-03-16, reporter hit a preview-build regression after install. + +Hey @newdev! Welcome to Squad 👋 Thanks for opening this. +We reproduced the issue in preview builds and we're checking the regression point now. +Let us know if you can share the command you ran right before the failure. + +## Post Result (post, delete actions) +https://github.com/bradygaster/squad/issues/426#issuecomment-123456 +``` + +### T1 — Welcome + +```text +Hey {author}! Welcome to Squad 👋 Thanks for opening this. +{specific acknowledgment or first answer} +Let us know if you have questions — happy to help! +``` + +### T2 — Troubleshooting + +```text +Thanks for the detailed report, {author}! +Here's what we think is happening: {explanation} +{steps or workaround} +Let us know if that helps, or if you're seeing something different. +``` + +### T3 — Feature Guidance + +```text +Great question! {context on current state} +{guidance or workaround} +We've noted this as a potential improvement — {tracking info if applicable}. +``` + +### T4 — Redirect + +```text +Thanks for reaching out! This one is actually better suited for {correct location}. +{brief explanation of why} +Feel free to open it there — they'll be able to help! +``` + +### T5 — Acknowledgment + +```text +Good catch, {author}. We've confirmed this is a real issue. +{what we know so far} +We'll update this thread when we have a fix. Thanks for flagging it! +``` + +### T6 — Closing + +```text +This should be resolved in {version/PR}! 🎉 +{brief summary of what changed} +Thanks for reporting this, {author} — it made Squad better. +``` + +### T7 — Technical Uncertainty + +```text +Interesting find, {author}. We're not 100% sure what's causing this yet. +Here's what we've ruled out: {list} +We'd love more context if you have it — {specific ask}. +We'll dig deeper and update this thread. +``` + +### T8 — Empathetic Disagreement + +```text +We hear you, {author}. That's a fair concern. + +The current design choice was driven by {reason}. We know it's not ideal for every use case. + +{what alternatives exist or what trade-off was made} + +If you have ideas for how to make this work better for your scenario, we'd love to hear them — open a discussion or drop your thoughts here! +``` + +### T9 — Information Request + +```text +Thanks for reporting this, {author}! + +To help us dig into this, could you share: +- {specific ask 1} +- {specific ask 2} +- {specific ask 3, if applicable} + +That context will help us narrow down what's happening. Appreciate it! +``` + +## Anti-Patterns + +- ❌ Posting without human review (NEVER — this is the cardinal rule) +- ❌ Drafting without reading full thread (context is everything) +- ❌ Ignoring confidence flags (🔴 items need Flight/human review) +- ❌ Scanning closed issues (only open items) +- ❌ Responding to issues labeled `squad:internal` or `wontfix` +- ❌ Skipping audit logging (every action must be recorded) +- ❌ Drafting for issues where a squad member already responded (avoid duplicates) +- ❌ Drafting pull request responses in Phase 1 (issues/discussions only) +- ❌ Treating templates like loose examples instead of reusable drafting assets +- ❌ Asking for more info without specific requests diff --git a/packages/squad-cli/templates/skills/gh-auth-isolation/SKILL.md b/packages/squad-cli/templates/skills/gh-auth-isolation/SKILL.md index a639835b1..e4ac1abda 100644 --- a/packages/squad-cli/templates/skills/gh-auth-isolation/SKILL.md +++ b/packages/squad-cli/templates/skills/gh-auth-isolation/SKILL.md @@ -1,183 +1,183 @@ ---- -name: "gh-auth-isolation" -description: "Safely manage multiple GitHub identities (EMU + personal) in agent workflows" -domain: "security, github-integration, authentication, multi-account" -confidence: "high" -source: "earned (production usage across 50+ sessions with EMU corp + personal GitHub accounts)" -tools: - - name: "gh" - description: "GitHub CLI for authenticated operations" - when: "When accessing GitHub resources requiring authentication" ---- - -## Context - -Many developers use GitHub through an Enterprise Managed User (EMU) account at work while maintaining a personal GitHub account for open-source contributions. AI agents spawned by Squad inherit the shell's default `gh` authentication — which is usually the EMU account. This causes failures when agents try to push to personal repos, create PRs on forks, or interact with resources outside the enterprise org. - -This skill teaches agents how to detect the active identity, switch contexts safely, and avoid mixing credentials across operations. - -## Patterns - -### Detect Current Identity - -Before any GitHub operation, check which account is active: - -```bash -gh auth status -``` - -Look for: -- `Logged in to github.com as USERNAME` — the active account -- `Token scopes: ...` — what permissions are available -- Multiple accounts will show separate entries - -### Extract a Specific Account's Token - -When you need to operate as a specific user (not the default): - -```bash -# Get the personal account token (by username) -gh auth token --user personaluser - -# Get the EMU account token -gh auth token --user corpalias_enterprise -``` - -**Use case:** Push to a personal fork while the default `gh` auth is the EMU account. - -### Push to Personal Repos from EMU Shell - -The most common scenario: your shell defaults to the EMU account, but you need to push to a personal GitHub repo. - -```bash -# 1. Extract the personal token -$token = gh auth token --user personaluser - -# 2. Push using token-authenticated HTTPS -git push https://personaluser:$token@github.com/personaluser/repo.git branch-name -``` - -**Why this works:** `gh auth token --user` reads from `gh`'s credential store without switching the active account. The token is used inline for a single operation and never persisted. - -### Create PRs on Personal Forks - -When the default `gh` context is EMU but you need to create a PR from a personal fork: - -```bash -# Option 1: Use --repo flag (works if token has access) -gh pr create --repo upstream/repo --head personaluser:branch --title "..." --body "..." - -# Option 2: Temporarily set GH_TOKEN for one command -$env:GH_TOKEN = $(gh auth token --user personaluser) -gh pr create --repo upstream/repo --head personaluser:branch --title "..." -Remove-Item Env:\GH_TOKEN -``` - -### Config Directory Isolation (Advanced) - -For complete isolation between accounts, use separate `gh` config directories: - -```bash -# Personal account operations -$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" -gh auth login # Login with personal account (one-time setup) -gh repo clone personaluser/repo - -# EMU account operations (default) -Remove-Item Env:\GH_CONFIG_DIR -gh auth status # Back to EMU account -``` - -**Setup (one-time):** -```bash -# Create isolated config for personal account -mkdir ~/.config/gh-public -$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" -gh auth login --web --git-protocol https -``` - -### Shell Aliases for Quick Switching - -Add to your shell profile for convenience: - -```powershell -# PowerShell profile -function ghp { $env:GH_CONFIG_DIR = "$HOME/.config/gh-public"; gh @args; Remove-Item Env:\GH_CONFIG_DIR } -function ghe { gh @args } # Default EMU - -# Usage: -# ghp repo clone personaluser/repo # Uses personal account -# ghe issue list # Uses EMU account -``` - -```bash -# Bash/Zsh profile -alias ghp='GH_CONFIG_DIR=~/.config/gh-public gh' -alias ghe='gh' - -# Usage: -# ghp repo clone personaluser/repo -# ghe issue list -``` - -## Examples - -### ✓ Correct: Agent pushes blog post to personal GitHub Pages - -```powershell -# Agent needs to push to personaluser.github.io (personal repo) -# Default gh auth is corpalias_enterprise (EMU) - -$token = gh auth token --user personaluser -git remote set-url origin https://personaluser:$token@github.com/personaluser/personaluser.github.io.git -git push origin main - -# Clean up — don't leave token in remote URL -git remote set-url origin https://github.com/personaluser/personaluser.github.io.git -``` - -### ✓ Correct: Agent creates a PR from personal fork to upstream - -```powershell -# Fork: personaluser/squad, Upstream: bradygaster/squad -# Agent is on branch contrib/fix-docs in the fork clone - -git push origin contrib/fix-docs # Pushes to fork (may need token auth) - -# Create PR targeting upstream -gh pr create --repo bradygaster/squad --head personaluser:contrib/fix-docs ` - --title "docs: fix installation guide" ` - --body "Fixes #123" -``` - -### ✗ Incorrect: Blindly pushing with wrong account - -```bash -# BAD: Agent assumes default gh auth works for personal repos -git push origin main -# ERROR: Permission denied — EMU account has no access to personal repo - -# BAD: Hardcoding tokens in scripts -git push https://personaluser:ghp_xxxxxxxxxxxx@github.com/personaluser/repo.git main -# SECURITY RISK: Token exposed in command history and process list -``` - -### ✓ Correct: Check before you push - -```bash -# Always verify which account has access before operations -gh auth status -# If wrong account, use token extraction: -$token = gh auth token --user personaluser -git push https://personaluser:$token@github.com/personaluser/repo.git main -``` - -## Anti-Patterns - -- ❌ **Hardcoding tokens** in scripts, environment variables, or committed files. Use `gh auth token --user` to extract at runtime. -- ❌ **Assuming the default `gh` auth works** for all repos. EMU accounts can't access personal repos and vice versa. -- ❌ **Switching `gh auth login`** globally mid-session. This changes the default for ALL processes and can break parallel agents. -- ❌ **Storing personal tokens in `.env`** or `.squad/` files. These get committed by Scribe. Use `gh`'s credential store. -- ❌ **Ignoring token cleanup** after inline HTTPS pushes. Always reset the remote URL to avoid persisting tokens. -- ❌ **Using `gh auth switch`** in multi-agent sessions. One agent switching affects all others sharing the shell. -- ❌ **Mixing EMU and personal operations** in the same git clone. Use separate clones or explicit remote URLs per operation. +--- +name: "gh-auth-isolation" +description: "Safely manage multiple GitHub identities (EMU + personal) in agent workflows" +domain: "security, github-integration, authentication, multi-account" +confidence: "high" +source: "earned (production usage across 50+ sessions with EMU corp + personal GitHub accounts)" +tools: + - name: "gh" + description: "GitHub CLI for authenticated operations" + when: "When accessing GitHub resources requiring authentication" +--- + +## Context + +Many developers use GitHub through an Enterprise Managed User (EMU) account at work while maintaining a personal GitHub account for open-source contributions. AI agents spawned by Squad inherit the shell's default `gh` authentication — which is usually the EMU account. This causes failures when agents try to push to personal repos, create PRs on forks, or interact with resources outside the enterprise org. + +This skill teaches agents how to detect the active identity, switch contexts safely, and avoid mixing credentials across operations. + +## Patterns + +### Detect Current Identity + +Before any GitHub operation, check which account is active: + +```bash +gh auth status +``` + +Look for: +- `Logged in to github.com as USERNAME` — the active account +- `Token scopes: ...` — what permissions are available +- Multiple accounts will show separate entries + +### Extract a Specific Account's Token + +When you need to operate as a specific user (not the default): + +```bash +# Get the personal account token (by username) +gh auth token --user personaluser + +# Get the EMU account token +gh auth token --user corpalias_enterprise +``` + +**Use case:** Push to a personal fork while the default `gh` auth is the EMU account. + +### Push to Personal Repos from EMU Shell + +The most common scenario: your shell defaults to the EMU account, but you need to push to a personal GitHub repo. + +```bash +# 1. Extract the personal token +$token = gh auth token --user personaluser + +# 2. Push using token-authenticated HTTPS +git push https://personaluser:$token@github.com/personaluser/repo.git branch-name +``` + +**Why this works:** `gh auth token --user` reads from `gh`'s credential store without switching the active account. The token is used inline for a single operation and never persisted. + +### Create PRs on Personal Forks + +When the default `gh` context is EMU but you need to create a PR from a personal fork: + +```bash +# Option 1: Use --repo flag (works if token has access) +gh pr create --repo upstream/repo --head personaluser:branch --title "..." --body "..." + +# Option 2: Temporarily set GH_TOKEN for one command +$env:GH_TOKEN = $(gh auth token --user personaluser) +gh pr create --repo upstream/repo --head personaluser:branch --title "..." +Remove-Item Env:\GH_TOKEN +``` + +### Config Directory Isolation (Advanced) + +For complete isolation between accounts, use separate `gh` config directories: + +```bash +# Personal account operations +$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" +gh auth login # Login with personal account (one-time setup) +gh repo clone personaluser/repo + +# EMU account operations (default) +Remove-Item Env:\GH_CONFIG_DIR +gh auth status # Back to EMU account +``` + +**Setup (one-time):** +```bash +# Create isolated config for personal account +mkdir ~/.config/gh-public +$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" +gh auth login --web --git-protocol https +``` + +### Shell Aliases for Quick Switching + +Add to your shell profile for convenience: + +```powershell +# PowerShell profile +function ghp { $env:GH_CONFIG_DIR = "$HOME/.config/gh-public"; gh @args; Remove-Item Env:\GH_CONFIG_DIR } +function ghe { gh @args } # Default EMU + +# Usage: +# ghp repo clone personaluser/repo # Uses personal account +# ghe issue list # Uses EMU account +``` + +```bash +# Bash/Zsh profile +alias ghp='GH_CONFIG_DIR=~/.config/gh-public gh' +alias ghe='gh' + +# Usage: +# ghp repo clone personaluser/repo +# ghe issue list +``` + +## Examples + +### ✓ Correct: Agent pushes blog post to personal GitHub Pages + +```powershell +# Agent needs to push to personaluser.github.io (personal repo) +# Default gh auth is corpalias_enterprise (EMU) + +$token = gh auth token --user personaluser +git remote set-url origin https://personaluser:$token@github.com/personaluser/personaluser.github.io.git +git push origin main + +# Clean up — don't leave token in remote URL +git remote set-url origin https://github.com/personaluser/personaluser.github.io.git +``` + +### ✓ Correct: Agent creates a PR from personal fork to upstream + +```powershell +# Fork: personaluser/squad, Upstream: bradygaster/squad +# Agent is on branch contrib/fix-docs in the fork clone + +git push origin contrib/fix-docs # Pushes to fork (may need token auth) + +# Create PR targeting upstream +gh pr create --repo bradygaster/squad --head personaluser:contrib/fix-docs ` + --title "docs: fix installation guide" ` + --body "Fixes #123" +``` + +### ✗ Incorrect: Blindly pushing with wrong account + +```bash +# BAD: Agent assumes default gh auth works for personal repos +git push origin main +# ERROR: Permission denied — EMU account has no access to personal repo + +# BAD: Hardcoding tokens in scripts +git push https://personaluser:ghp_xxxxxxxxxxxx@github.com/personaluser/repo.git main +# SECURITY RISK: Token exposed in command history and process list +``` + +### ✓ Correct: Check before you push + +```bash +# Always verify which account has access before operations +gh auth status +# If wrong account, use token extraction: +$token = gh auth token --user personaluser +git push https://personaluser:$token@github.com/personaluser/repo.git main +``` + +## Anti-Patterns + +- ❌ **Hardcoding tokens** in scripts, environment variables, or committed files. Use `gh auth token --user` to extract at runtime. +- ❌ **Assuming the default `gh` auth works** for all repos. EMU accounts can't access personal repos and vice versa. +- ❌ **Switching `gh auth login`** globally mid-session. This changes the default for ALL processes and can break parallel agents. +- ❌ **Storing personal tokens in `.env`** or `.squad/` files. These get committed by Scribe. Use `gh`'s credential store. +- ❌ **Ignoring token cleanup** after inline HTTPS pushes. Always reset the remote URL to avoid persisting tokens. +- ❌ **Using `gh auth switch`** in multi-agent sessions. One agent switching affects all others sharing the shell. +- ❌ **Mixing EMU and personal operations** in the same git clone. Use separate clones or explicit remote URLs per operation. diff --git a/packages/squad-cli/templates/skills/humanizer/SKILL.md b/packages/squad-cli/templates/skills/humanizer/SKILL.md index 63d760f9f..4dbb854df 100644 --- a/packages/squad-cli/templates/skills/humanizer/SKILL.md +++ b/packages/squad-cli/templates/skills/humanizer/SKILL.md @@ -1,105 +1,105 @@ ---- -name: "humanizer" -description: "Tone enforcement patterns for external-facing community responses" -domain: "communication, tone, community" -confidence: "low" -source: "manual (RFC #426 — PAO External Communications)" ---- - -## Context - -Use this skill whenever PAO drafts external-facing responses for issues or discussions. - -- Tone must be warm, helpful, and human-sounding — never robotic or corporate. -- Brady's constraint applies everywhere: **Humanized tone is mandatory**. -- This applies to **all external-facing content** drafted by PAO in Phase 1 issues/discussions workflows. - -## Patterns - -1. **Warm opening** — Start with acknowledgment ("Thanks for reporting this", "Great question!") -2. **Active voice** — "We're looking into this" not "This is being investigated" -3. **Second person** — Address the person directly ("you" not "the user") -4. **Conversational connectors** — "That said...", "Here's what we found...", "Quick note:" -5. **Specific, not vague** — "This affects the casting module in v0.8.x" not "We are aware of issues" -6. **Empathy markers** — "I can see how that would be frustrating", "Good catch!" -7. **Action-oriented closes** — "Let us know if that helps!" not "Please advise if further assistance is required" -8. **Uncertainty is OK** — "We're not 100% sure yet, but here's what we think is happening..." is better than false confidence -9. **Profanity filter** — Never include profanity, slurs, or aggressive language, even when quoting -10. **Baseline comparison** — Responses should align with tone of 5-10 "gold standard" responses (>80% similarity threshold) -11. **Empathetic disagreement** — "We hear you. That's a fair concern." before explaining the reasoning -12. **Information request** — Ask for specific details, not open-ended "can you provide more info?" -13. **No link-dumping** — Don't just paste URLs. Provide context: "Check out the [getting started guide](url) — specifically the section on routing" not just a bare link - -## Examples - -### 1. Welcome - -```text -Hey {author}! Welcome to Squad 👋 Thanks for opening this. -{substantive response} -Let us know if you have questions — happy to help! -``` - -### 2. Troubleshooting - -```text -Thanks for the detailed report, {author}! -Here's what we think is happening: {explanation} -{steps or workaround} -Let us know if that helps, or if you're seeing something different. -``` - -### 3. Feature guidance - -```text -Great question! {context on current state} -{guidance or workaround} -We've noted this as a potential improvement — {tracking info if applicable}. -``` - -### 4. Redirect - -```text -Thanks for reaching out! This one is actually better suited for {correct location}. -{brief explanation of why} -Feel free to open it there — they'll be able to help! -``` - -### 5. Acknowledgment - -```text -Good catch, {author}. We've confirmed this is a real issue. -{what we know so far} -We'll update this thread when we have a fix. Thanks for flagging it! -``` - -### 6. Closing - -```text -This should be resolved in {version/PR}! 🎉 -{brief summary of what changed} -Thanks for reporting this, {author} — it made Squad better. -``` - -### 7. Technical uncertainty - -```text -Interesting find, {author}. We're not 100% sure what's causing this yet. -Here's what we've ruled out: {list} -We'd love more context if you have it — {specific ask}. -We'll dig deeper and update this thread. -``` - -## Anti-Patterns - -- ❌ Corporate speak: "We appreciate your patience as we investigate this matter" -- ❌ Marketing hype: "Squad is the BEST way to..." or "This amazing feature..." -- ❌ Passive voice: "It has been determined that..." or "The issue is being tracked" -- ❌ Dismissive: "This works as designed" without empathy -- ❌ Over-promising: "We'll ship this next week" without commitment from the team -- ❌ Empty acknowledgment: "Thanks for your feedback" with no substance -- ❌ Robot signatures: "Best regards, PAO" or "Sincerely, The Squad Team" -- ❌ Excessive emoji: More than 1-2 emoji per response -- ❌ Quoting profanity: Even when the original issue contains it, paraphrase instead -- ❌ Link-dumping: Pasting URLs without context ("See: https://...") -- ❌ Open-ended info requests: "Can you provide more information?" without specifying what information +--- +name: "humanizer" +description: "Tone enforcement patterns for external-facing community responses" +domain: "communication, tone, community" +confidence: "low" +source: "manual (RFC #426 — PAO External Communications)" +--- + +## Context + +Use this skill whenever PAO drafts external-facing responses for issues or discussions. + +- Tone must be warm, helpful, and human-sounding — never robotic or corporate. +- Brady's constraint applies everywhere: **Humanized tone is mandatory**. +- This applies to **all external-facing content** drafted by PAO in Phase 1 issues/discussions workflows. + +## Patterns + +1. **Warm opening** — Start with acknowledgment ("Thanks for reporting this", "Great question!") +2. **Active voice** — "We're looking into this" not "This is being investigated" +3. **Second person** — Address the person directly ("you" not "the user") +4. **Conversational connectors** — "That said...", "Here's what we found...", "Quick note:" +5. **Specific, not vague** — "This affects the casting module in v0.8.x" not "We are aware of issues" +6. **Empathy markers** — "I can see how that would be frustrating", "Good catch!" +7. **Action-oriented closes** — "Let us know if that helps!" not "Please advise if further assistance is required" +8. **Uncertainty is OK** — "We're not 100% sure yet, but here's what we think is happening..." is better than false confidence +9. **Profanity filter** — Never include profanity, slurs, or aggressive language, even when quoting +10. **Baseline comparison** — Responses should align with tone of 5-10 "gold standard" responses (>80% similarity threshold) +11. **Empathetic disagreement** — "We hear you. That's a fair concern." before explaining the reasoning +12. **Information request** — Ask for specific details, not open-ended "can you provide more info?" +13. **No link-dumping** — Don't just paste URLs. Provide context: "Check out the [getting started guide](url) — specifically the section on routing" not just a bare link + +## Examples + +### 1. Welcome + +```text +Hey {author}! Welcome to Squad 👋 Thanks for opening this. +{substantive response} +Let us know if you have questions — happy to help! +``` + +### 2. Troubleshooting + +```text +Thanks for the detailed report, {author}! +Here's what we think is happening: {explanation} +{steps or workaround} +Let us know if that helps, or if you're seeing something different. +``` + +### 3. Feature guidance + +```text +Great question! {context on current state} +{guidance or workaround} +We've noted this as a potential improvement — {tracking info if applicable}. +``` + +### 4. Redirect + +```text +Thanks for reaching out! This one is actually better suited for {correct location}. +{brief explanation of why} +Feel free to open it there — they'll be able to help! +``` + +### 5. Acknowledgment + +```text +Good catch, {author}. We've confirmed this is a real issue. +{what we know so far} +We'll update this thread when we have a fix. Thanks for flagging it! +``` + +### 6. Closing + +```text +This should be resolved in {version/PR}! 🎉 +{brief summary of what changed} +Thanks for reporting this, {author} — it made Squad better. +``` + +### 7. Technical uncertainty + +```text +Interesting find, {author}. We're not 100% sure what's causing this yet. +Here's what we've ruled out: {list} +We'd love more context if you have it — {specific ask}. +We'll dig deeper and update this thread. +``` + +## Anti-Patterns + +- ❌ Corporate speak: "We appreciate your patience as we investigate this matter" +- ❌ Marketing hype: "Squad is the BEST way to..." or "This amazing feature..." +- ❌ Passive voice: "It has been determined that..." or "The issue is being tracked" +- ❌ Dismissive: "This works as designed" without empathy +- ❌ Over-promising: "We'll ship this next week" without commitment from the team +- ❌ Empty acknowledgment: "Thanks for your feedback" with no substance +- ❌ Robot signatures: "Best regards, PAO" or "Sincerely, The Squad Team" +- ❌ Excessive emoji: More than 1-2 emoji per response +- ❌ Quoting profanity: Even when the original issue contains it, paraphrase instead +- ❌ Link-dumping: Pasting URLs without context ("See: https://...") +- ❌ Open-ended info requests: "Can you provide more information?" without specifying what information diff --git a/packages/squad-cli/templates/skills/model-selection/SKILL.md b/packages/squad-cli/templates/skills/model-selection/SKILL.md index 4c6866fd4..a00b0d6c8 100644 --- a/packages/squad-cli/templates/skills/model-selection/SKILL.md +++ b/packages/squad-cli/templates/skills/model-selection/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "model-selection" +description: "Determines which LLM model to use for each agent spawn using a 5-layer resolution hierarchy" +domain: "orchestration" +confidence: "high" +source: "extracted" +--- + # Model Selection > Determines which LLM model to use for each agent spawn. diff --git a/packages/squad-cli/templates/skills/nap/SKILL.md b/packages/squad-cli/templates/skills/nap/SKILL.md index 5973b1cf2..5d3f7787c 100644 --- a/packages/squad-cli/templates/skills/nap/SKILL.md +++ b/packages/squad-cli/templates/skills/nap/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "nap" +description: "Context hygiene — compress, prune, archive .squad/ state to reclaim context window budget" +domain: "context-management" +confidence: "medium" +source: "extracted" +--- + # Skill: nap > Context hygiene — compress, prune, archive .squad/ state diff --git a/packages/squad-cli/templates/skills/personal-squad/SKILL.md b/packages/squad-cli/templates/skills/personal-squad/SKILL.md index f926821fa..d94b348eb 100644 --- a/packages/squad-cli/templates/skills/personal-squad/SKILL.md +++ b/packages/squad-cli/templates/skills/personal-squad/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "personal-squad" +description: "User-level agents that travel across projects via ambient discovery and ghost protocol" +domain: "agent-management" +confidence: "high" +source: "extracted" +--- + # Personal Squad — Skill Document ## What is a Personal Squad? diff --git a/packages/squad-cli/templates/skills/pr-review-response/SKILL.md b/packages/squad-cli/templates/skills/pr-review-response/SKILL.md new file mode 100644 index 000000000..dfe290a56 --- /dev/null +++ b/packages/squad-cli/templates/skills/pr-review-response/SKILL.md @@ -0,0 +1,268 @@ +--- +name: "pr-review-response" +description: "Teaches agents to reply to PR review comment threads after fixing issues, making resolutions traceable" +domain: "pull-requests, code-review, traceability" +confidence: "low" +source: "observed (agents fix review feedback silently — reviewers can't tell which comments were addressed)" +tools: + - name: "github-mcp-server-pull_request_read" + description: "Read PR review threads and comments" + when: "Step 1 — fetching review comments to understand what needs fixing" + - name: "gh api (REST)" + description: "Reply to review comment threads and resolve threads via GraphQL" + when: "Step 3 — posting reply to each comment thread after fixing" +--- + +## Context + +When an agent fixes code in response to PR review comments (from Copilot, a human reviewer, or any GitHub reviewer), the fix alone is not enough. The reviewer needs to see — on the PR thread itself — which comments were addressed and how. Without replies, comments stay visually unresolved, reviewers must re-read the entire diff to verify fixes, and there's no traceable link between feedback and resolution. + +Use this skill whenever: +- You are fixing code based on PR review feedback +- You are addressing Copilot review suggestions +- You are responding to reviewer-requested changes on a PR +- A squad member hands you review comments to resolve + +## SCOPE + +✅ THIS SKILL PRODUCES: +- Reply comments on each review thread explaining the fix +- Optionally resolved threads (via GraphQL when appropriate) +- Commit messages that reference the PR and review context + +❌ THIS SKILL DOES NOT PRODUCE: +- The code fixes themselves (that's the agent's domain work) +- New review comments or reviews +- PR descriptions or summaries + +## Patterns + +### Step 1: Read the review comments + +**Using MCP tools (preferred when available):** + +``` +github-mcp-server-pull_request_read + method: "get_review_comments" + owner: "{owner}" + repo: "{repo}" + pullNumber: {pr_number} +``` + +This returns review threads with metadata: `isResolved`, `isOutdated`, `isCollapsed`, and their associated comments. Each comment has an `id` you'll need for replies. + +**Using gh CLI (fallback):** + +```bash +gh api repos/{owner}/{repo}/pulls/{pr_number}/comments --paginate +``` + +Each comment object contains `id`, `body`, `path`, `line`, and `in_reply_to_id`. Top-level comments have no `in_reply_to_id` — those are the ones you reply to. + +### Step 2: Fix the code + +Make the actual code changes. This is your normal domain work — the skill doesn't prescribe how to fix, only how to communicate the fix. + +**Track what you changed.** For each review comment, note: +- The comment `id` (top-level, not a reply) +- The file and line referenced +- What you actually changed (brief description) +- The commit SHA after pushing (if available) + +### Step 3: Reply to each review thread + +After fixing and committing, reply to **each** review comment thread individually. + +**REST API call (via gh CLI):** + +```bash +gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \ + -f body="Fixed in {sha_short} — {brief description of what was changed}" +``` + +**Important:** `{comment_id}` must be the ID of the **top-level** comment in the thread. You cannot reply to a reply — only to the original review comment. + +**Example replies:** + +```bash +# Specific and traceable +gh api repos/bradygaster/squad/pulls/42/comments/18234/replies \ + -f body="Fixed in a1b2c3d — switched to path.dirname(squadDirInfo.path) for worktree consistency" + +# When applying a suggested code change +gh api repos/bradygaster/squad/pulls/42/comments/18235/replies \ + -f body="Applied suggestion — updated error message to include the file path for debuggability" + +# When pushing back on a suggestion +gh api repos/bradygaster/squad/pulls/42/comments/18236/replies \ + -f body="Considered but not applied — this path needs to stay absolute because worktree resolution depends on it. See detectSquadDir() in detect-squad-dir.ts." +``` + +### Step 4: Resolve threads (optional, GraphQL only) + +Thread resolution is only available via the GitHub GraphQL API. Use this when your fix fully addresses the comment and no further discussion is needed. + +**First, get the thread IDs** (they're different from comment IDs): + +```bash +gh api graphql -f query=' + query { + repository(owner: "{owner}", name: "{repo}") { + pullRequest(number: {pr_number}) { + reviewThreads(first: 100) { + nodes { + id + isResolved + comments(first: 1) { + nodes { body databaseId } + } + } + } + } + } + } +' +``` + +Match thread IDs to comment IDs using `databaseId`, then resolve: + +```bash +gh api graphql -f query=' + mutation { + resolveReviewThread(input: {threadId: "{thread_node_id}"}) { + thread { id isResolved } + } + } +' +``` + +**When to resolve vs. leave open:** +- ✅ Resolve: You fixed exactly what was requested, no ambiguity +- ❌ Don't resolve: You pushed back, applied a different fix, or the comment needs further discussion +- ❌ Don't resolve: The reviewer is a human — let them confirm and resolve themselves + +**Rule of thumb:** Agent-to-agent threads (e.g., Copilot review → agent fix) can be resolved by the fixer. Human reviewer threads should be left for the human to resolve. + +### Step 5: Commit message traceability + +Commit messages should reference the PR context: + +``` +fix: address review feedback on PR #{pr_number} + +- Switched to path.dirname() for worktree path resolution (comment #18234) +- Updated error message to include file path (comment #18235) + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> +``` + +For single-comment fixes, a shorter format works: + +``` +fix: use path.dirname() for worktree consistency (PR #{pr_number} review) + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> +``` + +## AGENT WORKFLOW (Summary) + +1. **READ** — Fetch review threads using MCP tool or `gh api` +2. **FIX** — Make code changes, tracking comment ID → change mapping +3. **COMMIT** — Push with traceable commit message referencing PR and comments +4. **REPLY** — Post individual reply to each thread via `gh api .../replies` +5. **RESOLVE** — (Optional) Resolve agent-to-agent threads via GraphQL +6. **STOP** — Do not batch-reply, do not skip threads, do not resolve human threads + +## Examples + +### Example: Copilot flags a potential null dereference + +**Review comment (id: 55123):** +> `squadDir` could be undefined here. Consider adding a null check. + +**Agent workflow:** +1. Read the comment via `get_review_comments` +2. Add the null check in `src/cli/core/detect-squad-dir.ts` +3. Commit: `fix: add null check for squadDir (PR #99 review)` +4. Reply: + ```bash + gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \ + -f body="Fixed in f4e5d6c — added early return when squadDir is undefined, matching the pattern in loadConfig()" + ``` +5. Resolve the thread (Copilot → agent, safe to resolve) + +### Example: Multiple review comments on one PR + +**Comments:** +- id: 55123 — "Null check needed" on `detect-squad-dir.ts:42` +- id: 55124 — "Consider using path.join()" on `detect-squad-dir.ts:58` +- id: 55125 — "This log message is too verbose" on `output.ts:15` + +**Agent handles each individually:** +```bash +# Fix all three, commit +git add packages/squad-cli/src/cli/core/detect-squad-dir.ts packages/squad-cli/src/cli/core/output.ts +git commit -m "fix: address 3 review comments on PR #99 + +- Added null check for squadDir (comment #55123) +- Switched to path.join() for cross-platform paths (comment #55124) +- Reduced log verbosity to debug level (comment #55125)" + +git push + +# Reply to each thread individually +gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \ + -f body="Fixed — added early return when squadDir is undefined" + +gh api repos/bradygaster/squad/pulls/99/comments/55124/replies \ + -f body="Fixed — switched to path.join(squadDir, 'config.json') for cross-platform consistency" + +gh api repos/bradygaster/squad/pulls/99/comments/55125/replies \ + -f body="Fixed — changed from console.log to debug() so it only shows with --verbose flag" +``` + +### Example: Handling Copilot suggestion blocks + +Copilot sometimes provides `suggestion` blocks with exact code to apply: + +**Review comment (id: 55130):** +```` +Consider using optional chaining: +```suggestion +const name = config?.agent?.name ?? 'default'; +``` +```` + +**Reply format when applying:** +```bash +gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \ + -f body="Applied suggestion — using optional chaining with nullish coalescing" +``` + +**Reply format when not applying:** +```bash +gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \ + -f body="Not applied — config is guaranteed non-null at this point (validated on line 12). Optional chaining would mask errors." +``` + +### Example: Pushing back on a review comment + +Not every review comment should be accepted. When a suggestion is incorrect or doesn't apply: + +```bash +gh api repos/bradygaster/squad/pulls/99/comments/55140/replies \ + -f body="Considered but not applied — this file is in the zero-dependency bootstrap set (see copilot-instructions.md § Protected Files). Adding path.join() would require importing from the SDK, which breaks the bootstrap constraint." +``` + +Do NOT resolve the thread when pushing back. Leave it open for the reviewer to confirm. + +## Anti-Patterns + +- ❌ **Fixing silently** — Making code changes without replying to the review thread. The reviewer has no way to know which comments were addressed. +- ❌ **Batch-replying "all fixed"** — A single comment saying "Addressed all review feedback" on the PR. Each thread needs its own reply so reviewers can verify individually. +- ❌ **Resolving without explaining** — Marking threads resolved without posting a reply first. The resolution gives no context on what was done. +- ❌ **Resolving human reviewer threads** — Only resolve threads from automated reviewers (Copilot, bots). Let human reviewers confirm and resolve their own threads. +- ❌ **Vague replies** — "Fixed" or "Done" without saying what was changed. The reply should be specific enough that the reviewer doesn't need to re-read the diff. +- ❌ **Replying before pushing** — Reply after your fix is committed and pushed, not before. The reply should reference actual committed code. +- ❌ **Ignoring comments you disagree with** — If you don't apply a suggestion, reply explaining why. Silence looks like you missed it. +- ❌ **Replying to replies** — The REST API only supports replying to top-level review comments. Attempting to reply to a reply will fail with a 404. diff --git a/packages/squad-cli/templates/skills/pr-screenshots/SKILL.md b/packages/squad-cli/templates/skills/pr-screenshots/SKILL.md index 7425ecf9e..fc93e8f77 100644 --- a/packages/squad-cli/templates/skills/pr-screenshots/SKILL.md +++ b/packages/squad-cli/templates/skills/pr-screenshots/SKILL.md @@ -1,149 +1,149 @@ ---- -name: "pr-screenshots" -description: "Capture Playwright screenshots and embed them in GitHub PR descriptions" -domain: "pull-requests, visual-review, docs, testing" -confidence: "high" -source: "earned (multiple sessions establishing the pattern for PR #11 TypeDoc API reference)" ---- - -## Context - -When a PR includes visual changes (docs sites, UI components, generated pages), reviewers -need to see what the PR delivers without checking out the branch. Screenshots belong in -the **PR description body**, not as committed files and not as text descriptions. - -Use this skill whenever: -- A PR touches docs site pages (Astro, Starlight, etc.) -- A PR adds or changes UI components -- A PR generates visual artifacts (TypeDoc, Storybook, diagrams) -- Playwright tests already capture screenshots as part of testing - -## Patterns - -### 1. Capture screenshots with Playwright - -If Playwright tests already exist and produce screenshots, reuse those. Otherwise, -write a minimal capture script: - -```javascript -// scripts/capture-pr-screenshots.mjs -import { chromium } from 'playwright'; - -const browser = await chromium.launch(); -const page = await browser.newPage({ viewport: { width: 1280, height: 720 } }); - -const screenshots = [ - { url: 'http://localhost:4321/path/to/page', name: 'feature-landing' }, - { url: 'http://localhost:4321/path/to/detail', name: 'feature-detail' }, -]; - -for (const { url, name } of screenshots) { - await page.goto(url, { waitUntil: 'networkidle' }); - await page.screenshot({ path: `screenshots/${name}.png`, fullPage: false }); -} - -await browser.close(); -``` - -### 2. Host screenshots on a temporary branch - -GitHub PR descriptions render images via URLs. The `gh` CLI cannot upload binary -images directly. Use a temporary orphan branch to host the images: - -```powershell -# Save current branch -$currentBranch = git branch --show-current - -# Create orphan branch with only screenshot files -git checkout --orphan screenshots-temp -git reset -git add screenshots/*.png -git commit -m "screenshots for PR review" -git push origin screenshots-temp --force - -# Build raw URLs -$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" -# Each image: $base/{name}.png - -# Return to working branch -git checkout -f $currentBranch -``` - -### 3. Embed in PR description - -Use `gh pr edit` with the raw URLs embedded as markdown images: - -```powershell -$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" - -gh pr edit {PR_NUMBER} --repo {owner}/{repo} --body @" -## {PR Title} - -### What this PR delivers -- {bullet points of changes} - ---- - -### Screenshots - -#### {Page/Feature Name} -![{alt text}]($base/{name}.png) - -#### {Another Page} -![{alt text}]($base/{another-name}.png) - ---- - -### To verify locally -```bash -{commands to run locally} -``` -"@ -``` - -### 4. Cleanup after merge - -After the PR is merged, delete the temporary branch: - -```bash -git push origin --delete screenshots-temp -``` - -### 5. Gitignore screenshots locally - -Screenshots are build artifacts — never commit them to feature branches: - -```gitignore -# PR screenshots (hosted on temp branch, not committed to features) -screenshots/ -docs/tests/screenshots/ -``` - -## Examples - -### Example: Docs site PR with 3 pages - -1. Start dev server: `cd docs && npm run dev` -2. Run Playwright tests (they capture screenshots as a side effect) -3. Push screenshots to `screenshots-temp` branch -4. Update PR body with embedded `![...]()` image references -5. Reviewer sees the pages inline without checking out the branch - -### Example: Reusing existing Playwright test screenshots - -If tests at `docs/tests/*.spec.mjs` already save to `docs/tests/screenshots/`: - -```powershell -cd docs && npx playwright test tests/api-reference.spec.mjs -# Screenshots now at docs/tests/screenshots/*.png -# Push those to screenshots-temp and embed in PR -``` - -## Anti-Patterns - -- ❌ **Committing screenshots to feature branches** — they bloat the repo and go stale -- ❌ **Posting text descriptions instead of actual images** — reviewers can't see what they're getting -- ❌ **Using `gh` CLI to "upload" images** — `gh issue comment` and `gh pr edit` don't support binary uploads -- ❌ **Asking the user to manually drag-drop images** — automate it with the temp branch pattern -- ❌ **Skipping screenshots for visual PRs** — if the PR changes what users see, show what users see -- ❌ **Leaving the screenshots-temp branch around forever** — clean up after merge +--- +name: "pr-screenshots" +description: "Capture Playwright screenshots and embed them in GitHub PR descriptions" +domain: "pull-requests, visual-review, docs, testing" +confidence: "high" +source: "earned (multiple sessions establishing the pattern for PR #11 TypeDoc API reference)" +--- + +## Context + +When a PR includes visual changes (docs sites, UI components, generated pages), reviewers +need to see what the PR delivers without checking out the branch. Screenshots belong in +the **PR description body**, not as committed files and not as text descriptions. + +Use this skill whenever: +- A PR touches docs site pages (Astro, Starlight, etc.) +- A PR adds or changes UI components +- A PR generates visual artifacts (TypeDoc, Storybook, diagrams) +- Playwright tests already capture screenshots as part of testing + +## Patterns + +### 1. Capture screenshots with Playwright + +If Playwright tests already exist and produce screenshots, reuse those. Otherwise, +write a minimal capture script: + +```javascript +// scripts/capture-pr-screenshots.mjs +import { chromium } from 'playwright'; + +const browser = await chromium.launch(); +const page = await browser.newPage({ viewport: { width: 1280, height: 720 } }); + +const screenshots = [ + { url: 'http://localhost:4321/path/to/page', name: 'feature-landing' }, + { url: 'http://localhost:4321/path/to/detail', name: 'feature-detail' }, +]; + +for (const { url, name } of screenshots) { + await page.goto(url, { waitUntil: 'networkidle' }); + await page.screenshot({ path: `screenshots/${name}.png`, fullPage: false }); +} + +await browser.close(); +``` + +### 2. Host screenshots on a temporary branch + +GitHub PR descriptions render images via URLs. The `gh` CLI cannot upload binary +images directly. Use a temporary orphan branch to host the images: + +```powershell +# Save current branch +$currentBranch = git branch --show-current + +# Create orphan branch with only screenshot files +git checkout --orphan screenshots-temp +git reset +git add screenshots/*.png +git commit -m "screenshots for PR review" +git push origin screenshots-temp --force + +# Build raw URLs +$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" +# Each image: $base/{name}.png + +# Return to working branch +git checkout -f $currentBranch +``` + +### 3. Embed in PR description + +Use `gh pr edit` with the raw URLs embedded as markdown images: + +```powershell +$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" + +gh pr edit {PR_NUMBER} --repo {owner}/{repo} --body @" +## {PR Title} + +### What this PR delivers +- {bullet points of changes} + +--- + +### Screenshots + +#### {Page/Feature Name} +![{alt text}]($base/{name}.png) + +#### {Another Page} +![{alt text}]($base/{another-name}.png) + +--- + +### To verify locally +```bash +{commands to run locally} +``` +"@ +``` + +### 4. Cleanup after merge + +After the PR is merged, delete the temporary branch: + +```bash +git push origin --delete screenshots-temp +``` + +### 5. Gitignore screenshots locally + +Screenshots are build artifacts — never commit them to feature branches: + +```gitignore +# PR screenshots (hosted on temp branch, not committed to features) +screenshots/ +docs/tests/screenshots/ +``` + +## Examples + +### Example: Docs site PR with 3 pages + +1. Start dev server: `cd docs && npm run dev` +2. Run Playwright tests (they capture screenshots as a side effect) +3. Push screenshots to `screenshots-temp` branch +4. Update PR body with embedded `![...]()` image references +5. Reviewer sees the pages inline without checking out the branch + +### Example: Reusing existing Playwright test screenshots + +If tests at `docs/tests/*.spec.mjs` already save to `docs/tests/screenshots/`: + +```powershell +cd docs && npx playwright test tests/api-reference.spec.mjs +# Screenshots now at docs/tests/screenshots/*.png +# Push those to screenshots-temp and embed in PR +``` + +## Anti-Patterns + +- ❌ **Committing screenshots to feature branches** — they bloat the repo and go stale +- ❌ **Posting text descriptions instead of actual images** — reviewers can't see what they're getting +- ❌ **Using `gh` CLI to "upload" images** — `gh issue comment` and `gh pr edit` don't support binary uploads +- ❌ **Asking the user to manually drag-drop images** — automate it with the temp branch pattern +- ❌ **Skipping screenshots for visual PRs** — if the PR changes what users see, show what users see +- ❌ **Leaving the screenshots-temp branch around forever** — clean up after merge diff --git a/packages/squad-cli/templates/skills/release-process/SKILL.md b/packages/squad-cli/templates/skills/release-process/SKILL.md index 28d62b5ed..9d5999fc0 100644 --- a/packages/squad-cli/templates/skills/release-process/SKILL.md +++ b/packages/squad-cli/templates/skills/release-process/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "release-process" +description: "Battle-tested release checklist and rules derived from the v0.9.0→v0.9.1 incident" +domain: "release-engineering" +confidence: "high" +source: "extracted" +--- + # Release Process > Earned knowledge from the v0.9.0→v0.9.1 incident. Every agent involved in releases MUST read this before starting release work. diff --git a/packages/squad-cli/templates/skills/versioning-policy/SKILL.md b/packages/squad-cli/templates/skills/versioning-policy/SKILL.md new file mode 100644 index 000000000..997d4c4aa --- /dev/null +++ b/packages/squad-cli/templates/skills/versioning-policy/SKILL.md @@ -0,0 +1,119 @@ +--- +name: "versioning-policy" +description: "Semver versioning rules for Squad SDK and CLI — prevents prerelease version incidents" +domain: "release, versioning, npm, CI" +confidence: "medium" +source: "earned (PR #640 workspace resolution incident, PR #116 prerelease leak, CI gate implementation)" +--- + +## Context + +Squad is a monorepo with two publishable npm packages (`@bradygaster/squad-sdk` and `@bradygaster/squad-cli`) managed via npm workspaces. Version mismatches and prerelease leaks have caused production incidents — most notably PR #640, where a `-build.N` prerelease version silently broke workspace dependency resolution. + +This skill codifies the versioning rules every agent must follow. + +## 1. Version Format + +All packages use **strict semver**: `MAJOR.MINOR.PATCH` + +- ✅ `0.9.1`, `1.0.0`, `0.10.0` +- ❌ `0.9.1-build.4`, `0.9.1-preview.1`, `0.8.6.1-preview` + +No prerelease suffixes on `dev` or `main` branches — ever. + +## 2. Prerelease Versions Are Ephemeral + +The `scripts/bump-build.mjs` script creates `-build.N` versions (e.g., `0.9.1-build.4`) for **local development testing only**. + +Rules: +- `-build.N` versions are created automatically during local `npm run build` +- They are **never committed** to `dev` or `main` +- The script skips itself in CI (`CI=true` or `SKIP_BUILD_BUMP=1`) +- If you see a `-build.N` version in a PR diff, it is a bug — reject the PR + +## 3. SDK and CLI Version Sync + +Both `@bradygaster/squad-sdk` and `@bradygaster/squad-cli` **MUST have the same version** at all times. The root `package.json` version must also match. + +`bump-build.mjs` enforces this by updating all three `package.json` files in lockstep (root + `packages/squad-sdk` + `packages/squad-cli`). + +If versions diverge, workspace resolution silently breaks (see §4). + +## 4. npm Workspace Semver Footgun + +The CLI depends on the SDK via a workspace dependency with a semver range: + +```json +"@bradygaster/squad-sdk": ">=0.9.0" +``` + +**Critical:** Per the semver specification, `>=0.9.0` does **NOT** match `0.9.1-build.4`. + +Semver prerelease versions (anything with a `-` suffix) are only matched by ranges that explicitly reference the same `MAJOR.MINOR.PATCH` base with a prerelease comparator. A bare `>=0.9.0` range skips all prerelease versions. + +**What happens:** When the local SDK has version `0.9.1-build.4`, npm's workspace resolution fails to match the `>=0.9.0` range. npm then **silently installs a stale published version** from the npm registry instead of using the local workspace link. The build succeeds but runs against old SDK code. + +This is the root cause of the **PR #640 incident**, where workspace packages appeared linked but were actually running against stale registry versions. + +## 5. Who Bumps Versions + +**Surgeon (Release Manager) owns all version bumps.** + +| Agent | May modify `version` in package.json? | +|-------|---------------------------------------| +| Surgeon | ✅ Yes — sole owner of version bumps | +| Any other agent | ❌ No — unless explicitly fixing a prerelease leak | + +If you discover a prerelease version committed to `dev` or `main`, you may fix it (revert to the clean release version) without Surgeon's approval. This is a safety escape hatch, not a license to manage versions. + +## 6. Version Bump Lifecycle + +``` +┌─────────────────────────────────────────────────────────┐ +│ Development phase │ +│ Versions stay at current release: 0.9.1 │ +│ bump-build.mjs creates -build.N locally (not committed)│ +├─────────────────────────────────────────────────────────┤ +│ Pre-release testing │ +│ bump-build.mjs → 0.9.1-build.1, -build.2, ... │ +│ Local only. Never committed. Never pushed. │ +├─────────────────────────────────────────────────────────┤ +│ Release │ +│ Surgeon bumps to next version (e.g., 0.9.2 or 0.10.0) │ +│ Tags, publishes to npm registry │ +├─────────────────────────────────────────────────────────┤ +│ Post-release │ +│ Versions stay at the new release version (e.g., 0.9.2) │ +│ Development continues on clean version │ +└─────────────────────────────────────────────────────────┘ +``` + +## 7. CI Enforcement + +The **`prerelease-version-guard`** CI gate blocks any PR to `dev` or `main` that contains prerelease version strings in `package.json` files. + +- The gate scans all three `package.json` files for `-` in the version field +- PRs with prerelease versions **cannot merge** until the version is cleaned +- The `skip-version-check` label bypasses the gate — use **only** for the bump-build script's own PR (if applicable), and only with Surgeon's approval + +## 8. Incident Reference — PR #640 + +**PR #640** is the cautionary tale for this entire policy. + +**What happened:** Prerelease versions (`0.9.1-build.4`) were committed to a branch. The workspace dependency `>=0.9.0` failed to match the prerelease version per semver spec. npm silently installed a stale published SDK from the registry instead of linking the local workspace copy. Four PRs (#637–#640) attempted iterative patches before the root cause was identified. + +**Root cause:** No versioning policy existed. Agents didn't know that prerelease versions break workspace resolution, or that only Surgeon should modify versions. + +**Resolution:** This skill, the `prerelease-version-guard` CI gate, and the team decision to centralize version ownership under Surgeon. + +## Quick Reference + +| Rule | Summary | +|------|---------| +| Format | `MAJOR.MINOR.PATCH` — no prerelease on dev/main | +| Prerelease | `-build.N` is local-only, never committed | +| Sync | SDK + CLI + root must have identical versions | +| Ownership | Surgeon bumps versions; others don't touch them | +| CI gate | `prerelease-version-guard` blocks prerelease PRs | +| Escape hatch | Any agent may revert a prerelease leak to clean version | +| Footgun | `>=0.9.0` does NOT match `0.9.1-build.4` per semver | diff --git a/packages/squad-sdk/templates/casting-reference.md b/packages/squad-sdk/templates/casting-reference.md index ab2ffe56b..f0a72e094 100644 --- a/packages/squad-sdk/templates/casting-reference.md +++ b/packages/squad-sdk/templates/casting-reference.md @@ -1,104 +1,104 @@ -# Casting Reference - -On-demand reference for Squad's casting system. Loaded during Init Mode or when adding team members. - -## Universe Table - -| Universe | Capacity | Shape Tags | Resonance Signals | -|---|---|---|---| -| The Usual Suspects | 6 | small, noir, ensemble | crime, heist, mystery, deception | -| Reservoir Dogs | 8 | small, noir, ensemble | crime, heist, tension, loyalty | -| Alien | 8 | small, sci-fi, survival | space, isolation, threat, engineering | -| Ocean's Eleven | 14 | medium, heist, ensemble | planning, coordination, roles, charm | -| Arrested Development | 15 | medium, comedy, ensemble | dysfunction, business, family, satire | -| Star Wars | 12 | medium, sci-fi, epic | conflict, mentorship, legacy, rebellion | -| The Matrix | 10 | medium, sci-fi, cyberpunk | systems, reality, hacking, philosophy | -| Firefly | 10 | medium, sci-fi, western | frontier, crew, independence, smuggling | -| The Goonies | 8 | small, adventure, ensemble | exploration, treasure, kids, teamwork | -| The Simpsons | 20 | large, comedy, ensemble | satire, community, family, absurdity | -| Breaking Bad | 12 | medium, drama, tension | chemistry, transformation, consequence, power | -| Lost | 18 | large, mystery, ensemble | survival, mystery, groups, leadership | -| Marvel Cinematic Universe | 25 | large, action, ensemble | heroism, teamwork, powers, scale | -| DC Universe | 18 | large, action, ensemble | justice, duality, powers, mythology | -| Futurama | 12 | medium, sci-fi, comedy | future, robots, space, absurdity | - -**Total: 15 universes** — capacity range 6–25. - -## Selection Algorithm - -Universe selection is deterministic. Score each universe and pick the highest: - -``` -score = size_fit + shape_fit + resonance_fit + LRU -``` - -| Factor | Description | -|---|---| -| `size_fit` | How well the universe capacity matches the team size. Prefer universes where capacity ≥ agent_count with minimal waste. | -| `shape_fit` | Match universe shape tags against the assignment shape derived from the project description. | -| `resonance_fit` | Match universe resonance signals against session and repo context signals. | -| `LRU` | Least-recently-used bonus — prefer universes not used in recent assignments (from `history.json`). | - -Same inputs → same choice (unless LRU changes between assignments). - -## Casting State File Schemas - -### policy.json - -Source template: `.squad/templates/casting-policy.json` -Runtime location: `.squad/casting/policy.json` - -```json -{ - "casting_policy_version": "1.1", - "allowlist_universes": ["Universe Name", "..."], - "universe_capacity": { - "Universe Name": 10 - } -} -``` - -### registry.json - -Source template: `.squad/templates/casting-registry.json` -Runtime location: `.squad/casting/registry.json` - -```json -{ - "agents": { - "agent-role-id": { - "persistent_name": "CharacterName", - "universe": "Universe Name", - "created_at": "ISO-8601", - "legacy_named": false, - "status": "active" - } - } -} -``` - -### history.json - -Source template: `.squad/templates/casting-history.json` -Runtime location: `.squad/casting/history.json` - -```json -{ - "universe_usage_history": [ - { - "universe": "Universe Name", - "assignment_id": "unique-id", - "used_at": "ISO-8601" - } - ], - "assignment_cast_snapshots": { - "assignment-id": { - "universe": "Universe Name", - "agents": { - "role-id": "CharacterName" - }, - "created_at": "ISO-8601" - } - } -} -``` +# Casting Reference + +On-demand reference for Squad's casting system. Loaded during Init Mode or when adding team members. + +## Universe Table + +| Universe | Capacity | Shape Tags | Resonance Signals | +|---|---|---|---| +| The Usual Suspects | 6 | small, noir, ensemble | crime, heist, mystery, deception | +| Reservoir Dogs | 8 | small, noir, ensemble | crime, heist, tension, loyalty | +| Alien | 8 | small, sci-fi, survival | space, isolation, threat, engineering | +| Ocean's Eleven | 14 | medium, heist, ensemble | planning, coordination, roles, charm | +| Arrested Development | 15 | medium, comedy, ensemble | dysfunction, business, family, satire | +| Star Wars | 12 | medium, sci-fi, epic | conflict, mentorship, legacy, rebellion | +| The Matrix | 10 | medium, sci-fi, cyberpunk | systems, reality, hacking, philosophy | +| Firefly | 10 | medium, sci-fi, western | frontier, crew, independence, smuggling | +| The Goonies | 8 | small, adventure, ensemble | exploration, treasure, kids, teamwork | +| The Simpsons | 20 | large, comedy, ensemble | satire, community, family, absurdity | +| Breaking Bad | 12 | medium, drama, tension | chemistry, transformation, consequence, power | +| Lost | 18 | large, mystery, ensemble | survival, mystery, groups, leadership | +| Marvel Cinematic Universe | 25 | large, action, ensemble | heroism, teamwork, powers, scale | +| DC Universe | 18 | large, action, ensemble | justice, duality, powers, mythology | +| Futurama | 12 | medium, sci-fi, comedy | future, robots, space, absurdity | + +**Total: 15 universes** — capacity range 6–25. + +## Selection Algorithm + +Universe selection is deterministic. Score each universe and pick the highest: + +``` +score = size_fit + shape_fit + resonance_fit + LRU +``` + +| Factor | Description | +|---|---| +| `size_fit` | How well the universe capacity matches the team size. Prefer universes where capacity ≥ agent_count with minimal waste. | +| `shape_fit` | Match universe shape tags against the assignment shape derived from the project description. | +| `resonance_fit` | Match universe resonance signals against session and repo context signals. | +| `LRU` | Least-recently-used bonus — prefer universes not used in recent assignments (from `history.json`). | + +Same inputs → same choice (unless LRU changes between assignments). + +## Casting State File Schemas + +### policy.json + +Source template: `.squad/templates/casting-policy.json` +Runtime location: `.squad/casting/policy.json` + +```json +{ + "casting_policy_version": "1.1", + "allowlist_universes": ["Universe Name", "..."], + "universe_capacity": { + "Universe Name": 10 + } +} +``` + +### registry.json + +Source template: `.squad/templates/casting-registry.json` +Runtime location: `.squad/casting/registry.json` + +```json +{ + "agents": { + "agent-role-id": { + "persistent_name": "CharacterName", + "universe": "Universe Name", + "created_at": "ISO-8601", + "legacy_named": false, + "status": "active" + } + } +} +``` + +### history.json + +Source template: `.squad/templates/casting-history.json` +Runtime location: `.squad/casting/history.json` + +```json +{ + "universe_usage_history": [ + { + "universe": "Universe Name", + "assignment_id": "unique-id", + "used_at": "ISO-8601" + } + ], + "assignment_cast_snapshots": { + "assignment-id": { + "universe": "Universe Name", + "agents": { + "role-id": "CharacterName" + }, + "created_at": "ISO-8601" + } + } +} +``` diff --git a/packages/squad-sdk/templates/ceremonies.md b/packages/squad-sdk/templates/ceremonies.md index 45b4a581a..e50c151f3 100644 --- a/packages/squad-sdk/templates/ceremonies.md +++ b/packages/squad-sdk/templates/ceremonies.md @@ -39,3 +39,31 @@ 2. Root cause analysis 3. What should change? 4. Action items for next iteration + + +--- + +## Retrospective with Enforcement + +| Field | Value | +|-------|-------| +| **Trigger** | auto | +| **When** | weekly | +| **Condition** | No *retrospective* log in .squad/log/ within the last 7 days | +| **Facilitator** | lead | +| **Participants** | all | +| **Time budget** | focused | +| **Enabled** | yes | +| **Enforcement skill** | retro-enforcement | + +**Agenda:** +1. What shipped this week? (closed issues, merged PRs) +2. What did not ship? (open issues, blockers) +3. Root cause on any failures +4. Action items -- each MUST become a GitHub Issue labeled retro-action + +**Coordinator integration:** +At round start, call Test-RetroOverdue (see skill retro-enforcement). If overdue, run this ceremony before the work queue. + +**Why GitHub Issues, not markdown:** +Production data: 0% completion across 6 retros using markdown checklists, 100% after switching to GitHub Issues. diff --git a/packages/squad-sdk/templates/orchestration-log.md b/packages/squad-sdk/templates/orchestration-log.md index 026963ea4..37d94d193 100644 --- a/packages/squad-sdk/templates/orchestration-log.md +++ b/packages/squad-sdk/templates/orchestration-log.md @@ -1,27 +1,27 @@ -# Orchestration Log Entry - -> One file per agent spawn. Saved to `.squad/orchestration-log/{timestamp}-{agent-name}.md` - ---- - -### {timestamp} — {task summary} - -| Field | Value | -|-------|-------| -| **Agent routed** | {Name} ({Role}) | -| **Why chosen** | {Routing rationale — what in the request matched this agent} | -| **Mode** | {`background` / `sync`} | -| **Why this mode** | {Brief reason — e.g., "No hard data dependencies" or "User needs to approve architecture"} | -| **Files authorized to read** | {Exact file paths the agent was told to read} | -| **File(s) agent must produce** | {Exact file paths the agent is expected to create or modify} | -| **Outcome** | {Completed / Rejected by {Reviewer} / Escalated} | - ---- - -## Rules - -1. **One file per agent spawn.** Named `{timestamp}-{agent-name}.md`. -2. **Log BEFORE spawning.** The entry must exist before the agent runs. -3. **Update outcome AFTER the agent completes.** Fill in the Outcome field. -4. **Never delete or edit past entries.** Append-only. -5. **If a reviewer rejects work,** log the rejection as a new entry with the revision agent. +# Orchestration Log Entry + +> One file per agent spawn. Saved to `.squad/orchestration-log/{timestamp}-{agent-name}.md` + +--- + +### {timestamp} — {task summary} + +| Field | Value | +|-------|-------| +| **Agent routed** | {Name} ({Role}) | +| **Why chosen** | {Routing rationale — what in the request matched this agent} | +| **Mode** | {`background` / `sync`} | +| **Why this mode** | {Brief reason — e.g., "No hard data dependencies" or "User needs to approve architecture"} | +| **Files authorized to read** | {Exact file paths the agent was told to read} | +| **File(s) agent must produce** | {Exact file paths the agent is expected to create or modify} | +| **Outcome** | {Completed / Rejected by {Reviewer} / Escalated} | + +--- + +## Rules + +1. **One file per agent spawn.** Named `{timestamp}-{agent-name}.md`. +2. **Log BEFORE spawning.** The entry must exist before the agent runs. +3. **Update outcome AFTER the agent completes.** Fill in the Outcome field. +4. **Never delete or edit past entries.** Append-only. +5. **If a reviewer rejects work,** log the rejection as a new entry with the revision agent. diff --git a/packages/squad-sdk/templates/skills/cli-wiring/SKILL.md b/packages/squad-sdk/templates/skills/cli-wiring/SKILL.md index 03f7bf55f..9d60aa343 100644 --- a/packages/squad-sdk/templates/skills/cli-wiring/SKILL.md +++ b/packages/squad-sdk/templates/skills/cli-wiring/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "cli-wiring" +description: "Checklist for correctly wiring new CLI commands in cli-entry.ts" +domain: "cli-development" +confidence: "high" +source: "extracted" +--- + # Skill: CLI Command Wiring **Bug class:** Commands implemented in `packages/squad-cli/src/cli/commands/` but never routed in `cli-entry.ts`. diff --git a/packages/squad-sdk/templates/skills/cross-machine-coordination/SKILL.md b/packages/squad-sdk/templates/skills/cross-machine-coordination/SKILL.md index 79c4bc7ea..229b62298 100644 --- a/packages/squad-sdk/templates/skills/cross-machine-coordination/SKILL.md +++ b/packages/squad-sdk/templates/skills/cross-machine-coordination/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "cross-machine-coordination" +description: "Git-based task queuing pattern for coordinating agents across multiple machines" +domain: "distributed-systems" +confidence: "medium" +source: "specification" +--- + # Skill: Cross-Machine Coordination Pattern **Skill ID:** `cross-machine-coordination` diff --git a/packages/squad-sdk/templates/skills/external-comms/SKILL.md b/packages/squad-sdk/templates/skills/external-comms/SKILL.md index 045b993f1..9ac372dca 100644 --- a/packages/squad-sdk/templates/skills/external-comms/SKILL.md +++ b/packages/squad-sdk/templates/skills/external-comms/SKILL.md @@ -1,329 +1,329 @@ ---- -name: "external-comms" -description: "PAO workflow for scanning, drafting, and presenting community responses with human review gate" -domain: "community, communication, workflow" -confidence: "low" -source: "manual (RFC #426 — PAO External Communications)" -tools: - - name: "github-mcp-server-list_issues" - description: "List open issues for scan candidates and lightweight triage" - when: "Use for recent open issue scans before thread-level review" - - name: "github-mcp-server-issue_read" - description: "Read the full issue, comments, and labels before drafting" - when: "Use after selecting a candidate so PAO has complete thread context" - - name: "github-mcp-server-search_issues" - description: "Search for candidate issues or prior squad responses" - when: "Use when filtering by keywords, labels, or duplicate response checks" - - name: "gh CLI" - description: "Fallback for GitHub issue comments and discussions workflows" - when: "Use gh issue list/comment and gh api or gh api graphql when MCP coverage is incomplete" ---- - -## Context - -Phase 1 is **draft-only mode**. - -- PAO scans issues and discussions, drafts responses with the humanizer skill, and presents a review table for human approval. -- **Human review gate is mandatory** — PAO never posts autonomously. -- Every action is logged to `.squad/comms/audit/`. -- This workflow is triggered manually only ("PAO, check community") — no automated or Ralph-triggered activation in Phase 1. - -## Patterns - -### 1. Scan - -Find unanswered community items with GitHub MCP tools first, or `gh issue list` / `gh api` as fallback for issues and discussions. - -- Include **open** issues and discussions only. -- Filter for items with **no squad team response**. -- Limit to items created in the last 7 days. -- Exclude items labeled `squad:internal` or `wontfix`. -- Include discussions **and** issues in the same sweep. -- Phase 1 scope is **issues and discussions only** — do not draft PR replies. - -### Discussion Handling (Phase 1) - -Discussions use the GitHub Discussions API, which differs from issues: - -- **Scan:** `gh api /repos/{owner}/{repo}/discussions --jq '.[] | select(.answer_chosen_at == null)'` to find unanswered discussions -- **Categories:** Filter by Q&A and General categories only (skip Announcements, Show and Tell) -- **Answers vs comments:** In Q&A discussions, PAO drafts an "answer" (not a comment). The human marks it as accepted answer after posting. -- **Phase 1 scope:** Issues and Discussions ONLY. No PR comments. - -### 2. Classify - -Determine the response type before drafting. - -- Welcome (new contributor) -- Troubleshooting (bug/help) -- Feature guidance (feature request/how-to) -- Redirect (wrong repo/scope) -- Acknowledgment (confirmed, no fix) -- Closing (resolved) -- Technical uncertainty (unknown cause) -- Empathetic disagreement (pushback on a decision or design) -- Information request (need more reproduction details or context) - -### Template Selection Guide - -| Signal in Issue/Discussion | → Response Type | Template | -|---------------------------|-----------------|----------| -| New contributor (0 prior issues) | Welcome | T1 | -| Error message, stack trace, "doesn't work" | Troubleshooting | T2 | -| "How do I...?", "Can Squad...?", "Is there a way to...?" | Feature Guidance | T3 | -| Wrong repo, out of scope for Squad | Redirect | T4 | -| Confirmed bug, no fix available yet | Acknowledgment | T5 | -| Fix shipped, PR merged that resolves issue | Closing | T6 | -| Unclear cause, needs investigation | Technical Uncertainty | T7 | -| Author disagrees with a decision or design | Empathetic Disagreement | T8 | -| Need more reproduction info or context | Information Request | T9 | - -Use exactly one template as the base draft. Replace placeholders with issue-specific details, then apply the humanizer patterns. If the thread spans multiple signals, choose the highest-risk template and capture the nuance in the thread summary. - -### Confidence Classification - -| Confidence | Criteria | Example | -|-----------|----------|---------| -| 🟢 High | Answer exists in Squad docs or FAQ, similar question answered before, no technical ambiguity | "How do I install Squad?" | -| 🟡 Medium | Technical answer is sound but involves judgment calls, OR docs exist but don't perfectly match the question, OR tone is tricky | "Can Squad work with Azure DevOps?" (yes, but setup is nuanced) | -| 🔴 Needs Review | Technical uncertainty, policy/roadmap question, potential reputational risk, author is frustrated/angry, question about unreleased features | "When will Squad support Claude?" | - -**Auto-escalation rules:** -- Any mention of competitors → 🔴 -- Any mention of pricing/licensing → 🔴 -- Author has >3 follow-up comments without resolution → 🔴 -- Question references a closed-wontfix issue → 🔴 - -### 3. Draft - -Use the humanizer skill for every draft. - -- Complete **Thread-Read Verification** before writing. -- Read the **full thread**, including all comments, before writing. -- Select the matching template from the **Template Selection Guide** and record the template ID in the review notes. -- Treat templates as reusable drafting assets: keep the structure, replace placeholders, and only improvise when the thread truly requires it. -- Validate the draft against the humanizer anti-patterns. -- Flag long threads (`>10` comments) with `⚠️`. - -### Thread-Read Verification - -Before drafting, PAO MUST verify complete thread coverage: - -1. **Count verification:** Compare API comment count with actually-read comments. If mismatch, abort draft. -2. **Deleted comment check:** Use `gh api` timeline to detect deleted comments. If found, flag as ⚠️ in review table. -3. **Thread summary:** Include in every draft: "Thread: {N} comments, last activity {date}, {summary of key points}" -4. **Long thread flag:** If >10 comments, add ⚠️ to review table and include condensed thread summary -5. **Evidence line in review table:** Each draft row includes "Read: {N}/{total} comments" column - -### 4. Present - -Show drafts for review in this exact format: - -```text -📝 PAO — Community Response Drafts -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -| # | Item | Author | Type | Confidence | Read | Preview | -|---|------|--------|------|------------|------|---------| -| 1 | Issue #N | @user | Type | 🟢/🟡/🔴 | N/N | "First words..." | - -Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review - -Full drafts below ▼ -``` - -Each full draft must begin with the thread summary line: -`Thread: {N} comments, last activity {date}, {summary of key points}` - -### 5. Human Action - -Wait for explicit human direction before anything is posted. - -- `pao approve 1 3` — approve drafts 1 and 3 -- `pao edit 2` — edit draft 2 -- `pao skip` — skip all -- `banana` — freeze all pending (safe word) - -### Rollback — Bad Post Recovery - -If a posted response turns out to be wrong, inappropriate, or needs correction: - -1. **Delete the comment:** - - Issues: `gh api -X DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}` - - Discussions: `gh api graphql -f query='mutation { deleteDiscussionComment(input: {id: "{node_id}"}) { comment { id } } }'` -2. **Log the deletion:** Write audit entry with action `delete`, include reason and original content -3. **Draft replacement** (if needed): PAO drafts a corrected response, goes through normal review cycle -4. **Postmortem:** If the error reveals a pattern gap, update humanizer anti-patterns or add a new test case - -**Safe word — `banana`:** -- Immediately freezes all pending drafts in the review queue -- No new scans or drafts until `pao resume` is issued -- Audit entry logged with halter identity and reason - -### 6. Post - -After approval: - -- Human posts via `gh issue comment` for issues or `gh api` for discussion answers/comments. -- PAO helps by preparing the CLI command. -- Write the audit entry after the posting action. - -### 7. Audit - -Log every action. - -- Location: `.squad/comms/audit/{timestamp}.md` -- Required fields vary by action — see `.squad/comms/templates/audit-entry.md` Conditional Fields table -- Universal required fields: `timestamp`, `action` -- All other fields are conditional on the action type - -## Examples - -These are reusable templates. Keep the structure, replace placeholders, and adjust only where the thread requires it. - -### Example scan command - -```bash -gh issue list --state open --json number,title,author,labels,comments --limit 20 -``` - -### Example review table - -```text -📝 PAO — Community Response Drafts -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -| # | Item | Author | Type | Confidence | Read | Preview | -|---|------|--------|------|------------|------|---------| -| 1 | Issue #426 | @newdev | Welcome | 🟢 | 1/1 | "Hey @newdev! Welcome to Squad..." | -| 2 | Discussion #18 | @builder | Feature guidance | 🟡 | 4/4 | "Great question! Today the CLI..." | -| 3 | Issue #431 ⚠️ | @debugger | Technical uncertainty | 🔴 | 12/12 | "Interesting find, @debugger..." | - -Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review - -Full drafts below ▼ -``` - -### Example audit entry (post action) - -```markdown ---- -timestamp: "2026-03-16T21:30:00Z" -action: "post" -item_number: 426 -draft_id: 1 -reviewer: "@bradygaster" ---- - -## Context (draft, approve, edit, skip, post, delete actions) -- Thread depth: 3 -- Response type: welcome -- Confidence: 🟢 -- Long thread flag: false - -## Draft Content (draft, edit, post actions) -Thread: 3 comments, last activity 2026-03-16, reporter hit a preview-build regression after install. - -Hey @newdev! Welcome to Squad 👋 Thanks for opening this. -We reproduced the issue in preview builds and we're checking the regression point now. -Let us know if you can share the command you ran right before the failure. - -## Post Result (post, delete actions) -https://github.com/bradygaster/squad/issues/426#issuecomment-123456 -``` - -### T1 — Welcome - -```text -Hey {author}! Welcome to Squad 👋 Thanks for opening this. -{specific acknowledgment or first answer} -Let us know if you have questions — happy to help! -``` - -### T2 — Troubleshooting - -```text -Thanks for the detailed report, {author}! -Here's what we think is happening: {explanation} -{steps or workaround} -Let us know if that helps, or if you're seeing something different. -``` - -### T3 — Feature Guidance - -```text -Great question! {context on current state} -{guidance or workaround} -We've noted this as a potential improvement — {tracking info if applicable}. -``` - -### T4 — Redirect - -```text -Thanks for reaching out! This one is actually better suited for {correct location}. -{brief explanation of why} -Feel free to open it there — they'll be able to help! -``` - -### T5 — Acknowledgment - -```text -Good catch, {author}. We've confirmed this is a real issue. -{what we know so far} -We'll update this thread when we have a fix. Thanks for flagging it! -``` - -### T6 — Closing - -```text -This should be resolved in {version/PR}! 🎉 -{brief summary of what changed} -Thanks for reporting this, {author} — it made Squad better. -``` - -### T7 — Technical Uncertainty - -```text -Interesting find, {author}. We're not 100% sure what's causing this yet. -Here's what we've ruled out: {list} -We'd love more context if you have it — {specific ask}. -We'll dig deeper and update this thread. -``` - -### T8 — Empathetic Disagreement - -```text -We hear you, {author}. That's a fair concern. - -The current design choice was driven by {reason}. We know it's not ideal for every use case. - -{what alternatives exist or what trade-off was made} - -If you have ideas for how to make this work better for your scenario, we'd love to hear them — open a discussion or drop your thoughts here! -``` - -### T9 — Information Request - -```text -Thanks for reporting this, {author}! - -To help us dig into this, could you share: -- {specific ask 1} -- {specific ask 2} -- {specific ask 3, if applicable} - -That context will help us narrow down what's happening. Appreciate it! -``` - -## Anti-Patterns - -- ❌ Posting without human review (NEVER — this is the cardinal rule) -- ❌ Drafting without reading full thread (context is everything) -- ❌ Ignoring confidence flags (🔴 items need Flight/human review) -- ❌ Scanning closed issues (only open items) -- ❌ Responding to issues labeled `squad:internal` or `wontfix` -- ❌ Skipping audit logging (every action must be recorded) -- ❌ Drafting for issues where a squad member already responded (avoid duplicates) -- ❌ Drafting pull request responses in Phase 1 (issues/discussions only) -- ❌ Treating templates like loose examples instead of reusable drafting assets -- ❌ Asking for more info without specific requests +--- +name: "external-comms" +description: "PAO workflow for scanning, drafting, and presenting community responses with human review gate" +domain: "community, communication, workflow" +confidence: "low" +source: "manual (RFC #426 — PAO External Communications)" +tools: + - name: "github-mcp-server-list_issues" + description: "List open issues for scan candidates and lightweight triage" + when: "Use for recent open issue scans before thread-level review" + - name: "github-mcp-server-issue_read" + description: "Read the full issue, comments, and labels before drafting" + when: "Use after selecting a candidate so PAO has complete thread context" + - name: "github-mcp-server-search_issues" + description: "Search for candidate issues or prior squad responses" + when: "Use when filtering by keywords, labels, or duplicate response checks" + - name: "gh CLI" + description: "Fallback for GitHub issue comments and discussions workflows" + when: "Use gh issue list/comment and gh api or gh api graphql when MCP coverage is incomplete" +--- + +## Context + +Phase 1 is **draft-only mode**. + +- PAO scans issues and discussions, drafts responses with the humanizer skill, and presents a review table for human approval. +- **Human review gate is mandatory** — PAO never posts autonomously. +- Every action is logged to `.squad/comms/audit/`. +- This workflow is triggered manually only ("PAO, check community") — no automated or Ralph-triggered activation in Phase 1. + +## Patterns + +### 1. Scan + +Find unanswered community items with GitHub MCP tools first, or `gh issue list` / `gh api` as fallback for issues and discussions. + +- Include **open** issues and discussions only. +- Filter for items with **no squad team response**. +- Limit to items created in the last 7 days. +- Exclude items labeled `squad:internal` or `wontfix`. +- Include discussions **and** issues in the same sweep. +- Phase 1 scope is **issues and discussions only** — do not draft PR replies. + +### Discussion Handling (Phase 1) + +Discussions use the GitHub Discussions API, which differs from issues: + +- **Scan:** `gh api /repos/{owner}/{repo}/discussions --jq '.[] | select(.answer_chosen_at == null)'` to find unanswered discussions +- **Categories:** Filter by Q&A and General categories only (skip Announcements, Show and Tell) +- **Answers vs comments:** In Q&A discussions, PAO drafts an "answer" (not a comment). The human marks it as accepted answer after posting. +- **Phase 1 scope:** Issues and Discussions ONLY. No PR comments. + +### 2. Classify + +Determine the response type before drafting. + +- Welcome (new contributor) +- Troubleshooting (bug/help) +- Feature guidance (feature request/how-to) +- Redirect (wrong repo/scope) +- Acknowledgment (confirmed, no fix) +- Closing (resolved) +- Technical uncertainty (unknown cause) +- Empathetic disagreement (pushback on a decision or design) +- Information request (need more reproduction details or context) + +### Template Selection Guide + +| Signal in Issue/Discussion | → Response Type | Template | +|---------------------------|-----------------|----------| +| New contributor (0 prior issues) | Welcome | T1 | +| Error message, stack trace, "doesn't work" | Troubleshooting | T2 | +| "How do I...?", "Can Squad...?", "Is there a way to...?" | Feature Guidance | T3 | +| Wrong repo, out of scope for Squad | Redirect | T4 | +| Confirmed bug, no fix available yet | Acknowledgment | T5 | +| Fix shipped, PR merged that resolves issue | Closing | T6 | +| Unclear cause, needs investigation | Technical Uncertainty | T7 | +| Author disagrees with a decision or design | Empathetic Disagreement | T8 | +| Need more reproduction info or context | Information Request | T9 | + +Use exactly one template as the base draft. Replace placeholders with issue-specific details, then apply the humanizer patterns. If the thread spans multiple signals, choose the highest-risk template and capture the nuance in the thread summary. + +### Confidence Classification + +| Confidence | Criteria | Example | +|-----------|----------|---------| +| 🟢 High | Answer exists in Squad docs or FAQ, similar question answered before, no technical ambiguity | "How do I install Squad?" | +| 🟡 Medium | Technical answer is sound but involves judgment calls, OR docs exist but don't perfectly match the question, OR tone is tricky | "Can Squad work with Azure DevOps?" (yes, but setup is nuanced) | +| 🔴 Needs Review | Technical uncertainty, policy/roadmap question, potential reputational risk, author is frustrated/angry, question about unreleased features | "When will Squad support Claude?" | + +**Auto-escalation rules:** +- Any mention of competitors → 🔴 +- Any mention of pricing/licensing → 🔴 +- Author has >3 follow-up comments without resolution → 🔴 +- Question references a closed-wontfix issue → 🔴 + +### 3. Draft + +Use the humanizer skill for every draft. + +- Complete **Thread-Read Verification** before writing. +- Read the **full thread**, including all comments, before writing. +- Select the matching template from the **Template Selection Guide** and record the template ID in the review notes. +- Treat templates as reusable drafting assets: keep the structure, replace placeholders, and only improvise when the thread truly requires it. +- Validate the draft against the humanizer anti-patterns. +- Flag long threads (`>10` comments) with `⚠️`. + +### Thread-Read Verification + +Before drafting, PAO MUST verify complete thread coverage: + +1. **Count verification:** Compare API comment count with actually-read comments. If mismatch, abort draft. +2. **Deleted comment check:** Use `gh api` timeline to detect deleted comments. If found, flag as ⚠️ in review table. +3. **Thread summary:** Include in every draft: "Thread: {N} comments, last activity {date}, {summary of key points}" +4. **Long thread flag:** If >10 comments, add ⚠️ to review table and include condensed thread summary +5. **Evidence line in review table:** Each draft row includes "Read: {N}/{total} comments" column + +### 4. Present + +Show drafts for review in this exact format: + +```text +📝 PAO — Community Response Drafts +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +| # | Item | Author | Type | Confidence | Read | Preview | +|---|------|--------|------|------------|------|---------| +| 1 | Issue #N | @user | Type | 🟢/🟡/🔴 | N/N | "First words..." | + +Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review + +Full drafts below ▼ +``` + +Each full draft must begin with the thread summary line: +`Thread: {N} comments, last activity {date}, {summary of key points}` + +### 5. Human Action + +Wait for explicit human direction before anything is posted. + +- `pao approve 1 3` — approve drafts 1 and 3 +- `pao edit 2` — edit draft 2 +- `pao skip` — skip all +- `banana` — freeze all pending (safe word) + +### Rollback — Bad Post Recovery + +If a posted response turns out to be wrong, inappropriate, or needs correction: + +1. **Delete the comment:** + - Issues: `gh api -X DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}` + - Discussions: `gh api graphql -f query='mutation { deleteDiscussionComment(input: {id: "{node_id}"}) { comment { id } } }'` +2. **Log the deletion:** Write audit entry with action `delete`, include reason and original content +3. **Draft replacement** (if needed): PAO drafts a corrected response, goes through normal review cycle +4. **Postmortem:** If the error reveals a pattern gap, update humanizer anti-patterns or add a new test case + +**Safe word — `banana`:** +- Immediately freezes all pending drafts in the review queue +- No new scans or drafts until `pao resume` is issued +- Audit entry logged with halter identity and reason + +### 6. Post + +After approval: + +- Human posts via `gh issue comment` for issues or `gh api` for discussion answers/comments. +- PAO helps by preparing the CLI command. +- Write the audit entry after the posting action. + +### 7. Audit + +Log every action. + +- Location: `.squad/comms/audit/{timestamp}.md` +- Required fields vary by action — see `.squad/comms/templates/audit-entry.md` Conditional Fields table +- Universal required fields: `timestamp`, `action` +- All other fields are conditional on the action type + +## Examples + +These are reusable templates. Keep the structure, replace placeholders, and adjust only where the thread requires it. + +### Example scan command + +```bash +gh issue list --state open --json number,title,author,labels,comments --limit 20 +``` + +### Example review table + +```text +📝 PAO — Community Response Drafts +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +| # | Item | Author | Type | Confidence | Read | Preview | +|---|------|--------|------|------------|------|---------| +| 1 | Issue #426 | @newdev | Welcome | 🟢 | 1/1 | "Hey @newdev! Welcome to Squad..." | +| 2 | Discussion #18 | @builder | Feature guidance | 🟡 | 4/4 | "Great question! Today the CLI..." | +| 3 | Issue #431 ⚠️ | @debugger | Technical uncertainty | 🔴 | 12/12 | "Interesting find, @debugger..." | + +Confidence: 🟢 High | 🟡 Medium | 🔴 Needs review + +Full drafts below ▼ +``` + +### Example audit entry (post action) + +```markdown +--- +timestamp: "2026-03-16T21:30:00Z" +action: "post" +item_number: 426 +draft_id: 1 +reviewer: "@bradygaster" +--- + +## Context (draft, approve, edit, skip, post, delete actions) +- Thread depth: 3 +- Response type: welcome +- Confidence: 🟢 +- Long thread flag: false + +## Draft Content (draft, edit, post actions) +Thread: 3 comments, last activity 2026-03-16, reporter hit a preview-build regression after install. + +Hey @newdev! Welcome to Squad 👋 Thanks for opening this. +We reproduced the issue in preview builds and we're checking the regression point now. +Let us know if you can share the command you ran right before the failure. + +## Post Result (post, delete actions) +https://github.com/bradygaster/squad/issues/426#issuecomment-123456 +``` + +### T1 — Welcome + +```text +Hey {author}! Welcome to Squad 👋 Thanks for opening this. +{specific acknowledgment or first answer} +Let us know if you have questions — happy to help! +``` + +### T2 — Troubleshooting + +```text +Thanks for the detailed report, {author}! +Here's what we think is happening: {explanation} +{steps or workaround} +Let us know if that helps, or if you're seeing something different. +``` + +### T3 — Feature Guidance + +```text +Great question! {context on current state} +{guidance or workaround} +We've noted this as a potential improvement — {tracking info if applicable}. +``` + +### T4 — Redirect + +```text +Thanks for reaching out! This one is actually better suited for {correct location}. +{brief explanation of why} +Feel free to open it there — they'll be able to help! +``` + +### T5 — Acknowledgment + +```text +Good catch, {author}. We've confirmed this is a real issue. +{what we know so far} +We'll update this thread when we have a fix. Thanks for flagging it! +``` + +### T6 — Closing + +```text +This should be resolved in {version/PR}! 🎉 +{brief summary of what changed} +Thanks for reporting this, {author} — it made Squad better. +``` + +### T7 — Technical Uncertainty + +```text +Interesting find, {author}. We're not 100% sure what's causing this yet. +Here's what we've ruled out: {list} +We'd love more context if you have it — {specific ask}. +We'll dig deeper and update this thread. +``` + +### T8 — Empathetic Disagreement + +```text +We hear you, {author}. That's a fair concern. + +The current design choice was driven by {reason}. We know it's not ideal for every use case. + +{what alternatives exist or what trade-off was made} + +If you have ideas for how to make this work better for your scenario, we'd love to hear them — open a discussion or drop your thoughts here! +``` + +### T9 — Information Request + +```text +Thanks for reporting this, {author}! + +To help us dig into this, could you share: +- {specific ask 1} +- {specific ask 2} +- {specific ask 3, if applicable} + +That context will help us narrow down what's happening. Appreciate it! +``` + +## Anti-Patterns + +- ❌ Posting without human review (NEVER — this is the cardinal rule) +- ❌ Drafting without reading full thread (context is everything) +- ❌ Ignoring confidence flags (🔴 items need Flight/human review) +- ❌ Scanning closed issues (only open items) +- ❌ Responding to issues labeled `squad:internal` or `wontfix` +- ❌ Skipping audit logging (every action must be recorded) +- ❌ Drafting for issues where a squad member already responded (avoid duplicates) +- ❌ Drafting pull request responses in Phase 1 (issues/discussions only) +- ❌ Treating templates like loose examples instead of reusable drafting assets +- ❌ Asking for more info without specific requests diff --git a/packages/squad-sdk/templates/skills/gh-auth-isolation/SKILL.md b/packages/squad-sdk/templates/skills/gh-auth-isolation/SKILL.md index a639835b1..e4ac1abda 100644 --- a/packages/squad-sdk/templates/skills/gh-auth-isolation/SKILL.md +++ b/packages/squad-sdk/templates/skills/gh-auth-isolation/SKILL.md @@ -1,183 +1,183 @@ ---- -name: "gh-auth-isolation" -description: "Safely manage multiple GitHub identities (EMU + personal) in agent workflows" -domain: "security, github-integration, authentication, multi-account" -confidence: "high" -source: "earned (production usage across 50+ sessions with EMU corp + personal GitHub accounts)" -tools: - - name: "gh" - description: "GitHub CLI for authenticated operations" - when: "When accessing GitHub resources requiring authentication" ---- - -## Context - -Many developers use GitHub through an Enterprise Managed User (EMU) account at work while maintaining a personal GitHub account for open-source contributions. AI agents spawned by Squad inherit the shell's default `gh` authentication — which is usually the EMU account. This causes failures when agents try to push to personal repos, create PRs on forks, or interact with resources outside the enterprise org. - -This skill teaches agents how to detect the active identity, switch contexts safely, and avoid mixing credentials across operations. - -## Patterns - -### Detect Current Identity - -Before any GitHub operation, check which account is active: - -```bash -gh auth status -``` - -Look for: -- `Logged in to github.com as USERNAME` — the active account -- `Token scopes: ...` — what permissions are available -- Multiple accounts will show separate entries - -### Extract a Specific Account's Token - -When you need to operate as a specific user (not the default): - -```bash -# Get the personal account token (by username) -gh auth token --user personaluser - -# Get the EMU account token -gh auth token --user corpalias_enterprise -``` - -**Use case:** Push to a personal fork while the default `gh` auth is the EMU account. - -### Push to Personal Repos from EMU Shell - -The most common scenario: your shell defaults to the EMU account, but you need to push to a personal GitHub repo. - -```bash -# 1. Extract the personal token -$token = gh auth token --user personaluser - -# 2. Push using token-authenticated HTTPS -git push https://personaluser:$token@github.com/personaluser/repo.git branch-name -``` - -**Why this works:** `gh auth token --user` reads from `gh`'s credential store without switching the active account. The token is used inline for a single operation and never persisted. - -### Create PRs on Personal Forks - -When the default `gh` context is EMU but you need to create a PR from a personal fork: - -```bash -# Option 1: Use --repo flag (works if token has access) -gh pr create --repo upstream/repo --head personaluser:branch --title "..." --body "..." - -# Option 2: Temporarily set GH_TOKEN for one command -$env:GH_TOKEN = $(gh auth token --user personaluser) -gh pr create --repo upstream/repo --head personaluser:branch --title "..." -Remove-Item Env:\GH_TOKEN -``` - -### Config Directory Isolation (Advanced) - -For complete isolation between accounts, use separate `gh` config directories: - -```bash -# Personal account operations -$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" -gh auth login # Login with personal account (one-time setup) -gh repo clone personaluser/repo - -# EMU account operations (default) -Remove-Item Env:\GH_CONFIG_DIR -gh auth status # Back to EMU account -``` - -**Setup (one-time):** -```bash -# Create isolated config for personal account -mkdir ~/.config/gh-public -$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" -gh auth login --web --git-protocol https -``` - -### Shell Aliases for Quick Switching - -Add to your shell profile for convenience: - -```powershell -# PowerShell profile -function ghp { $env:GH_CONFIG_DIR = "$HOME/.config/gh-public"; gh @args; Remove-Item Env:\GH_CONFIG_DIR } -function ghe { gh @args } # Default EMU - -# Usage: -# ghp repo clone personaluser/repo # Uses personal account -# ghe issue list # Uses EMU account -``` - -```bash -# Bash/Zsh profile -alias ghp='GH_CONFIG_DIR=~/.config/gh-public gh' -alias ghe='gh' - -# Usage: -# ghp repo clone personaluser/repo -# ghe issue list -``` - -## Examples - -### ✓ Correct: Agent pushes blog post to personal GitHub Pages - -```powershell -# Agent needs to push to personaluser.github.io (personal repo) -# Default gh auth is corpalias_enterprise (EMU) - -$token = gh auth token --user personaluser -git remote set-url origin https://personaluser:$token@github.com/personaluser/personaluser.github.io.git -git push origin main - -# Clean up — don't leave token in remote URL -git remote set-url origin https://github.com/personaluser/personaluser.github.io.git -``` - -### ✓ Correct: Agent creates a PR from personal fork to upstream - -```powershell -# Fork: personaluser/squad, Upstream: bradygaster/squad -# Agent is on branch contrib/fix-docs in the fork clone - -git push origin contrib/fix-docs # Pushes to fork (may need token auth) - -# Create PR targeting upstream -gh pr create --repo bradygaster/squad --head personaluser:contrib/fix-docs ` - --title "docs: fix installation guide" ` - --body "Fixes #123" -``` - -### ✗ Incorrect: Blindly pushing with wrong account - -```bash -# BAD: Agent assumes default gh auth works for personal repos -git push origin main -# ERROR: Permission denied — EMU account has no access to personal repo - -# BAD: Hardcoding tokens in scripts -git push https://personaluser:ghp_xxxxxxxxxxxx@github.com/personaluser/repo.git main -# SECURITY RISK: Token exposed in command history and process list -``` - -### ✓ Correct: Check before you push - -```bash -# Always verify which account has access before operations -gh auth status -# If wrong account, use token extraction: -$token = gh auth token --user personaluser -git push https://personaluser:$token@github.com/personaluser/repo.git main -``` - -## Anti-Patterns - -- ❌ **Hardcoding tokens** in scripts, environment variables, or committed files. Use `gh auth token --user` to extract at runtime. -- ❌ **Assuming the default `gh` auth works** for all repos. EMU accounts can't access personal repos and vice versa. -- ❌ **Switching `gh auth login`** globally mid-session. This changes the default for ALL processes and can break parallel agents. -- ❌ **Storing personal tokens in `.env`** or `.squad/` files. These get committed by Scribe. Use `gh`'s credential store. -- ❌ **Ignoring token cleanup** after inline HTTPS pushes. Always reset the remote URL to avoid persisting tokens. -- ❌ **Using `gh auth switch`** in multi-agent sessions. One agent switching affects all others sharing the shell. -- ❌ **Mixing EMU and personal operations** in the same git clone. Use separate clones or explicit remote URLs per operation. +--- +name: "gh-auth-isolation" +description: "Safely manage multiple GitHub identities (EMU + personal) in agent workflows" +domain: "security, github-integration, authentication, multi-account" +confidence: "high" +source: "earned (production usage across 50+ sessions with EMU corp + personal GitHub accounts)" +tools: + - name: "gh" + description: "GitHub CLI for authenticated operations" + when: "When accessing GitHub resources requiring authentication" +--- + +## Context + +Many developers use GitHub through an Enterprise Managed User (EMU) account at work while maintaining a personal GitHub account for open-source contributions. AI agents spawned by Squad inherit the shell's default `gh` authentication — which is usually the EMU account. This causes failures when agents try to push to personal repos, create PRs on forks, or interact with resources outside the enterprise org. + +This skill teaches agents how to detect the active identity, switch contexts safely, and avoid mixing credentials across operations. + +## Patterns + +### Detect Current Identity + +Before any GitHub operation, check which account is active: + +```bash +gh auth status +``` + +Look for: +- `Logged in to github.com as USERNAME` — the active account +- `Token scopes: ...` — what permissions are available +- Multiple accounts will show separate entries + +### Extract a Specific Account's Token + +When you need to operate as a specific user (not the default): + +```bash +# Get the personal account token (by username) +gh auth token --user personaluser + +# Get the EMU account token +gh auth token --user corpalias_enterprise +``` + +**Use case:** Push to a personal fork while the default `gh` auth is the EMU account. + +### Push to Personal Repos from EMU Shell + +The most common scenario: your shell defaults to the EMU account, but you need to push to a personal GitHub repo. + +```bash +# 1. Extract the personal token +$token = gh auth token --user personaluser + +# 2. Push using token-authenticated HTTPS +git push https://personaluser:$token@github.com/personaluser/repo.git branch-name +``` + +**Why this works:** `gh auth token --user` reads from `gh`'s credential store without switching the active account. The token is used inline for a single operation and never persisted. + +### Create PRs on Personal Forks + +When the default `gh` context is EMU but you need to create a PR from a personal fork: + +```bash +# Option 1: Use --repo flag (works if token has access) +gh pr create --repo upstream/repo --head personaluser:branch --title "..." --body "..." + +# Option 2: Temporarily set GH_TOKEN for one command +$env:GH_TOKEN = $(gh auth token --user personaluser) +gh pr create --repo upstream/repo --head personaluser:branch --title "..." +Remove-Item Env:\GH_TOKEN +``` + +### Config Directory Isolation (Advanced) + +For complete isolation between accounts, use separate `gh` config directories: + +```bash +# Personal account operations +$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" +gh auth login # Login with personal account (one-time setup) +gh repo clone personaluser/repo + +# EMU account operations (default) +Remove-Item Env:\GH_CONFIG_DIR +gh auth status # Back to EMU account +``` + +**Setup (one-time):** +```bash +# Create isolated config for personal account +mkdir ~/.config/gh-public +$env:GH_CONFIG_DIR = "$HOME/.config/gh-public" +gh auth login --web --git-protocol https +``` + +### Shell Aliases for Quick Switching + +Add to your shell profile for convenience: + +```powershell +# PowerShell profile +function ghp { $env:GH_CONFIG_DIR = "$HOME/.config/gh-public"; gh @args; Remove-Item Env:\GH_CONFIG_DIR } +function ghe { gh @args } # Default EMU + +# Usage: +# ghp repo clone personaluser/repo # Uses personal account +# ghe issue list # Uses EMU account +``` + +```bash +# Bash/Zsh profile +alias ghp='GH_CONFIG_DIR=~/.config/gh-public gh' +alias ghe='gh' + +# Usage: +# ghp repo clone personaluser/repo +# ghe issue list +``` + +## Examples + +### ✓ Correct: Agent pushes blog post to personal GitHub Pages + +```powershell +# Agent needs to push to personaluser.github.io (personal repo) +# Default gh auth is corpalias_enterprise (EMU) + +$token = gh auth token --user personaluser +git remote set-url origin https://personaluser:$token@github.com/personaluser/personaluser.github.io.git +git push origin main + +# Clean up — don't leave token in remote URL +git remote set-url origin https://github.com/personaluser/personaluser.github.io.git +``` + +### ✓ Correct: Agent creates a PR from personal fork to upstream + +```powershell +# Fork: personaluser/squad, Upstream: bradygaster/squad +# Agent is on branch contrib/fix-docs in the fork clone + +git push origin contrib/fix-docs # Pushes to fork (may need token auth) + +# Create PR targeting upstream +gh pr create --repo bradygaster/squad --head personaluser:contrib/fix-docs ` + --title "docs: fix installation guide" ` + --body "Fixes #123" +``` + +### ✗ Incorrect: Blindly pushing with wrong account + +```bash +# BAD: Agent assumes default gh auth works for personal repos +git push origin main +# ERROR: Permission denied — EMU account has no access to personal repo + +# BAD: Hardcoding tokens in scripts +git push https://personaluser:ghp_xxxxxxxxxxxx@github.com/personaluser/repo.git main +# SECURITY RISK: Token exposed in command history and process list +``` + +### ✓ Correct: Check before you push + +```bash +# Always verify which account has access before operations +gh auth status +# If wrong account, use token extraction: +$token = gh auth token --user personaluser +git push https://personaluser:$token@github.com/personaluser/repo.git main +``` + +## Anti-Patterns + +- ❌ **Hardcoding tokens** in scripts, environment variables, or committed files. Use `gh auth token --user` to extract at runtime. +- ❌ **Assuming the default `gh` auth works** for all repos. EMU accounts can't access personal repos and vice versa. +- ❌ **Switching `gh auth login`** globally mid-session. This changes the default for ALL processes and can break parallel agents. +- ❌ **Storing personal tokens in `.env`** or `.squad/` files. These get committed by Scribe. Use `gh`'s credential store. +- ❌ **Ignoring token cleanup** after inline HTTPS pushes. Always reset the remote URL to avoid persisting tokens. +- ❌ **Using `gh auth switch`** in multi-agent sessions. One agent switching affects all others sharing the shell. +- ❌ **Mixing EMU and personal operations** in the same git clone. Use separate clones or explicit remote URLs per operation. diff --git a/packages/squad-sdk/templates/skills/humanizer/SKILL.md b/packages/squad-sdk/templates/skills/humanizer/SKILL.md index 63d760f9f..4dbb854df 100644 --- a/packages/squad-sdk/templates/skills/humanizer/SKILL.md +++ b/packages/squad-sdk/templates/skills/humanizer/SKILL.md @@ -1,105 +1,105 @@ ---- -name: "humanizer" -description: "Tone enforcement patterns for external-facing community responses" -domain: "communication, tone, community" -confidence: "low" -source: "manual (RFC #426 — PAO External Communications)" ---- - -## Context - -Use this skill whenever PAO drafts external-facing responses for issues or discussions. - -- Tone must be warm, helpful, and human-sounding — never robotic or corporate. -- Brady's constraint applies everywhere: **Humanized tone is mandatory**. -- This applies to **all external-facing content** drafted by PAO in Phase 1 issues/discussions workflows. - -## Patterns - -1. **Warm opening** — Start with acknowledgment ("Thanks for reporting this", "Great question!") -2. **Active voice** — "We're looking into this" not "This is being investigated" -3. **Second person** — Address the person directly ("you" not "the user") -4. **Conversational connectors** — "That said...", "Here's what we found...", "Quick note:" -5. **Specific, not vague** — "This affects the casting module in v0.8.x" not "We are aware of issues" -6. **Empathy markers** — "I can see how that would be frustrating", "Good catch!" -7. **Action-oriented closes** — "Let us know if that helps!" not "Please advise if further assistance is required" -8. **Uncertainty is OK** — "We're not 100% sure yet, but here's what we think is happening..." is better than false confidence -9. **Profanity filter** — Never include profanity, slurs, or aggressive language, even when quoting -10. **Baseline comparison** — Responses should align with tone of 5-10 "gold standard" responses (>80% similarity threshold) -11. **Empathetic disagreement** — "We hear you. That's a fair concern." before explaining the reasoning -12. **Information request** — Ask for specific details, not open-ended "can you provide more info?" -13. **No link-dumping** — Don't just paste URLs. Provide context: "Check out the [getting started guide](url) — specifically the section on routing" not just a bare link - -## Examples - -### 1. Welcome - -```text -Hey {author}! Welcome to Squad 👋 Thanks for opening this. -{substantive response} -Let us know if you have questions — happy to help! -``` - -### 2. Troubleshooting - -```text -Thanks for the detailed report, {author}! -Here's what we think is happening: {explanation} -{steps or workaround} -Let us know if that helps, or if you're seeing something different. -``` - -### 3. Feature guidance - -```text -Great question! {context on current state} -{guidance or workaround} -We've noted this as a potential improvement — {tracking info if applicable}. -``` - -### 4. Redirect - -```text -Thanks for reaching out! This one is actually better suited for {correct location}. -{brief explanation of why} -Feel free to open it there — they'll be able to help! -``` - -### 5. Acknowledgment - -```text -Good catch, {author}. We've confirmed this is a real issue. -{what we know so far} -We'll update this thread when we have a fix. Thanks for flagging it! -``` - -### 6. Closing - -```text -This should be resolved in {version/PR}! 🎉 -{brief summary of what changed} -Thanks for reporting this, {author} — it made Squad better. -``` - -### 7. Technical uncertainty - -```text -Interesting find, {author}. We're not 100% sure what's causing this yet. -Here's what we've ruled out: {list} -We'd love more context if you have it — {specific ask}. -We'll dig deeper and update this thread. -``` - -## Anti-Patterns - -- ❌ Corporate speak: "We appreciate your patience as we investigate this matter" -- ❌ Marketing hype: "Squad is the BEST way to..." or "This amazing feature..." -- ❌ Passive voice: "It has been determined that..." or "The issue is being tracked" -- ❌ Dismissive: "This works as designed" without empathy -- ❌ Over-promising: "We'll ship this next week" without commitment from the team -- ❌ Empty acknowledgment: "Thanks for your feedback" with no substance -- ❌ Robot signatures: "Best regards, PAO" or "Sincerely, The Squad Team" -- ❌ Excessive emoji: More than 1-2 emoji per response -- ❌ Quoting profanity: Even when the original issue contains it, paraphrase instead -- ❌ Link-dumping: Pasting URLs without context ("See: https://...") -- ❌ Open-ended info requests: "Can you provide more information?" without specifying what information +--- +name: "humanizer" +description: "Tone enforcement patterns for external-facing community responses" +domain: "communication, tone, community" +confidence: "low" +source: "manual (RFC #426 — PAO External Communications)" +--- + +## Context + +Use this skill whenever PAO drafts external-facing responses for issues or discussions. + +- Tone must be warm, helpful, and human-sounding — never robotic or corporate. +- Brady's constraint applies everywhere: **Humanized tone is mandatory**. +- This applies to **all external-facing content** drafted by PAO in Phase 1 issues/discussions workflows. + +## Patterns + +1. **Warm opening** — Start with acknowledgment ("Thanks for reporting this", "Great question!") +2. **Active voice** — "We're looking into this" not "This is being investigated" +3. **Second person** — Address the person directly ("you" not "the user") +4. **Conversational connectors** — "That said...", "Here's what we found...", "Quick note:" +5. **Specific, not vague** — "This affects the casting module in v0.8.x" not "We are aware of issues" +6. **Empathy markers** — "I can see how that would be frustrating", "Good catch!" +7. **Action-oriented closes** — "Let us know if that helps!" not "Please advise if further assistance is required" +8. **Uncertainty is OK** — "We're not 100% sure yet, but here's what we think is happening..." is better than false confidence +9. **Profanity filter** — Never include profanity, slurs, or aggressive language, even when quoting +10. **Baseline comparison** — Responses should align with tone of 5-10 "gold standard" responses (>80% similarity threshold) +11. **Empathetic disagreement** — "We hear you. That's a fair concern." before explaining the reasoning +12. **Information request** — Ask for specific details, not open-ended "can you provide more info?" +13. **No link-dumping** — Don't just paste URLs. Provide context: "Check out the [getting started guide](url) — specifically the section on routing" not just a bare link + +## Examples + +### 1. Welcome + +```text +Hey {author}! Welcome to Squad 👋 Thanks for opening this. +{substantive response} +Let us know if you have questions — happy to help! +``` + +### 2. Troubleshooting + +```text +Thanks for the detailed report, {author}! +Here's what we think is happening: {explanation} +{steps or workaround} +Let us know if that helps, or if you're seeing something different. +``` + +### 3. Feature guidance + +```text +Great question! {context on current state} +{guidance or workaround} +We've noted this as a potential improvement — {tracking info if applicable}. +``` + +### 4. Redirect + +```text +Thanks for reaching out! This one is actually better suited for {correct location}. +{brief explanation of why} +Feel free to open it there — they'll be able to help! +``` + +### 5. Acknowledgment + +```text +Good catch, {author}. We've confirmed this is a real issue. +{what we know so far} +We'll update this thread when we have a fix. Thanks for flagging it! +``` + +### 6. Closing + +```text +This should be resolved in {version/PR}! 🎉 +{brief summary of what changed} +Thanks for reporting this, {author} — it made Squad better. +``` + +### 7. Technical uncertainty + +```text +Interesting find, {author}. We're not 100% sure what's causing this yet. +Here's what we've ruled out: {list} +We'd love more context if you have it — {specific ask}. +We'll dig deeper and update this thread. +``` + +## Anti-Patterns + +- ❌ Corporate speak: "We appreciate your patience as we investigate this matter" +- ❌ Marketing hype: "Squad is the BEST way to..." or "This amazing feature..." +- ❌ Passive voice: "It has been determined that..." or "The issue is being tracked" +- ❌ Dismissive: "This works as designed" without empathy +- ❌ Over-promising: "We'll ship this next week" without commitment from the team +- ❌ Empty acknowledgment: "Thanks for your feedback" with no substance +- ❌ Robot signatures: "Best regards, PAO" or "Sincerely, The Squad Team" +- ❌ Excessive emoji: More than 1-2 emoji per response +- ❌ Quoting profanity: Even when the original issue contains it, paraphrase instead +- ❌ Link-dumping: Pasting URLs without context ("See: https://...") +- ❌ Open-ended info requests: "Can you provide more information?" without specifying what information diff --git a/packages/squad-sdk/templates/skills/model-selection/SKILL.md b/packages/squad-sdk/templates/skills/model-selection/SKILL.md index 4c6866fd4..a00b0d6c8 100644 --- a/packages/squad-sdk/templates/skills/model-selection/SKILL.md +++ b/packages/squad-sdk/templates/skills/model-selection/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "model-selection" +description: "Determines which LLM model to use for each agent spawn using a 5-layer resolution hierarchy" +domain: "orchestration" +confidence: "high" +source: "extracted" +--- + # Model Selection > Determines which LLM model to use for each agent spawn. diff --git a/packages/squad-sdk/templates/skills/nap/SKILL.md b/packages/squad-sdk/templates/skills/nap/SKILL.md index 5973b1cf2..5d3f7787c 100644 --- a/packages/squad-sdk/templates/skills/nap/SKILL.md +++ b/packages/squad-sdk/templates/skills/nap/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "nap" +description: "Context hygiene — compress, prune, archive .squad/ state to reclaim context window budget" +domain: "context-management" +confidence: "medium" +source: "extracted" +--- + # Skill: nap > Context hygiene — compress, prune, archive .squad/ state diff --git a/packages/squad-sdk/templates/skills/personal-squad/SKILL.md b/packages/squad-sdk/templates/skills/personal-squad/SKILL.md index f926821fa..d94b348eb 100644 --- a/packages/squad-sdk/templates/skills/personal-squad/SKILL.md +++ b/packages/squad-sdk/templates/skills/personal-squad/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "personal-squad" +description: "User-level agents that travel across projects via ambient discovery and ghost protocol" +domain: "agent-management" +confidence: "high" +source: "extracted" +--- + # Personal Squad — Skill Document ## What is a Personal Squad? diff --git a/packages/squad-sdk/templates/skills/pr-review-response/SKILL.md b/packages/squad-sdk/templates/skills/pr-review-response/SKILL.md new file mode 100644 index 000000000..dfe290a56 --- /dev/null +++ b/packages/squad-sdk/templates/skills/pr-review-response/SKILL.md @@ -0,0 +1,268 @@ +--- +name: "pr-review-response" +description: "Teaches agents to reply to PR review comment threads after fixing issues, making resolutions traceable" +domain: "pull-requests, code-review, traceability" +confidence: "low" +source: "observed (agents fix review feedback silently — reviewers can't tell which comments were addressed)" +tools: + - name: "github-mcp-server-pull_request_read" + description: "Read PR review threads and comments" + when: "Step 1 — fetching review comments to understand what needs fixing" + - name: "gh api (REST)" + description: "Reply to review comment threads and resolve threads via GraphQL" + when: "Step 3 — posting reply to each comment thread after fixing" +--- + +## Context + +When an agent fixes code in response to PR review comments (from Copilot, a human reviewer, or any GitHub reviewer), the fix alone is not enough. The reviewer needs to see — on the PR thread itself — which comments were addressed and how. Without replies, comments stay visually unresolved, reviewers must re-read the entire diff to verify fixes, and there's no traceable link between feedback and resolution. + +Use this skill whenever: +- You are fixing code based on PR review feedback +- You are addressing Copilot review suggestions +- You are responding to reviewer-requested changes on a PR +- A squad member hands you review comments to resolve + +## SCOPE + +✅ THIS SKILL PRODUCES: +- Reply comments on each review thread explaining the fix +- Optionally resolved threads (via GraphQL when appropriate) +- Commit messages that reference the PR and review context + +❌ THIS SKILL DOES NOT PRODUCE: +- The code fixes themselves (that's the agent's domain work) +- New review comments or reviews +- PR descriptions or summaries + +## Patterns + +### Step 1: Read the review comments + +**Using MCP tools (preferred when available):** + +``` +github-mcp-server-pull_request_read + method: "get_review_comments" + owner: "{owner}" + repo: "{repo}" + pullNumber: {pr_number} +``` + +This returns review threads with metadata: `isResolved`, `isOutdated`, `isCollapsed`, and their associated comments. Each comment has an `id` you'll need for replies. + +**Using gh CLI (fallback):** + +```bash +gh api repos/{owner}/{repo}/pulls/{pr_number}/comments --paginate +``` + +Each comment object contains `id`, `body`, `path`, `line`, and `in_reply_to_id`. Top-level comments have no `in_reply_to_id` — those are the ones you reply to. + +### Step 2: Fix the code + +Make the actual code changes. This is your normal domain work — the skill doesn't prescribe how to fix, only how to communicate the fix. + +**Track what you changed.** For each review comment, note: +- The comment `id` (top-level, not a reply) +- The file and line referenced +- What you actually changed (brief description) +- The commit SHA after pushing (if available) + +### Step 3: Reply to each review thread + +After fixing and committing, reply to **each** review comment thread individually. + +**REST API call (via gh CLI):** + +```bash +gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \ + -f body="Fixed in {sha_short} — {brief description of what was changed}" +``` + +**Important:** `{comment_id}` must be the ID of the **top-level** comment in the thread. You cannot reply to a reply — only to the original review comment. + +**Example replies:** + +```bash +# Specific and traceable +gh api repos/bradygaster/squad/pulls/42/comments/18234/replies \ + -f body="Fixed in a1b2c3d — switched to path.dirname(squadDirInfo.path) for worktree consistency" + +# When applying a suggested code change +gh api repos/bradygaster/squad/pulls/42/comments/18235/replies \ + -f body="Applied suggestion — updated error message to include the file path for debuggability" + +# When pushing back on a suggestion +gh api repos/bradygaster/squad/pulls/42/comments/18236/replies \ + -f body="Considered but not applied — this path needs to stay absolute because worktree resolution depends on it. See detectSquadDir() in detect-squad-dir.ts." +``` + +### Step 4: Resolve threads (optional, GraphQL only) + +Thread resolution is only available via the GitHub GraphQL API. Use this when your fix fully addresses the comment and no further discussion is needed. + +**First, get the thread IDs** (they're different from comment IDs): + +```bash +gh api graphql -f query=' + query { + repository(owner: "{owner}", name: "{repo}") { + pullRequest(number: {pr_number}) { + reviewThreads(first: 100) { + nodes { + id + isResolved + comments(first: 1) { + nodes { body databaseId } + } + } + } + } + } + } +' +``` + +Match thread IDs to comment IDs using `databaseId`, then resolve: + +```bash +gh api graphql -f query=' + mutation { + resolveReviewThread(input: {threadId: "{thread_node_id}"}) { + thread { id isResolved } + } + } +' +``` + +**When to resolve vs. leave open:** +- ✅ Resolve: You fixed exactly what was requested, no ambiguity +- ❌ Don't resolve: You pushed back, applied a different fix, or the comment needs further discussion +- ❌ Don't resolve: The reviewer is a human — let them confirm and resolve themselves + +**Rule of thumb:** Agent-to-agent threads (e.g., Copilot review → agent fix) can be resolved by the fixer. Human reviewer threads should be left for the human to resolve. + +### Step 5: Commit message traceability + +Commit messages should reference the PR context: + +``` +fix: address review feedback on PR #{pr_number} + +- Switched to path.dirname() for worktree path resolution (comment #18234) +- Updated error message to include file path (comment #18235) + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> +``` + +For single-comment fixes, a shorter format works: + +``` +fix: use path.dirname() for worktree consistency (PR #{pr_number} review) + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> +``` + +## AGENT WORKFLOW (Summary) + +1. **READ** — Fetch review threads using MCP tool or `gh api` +2. **FIX** — Make code changes, tracking comment ID → change mapping +3. **COMMIT** — Push with traceable commit message referencing PR and comments +4. **REPLY** — Post individual reply to each thread via `gh api .../replies` +5. **RESOLVE** — (Optional) Resolve agent-to-agent threads via GraphQL +6. **STOP** — Do not batch-reply, do not skip threads, do not resolve human threads + +## Examples + +### Example: Copilot flags a potential null dereference + +**Review comment (id: 55123):** +> `squadDir` could be undefined here. Consider adding a null check. + +**Agent workflow:** +1. Read the comment via `get_review_comments` +2. Add the null check in `src/cli/core/detect-squad-dir.ts` +3. Commit: `fix: add null check for squadDir (PR #99 review)` +4. Reply: + ```bash + gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \ + -f body="Fixed in f4e5d6c — added early return when squadDir is undefined, matching the pattern in loadConfig()" + ``` +5. Resolve the thread (Copilot → agent, safe to resolve) + +### Example: Multiple review comments on one PR + +**Comments:** +- id: 55123 — "Null check needed" on `detect-squad-dir.ts:42` +- id: 55124 — "Consider using path.join()" on `detect-squad-dir.ts:58` +- id: 55125 — "This log message is too verbose" on `output.ts:15` + +**Agent handles each individually:** +```bash +# Fix all three, commit +git add packages/squad-cli/src/cli/core/detect-squad-dir.ts packages/squad-cli/src/cli/core/output.ts +git commit -m "fix: address 3 review comments on PR #99 + +- Added null check for squadDir (comment #55123) +- Switched to path.join() for cross-platform paths (comment #55124) +- Reduced log verbosity to debug level (comment #55125)" + +git push + +# Reply to each thread individually +gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \ + -f body="Fixed — added early return when squadDir is undefined" + +gh api repos/bradygaster/squad/pulls/99/comments/55124/replies \ + -f body="Fixed — switched to path.join(squadDir, 'config.json') for cross-platform consistency" + +gh api repos/bradygaster/squad/pulls/99/comments/55125/replies \ + -f body="Fixed — changed from console.log to debug() so it only shows with --verbose flag" +``` + +### Example: Handling Copilot suggestion blocks + +Copilot sometimes provides `suggestion` blocks with exact code to apply: + +**Review comment (id: 55130):** +```` +Consider using optional chaining: +```suggestion +const name = config?.agent?.name ?? 'default'; +``` +```` + +**Reply format when applying:** +```bash +gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \ + -f body="Applied suggestion — using optional chaining with nullish coalescing" +``` + +**Reply format when not applying:** +```bash +gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \ + -f body="Not applied — config is guaranteed non-null at this point (validated on line 12). Optional chaining would mask errors." +``` + +### Example: Pushing back on a review comment + +Not every review comment should be accepted. When a suggestion is incorrect or doesn't apply: + +```bash +gh api repos/bradygaster/squad/pulls/99/comments/55140/replies \ + -f body="Considered but not applied — this file is in the zero-dependency bootstrap set (see copilot-instructions.md § Protected Files). Adding path.join() would require importing from the SDK, which breaks the bootstrap constraint." +``` + +Do NOT resolve the thread when pushing back. Leave it open for the reviewer to confirm. + +## Anti-Patterns + +- ❌ **Fixing silently** — Making code changes without replying to the review thread. The reviewer has no way to know which comments were addressed. +- ❌ **Batch-replying "all fixed"** — A single comment saying "Addressed all review feedback" on the PR. Each thread needs its own reply so reviewers can verify individually. +- ❌ **Resolving without explaining** — Marking threads resolved without posting a reply first. The resolution gives no context on what was done. +- ❌ **Resolving human reviewer threads** — Only resolve threads from automated reviewers (Copilot, bots). Let human reviewers confirm and resolve their own threads. +- ❌ **Vague replies** — "Fixed" or "Done" without saying what was changed. The reply should be specific enough that the reviewer doesn't need to re-read the diff. +- ❌ **Replying before pushing** — Reply after your fix is committed and pushed, not before. The reply should reference actual committed code. +- ❌ **Ignoring comments you disagree with** — If you don't apply a suggestion, reply explaining why. Silence looks like you missed it. +- ❌ **Replying to replies** — The REST API only supports replying to top-level review comments. Attempting to reply to a reply will fail with a 404. diff --git a/packages/squad-sdk/templates/skills/pr-screenshots/SKILL.md b/packages/squad-sdk/templates/skills/pr-screenshots/SKILL.md index 7425ecf9e..fc93e8f77 100644 --- a/packages/squad-sdk/templates/skills/pr-screenshots/SKILL.md +++ b/packages/squad-sdk/templates/skills/pr-screenshots/SKILL.md @@ -1,149 +1,149 @@ ---- -name: "pr-screenshots" -description: "Capture Playwright screenshots and embed them in GitHub PR descriptions" -domain: "pull-requests, visual-review, docs, testing" -confidence: "high" -source: "earned (multiple sessions establishing the pattern for PR #11 TypeDoc API reference)" ---- - -## Context - -When a PR includes visual changes (docs sites, UI components, generated pages), reviewers -need to see what the PR delivers without checking out the branch. Screenshots belong in -the **PR description body**, not as committed files and not as text descriptions. - -Use this skill whenever: -- A PR touches docs site pages (Astro, Starlight, etc.) -- A PR adds or changes UI components -- A PR generates visual artifacts (TypeDoc, Storybook, diagrams) -- Playwright tests already capture screenshots as part of testing - -## Patterns - -### 1. Capture screenshots with Playwright - -If Playwright tests already exist and produce screenshots, reuse those. Otherwise, -write a minimal capture script: - -```javascript -// scripts/capture-pr-screenshots.mjs -import { chromium } from 'playwright'; - -const browser = await chromium.launch(); -const page = await browser.newPage({ viewport: { width: 1280, height: 720 } }); - -const screenshots = [ - { url: 'http://localhost:4321/path/to/page', name: 'feature-landing' }, - { url: 'http://localhost:4321/path/to/detail', name: 'feature-detail' }, -]; - -for (const { url, name } of screenshots) { - await page.goto(url, { waitUntil: 'networkidle' }); - await page.screenshot({ path: `screenshots/${name}.png`, fullPage: false }); -} - -await browser.close(); -``` - -### 2. Host screenshots on a temporary branch - -GitHub PR descriptions render images via URLs. The `gh` CLI cannot upload binary -images directly. Use a temporary orphan branch to host the images: - -```powershell -# Save current branch -$currentBranch = git branch --show-current - -# Create orphan branch with only screenshot files -git checkout --orphan screenshots-temp -git reset -git add screenshots/*.png -git commit -m "screenshots for PR review" -git push origin screenshots-temp --force - -# Build raw URLs -$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" -# Each image: $base/{name}.png - -# Return to working branch -git checkout -f $currentBranch -``` - -### 3. Embed in PR description - -Use `gh pr edit` with the raw URLs embedded as markdown images: - -```powershell -$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" - -gh pr edit {PR_NUMBER} --repo {owner}/{repo} --body @" -## {PR Title} - -### What this PR delivers -- {bullet points of changes} - ---- - -### Screenshots - -#### {Page/Feature Name} -![{alt text}]($base/{name}.png) - -#### {Another Page} -![{alt text}]($base/{another-name}.png) - ---- - -### To verify locally -```bash -{commands to run locally} -``` -"@ -``` - -### 4. Cleanup after merge - -After the PR is merged, delete the temporary branch: - -```bash -git push origin --delete screenshots-temp -``` - -### 5. Gitignore screenshots locally - -Screenshots are build artifacts — never commit them to feature branches: - -```gitignore -# PR screenshots (hosted on temp branch, not committed to features) -screenshots/ -docs/tests/screenshots/ -``` - -## Examples - -### Example: Docs site PR with 3 pages - -1. Start dev server: `cd docs && npm run dev` -2. Run Playwright tests (they capture screenshots as a side effect) -3. Push screenshots to `screenshots-temp` branch -4. Update PR body with embedded `![...]()` image references -5. Reviewer sees the pages inline without checking out the branch - -### Example: Reusing existing Playwright test screenshots - -If tests at `docs/tests/*.spec.mjs` already save to `docs/tests/screenshots/`: - -```powershell -cd docs && npx playwright test tests/api-reference.spec.mjs -# Screenshots now at docs/tests/screenshots/*.png -# Push those to screenshots-temp and embed in PR -``` - -## Anti-Patterns - -- ❌ **Committing screenshots to feature branches** — they bloat the repo and go stale -- ❌ **Posting text descriptions instead of actual images** — reviewers can't see what they're getting -- ❌ **Using `gh` CLI to "upload" images** — `gh issue comment` and `gh pr edit` don't support binary uploads -- ❌ **Asking the user to manually drag-drop images** — automate it with the temp branch pattern -- ❌ **Skipping screenshots for visual PRs** — if the PR changes what users see, show what users see -- ❌ **Leaving the screenshots-temp branch around forever** — clean up after merge +--- +name: "pr-screenshots" +description: "Capture Playwright screenshots and embed them in GitHub PR descriptions" +domain: "pull-requests, visual-review, docs, testing" +confidence: "high" +source: "earned (multiple sessions establishing the pattern for PR #11 TypeDoc API reference)" +--- + +## Context + +When a PR includes visual changes (docs sites, UI components, generated pages), reviewers +need to see what the PR delivers without checking out the branch. Screenshots belong in +the **PR description body**, not as committed files and not as text descriptions. + +Use this skill whenever: +- A PR touches docs site pages (Astro, Starlight, etc.) +- A PR adds or changes UI components +- A PR generates visual artifacts (TypeDoc, Storybook, diagrams) +- Playwright tests already capture screenshots as part of testing + +## Patterns + +### 1. Capture screenshots with Playwright + +If Playwright tests already exist and produce screenshots, reuse those. Otherwise, +write a minimal capture script: + +```javascript +// scripts/capture-pr-screenshots.mjs +import { chromium } from 'playwright'; + +const browser = await chromium.launch(); +const page = await browser.newPage({ viewport: { width: 1280, height: 720 } }); + +const screenshots = [ + { url: 'http://localhost:4321/path/to/page', name: 'feature-landing' }, + { url: 'http://localhost:4321/path/to/detail', name: 'feature-detail' }, +]; + +for (const { url, name } of screenshots) { + await page.goto(url, { waitUntil: 'networkidle' }); + await page.screenshot({ path: `screenshots/${name}.png`, fullPage: false }); +} + +await browser.close(); +``` + +### 2. Host screenshots on a temporary branch + +GitHub PR descriptions render images via URLs. The `gh` CLI cannot upload binary +images directly. Use a temporary orphan branch to host the images: + +```powershell +# Save current branch +$currentBranch = git branch --show-current + +# Create orphan branch with only screenshot files +git checkout --orphan screenshots-temp +git reset +git add screenshots/*.png +git commit -m "screenshots for PR review" +git push origin screenshots-temp --force + +# Build raw URLs +$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" +# Each image: $base/{name}.png + +# Return to working branch +git checkout -f $currentBranch +``` + +### 3. Embed in PR description + +Use `gh pr edit` with the raw URLs embedded as markdown images: + +```powershell +$base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots" + +gh pr edit {PR_NUMBER} --repo {owner}/{repo} --body @" +## {PR Title} + +### What this PR delivers +- {bullet points of changes} + +--- + +### Screenshots + +#### {Page/Feature Name} +![{alt text}]($base/{name}.png) + +#### {Another Page} +![{alt text}]($base/{another-name}.png) + +--- + +### To verify locally +```bash +{commands to run locally} +``` +"@ +``` + +### 4. Cleanup after merge + +After the PR is merged, delete the temporary branch: + +```bash +git push origin --delete screenshots-temp +``` + +### 5. Gitignore screenshots locally + +Screenshots are build artifacts — never commit them to feature branches: + +```gitignore +# PR screenshots (hosted on temp branch, not committed to features) +screenshots/ +docs/tests/screenshots/ +``` + +## Examples + +### Example: Docs site PR with 3 pages + +1. Start dev server: `cd docs && npm run dev` +2. Run Playwright tests (they capture screenshots as a side effect) +3. Push screenshots to `screenshots-temp` branch +4. Update PR body with embedded `![...]()` image references +5. Reviewer sees the pages inline without checking out the branch + +### Example: Reusing existing Playwright test screenshots + +If tests at `docs/tests/*.spec.mjs` already save to `docs/tests/screenshots/`: + +```powershell +cd docs && npx playwright test tests/api-reference.spec.mjs +# Screenshots now at docs/tests/screenshots/*.png +# Push those to screenshots-temp and embed in PR +``` + +## Anti-Patterns + +- ❌ **Committing screenshots to feature branches** — they bloat the repo and go stale +- ❌ **Posting text descriptions instead of actual images** — reviewers can't see what they're getting +- ❌ **Using `gh` CLI to "upload" images** — `gh issue comment` and `gh pr edit` don't support binary uploads +- ❌ **Asking the user to manually drag-drop images** — automate it with the temp branch pattern +- ❌ **Skipping screenshots for visual PRs** — if the PR changes what users see, show what users see +- ❌ **Leaving the screenshots-temp branch around forever** — clean up after merge diff --git a/packages/squad-sdk/templates/skills/release-process/SKILL.md b/packages/squad-sdk/templates/skills/release-process/SKILL.md index 28d62b5ed..9d5999fc0 100644 --- a/packages/squad-sdk/templates/skills/release-process/SKILL.md +++ b/packages/squad-sdk/templates/skills/release-process/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "release-process" +description: "Battle-tested release checklist and rules derived from the v0.9.0→v0.9.1 incident" +domain: "release-engineering" +confidence: "high" +source: "extracted" +--- + # Release Process > Earned knowledge from the v0.9.0→v0.9.1 incident. Every agent involved in releases MUST read this before starting release work. diff --git a/packages/squad-sdk/templates/skills/versioning-policy/SKILL.md b/packages/squad-sdk/templates/skills/versioning-policy/SKILL.md new file mode 100644 index 000000000..997d4c4aa --- /dev/null +++ b/packages/squad-sdk/templates/skills/versioning-policy/SKILL.md @@ -0,0 +1,119 @@ +--- +name: "versioning-policy" +description: "Semver versioning rules for Squad SDK and CLI — prevents prerelease version incidents" +domain: "release, versioning, npm, CI" +confidence: "medium" +source: "earned (PR #640 workspace resolution incident, PR #116 prerelease leak, CI gate implementation)" +--- + +## Context + +Squad is a monorepo with two publishable npm packages (`@bradygaster/squad-sdk` and `@bradygaster/squad-cli`) managed via npm workspaces. Version mismatches and prerelease leaks have caused production incidents — most notably PR #640, where a `-build.N` prerelease version silently broke workspace dependency resolution. + +This skill codifies the versioning rules every agent must follow. + +## 1. Version Format + +All packages use **strict semver**: `MAJOR.MINOR.PATCH` + +- ✅ `0.9.1`, `1.0.0`, `0.10.0` +- ❌ `0.9.1-build.4`, `0.9.1-preview.1`, `0.8.6.1-preview` + +No prerelease suffixes on `dev` or `main` branches — ever. + +## 2. Prerelease Versions Are Ephemeral + +The `scripts/bump-build.mjs` script creates `-build.N` versions (e.g., `0.9.1-build.4`) for **local development testing only**. + +Rules: +- `-build.N` versions are created automatically during local `npm run build` +- They are **never committed** to `dev` or `main` +- The script skips itself in CI (`CI=true` or `SKIP_BUILD_BUMP=1`) +- If you see a `-build.N` version in a PR diff, it is a bug — reject the PR + +## 3. SDK and CLI Version Sync + +Both `@bradygaster/squad-sdk` and `@bradygaster/squad-cli` **MUST have the same version** at all times. The root `package.json` version must also match. + +`bump-build.mjs` enforces this by updating all three `package.json` files in lockstep (root + `packages/squad-sdk` + `packages/squad-cli`). + +If versions diverge, workspace resolution silently breaks (see §4). + +## 4. npm Workspace Semver Footgun + +The CLI depends on the SDK via a workspace dependency with a semver range: + +```json +"@bradygaster/squad-sdk": ">=0.9.0" +``` + +**Critical:** Per the semver specification, `>=0.9.0` does **NOT** match `0.9.1-build.4`. + +Semver prerelease versions (anything with a `-` suffix) are only matched by ranges that explicitly reference the same `MAJOR.MINOR.PATCH` base with a prerelease comparator. A bare `>=0.9.0` range skips all prerelease versions. + +**What happens:** When the local SDK has version `0.9.1-build.4`, npm's workspace resolution fails to match the `>=0.9.0` range. npm then **silently installs a stale published version** from the npm registry instead of using the local workspace link. The build succeeds but runs against old SDK code. + +This is the root cause of the **PR #640 incident**, where workspace packages appeared linked but were actually running against stale registry versions. + +## 5. Who Bumps Versions + +**Surgeon (Release Manager) owns all version bumps.** + +| Agent | May modify `version` in package.json? | +|-------|---------------------------------------| +| Surgeon | ✅ Yes — sole owner of version bumps | +| Any other agent | ❌ No — unless explicitly fixing a prerelease leak | + +If you discover a prerelease version committed to `dev` or `main`, you may fix it (revert to the clean release version) without Surgeon's approval. This is a safety escape hatch, not a license to manage versions. + +## 6. Version Bump Lifecycle + +``` +┌─────────────────────────────────────────────────────────┐ +│ Development phase │ +│ Versions stay at current release: 0.9.1 │ +│ bump-build.mjs creates -build.N locally (not committed)│ +├─────────────────────────────────────────────────────────┤ +│ Pre-release testing │ +│ bump-build.mjs → 0.9.1-build.1, -build.2, ... │ +│ Local only. Never committed. Never pushed. │ +├─────────────────────────────────────────────────────────┤ +│ Release │ +│ Surgeon bumps to next version (e.g., 0.9.2 or 0.10.0) │ +│ Tags, publishes to npm registry │ +├─────────────────────────────────────────────────────────┤ +│ Post-release │ +│ Versions stay at the new release version (e.g., 0.9.2) │ +│ Development continues on clean version │ +└─────────────────────────────────────────────────────────┘ +``` + +## 7. CI Enforcement + +The **`prerelease-version-guard`** CI gate blocks any PR to `dev` or `main` that contains prerelease version strings in `package.json` files. + +- The gate scans all three `package.json` files for `-` in the version field +- PRs with prerelease versions **cannot merge** until the version is cleaned +- The `skip-version-check` label bypasses the gate — use **only** for the bump-build script's own PR (if applicable), and only with Surgeon's approval + +## 8. Incident Reference — PR #640 + +**PR #640** is the cautionary tale for this entire policy. + +**What happened:** Prerelease versions (`0.9.1-build.4`) were committed to a branch. The workspace dependency `>=0.9.0` failed to match the prerelease version per semver spec. npm silently installed a stale published SDK from the registry instead of linking the local workspace copy. Four PRs (#637–#640) attempted iterative patches before the root cause was identified. + +**Root cause:** No versioning policy existed. Agents didn't know that prerelease versions break workspace resolution, or that only Surgeon should modify versions. + +**Resolution:** This skill, the `prerelease-version-guard` CI gate, and the team decision to centralize version ownership under Surgeon. + +## Quick Reference + +| Rule | Summary | +|------|---------| +| Format | `MAJOR.MINOR.PATCH` — no prerelease on dev/main | +| Prerelease | `-build.N` is local-only, never committed | +| Sync | SDK + CLI + root must have identical versions | +| Ownership | Surgeon bumps versions; others don't touch them | +| CI gate | `prerelease-version-guard` blocks prerelease PRs | +| Escape hatch | Any agent may revert a prerelease leak to clean version | +| Footgun | `>=0.9.0` does NOT match `0.9.1-build.4` per semver | diff --git a/packages/squad-sdk/templates/workflows/squad-heartbeat.yml b/packages/squad-sdk/templates/workflows/squad-heartbeat.yml index 5494296fd..1b75fda3e 100644 --- a/packages/squad-sdk/templates/workflows/squad-heartbeat.yml +++ b/packages/squad-sdk/templates/workflows/squad-heartbeat.yml @@ -1,167 +1,167 @@ -name: Squad Heartbeat (Ralph) -# ⚠️ SYNC: This workflow is maintained in 4 locations. Changes must be applied to all: -# - templates/workflows/squad-heartbeat.yml (source template) -# - packages/squad-cli/templates/workflows/squad-heartbeat.yml (CLI package) -# - .squad/templates/workflows/squad-heartbeat.yml (installed template) -# - .github/workflows/squad-heartbeat.yml (active workflow) -# Run 'squad upgrade' to sync installed copies from source templates. - -on: - # React to completed work or new squad work - issues: - types: [closed, labeled] - pull_request: - types: [closed] - - # Manual trigger - workflow_dispatch: - -permissions: - issues: write - contents: read - pull-requests: read - -jobs: - heartbeat: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Check triage script - id: check-script - run: | - if [ -f ".squad/templates/ralph-triage.js" ]; then - echo "has_script=true" >> $GITHUB_OUTPUT - else - echo "has_script=false" >> $GITHUB_OUTPUT - echo "⚠️ ralph-triage.js not found — run 'squad upgrade' to install" - fi - - - name: Ralph — Smart triage - if: steps.check-script.outputs.has_script == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - node .squad/templates/ralph-triage.js \ - --squad-dir .squad \ - --output triage-results.json - - - name: Ralph — Apply triage decisions - if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != '' - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const path = 'triage-results.json'; - if (!fs.existsSync(path)) { - core.info('No triage results — board is clear'); - return; - } - - const results = JSON.parse(fs.readFileSync(path, 'utf8')); - if (results.length === 0) { - core.info('📋 Board is clear — Ralph found no untriaged issues'); - return; - } - - for (const decision of results) { - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: decision.issueNumber, - labels: [decision.label] - }); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: decision.issueNumber, - body: [ - '### 🔄 Ralph — Auto-Triage', - '', - `**Assigned to:** ${decision.assignTo}`, - `**Reason:** ${decision.reason}`, - `**Source:** ${decision.source}`, - '', - '> Ralph auto-triaged this issue using routing rules.', - '> To reassign, swap the `squad:*` label.' - ].join('\n') - }); - - core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`); - } catch (e) { - core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`); - } - } - - core.info(`🔄 Ralph triaged ${results.length} issue(s)`); - - # Copilot auto-assign step (uses PAT if available) - - name: Ralph — Assign @copilot issues - if: success() - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); - - let teamFile = '.squad/team.md'; - if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) return; - - const content = fs.readFileSync(teamFile, 'utf8'); - - // Check if @copilot is on the team with auto-assign - const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot'); - const autoAssign = content.includes(''); - if (!hasCopilot || !autoAssign) return; - - // Find issues labeled squad:copilot with no assignee - try { - const { data: copilotIssues } = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - labels: 'squad:copilot', - state: 'open', - per_page: 5 - }); - - const unassigned = copilotIssues.filter(i => - !i.assignees || i.assignees.length === 0 - ); - - if (unassigned.length === 0) { - core.info('No unassigned squad:copilot issues'); - return; - } - - // Get repo default branch - const { data: repoData } = await github.rest.repos.get({ - owner: context.repo.owner, - repo: context.repo.repo - }); - - for (const issue of unassigned) { - try { - await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - assignees: ['copilot-swe-agent[bot]'], - agent_assignment: { - target_repo: `${context.repo.owner}/${context.repo.repo}`, - base_branch: repoData.default_branch, - custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` - } - }); - core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); - } catch (e) { - core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`); - } - } - } catch (e) { - core.info(`No squad:copilot label found or error: ${e.message}`); - } +name: Squad Heartbeat (Ralph) +# ⚠️ SYNC: This workflow is maintained in 4 locations. Changes must be applied to all: +# - templates/workflows/squad-heartbeat.yml (source template) +# - packages/squad-cli/templates/workflows/squad-heartbeat.yml (CLI package) +# - .squad/templates/workflows/squad-heartbeat.yml (installed template) +# - .github/workflows/squad-heartbeat.yml (active workflow) +# Run 'squad upgrade' to sync installed copies from source templates. + +on: + # React to completed work or new squad work + issues: + types: [closed, labeled] + pull_request: + types: [closed] + + # Manual trigger + workflow_dispatch: + +permissions: + issues: write + contents: read + pull-requests: read + +jobs: + heartbeat: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check triage script + id: check-script + run: | + if [ -f ".squad/templates/ralph-triage.js" ]; then + echo "has_script=true" >> $GITHUB_OUTPUT + else + echo "has_script=false" >> $GITHUB_OUTPUT + echo "⚠️ ralph-triage.js not found — run 'squad upgrade' to install" + fi + + - name: Ralph — Smart triage + if: steps.check-script.outputs.has_script == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + node .squad/templates/ralph-triage.js \ + --squad-dir .squad \ + --output triage-results.json + + - name: Ralph — Apply triage decisions + if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != '' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = 'triage-results.json'; + if (!fs.existsSync(path)) { + core.info('No triage results — board is clear'); + return; + } + + const results = JSON.parse(fs.readFileSync(path, 'utf8')); + if (results.length === 0) { + core.info('📋 Board is clear — Ralph found no untriaged issues'); + return; + } + + for (const decision of results) { + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: decision.issueNumber, + labels: [decision.label] + }); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: decision.issueNumber, + body: [ + '### 🔄 Ralph — Auto-Triage', + '', + `**Assigned to:** ${decision.assignTo}`, + `**Reason:** ${decision.reason}`, + `**Source:** ${decision.source}`, + '', + '> Ralph auto-triaged this issue using routing rules.', + '> To reassign, swap the `squad:*` label.' + ].join('\n') + }); + + core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`); + } catch (e) { + core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`); + } + } + + core.info(`🔄 Ralph triaged ${results.length} issue(s)`); + + # Copilot auto-assign step (uses PAT if available) + - name: Ralph — Assign @copilot issues + if: success() + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + + let teamFile = '.squad/team.md'; + if (!fs.existsSync(teamFile)) { + teamFile = '.ai-team/team.md'; + } + if (!fs.existsSync(teamFile)) return; + + const content = fs.readFileSync(teamFile, 'utf8'); + + // Check if @copilot is on the team with auto-assign + const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot'); + const autoAssign = content.includes(''); + if (!hasCopilot || !autoAssign) return; + + // Find issues labeled squad:copilot with no assignee + try { + const { data: copilotIssues } = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + labels: 'squad:copilot', + state: 'open', + per_page: 5 + }); + + const unassigned = copilotIssues.filter(i => + !i.assignees || i.assignees.length === 0 + ); + + if (unassigned.length === 0) { + core.info('No unassigned squad:copilot issues'); + return; + } + + // Get repo default branch + const { data: repoData } = await github.rest.repos.get({ + owner: context.repo.owner, + repo: context.repo.repo + }); + + for (const issue of unassigned) { + try { + await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + assignees: ['copilot-swe-agent[bot]'], + agent_assignment: { + target_repo: `${context.repo.owner}/${context.repo.repo}`, + base_branch: repoData.default_branch, + custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` + } + }); + core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); + } catch (e) { + core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`); + } + } + } catch (e) { + core.info(`No squad:copilot label found or error: ${e.message}`); + } diff --git a/templates/ceremonies.md b/templates/ceremonies.md index 45b4a581a..e50c151f3 100644 --- a/templates/ceremonies.md +++ b/templates/ceremonies.md @@ -39,3 +39,31 @@ 2. Root cause analysis 3. What should change? 4. Action items for next iteration + + +--- + +## Retrospective with Enforcement + +| Field | Value | +|-------|-------| +| **Trigger** | auto | +| **When** | weekly | +| **Condition** | No *retrospective* log in .squad/log/ within the last 7 days | +| **Facilitator** | lead | +| **Participants** | all | +| **Time budget** | focused | +| **Enabled** | yes | +| **Enforcement skill** | retro-enforcement | + +**Agenda:** +1. What shipped this week? (closed issues, merged PRs) +2. What did not ship? (open issues, blockers) +3. Root cause on any failures +4. Action items -- each MUST become a GitHub Issue labeled retro-action + +**Coordinator integration:** +At round start, call Test-RetroOverdue (see skill retro-enforcement). If overdue, run this ceremony before the work queue. + +**Why GitHub Issues, not markdown:** +Production data: 0% completion across 6 retros using markdown checklists, 100% after switching to GitHub Issues. diff --git a/templates/skills/nap/SKILL.md b/templates/skills/nap/SKILL.md index 5973b1cf2..5d3f7787c 100644 --- a/templates/skills/nap/SKILL.md +++ b/templates/skills/nap/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "nap" +description: "Context hygiene — compress, prune, archive .squad/ state to reclaim context window budget" +domain: "context-management" +confidence: "medium" +source: "extracted" +--- + # Skill: nap > Context hygiene — compress, prune, archive .squad/ state diff --git a/templates/workflows/squad-heartbeat.yml b/templates/workflows/squad-heartbeat.yml index 5494296fd..1b75fda3e 100644 --- a/templates/workflows/squad-heartbeat.yml +++ b/templates/workflows/squad-heartbeat.yml @@ -1,167 +1,167 @@ -name: Squad Heartbeat (Ralph) -# ⚠️ SYNC: This workflow is maintained in 4 locations. Changes must be applied to all: -# - templates/workflows/squad-heartbeat.yml (source template) -# - packages/squad-cli/templates/workflows/squad-heartbeat.yml (CLI package) -# - .squad/templates/workflows/squad-heartbeat.yml (installed template) -# - .github/workflows/squad-heartbeat.yml (active workflow) -# Run 'squad upgrade' to sync installed copies from source templates. - -on: - # React to completed work or new squad work - issues: - types: [closed, labeled] - pull_request: - types: [closed] - - # Manual trigger - workflow_dispatch: - -permissions: - issues: write - contents: read - pull-requests: read - -jobs: - heartbeat: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Check triage script - id: check-script - run: | - if [ -f ".squad/templates/ralph-triage.js" ]; then - echo "has_script=true" >> $GITHUB_OUTPUT - else - echo "has_script=false" >> $GITHUB_OUTPUT - echo "⚠️ ralph-triage.js not found — run 'squad upgrade' to install" - fi - - - name: Ralph — Smart triage - if: steps.check-script.outputs.has_script == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - node .squad/templates/ralph-triage.js \ - --squad-dir .squad \ - --output triage-results.json - - - name: Ralph — Apply triage decisions - if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != '' - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const path = 'triage-results.json'; - if (!fs.existsSync(path)) { - core.info('No triage results — board is clear'); - return; - } - - const results = JSON.parse(fs.readFileSync(path, 'utf8')); - if (results.length === 0) { - core.info('📋 Board is clear — Ralph found no untriaged issues'); - return; - } - - for (const decision of results) { - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: decision.issueNumber, - labels: [decision.label] - }); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: decision.issueNumber, - body: [ - '### 🔄 Ralph — Auto-Triage', - '', - `**Assigned to:** ${decision.assignTo}`, - `**Reason:** ${decision.reason}`, - `**Source:** ${decision.source}`, - '', - '> Ralph auto-triaged this issue using routing rules.', - '> To reassign, swap the `squad:*` label.' - ].join('\n') - }); - - core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`); - } catch (e) { - core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`); - } - } - - core.info(`🔄 Ralph triaged ${results.length} issue(s)`); - - # Copilot auto-assign step (uses PAT if available) - - name: Ralph — Assign @copilot issues - if: success() - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); - - let teamFile = '.squad/team.md'; - if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) return; - - const content = fs.readFileSync(teamFile, 'utf8'); - - // Check if @copilot is on the team with auto-assign - const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot'); - const autoAssign = content.includes(''); - if (!hasCopilot || !autoAssign) return; - - // Find issues labeled squad:copilot with no assignee - try { - const { data: copilotIssues } = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - labels: 'squad:copilot', - state: 'open', - per_page: 5 - }); - - const unassigned = copilotIssues.filter(i => - !i.assignees || i.assignees.length === 0 - ); - - if (unassigned.length === 0) { - core.info('No unassigned squad:copilot issues'); - return; - } - - // Get repo default branch - const { data: repoData } = await github.rest.repos.get({ - owner: context.repo.owner, - repo: context.repo.repo - }); - - for (const issue of unassigned) { - try { - await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - assignees: ['copilot-swe-agent[bot]'], - agent_assignment: { - target_repo: `${context.repo.owner}/${context.repo.repo}`, - base_branch: repoData.default_branch, - custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` - } - }); - core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); - } catch (e) { - core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`); - } - } - } catch (e) { - core.info(`No squad:copilot label found or error: ${e.message}`); - } +name: Squad Heartbeat (Ralph) +# ⚠️ SYNC: This workflow is maintained in 4 locations. Changes must be applied to all: +# - templates/workflows/squad-heartbeat.yml (source template) +# - packages/squad-cli/templates/workflows/squad-heartbeat.yml (CLI package) +# - .squad/templates/workflows/squad-heartbeat.yml (installed template) +# - .github/workflows/squad-heartbeat.yml (active workflow) +# Run 'squad upgrade' to sync installed copies from source templates. + +on: + # React to completed work or new squad work + issues: + types: [closed, labeled] + pull_request: + types: [closed] + + # Manual trigger + workflow_dispatch: + +permissions: + issues: write + contents: read + pull-requests: read + +jobs: + heartbeat: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check triage script + id: check-script + run: | + if [ -f ".squad/templates/ralph-triage.js" ]; then + echo "has_script=true" >> $GITHUB_OUTPUT + else + echo "has_script=false" >> $GITHUB_OUTPUT + echo "⚠️ ralph-triage.js not found — run 'squad upgrade' to install" + fi + + - name: Ralph — Smart triage + if: steps.check-script.outputs.has_script == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + node .squad/templates/ralph-triage.js \ + --squad-dir .squad \ + --output triage-results.json + + - name: Ralph — Apply triage decisions + if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != '' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = 'triage-results.json'; + if (!fs.existsSync(path)) { + core.info('No triage results — board is clear'); + return; + } + + const results = JSON.parse(fs.readFileSync(path, 'utf8')); + if (results.length === 0) { + core.info('📋 Board is clear — Ralph found no untriaged issues'); + return; + } + + for (const decision of results) { + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: decision.issueNumber, + labels: [decision.label] + }); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: decision.issueNumber, + body: [ + '### 🔄 Ralph — Auto-Triage', + '', + `**Assigned to:** ${decision.assignTo}`, + `**Reason:** ${decision.reason}`, + `**Source:** ${decision.source}`, + '', + '> Ralph auto-triaged this issue using routing rules.', + '> To reassign, swap the `squad:*` label.' + ].join('\n') + }); + + core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`); + } catch (e) { + core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`); + } + } + + core.info(`🔄 Ralph triaged ${results.length} issue(s)`); + + # Copilot auto-assign step (uses PAT if available) + - name: Ralph — Assign @copilot issues + if: success() + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + + let teamFile = '.squad/team.md'; + if (!fs.existsSync(teamFile)) { + teamFile = '.ai-team/team.md'; + } + if (!fs.existsSync(teamFile)) return; + + const content = fs.readFileSync(teamFile, 'utf8'); + + // Check if @copilot is on the team with auto-assign + const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot'); + const autoAssign = content.includes(''); + if (!hasCopilot || !autoAssign) return; + + // Find issues labeled squad:copilot with no assignee + try { + const { data: copilotIssues } = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + labels: 'squad:copilot', + state: 'open', + per_page: 5 + }); + + const unassigned = copilotIssues.filter(i => + !i.assignees || i.assignees.length === 0 + ); + + if (unassigned.length === 0) { + core.info('No unassigned squad:copilot issues'); + return; + } + + // Get repo default branch + const { data: repoData } = await github.rest.repos.get({ + owner: context.repo.owner, + repo: context.repo.repo + }); + + for (const issue of unassigned) { + try { + await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + assignees: ['copilot-swe-agent[bot]'], + agent_assignment: { + target_repo: `${context.repo.owner}/${context.repo.repo}`, + base_branch: repoData.default_branch, + custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` + } + }); + core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); + } catch (e) { + core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`); + } + } + } catch (e) { + core.info(`No squad:copilot label found or error: ${e.message}`); + }