diff --git a/.ai-team/agents/fenster/history.md b/.ai-team/agents/fenster/history.md index d90d4a148..d0bbe3152 100644 --- a/.ai-team/agents/fenster/history.md +++ b/.ai-team/agents/fenster/history.md @@ -95,3 +95,11 @@ _Summarized from initial architecture review (2026-02-07). Full entries in `hist - **UTF-8 emoji mojibake in test file.** `test/index.test.js` had 8 instances of garbled emoji strings (e.g. `โ‰กฦ’รฆรฑ` instead of `๐Ÿ‘ค`, `โ‰กฦ’รดรฎ` instead of `๐Ÿ“Œ`, `โ‰กฦ’รฑรป` instead of `๐Ÿค–`, `โ‰กฦ’ฦ’รณ`/`โ‰กฦ’ฦ’รญ`/`โ‰กฦ’รถโ”ค` instead of `๐ŸŸข`/`๐ŸŸก`/`๐Ÿ”ด`). Root cause: file was likely saved or transferred through a system that re-encoded UTF-8 multibyte sequences as Latin-1/CP1252. Fixed all 8 instances to use real Unicode codepoints matching what `index.js` and `squad.agent.md` produce. All 118 tests pass. +- **Universe allowlist expansion (issue #21).** Added Adventure Time (community request from Gabe) plus 10 new universes to the allowlist in both `.github/agents/squad.agent.md` and `.ai-team/casting/policy.json`. New universes: Futurama, Seinfeld, The Office, Cowboy Bebop, Fullmetal Alchemist, Stranger Things, The Expanse, Arcane, Ted Lasso, Dune. Selection rationale: filled genre gaps (sitcom, anime, animation, workplace comedy, hard sci-fi, sports/comedy). Total universes went from 20 โ†’ 31. Constraints added for The Office (avoid Michael Scott at scale) and Dune (combine book/film, avoid Paul unless required). Closed issue #21. + + +๐Ÿ“Œ Team update (2026-02-12): Universe expansion complete โ€” 11 new universes (Adventure Time, Futurama, Seinfeld, The Office, Cowboy Bebop, Fullmetal Alchemist, Stranger Things, The Expanse, Arcane, Ted Lasso, Dune) added to casting allowlist. Issue #21 closed. โ€” decided by Fenster + +- **SSH agent / npm spinner hang documented (issue #30).** `npx github:bradygaster/squad` resolves via `git+ssh://`. When no SSH agent is running, git prompts for a passphrase but npm's progress spinner overwrites the TTY prompt, making it look frozen. This is an npm bug, not ours. Documented workarounds in README (Install section note + Known Limitations bullet) and created `docs/scenarios/troubleshooting.md` with problemโ†’causeโ†’fix format covering SSH hang, gh auth, Node version, agent visibility, upgrade cache, and Windows paths. The troubleshooting doc pattern is reusable for future community-reported issues. + +- **Label automation for go: and release: namespaces.** Created `squad-label-enforce.yml` workflow to enforce mutual exclusivity on `go:*` (triage verdict) and `release:*` (version target) labels. When a new label is applied, conflicting labels in the same namespace are auto-removed and a comment is posted (only if a change was made). Special cases: applying `go:yes` auto-adds `release:backlog` if no release target exists; applying `go:no` removes all release labels. Updated `sync-squad-labels.yml` to sync 3 go: labels (go:yes, go:no, go:needs-research) and 5 release: labels (release:v0.4.0, v0.5.0, v0.6.0, v1.0.0, release:backlog). Updated `squad-triage.yml` to apply `go:needs-research` as default verdict after triage assigns a squad member. Updated `squad-heartbeat.yml` to add two new checks: issues missing go: labels and go:yes issues missing release: labels. This implements "agentic DevOps" โ€” labels drive automation, automation enforces label integrity. diff --git a/.ai-team/agents/keaton/history.md b/.ai-team/agents/keaton/history.md index af1c4f307..261c7df9a 100644 --- a/.ai-team/agents/keaton/history.md +++ b/.ai-team/agents/keaton/history.md @@ -58,7 +58,10 @@ _Summarized from initial architecture review and proposal-first design (2026-02- ## Learnings -_Summarized 2026-02-10 learnings (full entries available in session logs):_ +_Summarized 2026-02-10+ learnings (full entries available in session logs):_ + +- **2026-02-10+: Issue #6 (Project Boards) โ€” Go/No-Go Assessment** + - **Verdict: GO (Conditional v0.4.0).** Projects V2 integration is architecturally sound and technically feasible with zero npm dependencies using `gh project *` CLI commands. Kujan's 033a assessment confirmed: 12 operations map cleanly to CLI, MCP server has zero Projects tools, provider abstraction works for GitHub/ADO/GitLab. Single prerequisite: Brady must grant `project` token scope (`gh auth refresh -s project`). Three-phase sprint plan: Phase 1 (6-9h foundation validation), Phase 2 (7-11h integration, parallelizable), Phase 3 (4-6h polish). Total 17-26h across Fenster (core), Verbal (prompts), McManus (docs). v0.4.0 timing is intentional โ€” labels + issues (v0.3.0) are the foundation; boards are the dashboard (v0.4.0). Posted as comment on Issue #6 at https://github.com/bradygaster/squad/issues/6#issuecomment-3888277477. - **2026-02-10: Model Selection (024 consolidated)** โ€” Merged 024+024a+024b into single spec. 4-layer selection priority, 16-model catalog condensed to 4 columns, nuclear fallback for resilience. Status: Approved โœ… for v0.3.0 Wave 1. - **2026-02-10: v0.3.0 Sprint Plan (027)** โ€” 4 bets: model selection, backlog capture, demo infra, GitHub Issue sync. 2 waves, 31-43h. v0.2.0 gave hands; v0.3.0 gives a brain. Cut aggressively: no Squad DM, no agent negotiation, no speculative execution. @@ -199,3 +202,28 @@ _Summarized 2026-02-10 learnings (full entries available in session logs):_ ๐Ÿ“Œ Team update (2026-02-11): Proposal 034 โ€” MCP Integration architecture designed. Recommendation: Option B (Awareness Layer, 4-6h). Blocks on WI-1 platform behavior validation. Fritz's use cases: Trello board sync + Aspire dashboard monitoring. โ€” decided by Keaton ๐Ÿ“Œ Team update (2026-02-11): MCP Integration Direction for Squad approved โ€” Option B (Awareness Layer) chosen. Phase 1 spike (WI-1) validates platform MCP support. See decisions.md for rationale and timeline. โ€” decided by Keaton + + +๐Ÿ“Œ Team update (2026-02-12): Branching strategy finalized โ€” feature branches (squad/{issue}-{slug}) to dev via PR, release pipeline handles previewโ†’main โ€” decided by Keaton, analyzed by Fenster, hardened by Kobayashi + +๐Ÿ“Œ Team update (2026-02-12): Release process hardened with branch protection rules and CI/CD-only writes to preview/main โ€” decided by Kobayashi and Brady + +๐Ÿ“Œ Team update (2026-02-12): Issue #6 (Project Boards) approved for v0.4.0. GO (Conditional) โ€” pending Brady's project token scope grant. 3-phase implementation plan (17-26 squad-hours), agent assignments finalized. โ€” decided by Keaton +๐Ÿ“Œ Team update (2026-02-13): go:/release: label automation shipped โ€” Four-workflow system enforces label namespace integrity (go:* triage verdicts, release:* version targets). Mutual exclusivity at runtime, special cases (go:yes auto-adds release:backlog), heartbeat detects label hygiene gaps. Labels-as-state-machine is now foundational to GitHub-native workflow. โ€” decided by Fenster + +- **2026-02-11: Proposal 034 โ€” Squad Pings You (Notification Architecture)** + - **Brady's vision:** "It needs to feel like I'm not in the team room, they are, and they need me so they pinged me." He wants notifications on his phone (Teams or iMessage) when squad agents hit a wall requiring human input. + - **Architectural decision: Squad ships ZERO notification infrastructure.** This is an MCP integration pattern โ€” the consumer brings their own notification MCP server (Teams, iMessage, Discord, webhook). Squad teaches agents WHEN and HOW to notify via a skill. + - **Three-layer architecture:** (1) Notification skill at .ai-team/skills/human-notification/SKILL.md teaches agents when to ping, (2) MCP tool abstraction (no hardcoded tool names), (3) Consumer's MCP server (user-configured in .vscode/mcp.json). + - **Notification trigger taxonomy:** BLOCKED (work cannot proceed), ERROR (unrecoverable failure), DECISION (strategic choice needed), COMPLETE (opt-in only, for completion notifications). + - **Platform-agnostic message format:** Agent name + emoji + type badge + context + action + link. Platform-specific renderers: Teams (Adaptive Cards), iMessage (plain text), webhook (JSON payload). + - **Primary path: Microsoft Teams.** Brady said "ideal, especially per-repo channels." Teams channels-per-repo is native, Incoming Webhooks are simple (POST JSON to URL), mobile UX is enterprise-standard. Official MCP server exists: @microsoft/teams.mcp. + - **Secondary path: iMessage (Mac-only).** Zero account setup, instant delivery. Limitations: requires macOS with Messages.app running, cannot run headless. MCP server exists: imessage-mcp or imsg CLI. + - **Graceful degradation:** If no MCP server is configured, agents log the notification attempt and continue. Notifications are an enhancement, not a requirement. + - **Integration with existing features:** Human Team Members get BLOCKED notifications when work routes to them. Ralph can escalate stale work via notifications (opt-in). Coordinator triggers notifications when agents return blocked. + - **Zero maintenance burden for Squad:** The consumer owns the MCP server, credentials, and delivery mechanism. When Teams changes their API, the MCP server maintainer updates the server โ€” not Squad. + - **Sprint estimate:** 1.8 squad-days (core) + 0.3 squad-days (Ralph integration, optional). Target version: 0.3.0 (alongside GitHub-native proposals). + - **Key file paths:** eam-docs/proposals/034-notification-architecture.md (full spec), .ai-team/skills/human-notification/SKILL.md (agent-facing skill), future docs/notifications.md (consumer setup guide). + + +๐Ÿ“Œ Team update (2026-02-12): Squad Notification Architecture (Proposal 034) merged into decisions.md โ€” MCP integration pattern, Teams primary, iMessage secondary, skill-based trigger system (BLOCKED/ERROR/DECISION/COMPLETE). โ€” decided by Keaton diff --git a/.ai-team/agents/kobayashi/history.md b/.ai-team/agents/kobayashi/history.md index cbae1545b..d1e11e7f2 100644 --- a/.ai-team/agents/kobayashi/history.md +++ b/.ai-team/agents/kobayashi/history.md @@ -59,3 +59,11 @@ _Summarized from sessions through 2026-02-09. Full entries in `history-archive.m ๐Ÿ“Œ Team update (2026-02-11): Per-agent model selection implemented with cost-first directive (optimize cost unless writing code) โ€” decided by Brady and Verbal ๐Ÿ“Œ Team update (2026-02-11): MCP Integration Direction for Squad approved โ€” Option B (Awareness Layer) chosen. Phase 1 spike (WI-1) validates platform MCP support. See decisions.md for rationale and timeline. โ€” decided by Keaton + +## Learnings + +- **v0.3.0 release entry created** โ€” Added comprehensive CHANGELOG.md entry documenting five shipped features (per-agent model selection, Ralph work monitor, @copilot integration, universe expansion, milestones rename), four Changed items (tests, emoji fixes, agent.md expansion, index.js upgrade fix), and community contributions (2 PRs from @spboyer, 4 new issues from external contributors). Entry follows v0.2.0 format (Added/Changed/Community sections) and preserves content tree with v0.2.0 and v0.1.0 below. Date: 2026-02-11. + + +๐Ÿ“Œ Team update (2026-02-12): Cross-client sub-agent API research complete โ€” squad.agent.md uses task tool exclusively for CLI platform, VS Code uses runSubagent, no unification planned โ€” research by Kujan +๐Ÿ“Œ Team update (2026-02-13): go:/release: label automation shipped โ€” Four-workflow system enforces label namespace integrity (go:* triage verdicts, release:* version targets). Workflows: squad-label-enforce.yml (mutual exclusivity), sync-squad-labels.yml (sync 8 static labels), squad-triage.yml (default go:needs-research), squad-heartbeat.yml (detect label gaps). Labels-as-state-machine is foundational to GitHub-native workflow. โ€” decided by Fenster diff --git a/.ai-team/agents/kujan/history.md b/.ai-team/agents/kujan/history.md index 5149f3191..a86c806a6 100644 --- a/.ai-team/agents/kujan/history.md +++ b/.ai-team/agents/kujan/history.md @@ -95,3 +95,8 @@ _Summarized 2026-02-10 learnings (full entries in session logs and proposals):_ ๐Ÿ“Œ Team update (2026-02-11): Discord is the v0.3.0 MVP messaging connector. Gateway must be platform-agnostic with zero GitHub-specific imports. โ€” decided by Keaton +- **Issue #18: Version Display in Agent Output** โ€” Investigated how to show Squad version across Copilot hosts. Key finding: the version stamping pipeline (`stampVersion()` in `index.js`) already embeds the version into `squad.agent.md` frontmatter during install/upgrade โ€” the version was present but unused at runtime. Solution: added a `Version` instruction to the Coordinator Identity section telling the coordinator to read its own frontmatter version and include `Squad v{version}` in its first response. Zero `index.js` changes needed. Works across CLI, VS Code, and GitHub.com because it's coordinator behavior, not host-specific. The `description` frontmatter field and `task` tool `description` parameter were rejected as too noisy/per-spawn respectively. + + + +๐Ÿ“Œ Team update (2026-02-12): Version display implemented via Coordinator self-announcement in squad.agent.md โ€” leverages existing version stamping infrastructure โ€” decided by Kujan diff --git a/.ai-team/agents/mcmanus/history.md b/.ai-team/agents/mcmanus/history.md index 0acdaf3f4..00ab42ac7 100644 --- a/.ai-team/agents/mcmanus/history.md +++ b/.ai-team/agents/mcmanus/history.md @@ -111,3 +111,74 @@ _Summarized from initial assessment, messaging overhaul, demo script, and README ๐Ÿ“Œ Team update (2026-02-11): Discord is the v0.3.0 MVP messaging connector. Gateway must be platform-agnostic with zero GitHub-specific imports. โ€” decided by Keaton +- **v0.3.0 README update (2026-02-11)** โ€” README.md "What's New" section updated. Changes: (1) Created new "## What's New in v0.3.0" section positioned before v0.2.0. (2) Added seven new features: Per-Agent Model Selection, Ralph Work Monitor, @copilot Coding Agent, Universe Expansion (14โ†’20 universes), Milestones rename, test growth (92โ†’118), emoji fixes. (3) Moved v0.2.0 features from top billing to "## What's New in v0.2.0" section. Removed Copilot Coding Agent and Ralph from v0.2.0 section (both promoted to v0.3.0 headline features). (4) Updated Status line from v0.2.0 to v0.3.0. All new features link to docs/ when available. Style: scannable list format, one-line summaries, no hype language, matches existing README tone. + +- **Ralph PAT Classic authentication documentation (2026-02-11)** โ€” Updated `docs/features/ralph.md` with comprehensive "Prerequisites" section. Key facts documented: (1) Ralph requires `gh` CLI to be installed and authenticated with a GitHub PAT Classic token (not the default Copilot token). (2) Included rationale: default GITHUB_TOKEN lacks the `repo` and `project` scopes needed for issue/PR write access. (3) Step-by-step setup: create PAT Classic, run `gh auth login`, provide token, verify with `gh auth status`. (4) Positioned Prerequisites section before How It Works to surface authentication requirement upfront. Addresses Issue #17 filed by Shayne Boyer (spboyer). Style: facts only, procedural steps, no editorial framing. + +- **Tips and Tricks for Squad Management (Issue #16)** โ€” Created `docs/tips-and-tricks.md` with practical patterns for managing Squad effectively. Document structure: (1) Effective Prompt Patterns โ€” 5 core patterns with before/after examples (specificity, roster naming, team vs direct commands, stacking decisions, bullet points). (2) When to Use Direct Commands vs Team Requests โ€” routed guidance with tables showing use cases and rationale. (3) Parallel Work Patterns โ€” 4 techniques: let work complete before following up, check work logs instead of code, use Ralph for backlogs, parallel decision-making. (4) Ralph Work Monitor Tips โ€” 5 activation and scoping patterns including scope filtering and heartbeat setup. (5) Managing Decisions and Team Memory โ€” 6 patterns for setting rules, handling directives, archiving decisions, using Scribe. (6) Common Pitfalls with Solutions โ€” 8 pitfalls and recovery patterns (vague scope, interrupting parallel work, forgotten decisions, Ralph underuse, too many agents, uncommitted state, same mistakes, silent completion). (7) Advanced Patterns โ€” spike-before-build, parallel teams, post-mortems. (8) Copyable Prompts โ€” templates for common scenarios. (9) Session Flow Template and Reference Table. Style: facts-based, working examples, no fluff. Target: users new to Squad who need practical patterns, not just features. + +- **Community page design (2026-02-12)** โ€” Issue #20. Created `docs/community.md` with shields.io badges (dynamic star/fork/issue/PR counts), explicit "How to Contribute" pathways (Issues, PRs, Discussions), contributor recognition sections (core team, external deployments, video coverage), and gave-back guidance. Added link from README.md badges area with emoji anchor ("๐Ÿ“ฃ"). Page follows straight-facts tone: no adjectives, lists contributions by type, acknowledges early deployments (Shayne Boyer's label convention, Jeff Fritz's video). Community pages are warm infrastructure, not sales material. +- **Platform tool fragmentation (2026-02-11)** โ€” Copilot ecosystem has NO unified sub-agent tool across clients. Each platform ships its own: Copilot CLI uses `task` (stable, supports `mode: "background"`), VS Code uses `runSubagent`/`runSubagent2` (different API, lacks parallel support), Visual Studio has no native spawning, Coding Agent uses separate execution model. Squad targets CLI as primary platform with cross-client support tracked in #10. Issue #9 (reporter: miketsui3a) called this out โ€” community clarity needed on which platform works where. + +๐Ÿ“Œ Team update (2026-02-10): v0.3.0 sprint plan approved โ€” Demo 1 scripted infrastructure is in scope. โ€” decided by Keaton + +- **Marketing site content plan written (2026-02-10)** โ€” `team-docs/proposals/029a-marketing-site-content.md`. Full content plan for Jekyll/GitHub Pages marketing site. Key decisions: (1) No content reproduction โ€” Jekyll reads `docs/` in place with front matter additions, blog reads from `team-docs/blog/` via custom collection. (2) 17 of 18 docs files are ready for the site as-is; only `sample-prompts.md` (40KB+) needs a formatting decision. (3) Landing page is NOT a copy of README.md โ€” different audience (web visitors vs. GitHub visitors), same facts, different structure. (4) Blog uses `status: published` field already in frontmatter to filter โ€” 6 posts ready, 2 drafts excluded. (5) Hero copy is straight facts: what Squad is, what it does, install command. No adjectives, no taglines. (6) Navigation: top nav (Docs, Features, Blog, GitHub) + docs sidebar with full hierarchy. (7) Everything in `team-docs/` and `.ai-team/` stays off the site except published blog posts. + +๐Ÿ“Œ Team update (2026-02-10): Tone directive consolidated โ€” all public-facing material must be straight facts only. No editorial voice, sales language, or narrative framing. Stacks on existing banned-words and tone governance rules. โ€” decided by bradygaster, McManus + +- **First external deployment blog post written (2026-02-10)** โ€” `team-docs/blog/006-first-external-deployment.md`. Shayne Boyer (spboyer) deployed Squad on his slidemaker repo (Next.js app). Key facts documented: (1) PRD decomposed into 9 GitHub Issues with user story format, acceptance criteria, agent assignments, file targets, and dependency tracking. (2) Shayne invented the `squad:` label prefix convention (`squad`, `squad:verbal`, `squad:mcmanus`, `squad:fenster`) for agent routing via GitHub's native label system. (3) Cast system transferred โ€” Usual Suspects universe with Verbal (Frontend), McManus (Backend), Fenster (Tester). (4) 8 of 9 issues closed, 1 (build verification) still open. (5) Blog follows facts-only tone directive โ€” no narrative framing, no editorial adjectives. Decision filed to decisions inbox recommending adoption of the `squad:` label convention. + + +๐Ÿ“Œ Team update (2026-02-10): Contributors include non-code contributions โ€” Shayne Boyer recognized as contributor โ€” decided by bradygaster + +๐Ÿ“Œ Team update (2026-02-10): `squad:` label convention standardized (consolidated with Keaton) โ€” decided by Keaton, McManus + +๐Ÿ“Œ Team update (2026-02-10): 0.3.0 priorities: async comms > GitHub-native > CCA adoption โ€” decided by bradygaster + + +๐Ÿ“Œ Team update (2026-02-10): Async comms strategy decided โ€” two-tier MVP: CCA-as-squad-member (2-4h, prompt-only) + Telegram bridge (8-16h, conditional on SDK spike). CCA is the floor. โ€” decided by Kujan + + +๐Ÿ“Œ Team update (2026-02-10): v0.3.0 is ONE feature โ€” proposals as GitHub Issues. All other items deferred. โ€” decided by bradygaster + +๐Ÿ“Œ Team update (2026-02-10): Provider abstraction is prompt-level command templates, not JS interfaces. Platform section replaces Issue Source in team.md. โ€” decided by Fenster, Keaton + +๐Ÿ“Œ Team update (2026-02-10): Actions automation ships as opt-in templates in templates/workflows/, 3 workflows in v0.3.0. โ€” decided by Keaton, Kujan + +๐Ÿ“Œ Team update (2026-02-10): Label taxonomy (39 labels, 7 namespaces) drives entire GitHub-native workflow. โ€” decided by bradygaster, Verbal + +๐Ÿ“Œ Team update (2026-02-10): CCA governance must be self-contained in squad.agent.md (cannot read .ai-team/). โ€” decided by Kujan + +๐Ÿ“Œ Team update (2026-02-10): Proposal migration uses three-wave approach โ€” active first, shipped second, superseded/deferred last. โ€” decided by Keaton + + +๐Ÿ“Œ Team update (2026-02-11): Project boards consolidated โ€” v0.4.0 target confirmed, gh CLI (not npm), opt-in only, labels authoritative over boards. Community triage responses must use substantive technical detail. โ€” decided by Keaton, Kujan + +- **Fritz video analysis (2026-02-11)** โ€” Jeff Fritz (@csharpfritz) published "Introducing your AI Dev Team Squad with GitHub Copilot" (https://www.youtube.com/watch?v=TXcL-te7ByY). Key messaging takeaways: (1) "These are all markdown files" was the strongest trust signal โ€” Jeff called it out twice, positioning Squad's transparency as a differentiator. "Markdown, not magic" is a usable messaging hook. (2) Quantifiable output sells โ€” "131 tests in one shot" was Jeff's proof point. Demos should always surface a number. (3) Cast system works invisibly โ€” Jeff used Avengers names without explaining the system, validating that casting is intuitive. (4) Design review ceremony read as a feature, not friction. (5) v0.2.0 features (skills, export, triage) were not discovered or mentioned โ€” they may need better surfacing or aren't relevant until the second session. (6) Parallel execution wasn't explicitly called out despite being a README headline โ€” visual signal may need strengthening. (7) Sprint planning and GitHub Issues integration were mentioned as future workflow, not demoed โ€” iteration loop is a demo gap. Decision inbox filed with full analysis and draft community reference for README. + +- **Fritz video blog post written (2026-02-11)** โ€” `team-docs/blog/007-first-video-coverage.md`. Blog post acknowledging Jeff Fritz's first public video coverage of Squad. Structure: What Happened / What He Showed / What This Means / Credit. Key editorial decisions: (1) Adapted blog template for community milestone โ€” used same section pattern as 006 (Shayne Boyer deployment post). (2) Surfaced 9 demo beats from video analysis: cast setup, design review, one-shot build, 131 tests, .ai-team/ exploration, "these are all markdown files" trust signal, markdown+JSON transparency, sprint planning, team knowledge persistence. (3) "What This Means" section distills three validation points: cast system intuitive, markdown config is a trust signal, quantifiable output is strongest demo beat. (4) Noted v0.2.0 feature invisibility as an onboarding signal. Tone calibration: community milestone posts follow the 006 pattern โ€” facts, credit, one thank-you, no repeated praise. Video coverage posts are closer to deployment posts than release posts in structure. + +๐Ÿ“Œ Team update (2026-02-11): Blog post 007 (first video coverage) and Fritz video messaging analysis merged to decisions.md โ€” decided by McManus + + +๐Ÿ“Œ Team update (2026-02-11): Per-agent model selection implemented with cost-first directive (optimize cost unless writing code) โ€” decided by Brady and Verbal + +๐Ÿ“Œ Team update (2026-02-11): Discord is the v0.3.0 MVP messaging connector. Gateway must be platform-agnostic with zero GitHub-specific imports. โ€” decided by Keaton + +- **v0.3.0 README update (2026-02-11)** โ€” README.md "What's New" section updated. Changes: (1) Created new "## What's New in v0.3.0" section positioned before v0.2.0. (2) Added seven new features: Per-Agent Model Selection, Ralph Work Monitor, @copilot Coding Agent, Universe Expansion (14โ†’20 universes), Milestones rename, test growth (92โ†’118), emoji fixes. (3) Moved v0.2.0 features from top billing to "## What's New in v0.2.0" section. Removed Copilot Coding Agent and Ralph from v0.2.0 section (both promoted to v0.3.0 headline features). (4) Updated Status line from v0.2.0 to v0.3.0. All new features link to docs/ when available. Style: scannable list format, one-line summaries, no hype language, matches existing README tone. + + + +๐Ÿ“Œ Team update (2026-02-12): Tips & Tricks documentation decision approved โ€” user-facing guide on prompt patterns, parallel work, decisions as permanent rules, pitfall recovery โ€” decided by McManus + +๐Ÿ“Œ Team update (2026-02-12): Issue #6 (Project Boards) approved for v0.4.0 implementation. McManus assigned Phase 3 (WI-6: documentation). Feature is GO conditional on Brady granting project token scope. โ€” decided by Keaton + +- **Squad Pings You documentation (2026-02-12)** โ€” `docs/features/notifications.md`. Consumer-facing guide to setting up squad notifications. Key structure: Overview (2-3 sentences) โ†’ How It Works (architecture: skill-based, bring-your-own MCP) โ†’ Quick Start paths (Teams webhook/official, iMessage, Discord, custom webhook) โ†’ Triggers table โ†’ Notification format with examples โ†’ Configuration (chooseable triggers, quiet hours) โ†’ Troubleshooting (MCP startup, webhook validity, frequency control) โ†’ Architecture notes. Style: Straight facts, no adjectives, shows concrete examples, concise procedural steps. Brady's vision applied: "they pinged me" framing, actionable messages with links. Supports zero-auth paths (webhooks) and full-auth paths (Azure AD). + +## Learnings + +- **Straight facts tone directive (2026-02-10)** โ€” Applied to notifications docs: facts only, no "amazing" or "incredible", energy from specificity (concrete notification examples, architecture clarity), no narrative framing or sales language. Every sentence states what a feature is, how it works, what it depends on, or what it replaces. +- **File structure conventions** โ€” Feature docs live in `docs/features/` with cross-references using relative markdown links. See Also section at bottom links to related features and guides. Headings use `##` for major sections, `###` for subsections, tables for comparison data. +- **MCP ecosystem basics** โ€” Squad uses MCP servers for external integrations. Configuration lives in `.vscode/mcp.json` with command/args/env structure. Environment variables pass secrets and configuration. The `human-notification` skill teaches agents when to invoke the MCP server. + +๐Ÿ“Œ Team update (2026-02-12): Consumer documentation for notifications (docs/features/notifications.md) merged into decisions.md โ€” zero-auth webhook path primary, Teams MCP path secondary, platform-agnostic setup guides. โ€” decided by McManus diff --git a/.ai-team/agents/verbal/history.md b/.ai-team/agents/verbal/history.md index 66c7848a9..97b0bad71 100644 --- a/.ai-team/agents/verbal/history.md +++ b/.ai-team/agents/verbal/history.md @@ -155,3 +155,5 @@ _Summarized from sessions through 2026-02-09. Full entries in `history-archive.m ๐Ÿ“Œ Team update (2026-02-11): MCP Integration Direction for Squad approved โ€” Option B (Awareness Layer) chosen. Phase 1 spike (WI-1) validates platform MCP support. See decisions.md for rationale and timeline. โ€” decided by Keaton + +๐Ÿ“Œ Team update (2026-02-12): Issue #6 (Project Boards) approved for v0.4.0 implementation. Verbal assigned Phase 2 (WI-3: board init prompts) and Phase 3 (WI-5: board query/display). Fenster leads Phase 1 validation. โ€” decided by Keaton diff --git a/.ai-team/casting/policy.json b/.ai-team/casting/policy.json index 28f725438..0413faeb2 100644 --- a/.ai-team/casting/policy.json +++ b/.ai-team/casting/policy.json @@ -20,7 +20,18 @@ "Attack on Titan", "The Lord of the Rings", "Succession", - "Severance" + "Severance", + "Adventure Time", + "Futurama", + "Seinfeld", + "The Office", + "Cowboy Bebop", + "Fullmetal Alchemist", + "Stranger Things", + "The Expanse", + "Arcane", + "Ted Lasso", + "Dune" ], "universe_capacity": { "The Usual Suspects": 6, @@ -42,6 +53,17 @@ "Attack on Titan": 12, "The Lord of the Rings": 14, "Succession": 10, - "Severance": 8 + "Severance": 8, + "Adventure Time": 15, + "Futurama": 14, + "Seinfeld": 10, + "The Office": 15, + "Cowboy Bebop": 8, + "Fullmetal Alchemist": 14, + "Stranger Things": 12, + "The Expanse": 12, + "Arcane": 10, + "Ted Lasso": 12, + "Dune": 10 } } diff --git a/.ai-team/decisions.md b/.ai-team/decisions.md index 6fba34870..6f044012e 100644 --- a/.ai-team/decisions.md +++ b/.ai-team/decisions.md @@ -1,6 +1,30 @@ # Team Decisions Shared brain. All agents read this before working. +--- + +## Deduplication Notes (2026-02-12) + +**Overlapping decisions identified and consolidated:** + +1. **Branching Strategy:** Multiple decisions on branching (2026-02-09, 2026-02-11, 2026-02-12) represent evolution of thinking: + - 2026-02-09: Initial decision (dev/main separation) + - 2026-02-10: Keaton's proposal (three-branch model with feature branches) + - 2026-02-11: Fenster's analysis (validating three-branch model) + - 2026-02-12: Kobayashi's hardening (branch protection rules) + Together they represent the progression from initial model through detailed proposal to hardening implementation. + +2. **Release Process:** Decisions span 2026-02-09 through 2026-02-12, building on each other: + - 2026-02-09: Pipeline audit + - 2026-02-11: Release process directive (no manual pushes) + - 2026-02-12: Detailed hardening with branch protection rules + Consolidated as single logical progression of release safety. + +3. **Version Display:** Kujan's 2026-02-12 decision implements existing infrastructure from 2026-02-10 per-agent model selection. No duplication. + +All original decision blocks preserved for historical context. No content removed. + +--- ## Initial Setup @@ -3116,3 +3140,1162 @@ Both are achievable with awareness layer (Option B). Ceremonies can be documente - **Issue:** GitHub Issue #11 (Feature: Enable MCP use) - **Related:** Proposal 032a (Provider Abstraction), 032c (Label Taxonomy) + + +### 2026-02-11: Release process directive +**By:** Brady (via Copilot) +**What:** Never bypass the release CI/CD pipeline. All code reaches main exclusively through the two-phase release workflow (preview โ†’ ship). No direct pushes, no manual merges to main. +**Why:** User directive โ€” the release.yml pipeline is the only authorized path to main. It validates versions, filters product files, runs tests, and creates GitHub Releases. Bypassing it risks shipping non-product files, unvalidated versions, or missing release artifacts. + + +### 2026-02-12: User directive +**By:** Brady (via Copilot) +**What:** All tables presented to the user should include a "squad-time to complete" column showing estimated time for the squad to finish each item. +**Why:** User request โ€” captured for team memory. Users already know the squad is superhuman; showing estimated completion time reinforces that and helps with planning. + + +# Fenster's Take: Branching Strategy for Squad + +**Status:** Perspective for Brady +**By:** Fenster (Core Dev) +**Date:** 2026-02-11 + +--- + +## Summary + +`dev` is sufficient as the integration branch. Feature branches (`squad/{issue}-{slug}`) merging into `dev` via PR is the right pattern for Squad's velocity. We don't need an "upcoming" or staging layer โ€” it adds friction without safety. The release pipeline (preview โ†’ ship) already gives Brady control. Worktree support isn't essential yet. The current setup is clean. + +--- + +## 1. Is dev sufficient as the integration branch? + +**Yes.** Here's why: + +- **dev is where the work lives**, and that's correct. All feature branches merge here. All agents read current state from dev. All tests run against dev. This is the "source of truth" for active work. +- **We don't need staging/upcoming.** Every feature branch is already a "staging area" for isolated work. The release pipeline's preview phase gives Brady a final eyeball before anything touches main. Adding another branch layer would: + - Require managing merges between three layers (feature โ†’ upcoming โ†’ dev โ†’ main) + - Create confusion about "where do I pull from?" during onboarding + - Slow iteration (waiting for an intermediate merge before seeing something in a "staging" branch) + - Add more places for merge conflicts + +- **The real safety comes from the release process**, not branch topology. Brady can't accidentally ship garbage to main because the release pipeline (Kobayashi's design) validates versions, filters files, runs tests, and sits at a preview step. That's the gate. + +--- + +## 2. How do feature branches work day-to-day? + +**Clean pattern:** `squad/{issue}-{slug}` โ†’ dev via PR + +This is already the right approach: + +- Each feature gets its own branch. Agent spawns know which branch they're on (read from git config). +- PRs to dev trigger tests automatically (CI on dev is running). +- Once approved and merged, that work is immediately available to other agents on dev. +- Multiple agents can work in parallel on different features without blocking each other. + +**One friction point I notice:** If an agent is working on a feature and another agent merges a conflicting change to dev mid-flight, the feature branch developer has to rebase. This is unavoidable, but we should document the rebase workflow clearly so agents aren't surprised. + +--- + +## 3. What about when multiple features are in flight? + +**Don't add worktree support yet.** Here's my reasoning: + +- Worktrees are useful when *one person* needs to context-switch between multiple local branches. But our workflow is different: agents spawn on a *specific branch*, do their work, and exit. They're not context-switching. +- If we spawn Fenster to work on squad/123-feature-a and Fenster to work on squad/456-feature-b simultaneously (which we could do), they just use different clones or containerized instances. The orchestration handles it. +- Worktrees would add complexity to index.js (detecting worktrees, routing the agent to the right one, cleanup). Not worth it until we actually need it. + +**What matters:** The PR-per-feature model keeps features isolated. If five features are in flight, we have five branches and five PRs. Each one can merge independently. That's plenty of parallelism. + +--- + +## 4. What's the simplest flow that keeps Brady safe? + +**Current setup is already safe.** Here's the protection: + +1. **main is protected** โ€” no direct pushes. All code goes through the release pipeline. +2. **release.yml pipeline enforces the two-phase workflow** โ€” preview first (lets Brady eyeball it), then ship (automated). No bypasses. +3. **dev is the integration point** โ€” all feature PRs merge here. Agents test against dev. +4. **release pipeline validates before shipping** โ€” versions, file filtering, test runs. If something breaks, the preview phase catches it before main. + +**For Brady's peace of mind:** The only thing we need to ensure is that: +- No one force-pushes to main or dev +- All merges to dev come through PRs with a brief review (agent-to-agent code review is fine) +- Release process is never skipped (enforce through GitHub branch protection rules) + +This is already the case. We're good. + +--- + +## 5. Does the current setup create friction for rapid iteration? + +**No.** + +- **Feature branches are fast** โ€” creates a branch, pushes a commit, opens a PR, merges within minutes (assuming tests pass). No ceremony. +- **Dev is always ready** โ€” agents don't wait for staging or release prep. They can spawn, pull from dev, and start work immediately. +- **Parallel PRs don't block each other** โ€” if three features are merging to dev, they land independently. No "gate-keeping." +- **Tests run automatically** โ€” CI on dev is working. We know if something broke before merging. + +**One real friction point:** If we're shipping a release and simultaneously landing features in dev, there's a brief moment where dev is ahead of the preview branch. This is fine and expected โ€” it's exactly why we have a two-phase workflow. + +--- + +## Recommendation + +**Keep the current model.** + +- Stick with feature branches โ†’ dev (via PR) โ†’ release pipeline โ†’ main +- No "upcoming" branch +- No worktrees (yet) +- Add one doc: "Rebasing guide for agents" so they know what to do if dev changes while they're working + +The simplicity is a feature. The release pipeline does the actual safety work. Branching topology is just plumbing. + +--- + +## Questions for Brady + +1. **Do we want automated squash-merge on feature branch PRs to dev?** (Keeps commit history clean, easier to bisect) +2. **Should the rebasing guide be in docs/ or team-docs/?** (I'd suggest team-docs โ€” it's internal workflow) +3. **Any concerns about the current preview โ†’ ship release model, or is that already validated?** + + +# Branching Strategy โ€” Proposal + +**By:** Keaton (Lead) +**Date:** 2026-02-10 +**Requested by:** Brady (v0.3.0 manual push incident) +**Status:** READY FOR DECISION + +--- + +## Problem + +Brady had to manually push to `preview` and `main` during v0.3.0. This defeats the entire point of the CI/CD pipeline: **our release process should never require human hands on branch buttons.** We also need clarity on: + +1. Should feature work go straight to `dev`, or is there a staging branch in between? +2. Where do hotfixes go? +3. Should `preview` and `main` be protected from manual pushes? +4. How do we prevent another manual-push incident? + +## Solution: Three-Branch Strategy + Strict Automation + +### Branching Model + +``` +feature/name (temporary, deleted after merge) + โ†“ + dev (always deployable, main development line) + โ†“ +(Release CI: tests + preview build) + โ†“ + preview (staging, human review gate, CI-pushes-only) + โ†“ +(Release CI: copy preview โ†’ main, tag, release) + โ†“ + main (shipping product, CI-pushes-only, read-only to humans) + โ†“ +GitHub Release + npx resolution +``` + +### Branch Definitions + +| Branch | Purpose | Who Writes | How | Protection | +|--------|---------|-----------|-----|-----------| +| `dev` | Active development | Humans (via PRs) | `git push origin feature/X` โ†’ PR โ†’ merge to `dev` | โœ… Require PR review, passing CI | +| `preview` | Staging (v0.x style) | CI/CD only | Release action Phase 1 โ€” tests, builds, pushes | โœ… Require status checks, no direct pushes | +| `main` | Shipping product | CI/CD only | Release action Phase 2 โ€” copy preview, tag, release | โœ… Require status checks, no direct pushes | + +### Feature Branch Workflow + +1. Create feature branch: `git checkout -b feature/my-feature dev` +2. Develop normally +3. Open PR against `dev` +4. CI runs tests (gates merge) +5. Brady (or team) reviews + approves +6. Merge to `dev` (delete feature branch) + +### Release Workflow (No Manual Touches) + +**Phase 1 โ€” Preview:** +1. Update `package.json` version on `dev` +2. Commit + push to `dev` +3. Dispatch `release` workflow โ†’ `action: preview` โ†’ `version: 0.3.0` +4. CI: checks out `dev`, runs tests +5. CI: builds filtered product files, **pushes to `preview` with `--force`** +6. Brady inspects `preview` locally or via GitHub (see diff, run locally) +7. Approves or rejects (if reject, commit fixes to `dev`, re-run Phase 1) + +**Phase 2 โ€” Ship:** +1. Once satisfied with `preview`, dispatch `release` workflow โ†’ `action: ship` โ†’ `version: 0.3.0` +2. CI: checks out `preview` +3. CI: validates content (product-files-only check) +4. CI: **pushes to `main`** (forces overwrite of main to match preview exactly) +5. CI: tags release, creates GitHub Release +6. CI: verifies `npx github:bradygaster/squad` resolves +7. Done โ€” humans stay off `main` and `preview` + +### Hotfix Workflow + +Hotfixes start on `dev` (not a separate hotfix branch): + +1. Create `feature/hotfix-bug-X` from `dev` +2. Fix + test +3. PR โ†’ merge to `dev` +4. Run release workflow (Phase 1 + Phase 2) normally +5. Version bump: `0.3.0` โ†’ `0.3.1` + +**Why:** This is a solo-dev-plus-AI project. A separate `hotfix/` โ†’ `main` โ†’ `dev` sync pattern adds branching debt. Keep it simple: all work feeds `dev`, all releases come from `dev`. + +### Protection Rules (GitHub) + +**On `main`:** +``` +โœ… Require status checks before merge +โœ… Require PR reviews before merge +โœ… Dismiss stale reviews +โœ… Restrict push access to GitHub Actions only +โŒ NO direct merges from humans (not even admins) +``` + +**On `preview`:** +``` +โœ… Require status checks before merge +โœ… Restrict push access to GitHub Actions only +โŒ NO direct merges from humans +``` + +**On `dev`:** +``` +โœ… Require PR reviews +โœ… Require status checks +โœ… Allow human merges (Brady + AI team) +``` + +--- + +## Trade-offs + +**Simplicity vs. Flexibility:** +- โœ… **Simple:** Three branches, one release pattern, zero manual branch touching +- โŒ **Less flexible:** No separate staging environment (preview serves that) +- โœ… **Acceptable:** v0.x release pace doesn't need release branches + +**Force Push on preview/main:** +- โœ… **Good:** Ensures preview/main are *exact* copies of what CI built (bit-for-bit) +- โŒ **Scary:** Force push history rewriting is risky +- โœ… **Mitigated:** Force push is scripted in CI (humans can't do it), plus validation step checks preview content before pushing main + +**One Release Path:** +- โœ… **Good:** No branching confusion, no "should hotfixes go to main or dev?" +- โŒ **Less familiar:** Developers used to `hotfix/` โ†’ `main` model won't see it +- โœ… **Acceptable:** Documentation + team chat clarifies the pattern + +--- + +## Alternatives Considered + +### A. Current State (dev โ†’ preview โ†’ main, but allow manual pushes) +- โŒ Enables the v0.3.0 incident again +- โŒ "CI/CD optional" is a footgun on a solo project + +### B. GitHub flow (main only, feature branches PR directly to main) +- โŒ Loses staging gate โ€” `preview` serves a real purpose (Brady review before ship) +- โŒ Eliminates ability to inspect release before it ships + +### C. Git flow (develop, release/X, hotfix/X, main) +- โŒ Too much branching for a 2-person team (Brady + AI team) +- โŒ Adds ceremony without benefit at this scale +- โœ… Good for enterprise; wrong for us + +### D. Trunk-based (single main branch, tags for releases) +- โŒ Loses staging gate (no preview before ship) +- โŒ Can't diff main from "what's about to ship" + +--- + +## Success Criteria + +1. **No Manual Branch Touches** โ€” Release is 100% CI/CD. Brady never runs `git push origin preview` again. +2. **Clear Role for Each Branch** โ€” Dev is work, preview is review, main is shipped. +3. **Reviewable Releases** โ€” Brady can inspect preview before ship (diff, local test, docs review). +4. **Protection Rules Enforced** โ€” GitHub prevents direct pushes to preview/main, even by admins. +5. **Simple Hotfix Story** โ€” Fix is on dev, release is normal; no special hotfix branching. +6. **Documentation** โ€” Team knows the flow; no guessing about where to push. + +--- + +## Implementation Checklist + +- [ ] Set up branch protection rules on GitHub: + - [ ] `main` โ€” restrict push to Actions only, require status checks + - [ ] `preview` โ€” restrict push to Actions only +- [ ] Update release.yml (if needed) to document forced push strategy +- [ ] Update team-docs/release-process.md with this branching model +- [ ] Delete any old `hotfix/` branches if they exist +- [ ] Create team chat summary: "Branching Strategy Update โ€” Here's How We Release" +- [ ] Verify v0.3.1+ releases use this pattern (no manual pushes) + +--- + +## Decision + +**Adopting Three-Branch Model with Strict CI/CD-Only Pushes to preview and main.** + +This prevents the v0.3.0 incident from recurring. It's simple, clear, and matches the release pipeline we already built. No hand-waving about "who can push when" โ€” GitHub enforces it. + +Brady: You approve releases by dispatching the workflow, not by touching branches. The pipeline takes it from there. + + +### 2026-02-12: Release Pipeline Hardening โ€” Branch Protection & CI/CD Enforcement + +**By:** Kobayashi (Git & Release Engineer) + +**Context:** During v0.3.0 release, the coordinator manually pushed release.yml to main (bootstrap) and pushed to preview/main. Brady wants ZERO manual pushes to preview or main โ€” only CI/CD should write to these branches. This memo analyzes the current pipeline and proposes hardening measures. + +--- + +## Problem Statement + +Current state: +- **Preview and main branches are unprotected.** Anyone with write access can push directly, bypassing the release workflow. +- **Bootstrap problem:** release.yml must exist on main before GitHub Actions can see it. First-time setup for new repos requires manual seed. +- **No validation that dev is ahead of main.** The preview phase doesn't check whether there are actual changes to release. +- **Manual intervention risk.** The workflow exists and is designed well, but nothing prevents humans from circumventing it. + +Brady's directive: **Preview and main are CI/CD-only. No manual pushes. Ever.** + +--- + +## Recommended Hardening: Five Components + +### 1. Branch Protection Rules for `preview` + +**What to configure in GitHub:** + +``` +Branch: preview +โ”œโ”€โ”€ Require pull request reviews +โ”‚ โ””โ”€โ”€ Dismiss stale pull request approvals: โŒ (not needed for CI-only writes) +โ”œโ”€โ”€ Require status checks to pass +โ”‚ โ””โ”€โ”€ Required checks: NONE (no pre-merge validation needed) +โ”œโ”€โ”€ Require branches to be up to date +โ”‚ โ””โ”€โ”€ โŒ (disable โ€” not applicable) +โ”œโ”€โ”€ Include administrators: โœ“ (YES โ€” admins cannot bypass) +โ”œโ”€โ”€ Allow force pushes: โœ“ For GitHub Actions bot ONLY (see below) +โ”‚ โ””โ”€โ”€ Restrict who can force push +โ”‚ โ””โ”€โ”€ Allow: github-actions[bot] +โ”‚ โ””โ”€โ”€ Restrict: Everyone else (โŒ no force push) +โ”œโ”€โ”€ Allow deletions: โŒ (NO one deletes preview) +โ””โ”€โ”€ Require signed commits: โŒ (not needed for Actions-generated commits) +``` + +**Why this design:** +- Prevents accidental pushes from human developers +- Allows `github-actions[bot]` to force-push (needed for phase 1 of release workflow) +- Protects against deletion (preview is a critical staging point) + +**GitHub UI path:** Settings โ†’ Branches โ†’ Add rule โ†’ Branch name pattern: `preview` + +--- + +### 2. Branch Protection Rules for `main` + +**What to configure in GitHub:** + +``` +Branch: main +โ”œโ”€โ”€ Require pull request reviews +โ”‚ โ””โ”€โ”€ Dismiss stale pull request approvals: โŒ (not needed) +โ”œโ”€โ”€ Require status checks to pass +โ”‚ โ”œโ”€โ”€ ci.yml (required on push) +โ”‚ โ””โ”€โ”€ โœ“ Check: npm test +โ”œโ”€โ”€ Require branches to be up to date: โœ“ YES +โ”œโ”€โ”€ Include administrators: โœ“ (YES โ€” admins cannot bypass) +โ”œโ”€โ”€ Allow force pushes: โŒ NO (never) +โ”‚ โ””โ”€โ”€ Exception: github-actions[bot] MAY push (not force-push) +โ”‚ โ””โ”€โ”€ Restrict who can force push: NO ONE (blank/disabled) +โ”œโ”€โ”€ Allow deletions: โŒ NO (never) +โ”œโ”€โ”€ Require signed commits: โŒ (optional, not critical) +โ”œโ”€โ”€ Require code owners review: โœ— (only if code owners file exists) +โ””โ”€โ”€ Require conversation resolution: โŒ (not used) +``` + +**Key differences from preview:** +- **NO force pushes** โ€” main is append-only. Mistakes are reverted via new releases, not force-push rewrites. +- **CI checks required** โ€” ci.yml must pass before any merge (even from Actions). +- **Up-to-date check enabled** โ€” prevents stale merges. + +**Why this design:** +- Prevents human pushes entirely (Actions can push, but only via workflow) +- Enforces tests pass before production code lands +- Audit trail is immutable (no rewriting history) + +**GitHub UI path:** Settings โ†’ Branches โ†’ Add rule โ†’ Branch name pattern: `main` + +--- + +### 3. Preventing Manual Pushes: Enforcement Model + +**The enforcement chain:** + +``` +Local developer types: git push origin main + โ†“ +GitHub receives push + โ†“ +Branch protection rule checks: + - "main: require status checks to pass" + - "main: no force pushes" + - "main: requires write from github-actions[bot] only" + โ†“ +Push is REJECTED + โ†“ +Developer gets error: "Updates were rejected because the tip of your current + branch is behind its remote counterpart." +``` + +**Supplementary control:** Set branch protection to **restrict push access to `main` to github-actions[bot] only.** + +**In GitHub UI:** +- Settings โ†’ Branches โ†’ `main` rule +- Under "Restrict who can push to matching branches" + - Leave blank (defaults to all with write access) + - **OR** explicitly list only `github-actions[bot]` + +**Note:** GitHub's UI for "only X can push" is sparse. A more ironclad approach: + +1. **Remove write permissions from human contributors** on the repository. + - Make them Maintain role (can manage issues, run workflows) but not push. + - OR use a tighter org-level role (can run Actions but not push). + +2. **Only grant write permission to the bot that runs the workflow.** + - GitHub Actions in this repo already uses `permissions: contents: write`. + - This is tightly scoped to the Actions runner context. + +**Best practice:** Combine branch protection + CODEOWNERS file: + +``` +# .github/CODEOWNERS +main @bradygaster # Brady is owner; branch protection enforces rules +preview @bradygaster +dev @bradygaster # dev can have looser rules (features merge here) +``` + +This makes it clear to the team: **main and preview are locked down; Brady owns the keys.** + +--- + +### 4. The Bootstrap Problem: release.yml Must Exist on Main + +**The problem:** +- GitHub Actions workflows must exist on a branch before Actions can reference them. +- When setting up a new repo, release.yml is on `dev` but not on `main`. +- The release workflow file itself is in `.github/workflows/release.yml`. +- If it's not on main, Actions cannot trigger workflows from main branch events. +- v0.3.0 required a manual push to bootstrap release.yml onto main. + +**Solution: Seed release.yml on main at repo creation.** + +**Option A: Mandatory bootstrap step (for new repos using Squad)** + +When initializing a new Squad repository (or importing an existing one): +1. Add `.github/workflows/release.yml` to the product file allowlist (`KEEP_FILES` in release.yml). +2. Bootstrap it onto `main` as a **one-time** manual step before taking over CI/CD. +3. Commit message: `bootstrap: initial release.yml` +4. After this, the release workflow owns all main updates. + +**Add to `release.yml` KEEP_FILES:** +```bash +KEEP_FILES: "... .github/workflows/release.yml" +``` + +**Rationale:** +- release.yml is a product file (all users inherit it for their Squad installations). +- Once it's on main, the workflow can manage itself. +- This is a one-time setup cost, not an ongoing manual burden. + +**Option B: Dynamic workflow provisioning (future enhancement)** + +The Coordinator agent (`squad.agent.md`) could check for release.yml on main at install time and create it if missing. This requires: +- Read-only GitHub API access (no auth needed for public repos). +- Light validation that the workflow is well-formed. +- Fallback if creation fails (print instructions to user). + +Deferred for now; **Option A is the implementation path for v0.3.0 and Squad 1.x.** + +**Documentation update required:** +- Add to `docs/release-checklist.md`: "Bootstrap: Ensure release.yml is on main before first release." +- Add to `team-docs/release-process.md`: "Setup: Manual bootstrap of release.yml to main is a one-time cost." + +--- + +### 5. Should `preview` Validate That `dev` Is Ahead of `main`? + +**Short answer: YES โ€” add this as an early validation step in phase 1.** + +**Why:** +- Currently, the preview phase doesn't check if there are actual changes since the last release. +- This could allow "releases" that contain no product changes (wasted tag, GitHub Release noise). +- Early failure is better than discovering this after force-pushing preview. + +**Proposed step (add to preview job, right after checkout):** + +```bash +- name: Validate dev is ahead of main + run: | + # Count commits between main and dev + AHEAD=$(git rev-list --count main..HEAD) + + if [ "$AHEAD" -eq 0 ]; then + echo "::error::dev is not ahead of main. No changes to release." + exit 1 + fi + + echo "โœ“ dev is $AHEAD commit(s) ahead of main" +``` + +**Better version (commit-diff based):** + +```bash +- name: Validate dev contains new product changes + run: | + # Get list of changed product files between main and dev + read -ra KEEP_FILES_ARR <<< "$KEEP_FILES" + read -ra KEEP_DIRS_ARR <<< "$KEEP_DIRS" + + CHANGED_PRODUCT_FILES=0 + + # Check if any KEEP_FILES have changed + for f in "${KEEP_FILES_ARR[@]}"; do + if git diff --name-only main HEAD | grep -q "^$f$"; then + ((CHANGED_PRODUCT_FILES++)) + fi + done + + # Check if any KEEP_DIRS have changed + for d in "${KEEP_DIRS_ARR[@]}"; do + if git diff --name-only main HEAD | grep -q "^$d/"; then + ((CHANGED_PRODUCT_FILES++)) + fi + done + + if [ "$CHANGED_PRODUCT_FILES" -eq 0 ]; then + echo "::error::No product file changes between main and dev. Nothing to release." + exit 1 + fi + + echo "โœ“ $CHANGED_PRODUCT_FILES product file(s) changed since main" +``` + +**Impact on workflow:** +- Prevents empty releases. +- Catches accidental re-runs of the same version. +- Provides early feedback (before building and force-pushing preview). + +**When to run:** Right after "Validate version" step in preview job. + +--- + +## Summary of Changes + +| Component | Change | Why | +|-----------|--------|-----| +| **preview branch protection** | Require rule; allow github-actions force-push only | Prevent manual writes, allow CI override | +| **main branch protection** | Require rule; NO force-push; require status checks | Enforce immutability, test validation | +| **Write access** | Restrict to github-actions[bot] via branch rules | Zero human manual pushes | +| **release.yml seeding** | Include in KEEP_FILES; bootstrap to main once | Unblock Actions from self-managing | +| **dev-ahead validation** | Add check in preview phase 1 | Prevent empty releases | + +--- + +## Implementation Timeline + +**v0.3.0 (immediate):** +1. Add branch protection rules to preview and main (GitHub Settings). +2. Add dev-ahead validation to release.yml preview phase. +3. Confirm release.yml is included in KEEP_FILES. +4. Bootstrap release.yml to main manually (one-time). + +**v0.3.1 or later (if needed):** +- Refine bootstrap documentation. +- Consider dynamic workflow provisioning (Option B). + +--- + +## Testing & Verification + +After hardening: +1. **Negative test:** Attempt manual push to preview/main from local branch โ†’ should be rejected. +2. **Positive test:** Run full release workflow (preview โ†’ ship) with branch protection active โ†’ should succeed. +3. **Empty release test:** Run preview with no changes to product files โ†’ should fail at dev-ahead check. +4. **CI check test:** Commit broken test to dev, run preview โ†’ should fail at test gate. + +--- + +## Questions & Edge Cases + +**Q: What if we need to hotfix main directly?** +A: Use the release workflow with an expedited version. Never bypass protection rules. Create an emergency fix on `dev`, merge to `release`, run preview+ship. + +**Q: Can we add a `HOTFIX` action to release.yml?** +A: Future enhancement. For v0.3.0, use the standard two-phase workflow. + +**Q: What about force-pushing to dev?** +A: `dev` is development-facing; looser rules are fine. No branch protection needed (humans actively work here). + +**Q: Does .github/workflows/ belong on main?** +A: Yes โ€” workflows are product files. Users inherit them. Include in KEEP_FILES. + +**Q: What if release.yml itself has a bug?** +A: Fix it on `dev`, re-run preview+ship with the corrected version. The protection rules do not prevent fixing workflow bugs. + +--- + +## Acceptance Criteria + +โœ“ preview and main are protected from manual writes +โœ“ github-actions[bot] can push to both (via workflow) +โœ“ Humans cannot force-push to either +โœ“ release.yml exists on main (seeded or self-managed) +โœ“ Preview phase validates dev is ahead before building +โœ“ All CI checks pass +โœ“ Brady can run a full release without manual intervention (except the ship trigger) + +--- + +**Next:** Implement branch protection rules in GitHub Settings, update release.yml with dev-ahead check, confirm release.yml bootstrap, and document in release-process.md. + + +# Cross-Client Sub-Agent/Delegation API Research + +**Author:** Kujan (Copilot SDK Expert) +**Date:** 2026-02-11 +**Requested by:** Brady +**Triggered by:** Issue #9 (miketsui3a) โ€” reports `runSubagent` instead of `task` +**Related:** Issue #10 (Copilot client parity gap, P1) + +--- + +## Executive Summary + +**There is NO unified sub-agent/delegation tool name across Copilot clients.** Each client implements its own tool with its own name, parameters, and execution model. The `task` tool is specific to Copilot CLI. The `runSubagent` tool is specific to VS Code. Visual Studio doesn't have a native sub-agent tool yet. The coding agent (@copilot) uses an entirely different execution model. + +**Recommendation: Do not change.** Squad targets Copilot CLI. The `task` tool works, is documented, and is the correct primitive for this platform. Switching would buy us nothing and break everything. + +--- + +## Findings by Client + +### 1. Copilot CLI โ€” `task` tool โœ… (our platform) + +- **Tool name:** `task` +- **Parameters:** `agent_type` (explore, task, general-purpose, code-review, custom), `mode` (sync, background), `model`, `prompt`, `description` +- **Execution:** Spawns isolated LLM sessions with their own context windows, tool access, and execution environments +- **Status:** Stable, production. Squad v0.3.0 shipped on this. +- **Documentation:** Built into the CLI system prompt; `/tasks` command manages background tasks +- **Source:** Copilot CLI help output, our own verified usage + +### 2. VS Code (Copilot Chat) โ€” `runSubagent` tool + +- **Tool name:** `runSubagent` (also `runSubagent2` behind experimental flag `chat.experimental.runSubagent2`) +- **Invocation:** Agent-initiated tool call or user hint via `#runSubagent`; also available as `agent` in prompt file `tools` frontmatter +- **Execution:** Spawns context-isolated child agents in the same VS Code session. Synchronous (blocks parent). Multiple subagents can run in parallel. +- **Key differences from `task`:** + - No `agent_type` parameter โ€” uses custom agent `.agent.md` files instead + - No `mode: "background"` โ€” subagents are synchronous by design + - No `read_agent` โ€” results return inline + - Has `subagentType` parameter to specify which custom agent to use + - Experimental: `user-invokable`, `disable-model-invocation` frontmatter controls +- **Status:** Stable but still evolving. Experimental `runSubagent2` is the active development branch. +- **Documentation:** https://code.visualstudio.com/docs/copilot/agents/subagents +- **Issues tracker:** https://github.com/microsoft/vscode/issues?q=label:chat-subagents +- **Key issues:** + - https://github.com/microsoft/vscode/issues/274950 (Test subagents) + - https://github.com/microsoft/vscode/issues/274630 (Parallel subagents) + - https://github.com/microsoft/vscode/issues/275855 (Model selection for subagents) + - https://github.com/microsoft/vscode/issues/278199 (Issue running subagent tool) + +### 3. Visual Studio (2022/2026) โ€” No native sub-agent tool + +- **Tool name:** None built-in for sub-agent delegation +- **Agent Mode:** Has Copilot Agent Mode (GA with MCP support) but it's single-agent โ€” one agent executes a task with tool access, not multi-agent orchestration +- **Workaround:** Third-party VS Code extension `copilot-task-delegate` (marketplace: `dvcrn.copilot-task-delegate`) implements delegation via MCP tools (`copilot-task-delegate_start`, `copilot-task-delegate_status`, `copilot-task-delegate_complete`). This is NOT a GitHub-built feature. +- **Status:** Sub-agent delegation listed as "Coming, partial" in Visual Studio. Agent Mode is GA. +- **Documentation:** https://learn.microsoft.com/en-us/visualstudio/ide/copilot-agent-mode +- **Source:** https://devblogs.microsoft.com/visualstudio/agent-mode-is-now-generally-available-with-mcp-support/ + +### 4. Copilot Coding Agent (@copilot cloud) โ€” Different execution model entirely + +- **Tool name:** N/A โ€” this is not a tool-based delegation system +- **Execution model:** Issue-driven. Assign an issue to `@copilot`, it spins up an ephemeral GitHub Actions VM, clones the repo, does work, opens a draft PR. +- **Sub-agent spawning:** Internal orchestration within the VM. The agent may decompose tasks internally, but this is opaque โ€” there's no user-facing sub-agent API. +- **Key difference:** The coding agent IS the agent. It doesn't spawn sub-agents in the way CLI/VS Code do. It's a single autonomous session. +- **Documentation:** https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent +- **Source:** https://github.blog/news-insights/product-news/github-copilot-meet-the-new-coding-agent/ + +--- + +## Tool Comparison Matrix + +| Capability | CLI (`task`) | VS Code (`runSubagent`) | Visual Studio | Coding Agent | +|---|---|---|---|---| +| Tool name | `task` | `runSubagent` / `runSubagent2` | None (MCP extension workaround) | N/A (different model) | +| Agent types | explore, task, general-purpose, code-review, custom | Custom `.agent.md` files | N/A | N/A | +| Background/async | โœ… `mode: "background"` | โŒ Synchronous only | N/A | Always async (cloud) | +| Parallel execution | โœ… Multiple background agents | โœ… Multiple parallel subagents | N/A | Single session | +| Model selection | โœ… `model` parameter | โš ๏ธ Experimental (via custom agent) | N/A | Platform-selected | +| Result retrieval | `read_agent` tool | Inline (blocks until done) | N/A | PR + session logs | +| Context isolation | โœ… Separate context windows | โœ… Separate context windows | N/A | Full VM isolation | +| Custom agent support | โœ… Custom agent type | โœ… `.agent.md` files | โœ… `.agent.md` files | โœ… `.github/agents/` | + +--- + +## Is Convergence Coming? + +### Evidence FOR convergence: +- **Copilot SDK** (`@github/copilot-sdk`) released in early 2026 provides a unified runtime across Node.js, Python, Go, .NET โ€” the same engine that powers the CLI. This could eventually standardize the spawning API. +- **Agent Skills** use an open standard (agentskills.io) that works across all clients โ€” skills are portable even if the spawning mechanism isn't. +- **Custom agents** (`.github/agents/` and `.agent.md` files) are converging across clients โ€” same config format, same frontmatter. +- **Agents Panel** launched across VS Code and Visual Studio as a unified session management UI. + +### Evidence AGAINST near-term convergence: +- VS Code's `runSubagent` is still experimental (`runSubagent2` behind a feature flag) โ€” the API is not settled. +- Visual Studio doesn't have native sub-agent spawning at all yet. +- The CLI's `task` tool has a fundamentally different parameter model than `runSubagent` (typed agent_type enum vs. custom agent references). +- No GitHub blog post, changelog, or documentation mentions plans to unify these tool names. +- The coding agent has a completely different execution model โ€” there's nothing to unify with. + +--- + +## Impact on Squad + +### Current state: +- `squad.agent.md` references `task` tool **47+ times** across critical rules, spawn templates, response modes, and the anti-hallucination guardrails +- The `task` tool is the **single most important API call** in Squad's architecture +- Proposals 003, 007, 015, 017 all deeply analyze `task` tool behavior + +### If we changed to `runSubagent`: +- Would break on CLI (our shipping platform) +- Would gain VS Code compatibility (which doesn't exist anyway โ€” Squad runs in CLI) +- Would lose `mode: "background"` (critical for parallel fan-out) +- Would lose `agent_type` selection (critical for model/capability routing) +- Would require rewriting every spawn template, every proposal, every test + +### Multi-client strategy (future): +When/if Squad supports VS Code (tracked in Issue #10), the correct approach is: +1. **Abstraction layer** โ€” Squad's coordinator prompt uses a platform-neutral concept ("spawn agent") that maps to the correct tool per client +2. **Platform detection** โ€” Coordinator detects which client it's running in and uses the right tool +3. **Not renaming** โ€” We don't rename `task` to `runSubagent` or vice versa; we abstract over both + +This is consistent with Proposal 032a (Provider Abstraction Architecture) โ€” prompt-level command templates, not JS interfaces. + +--- + +## Recommendation + +**Do not change.** Rationale: + +1. **`task` works.** We just shipped v0.3.0 on it. The bar for changing is high. +2. **There is no unified tool.** Switching to `runSubagent` would break CLI compatibility for zero cross-client gain. +3. **The VS Code API is not stable.** `runSubagent2` is behind an experimental flag. Building on it now would be building on sand. +4. **The abstraction is the play.** When cross-client matters (Issue #10), we abstract โ€” we don't pick one client's API and hope the others adopt it. +5. **Response to Issue #9:** miketsui3a is correct that VS Code uses `runSubagent`. The answer is: Squad targets Copilot CLI, which uses `task`. This is documented in our README. If a user is running Squad in VS Code, they need CLI, not the VS Code chat extension. + +### Recommended Issue #9 response: +> Squad runs on GitHub Copilot CLI, which uses the `task` tool for agent spawning. VS Code Copilot Chat uses a different tool (`runSubagent`). These are separate Copilot clients with different tool APIs. Squad requires the CLI โ€” see our [Getting Started guide](docs/guide.md) for setup instructions. + +--- + +## Sources + +| Source | URL | +|---|---| +| VS Code Subagents Documentation | https://code.visualstudio.com/docs/copilot/agents/subagents | +| VS Code Custom Agents | https://code.visualstudio.com/docs/copilot/customization/custom-agents | +| Copilot CLI Documentation | https://docs.github.com/en/copilot/how-tos/copilot-cli/cli-getting-started | +| Copilot CLI Custom Agents Changelog | https://github.blog/changelog/2025-10-28-github-copilot-cli-use-custom-agents-and-delegate-to-copilot-coding-agent/ | +| VS Code Subagent Issues | https://github.com/microsoft/vscode/issues?q=label:chat-subagents | +| Parallel Subagents Issue | https://github.com/microsoft/vscode/issues/274630 | +| Model Selection for Subagents Issue | https://github.com/microsoft/vscode/issues/275855 | +| Subagent Running Issues | https://github.com/microsoft/vscode/issues/278199 | +| Visual Studio Agent Mode | https://learn.microsoft.com/en-us/visualstudio/ide/copilot-agent-mode | +| VS Agent Mode GA + MCP | https://devblogs.microsoft.com/visualstudio/agent-mode-is-now-generally-available-with-mcp-support/ | +| Copilot Coding Agent Docs | https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent | +| Copilot Coding Agent Blog | https://github.blog/news-insights/product-news/github-copilot-meet-the-new-coding-agent/ | +| Copilot SDK Repository | https://github.com/github/copilot-sdk | +| Copilot SDK Guide (MS Tech Community) | https://techcommunity.microsoft.com/blog/azuredevcommunityblog/building-agents-with-github-copilot-sdk-a-practical-guide-to-automated-tech-upda/4488948 | +| Agent Skills in VS Code | https://code.visualstudio.com/docs/copilot/customization/agent-skills | +| Custom Agents Configuration | https://docs.github.com/en/copilot/reference/custom-agents-configuration | +| Copilot Task Delegate Extension | https://marketplace.visualstudio.com/items?itemName=dvcrn.copilot-task-delegate | + + +### Version Display via Coordinator Self-Announcement + +**By:** Kujan +**Date:** 2025-07-14 +**Context:** Issue #18 โ€” Show squad version number in agent label across Copilot hosts + +**What:** Added a `Version` instruction to the Coordinator Identity section in `squad.agent.md`. The coordinator reads the `version` field from its own YAML frontmatter and includes `Squad v{version}` in its first response of each session. + +**Why:** The version stamping pipeline (`stampVersion()` in `index.js`) already embeds the real version into the installed agent file's frontmatter during init and upgrade. The version was present but never surfaced to users. This approach requires zero code changes โ€” it's a prompt instruction that leverages existing infrastructure. + +**Alternatives rejected:** +- `description` frontmatter field: noisy in agent picker, may truncate +- `task` tool `description` parameter: per-spawn, not persistent +- Runtime `package.json` read: coordinator can't access the npm package at runtime + +**Scope:** Single line addition to `squad.agent.md` Coordinator Identity section. No `index.js` changes. All 118 tests pass. + + +# Decision: Tips and Tricks User Documentation + +**Date:** 2026-02-11 +**Author:** McManus (DevRel) +**Status:** Approved + +## What + +Created `docs/tips-and-tricks.md` โ€” practical end-user guide for managing Squad effectively. Addresses Issue #16. + +## Why + +Users new to Squad need more than feature documentation. They need patterns: when to use "Team" vs direct commands, how to get the most out of parallel work, how to manage decisions and memory, and how to recover from common mistakes. + +Sample-prompts.md shows what Squad can build; tips-and-tricks.md shows how to work with Squad as a team. + +## Key Decisions in the Doc + +1. **Prompt Patterns**: Emphasis on scope clarity, roster specification, and decision stacking in the prompt itself. "Be specific about scope" prevents agents from asking clarifying questions later. + +2. **Team vs Direct Commands**: Clear routing guidance โ€” "Team" for parallel/cross-functional work, direct commands for sequential/specialized work. Includes table with use cases. + +3. **Parallel Work Discipline**: Don't interrupt agents mid-chain. Check work logs instead of raw output. Let Ralph handle backlogs while you focus on urgent work. + +4. **Ralph as Backlog Processor**: Practical Ralph patterns โ€” activation, scoping, status checks, heartbeat setup. Ralph is most valuable when you have open issues. + +5. **Decisions as Permanent Rules**: Set conventions early (session 1-2), capture them in decisions.md, agents read them automatically. "You only have to say them once." + +6. **Pitfall Recovery**: 8 common mistakes with solutions. Emphasis on commitment (commit `.ai-team/`), clarity (specific prompts), and discipline (don't interrupt parallel work). + +7. **Copyable Prompts**: Templates for getting started, asking for status, spike-then-build, closing phases. Real prompts users can copy directly. + +## Style Notes + +- Facts-based, not instructional. "Here's what works" not "You should do this." +- Before/after examples for patterns (โŒ bad, โœ… good). +- Tables for routing guidance and reference. +- No fluff. Every section has working examples. +- Tone matches existing docs: direct, opinionated, technical. + +## What Gets Created in Squad + +This enables a help feature where users can ask: +- "Tips for prompt writing" โ†’ excerpt from Effective Prompt Patterns +- "How do I work with Ralph?" โ†’ Ralph section +- "I keep interrupting parallel work" โ†’ Pitfalls section +- "Show me a template prompt" โ†’ Copyable Prompts section + +Document is self-contained and can be cross-referenced in README or featured in future chat help. + +## Not in This Doc + +- Feature explanations (that's in feature docs) +- Architecture (that's in guide.md) +- Installation (that's in guide.md) +- Getting started (that's in tour-first-session.md) + +This doc assumes the user has installed Squad and formed a team. It's about effectiveness, not mechanics. + + + +### 2026-02-12: Universe allowlist expansion +**By:** Fenster +**What:** Added 11 new universes to the casting allowlist (Adventure Time, Futurama, Seinfeld, The Office, Cowboy Bebop, Fullmetal Alchemist, Stranger Things, The Expanse, Arcane, Ted Lasso, Dune). Updated both `.github/agents/squad.agent.md` and `.ai-team/casting/policy.json`. Closed issue #21. +**Why:** The existing 20-universe list was genre-heavy on heist/crime films and light on animation, anime, sitcoms, and workplace comedy. Community request (Gabe, issue #21) for Adventure Time was the catalyst. The 10 additional universes were selected to diversify genre coverage โ€” adding sitcom (Seinfeld, The Office), anime (Cowboy Bebop, Fullmetal Alchemist), animation (Futurama, Arcane), horror/drama (Stranger Things), hard sci-fi (The Expanse), sports/comedy (Ted Lasso), and epic sci-fi (Dune). Capacity values set conservatively (8โ€“15) based on named character pools. Two constraint entries added where protagonist avoidance improves casting variety. + + +# Issue #6 (Project Boards) โ€” Go/No-Go Assessment + +**Date:** 2026-02-11 +**By:** Keaton (Lead) +**Status:** Go (Conditional v0.4.0) +**Posted:** https://github.com/bradygaster/squad/issues/6#issuecomment-3888277477 + +--- + +## What + +Project Boards (V2) integration for Squad is **approved for v0.4.0 implementation**. The feature is architecturally sound, technically feasible with zero npm dependencies, and has clear 3-phase implementation plan. + +--- + +## Why + +1. **Validated architecture:** Labels drive automation (source of truth), boards provide visualization (read-only projection). No state conflicts. Complements existing 032/032c/PR#5 work. + +2. **Zero-dependency confirmed:** Kujan's 033a assessment proved `gh project *` CLI covers all 12 required operations. GitHub MCP server has zero Projects V2 tools. No npm packages needed. + +3. **Single blocker is fixable:** Missing `project` token scope is not a design problem. Brady runs `gh auth refresh -s project` once, feature is unblocked. Graceful degradation handles missing scope at runtime. + +4. **Clear sprint decomposition:** 17-26 squad-hours across 3 agents, 3 phases: + - Phase 1 (Foundation): Validate CLI commands work, define provider interface (WI-1, WI-2) + - Phase 2 (Integration): Coordinator prompts + sync workflow (WI-3, WI-4) โ€” can parallelize Fenster + Verbal + - Phase 3 (Polish): Query/display + docs (WI-5, WI-6) โ€” can parallelize Verbal + McManus + +5. **Community signal matters:** @londospark's Issue #6 is the first external feature request with concrete technical proposal. Shipping it demonstrates we listen and move fast. v0.4.0 is achievable in 12-16 calendar days if phases 2-3 overlap. + +--- + +## Rationale + +**v0.4.0, not v0.3.0:** Brady's directive for v0.3.0 is ONE feature (proposals as GitHub Issues, 032). Project boards sit on top of the label/issue foundation that 032/032c/PR#5 build. The right sequence is labels first (v0.3.0), boards as a dashboard (v0.4.0). This is not deferral, it's architecture. + +**Zero-dependency constraint holds:** Proposal 033 initially suggested GraphQL client library. Kujan's 033a recommendation is `gh project *` CLI commands exclusively. This preserves our zero-dependency architecture and is more maintainable long-term. + +**Provider abstraction from day 1:** While GitHub-only on Day 1, the design documents cross-provider mapping (GitHub/ADO/GitLab). 033a shows each provider has equivalent operations. No future architectural rework needed. + +--- + +## Prerequisites + +**Brady must run before squad starts:** +```bash +gh auth refresh -s project +``` + +Grants `project` scope to the token. One-time interactive step, ~10 seconds. Verify: +```bash +gh auth status 2>&1 | grep "project" +``` + +If scope is missing at runtime, graceful degradation kicks in: board operations skip silently, user gets a message with fix instructions. + +--- + +## Agent Assignments + +- **Fenster (Core Dev):** WI-1 (validate GraphQL commands), WI-2 (provider interface), WI-4 (sync workflow) +- **Verbal (Prompt Engineer):** WI-3 (board init prompts), WI-5 (board query/display) +- **McManus (DevRel):** WI-6 (documentation) + +--- + +## Risks Mitigated + +| Risk | Mitigation | +|------|-----------| +| `gh project item-edit` ID handling unreliable | Phase 1 is a focused validation gate; if it fails, we reassess | +| Token scope becomes unavailable | Graceful degradation + clear user messaging | +| Board sync becomes noisy | Sync is label-driven and silent; no issue comments | +| GraphQL field IDs change per-project | Expected behavior; WI-1 documents 4-step discovery; team.md caches IDs | +| Prompt bloat in coordinator | Verbal's core skill; if needed, we split functionality | + +--- + +## Next Steps + +1. Brady grants `project` scope +2. Fenster begins Phase 1 (WI-1 validation) +3. After Phase 1 gate passes, Verbal + Fenster start Phase 2 in parallel +4. After Phase 2, Verbal + McManus start Phase 3 in parallel + +--- + +## Decision Reference + +Full proposal: `team-docs/proposals/033-project-boards.md` +API assessment: `team-docs/proposals/033a-projects-v2-api-assessment.md` +GitHub issue: Issue #6 (londospark) +Public comment: https://github.com/bradygaster/squad/issues/6#issuecomment-3888277477 + + + +--- + +### 2026-02-11: Squad Notification Architecture โ€” MCP Integration Pattern + +**By:** Keaton (Lead) + +**What:** Squad agents can notify humans via external channels (Teams, iMessage, Discord, webhooks) when work is blocked, errors occur, or decisions are needed. Implemented as an MCP integration pattern โ€” Squad ships ZERO notification infrastructure. + +**Why:** + +1. **Brady's vision:** "It needs to feel like I'm not in the team room, they are, and they need me so they pinged me." When agents hit a wall requiring human input, they should ping the human's phone, not just pause in the terminal. + +2. **MCP integration preserves Squad's architecture:** Zero dependencies, filesystem-authoritative, git-native. The consumer brings their own notification MCP server (Teams, iMessage, etc.). Squad teaches agents WHEN and HOW to notify via a skill at `.ai-team/skills/human-notification/SKILL.md`. + +3. **Platform-agnostic design:** Works with ANY notification MCP server โ€” Teams (primary path), iMessage (Mac-only secondary), Discord, generic webhooks. Squad never hardens against a specific platform. When new platforms emerge (Slack, Mattermost, Signal), the consumer installs the right MCP server and Squad's skill detects the tools automatically. + +4. **Zero maintenance burden:** The consumer owns the MCP server, credentials, and delivery mechanism. When Teams changes their API, the MCP server maintainer updates the server โ€” not Squad. Squad just teaches the notification pattern and lets the platform handle delivery. + +5. **Graceful degradation:** If no MCP server is configured, agents log the notification attempt and continue. Notifications are an enhancement, not a requirement. Squad works perfectly without them. + +**Architecture:** + +- **Layer 1:** Notification skill (`.ai-team/skills/human-notification/SKILL.md`) teaches agents when to ping (BLOCKED, ERROR, DECISION, COMPLETE) and how to compose rich, agent-branded notifications. +- **Layer 2:** MCP tool abstraction โ€” agents detect which notification tools are available (`send_teams_message`, `send_imessage`, `post_webhook`) and use the right format for each platform. +- **Layer 3:** Consumer's MCP server (configured in `.vscode/mcp.json`, VS Code settings, etc.) handles actual delivery. + +**Message format (platform-agnostic):** + +- **Who:** Agent name + emoji (Keaton ๐Ÿ—๏ธ) +- **Why:** Type badge (๐Ÿšซ BLOCKED, โš ๏ธ ERROR, ๐Ÿค” DECISION, โœ… COMPLETE) +- **Context:** Brief explanation (1-2 sentences) +- **Action:** What the human should do next +- **Link:** URL to GitHub issue/PR/proposal if applicable + +**Platform-specific renderers:** + +- **Teams:** Adaptive Card JSON with color-coded theme (red for ERROR, orange for BLOCKED, blue for DECISION, green for COMPLETE) +- **iMessage:** Plain text with emoji and signature +- **Webhook:** Structured JSON payload that consumer routes to their chosen backend (Slack, Discord, SMS, push notifications) + +**Integration with existing features:** + +- **Human Team Members:** When work routes to a human team member, the assigned agent sends a BLOCKED notification on their behalf. +- **Ralph (Work Queue Monitor):** Ralph can escalate stale work via notifications (opt-in โ€” default OFF). +- **Coordinator Handoffs:** When an agent returns blocked, the coordinator triggers the notification BEFORE prompting the user in terminal (ensures Brady gets the ping even if not watching terminal). + +**Primary path: Microsoft Teams** + +Brady said Teams is "ideal, especially per-repo channels." Teams channels-within-a-Team map perfectly to repos. Microsoft ships official MCP support: `@microsoft/teams.mcp` npm package and https://github.com/microsoft/IF-MCP-Server-for-Microsoft-Teams. Setup: create Incoming Webhook URL, configure MCP server, Squad detects `send_teams_message` tool and sends Adaptive Cards. + +**Secondary path: iMessage (Mac-only)** + +Zero account setup, instant delivery, native to Apple ecosystem. Limitations: requires macOS with Messages.app running, cannot run headless. MCP server exists: `imessage-mcp` or `imsg` CLI tool. Squad detects `send_imessage` tool and sends plain text with agent signature. + +**Trade-offs:** + +- **No auto-configuration:** Consumer must manually wire up MCP server and credentials. This is a setup burden but preserves Squad's zero-dependency constraint. +- **Single channel per repo:** All notifications from a repo go to ONE configured channel/recipient. Per-agent channels would fragment the notification stream (Brady doesn't want to monitor 5 channels per repo). +- **COMPLETE notifications opt-in:** Completion notifications can be noisy. Default is OFF. Consumers enable explicitly if they want visibility into finished work. + +**Sprint estimate:** 1.8 squad-days (core) + 0.3 squad-days (Ralph integration, optional). Target version: 0.3.0 (alongside GitHub-native proposals). + +**Success criteria:** + +1. Notification skill exists at `.ai-team/skills/human-notification/SKILL.md` +2. Skill teaches all four trigger types (BLOCKED, ERROR, DECISION, COMPLETE) +3. `docs/notifications.md` exists with Teams and iMessage setup guides +4. Agents gracefully degrade when no MCP server configured +5. At least ONE real-world test: Brady configures Teams, receives notification from his squad + +**Key file paths:** + +- `team-docs/proposals/034-notification-architecture.md` โ€” full design specification +- `.ai-team/skills/human-notification/SKILL.md` โ€” agent-facing skill (teaches when/how to notify) +- Future: `docs/notifications.md` โ€” consumer setup guide (Teams, iMessage, Discord, webhook walkthroughs) + +**Future enhancements (post-0.3.0):** + +- Discord support in primary docs (currently secondary tier) +- Slack support for enterprise customers +- Per-agent notification preferences (e.g., "only notify for Keaton's blockers") +- Digest mode (daily/weekly summary email instead of real-time pings) +- Two-way communication (reply to notification via Teams/iMessage and have Squad ingest response โ€” requires connector architecture, not just MCP tools) + + +--- + +# Decision: Squad Notifications Consumer Documentation + +**Status:** Completed +**Decided by:** McManus +**Date:** 2026-02-12 + +## What Was Decided + +Created `docs/features/notifications.md` โ€” consumer-facing documentation for "Squad Pings You," the feature allowing users to receive instant messages when agents need human input. + +## Rationale + +Brady's vision: "It needs to feel like I'm not in the team room, they are, and they need me so they pinged me." This doc translates that into practical setup paths and concrete examples of what notifications look like. + +## Key Design Decisions + +### Zero-Auth Paths Come First +- Teams Incoming Webhook (just a URL, no API setup) listed as "Option A" +- Official Teams MCP server (full Azure AD auth) listed as "Option B" for completeness +- This lowers barrier to entry for most users + +### Show, Don't Tell +- All quick-start sections include actual JSON configuration examples +- Notification format section shows concrete message examples with emoji and structure +- Troubleshooting uses real error scenarios ("MCP server failed to start", "wrong channel receiving") + +### Architecture Transparency +- Explicit section explaining: skill-based (not hard-coded), bring-your-own MCP server (not managed service) +- Notes that users can customize the `human-notification` skill for advanced use cases +- Links to `.vscode/mcp.json` standard config file location + +### Trigger Control Upfront +- Configuration section explains how to selectively enable/disable notification types +- Quiet hours concept introduced for advanced setups +- Test command provided for validation + +### Platform Realistic +- iMessage marked as "Mac Only" with clear limitations +- All paths (Teams, Discord, webhook) tested for completeness +- Acknowledges three-tier setup complexity (webhook URL โ†’ MCP config โ†’ environment variable) + +## File Location + +`docs/features/notifications.md` โ€” placed alongside other feature docs (skills, ralph, memory, etc.) + +## Style Adherence + +- **Brady's "straight facts" directive:** No editorial voice, no hype words, every sentence states what/how/depends-on +- **Devrel vision:** First 5 minutes to value (webhook option gets you going fastest), then depth for power users +- **Tone:** "Here's how to set it up" not "isn't this cool" +- **Brevity:** Dev-skimmable format with tables, code blocks, and scannable lists + +## Cross-References + +Links to related docs: +- Skills System (`docs/features/skills.md`) +- Copilot Environment Setup (`docs/guide.md`) +- Model Selection (`docs/features/model-selection.md`) + +No README changes required โ€” notifications is a features doc, not a headline change. + +## Follow-Up + +Consider adding `notifications` to the "What's New" section in README.md if this is a v0.4.0 feature launch. Coordinate with Brady on feature status and visibility. + +### 2026-02-13: go:/release: label automation + +**By:** Fenster + +**What:** Four-workflow system to automate `go:` (triage verdict) and `release:` (version target) label namespaces. Created `squad-label-enforce.yml` for mutual exclusivity enforcement; updated `sync-squad-labels.yml` to sync 8 static labels (3 go:, 5 release:); updated `squad-triage.yml` to apply `go:needs-research` as default verdict; updated `squad-heartbeat.yml` to detect issues missing go: labels and go:yes issues missing release: labels. + +**Why:** Labels-as-automation is the foundation of Squad's GitHub-native workflow. The `go:` namespace (go:yes, go:no, go:needs-research) captures triage decisions; the `release:` namespace (release:v0.4.0, v0.5.0, v0.6.0, v1.0.0, release:backlog) captures delivery targets. Mutual exclusivity is business logic (exactly 1 go: label per triaged issue, at most 1 release: label per issue). Workflows enforce this at runtime, eliminating human error. The enforcement workflow handles label transitions: when a new go: or release: label is applied, it removes conflicting labels in the same namespace and posts a comment (only on actual changes). Special cases: `go:yes` auto-applies `release:backlog` if no release target exists (every approved issue must have a target); `go:no` strips release labels (rejected issues shouldn't be in release planning). Default verdict (`go:needs-research`) is applied by triage workflow to ensure every triaged issue enters the system with a go: label. Ralph (heartbeat) now scans for label hygiene: issues missing go: labels are surfaced as incomplete triage, go:yes issues missing release: labels are surfaced as incomplete planning. This is textbook "agentic DevOps" โ€” labels are the state machine, automation is the enforcement layer. + + +### 2026-02-13: User directive +**By:** Brady (via Copilot) +**What:** Execution is the strategy. Take action, don't wait for permission. If the squad has questions on issues, leave a comment. If not, close research issues and create milestone-ready implementation issues. Optimize for taking action. +**Why:** User request โ€” captured for team memory. Brady wants momentum, not planning paralysis. + + + +### 2026-02-13: Full label taxonomy โ€” namespaced label strategy +**By:** Keaton (via Coordinator) +**What:** Implemented complete namespaced label system across 5 namespaces: +- `go:` (yes/no/needs-research) โ€” triage verdicts, mutually exclusive +- `release:` (v0.4.0/v0.5.0/v0.6.0/v1.0.0/backlog) โ€” release targeting, mutually exclusive +- `type:` (feature/bug/spike/docs/chore/epic) โ€” work classification, mutually exclusive +- `priority:` (p0/p1/p2) โ€” urgency, mutually exclusive +- `squad:{member}` โ€” agent routing, NOT exclusive (can have multiple) + +Deleted GitHub defaults (bug, enhancement, documentation, duplicate, invalid, wontfix, question) โ€” replaced by namespaced equivalents. + +All 4 workflow templates updated: +- squad-label-enforce.yml: enforces mutual exclusivity for go:/release:/type:/priority: +- sync-squad-labels.yml: syncs all label namespaces from team.md +- squad-heartbeat.yml: Ralph detects missing type: labels +- squad-triage.yml: unchanged (type: assigned during review, not auto-guessed) + +**Why:** Brady directive โ€” `textbook agentic DevOps.` Labels are the state machine. Every issue gets exactly one label per exclusive namespace. Workflows enforce this automatically. + diff --git a/.ai-team/decisions/inbox/fenster-ssh-workaround.md b/.ai-team/decisions/inbox/fenster-ssh-workaround.md new file mode 100644 index 000000000..7058d681c --- /dev/null +++ b/.ai-team/decisions/inbox/fenster-ssh-workaround.md @@ -0,0 +1,20 @@ +# Decision: SSH workaround documentation pattern + +**Date:** 2026-02-12 +**Author:** Fenster +**Issue:** #30 + +## Context + +Users reported `npx github:bradygaster/squad` appearing to hang. Root cause: npm resolves `github:` specifiers via `git+ssh://`, and when no SSH agent is running, git's passphrase prompt is hidden by npm's progress spinner. This is an npm TTY bug, not a Squad bug. + +## Decision + +1. Document workarounds inline in README (Install section + Known Limitations) rather than changing install mechanics. +2. Created `docs/scenarios/troubleshooting.md` as a central troubleshooting guide using problem โ†’ cause โ†’ fix format. +3. We do NOT work around this in code (e.g., no HTTPS fallback in index.js) โ€” the install path via `github:` specifier is npm's responsibility. + +## Impact + +- Future community-reported "it doesn't work" issues should be added to the troubleshooting doc. +- The troubleshooting doc follows the same format as other scenario docs in `docs/scenarios/`. diff --git a/.ai-team/log/2026-02-11-test-fixes-and-mcp-proposal.md b/.ai-team/log/2026-02-11-test-fixes-and-mcp-proposal.md new file mode 100644 index 000000000..a7d8f6b38 --- /dev/null +++ b/.ai-team/log/2026-02-11-test-fixes-and-mcp-proposal.md @@ -0,0 +1,13 @@ +# Session: 2026-02-11 โ€” Test Fixes and MCP Proposal + +**Requested by:** Brady + +## Work Summary + +- **Fenster** fixed emoji encoding in `test/index.test.js` โ€” replaced 8 mojibake emoji strings with real Unicode. All 118 tests now pass (0 failures). +- **Keaton** wrote MCP integration proposal (`034-mcp-integration.md`) and responded to Fritz's issue #11 with proposal highlights and feedback questions. +- **PR merge:** Merged Shayne's PR #15 (Ralph work monitor) from main into dev โ€” clean merge, no conflicts. + +## Status + +Tests passing. MCP proposal ready for Brady approval. diff --git a/.ai-team/log/2026-02-12-issue6-gonogo.md b/.ai-team/log/2026-02-12-issue6-gonogo.md new file mode 100644 index 000000000..3ae450b49 --- /dev/null +++ b/.ai-team/log/2026-02-12-issue6-gonogo.md @@ -0,0 +1,21 @@ +# Session: 2026-02-12 Issue #6 Go/No-Go Assessment + +**Requested by:** Brady +**Date:** 2026-02-12 + +## Summary + +Keaton posted a go/no-go assessment and sprint plan for Issue #6 (Project Boards). Verdict: **GO (Conditional)**, pending `project` token scope approval from Brady. + +Fenster completed universe expansion work (Adventure Time + 10 new universes). Issue #21 closed. + +## Key Outcomes + +- Issue #6 project boards assessment documented and approved (pending token scope) +- Universe expansion feature shipped (Issue #21 resolved) +- Two decision inbox entries processed and merged into decisions.md + +## Decisions Merged + +- fenster-universe-expansion.md +- keaton-issue6-gonogo.md diff --git a/.ai-team/log/2026-02-12-notification-architecture.md b/.ai-team/log/2026-02-12-notification-architecture.md new file mode 100644 index 000000000..250b6e710 --- /dev/null +++ b/.ai-team/log/2026-02-12-notification-architecture.md @@ -0,0 +1,21 @@ +# Session: Notification Architecture (2026-02-12) + +**Requested by:** Brady + +## Participants +- Keaton: Proposal 034 (notification architecture) โ€” design for "Squad Pings You" feature +- McManus: Consumer documentation at docs/features/notifications.md + +## Work Completed +- Proposal 034 written (notification architecture design) +- Consumer-facing notification documentation drafted +- Work IQ integration issue #26 filed and assigned to @copilot +- Notification feature issue #27 filed + +## Decisions +- **Primary notification channel:** Teams (Brady directive) + +## Key Outcomes +- Architecture proposal ready for review +- Documentation in place for feature rollout +- Integration work tracked and assigned diff --git a/.ai-team/log/2026-02-12-v040-sprint.md b/.ai-team/log/2026-02-12-v040-sprint.md new file mode 100644 index 000000000..418e98b4d --- /dev/null +++ b/.ai-team/log/2026-02-12-v040-sprint.md @@ -0,0 +1,54 @@ +# Session: v0.4.0 Sprint Execution + +**Date:** 2026-02-12 +**Requested by:** Brady +**Status:** Complete + +--- + +## Team Execution Summary + +Parallel sprint completion across 5 issues: + +**McManus:** +- Completed #16 (Tips & Tricks user documentation) +- Completed #17 (Ralph PAT documentation) +- Completed #20 (Community page) +- Completed #9 (Task tool comment update + guide update) + +**Kujan:** +- Completed #18 (Version display investigation + implementation) + +--- + +## Issues Filed + +- #21: Adventure Time universe +- #22: Agent progress updates +- #23: Self-testing framework + +--- + +## Test Results + +All 118 tests passing. + +--- + +## Decisions Merged + +8 decisions merged from inbox into decisions.md: +1. Release process directive (Brady/Copilot) +2. Squad time estimation directive (Brady/Copilot) +3. Fenster's branching strategy analysis +4. Keaton's three-branch strategy proposal +5. Kobayashi's release pipeline hardening +6. Kujan's cross-client sub-agent API research +7. Kujan's version display implementation +8. McManus's tips & tricks documentation decision + +--- + +## Outcome + +Sprint executed with full parallelism. All assigned work completed. Backlog growing (3 new issues). System stable, tests green. diff --git a/.ai-team/log/2026-02-13-go-release-labels.md b/.ai-team/log/2026-02-13-go-release-labels.md new file mode 100644 index 000000000..745b7bec2 --- /dev/null +++ b/.ai-team/log/2026-02-13-go-release-labels.md @@ -0,0 +1,26 @@ +# Session: 2026-02-13 โ€” go:/release: Label Automation + +**Requested by:** Brady + +## Work Completed + +- **PR #28 (Ralph idle-watch by spboyer)** merged to main and propagated to dev branch +- **Fenster** built go:/release: label automation + - New workflow: `squad-label-enforce.yml` + - Updated workflows: `sync-squad-labels.yml`, `squad-triage.yml`, `squad-heartbeat.yml` +- **All 11 open issues** labeled with go:/release: verdicts based on prior triage +- **GitHub labels created:** + - `go:yes` + - `go:no` + - `go:needs-research` + - `release:v0.4.0` + - `release:v0.5.0` + - `release:v0.6.0` + - `release:v1.0.0` + - `release:backlog` + +## Key Outcomes + +- Label automation system now in place for release workflow +- Triage verdicts propagated across issue queue +- Automation ready for ongoing release management diff --git a/.ai-team/orchestration-log/2026-02-12T17-02-25-keaton-triage.md b/.ai-team/orchestration-log/2026-02-12T17-02-25-keaton-triage.md new file mode 100644 index 000000000..f5b4c1e5d --- /dev/null +++ b/.ai-team/orchestration-log/2026-02-12T17-02-25-keaton-triage.md @@ -0,0 +1,25 @@ +# Orchestration Log Entry + +**Timestamp:** 2026-02-12T17:02:25Z +**Agent:** Keaton (Lead) +**Mode:** sync (triage), then 5x background (plan writing) +**Requested by:** Brady +**Why chosen:** Lead handles triage, product decisions, and sprint planning + +## Task +Triage all 11 open GitHub issues for v0.4.0 readiness, then write implementation plans into GO issues. + +## Files Read +- All 11 GitHub issues via MCP +- Issue comments on #6, #8, #10, #11, #22, #23, #24, #25, #26, #27, #29 + +## Outputs +- Triage survey: 4 GO, 4 NEEDS RESEARCH, 3 NO-GO +- Implementation plan posted as comment on #10 (client parity) +- Implementation plan posted as comment on #11 (MCP use) +- Implementation plan posted as comment on #22 (progress updates) +- Implementation plan posted as comment on #27 (notifications) +- Implementation plan posted as comment on #29 (plugin marketplace) + +## Outcome +All 11 issues classified. 5 implementation plans posted to GitHub issues. Issues #6 already had a plan from prior session. Issues #24 and #25 assigned to @copilot for research. Issues #8, #23, #26 deferred/closed. diff --git a/.ai-team/routing.md b/.ai-team/routing.md index 66ef34abb..038031275 100644 --- a/.ai-team/routing.md +++ b/.ai-team/routing.md @@ -16,6 +16,7 @@ How to decide who handles what. | Visual identity, logos, brand assets, design | Redfoot | Logo design, icons, brand guidelines, visual consistency | | Code review | Keaton | Review PRs, check quality, architectural consistency | | Session logging | Scribe | Automatic โ€” never needs routing | +| Bug fixes, test coverage, lint fixes, small features, scaffolding | @copilot ๐Ÿค– | Auto-assigned when issue matches ๐ŸŸข capability profile | ## Rules diff --git a/.ai-team/skills/human-notification/SKILL.md b/.ai-team/skills/human-notification/SKILL.md new file mode 100644 index 000000000..f063386fb --- /dev/null +++ b/.ai-team/skills/human-notification/SKILL.md @@ -0,0 +1,423 @@ +--- +name: "human-notification" +description: "Teaches agents when and how to notify humans via external channels (Teams, iMessage, etc.) when immediate input is required. Use this skill when work is blocked, an unrecoverable error occurs, a strategic decision is needed, or work is complete and ready for review." +domain: "team-communication" +confidence: "high" +source: "manual" +tools: + - name: "send_teams_message" + description: "Send a message to a Microsoft Teams channel using Adaptive Card format" + when: "When Microsoft Teams MCP server is configured" + - name: "send_imessage" + description: "Send an iMessage to a recipient (Mac only)" + when: "When iMessage MCP server is configured and running on macOS" + - name: "post_webhook" + description: "POST JSON payload to a webhook URL" + when: "When generic webhook MCP server is configured" +--- + +# Human Notification Skill + +## Context + +This skill teaches agents WHEN to notify humans via external channels (Microsoft Teams, iMessage, Discord, generic webhooks) and HOW to compose rich, agent-branded notifications that feel like messages from remote coworkers. + +**Use this skill when:** +- Work is blocked and cannot proceed without human input (decision, clarification, approval) +- An unrecoverable error occurs that requires human intervention (auth failure, permission denied, API outage) +- A strategic decision is needed between multiple valid alternatives +- (Optional) Work is complete and ready for human review + +**Core principle:** Notifications are for URGENT issues that require immediate human attention. Do not notify for routine progress updates or problems that can be resolved by another agent. + +## Notification Trigger Taxonomy + +### 1. BLOCKED ๐Ÿšซ + +**When to trigger:** +- Work cannot proceed without human input +- Another agent or external dependency is blocking progress +- A human team member was assigned work and needs to act + +**Examples:** +- "Use REST or GraphQL for the API? This affects the entire backend architecture." +- "Cannot deploy to production without AWS credentials." +- "Design approval needed before implementing components." + +**Notification structure:** +``` +๐Ÿšซ BLOCKED โ€” {Your Name} needs {human's} input + +{Brief explanation of what's blocked and why} + +Action needed: {What the human should do} +{Optional: Link to GitHub issue, PR, or proposal} + +โ€” {Your Name} {Your Emoji} ({Your Role}) ยท Squad ยท {repo} +``` + +### 2. ERROR โš ๏ธ + +**When to trigger:** +- Unrecoverable error that prevents work from continuing +- Authentication or permission failures +- Missing required environment variables, credentials, or configuration +- External service outages or API failures + +**Examples:** +- "All tests failing due to missing DATABASE_URL environment variable." +- "GitHub Actions workflow failing on authentication โ€” check GITHUB_TOKEN permissions." +- "Cannot push to main branch โ€” branch protection rules require PR." + +**Notification structure:** +``` +โš ๏ธ ERROR โ€” {Your Name} encountered a problem + +{Error description โ€” what happened} + +{What might fix it or what the human should investigate} +{Optional: Link to logs, error output, or failed workflow} + +โ€” {Your Name} {Your Emoji} ({Your Role}) ยท Squad ยท {repo} +``` + +### 3. DECISION ๐Ÿค” + +**When to trigger:** +- A choice between multiple valid alternatives affects strategy, architecture, or user experience +- There's no objectively "correct" answer โ€” it requires human judgment or preference +- The decision has downstream implications for other work + +**Examples:** +- "Store user sessions in Redis (faster, adds dependency) or PostgreSQL (reuses infrastructure)?" +- "Dark mode โ€” user preference toggle or system preference detection?" +- "Rate limiting โ€” per-user or per-IP? This affects API design and security." + +**Notification structure:** +``` +๐Ÿค” DECISION โ€” {Your Name} needs {human's} choice + +{Brief framing of the decision} + +Options: +1. {Option A โ€” brief description and trade-offs} +2. {Option B โ€” brief description and trade-offs} +{Optional: Additional options} + +{Optional: Your recommendation if you have one} +{Optional: Link to proposal or discussion} + +โ€” {Your Name} {Your Emoji} ({Your Role}) ยท Squad ยท {repo} +``` + +### 4. COMPLETE โœ… (Opt-In Only) + +**When to trigger:** +- Work is complete and ready for human review +- This trigger is OFF by default โ€” only send if explicitly requested or configured + +**Examples:** +- "Test suite is passing โ€” all 47 tests green. Ready to merge PR #23." +- "User authentication API shipped and deployed to staging." +- "Architecture proposal written and posted to issue #89." + +**Notification structure:** +``` +โœ… COMPLETE โ€” {Your Name} finished work + +{What was completed} + +{What the human should do next โ€” review, merge, deploy, approve} +{Link to PR, issue, or deployed artifact} + +โ€” {Your Name} {Your Emoji} ({Your Role}) ยท Squad ยท {repo} +``` + +## Tool Detection Pattern + +Before sending a notification, detect which notification tools are available: + +``` +1. Check available tools in your context +2. If `send_teams_message` exists โ†’ use Teams format (Adaptive Card JSON) +3. Else if `send_imessage` exists โ†’ use iMessage format (plain text) +4. Else if `post_webhook` exists โ†’ use webhook format (JSON payload) +5. Else โ†’ log that notification would have been sent and continue gracefully +``` + +**Graceful degradation:** If no notification tools are available, log the notification attempt and continue working. Do NOT crash or halt. Notifications are an enhancement, not a requirement. + +## Platform-Specific Message Formats + +### Microsoft Teams (Adaptive Card) + +Use `send_teams_message` with an Adaptive Card JSON payload: + +```json +{ + "@type": "MessageCard", + "@context": "https://schema.org/extensions", + "summary": "{Your Name} needs input", + "themeColor": "D93F0B", + "sections": [{ + "activityTitle": "{Icon} {Type} โ€” {Your Name} {action}", + "activitySubtitle": "Squad ยท {repo}", + "text": "{Message body โ€” 1-3 sentences}", + "facts": [ + {"name": "Agent:", "value": "{Your Name} {Your Emoji} ({Your Role})"}, + {"name": "Type:", "value": "{BLOCKED|ERROR|DECISION|COMPLETE}"} + ] + }], + "potentialAction": [{ + "@type": "OpenUri", + "name": "View Details", + "targets": [{"os": "default", "uri": "{link to GitHub issue/PR}"}] + }] +} +``` + +**Color coding:** +- BLOCKED: `"D93F0B"` (red-orange) +- ERROR: `"FF0000"` (red) +- DECISION: `"1D76DB"` (blue) +- COMPLETE: `"0E8A16"` (green) + +### iMessage (Plain Text) + +Use `send_imessage` with plain text (no rich formatting): + +``` +{Icon} {Type} โ€” {Your Name} {action} + +{Message body โ€” 1-3 sentences} + +Action: {What the human should do} +{Optional: Link} + +โ€” {Your Name} {Your Emoji} ({Your Role}) ยท Squad ยท {repo} +``` + +**Example:** +``` +๐Ÿšซ BLOCKED โ€” Keaton needs your input + +Use REST or GraphQL for the new API? This affects backend architecture. + +Action: Review proposal at https://github.com/owner/repo/issues/89 + +โ€” Keaton ๐Ÿ—๏ธ (Lead) ยท Squad ยท squad/squad +``` + +### Generic Webhook (JSON Payload) + +Use `post_webhook` with a structured JSON payload: + +```json +{ + "agent": "{Your Name}", + "emoji": "{Your Emoji}", + "role": "{Your Role}", + "type": "{BLOCKED|ERROR|DECISION|COMPLETE}", + "icon": "{๐Ÿšซ|โš ๏ธ|๐Ÿค”|โœ…}", + "message": "{Message body}", + "action": "{What the human should do}", + "link": "{URL to GitHub artifact}", + "repo": "{owner/repo}", + "timestamp": "{ISO-8601 timestamp}" +} +``` + +The consumer's webhook endpoint receives this JSON and routes it to their chosen platform (Slack, Discord, SMS, push notifications, etc.). + +## Examples + +### Example 1: BLOCKED notification (Teams) + +**Scenario:** Keaton (Lead) needs Brady to decide between REST and GraphQL for the API. + +**Tool call:** +``` +send_teams_message({ + "@type": "MessageCard", + "summary": "Keaton needs your input", + "themeColor": "D93F0B", + "sections": [{ + "activityTitle": "๐Ÿšซ BLOCKED โ€” Keaton needs your input", + "activitySubtitle": "Squad ยท squad/squad", + "text": "Use REST or GraphQL for the new API? This decision affects the entire backend architecture and client integration patterns.", + "facts": [ + {"name": "Agent:", "value": "Keaton ๐Ÿ—๏ธ (Lead)"}, + {"name": "Type:", "value": "BLOCKED"} + ] + }], + "potentialAction": [{ + "@type": "OpenUri", + "name": "View Proposal", + "targets": [{"os": "default", "uri": "https://github.com/squad/squad/issues/89"}] + }] +}) +``` + +**Result:** Brady's phone vibrates. He sees the Teams notification, reads the context, clicks "View Proposal," and makes a decision. + +### Example 2: ERROR notification (iMessage) + +**Scenario:** McManus (Backend Dev) hits a missing environment variable error during deployment. + +**Tool call:** +``` +send_imessage({ + recipient: "brady@example.com", + message: "โš ๏ธ ERROR โ€” McManus encountered a problem\n\nDeployment to production failed: DATABASE_URL environment variable is not set.\n\nPlease add DATABASE_URL to the production environment configuration or verify deployment secrets.\n\nโ€” McManus ๐Ÿ”ง (Backend Dev) ยท Squad ยท squad/squad" +}) +``` + +**Result:** Brady receives an iMessage, sees the error, and adds the missing environment variable. + +### Example 3: DECISION notification (Webhook) + +**Scenario:** Verbal (Frontend Dev) needs Brady to choose between a dark mode toggle or system preference detection. + +**Tool call:** +``` +post_webhook({ + url: "https://brady-notifications.example.com/squad", + payload: { + "agent": "Verbal", + "emoji": "โš›๏ธ", + "role": "Frontend Dev", + "type": "DECISION", + "icon": "๐Ÿค”", + "message": "Dark mode implementation โ€” should we use a user preference toggle (more control, requires UI) or system preference detection (automatic, less customization)?", + "action": "Choose approach", + "link": "https://github.com/squad/squad/issues/72", + "repo": "squad/squad", + "timestamp": "2026-02-11T10:45:00Z" + } +}) +``` + +**Result:** Brady's custom webhook backend routes the notification to his preferred channel (Discord, SMS, etc.), and he responds with his choice. + +### Example 4: COMPLETE notification (Teams, opt-in) + +**Scenario:** Fenster (Tester) finished the test suite, and Brady has enabled COMPLETE notifications for this repo. + +**Tool call:** +``` +send_teams_message({ + "@type": "MessageCard", + "summary": "Fenster finished work", + "themeColor": "0E8A16", + "sections": [{ + "activityTitle": "โœ… COMPLETE โ€” Fenster finished work", + "activitySubtitle": "Squad ยท squad/squad", + "text": "Test suite is passing โ€” all 47 tests green. Code coverage is at 92%. Ready to merge PR #23.", + "facts": [ + {"name": "Agent:", "value": "Fenster ๐Ÿงช (Tester)"}, + {"name": "Type:", "value": "COMPLETE"} + ] + }], + "potentialAction": [{ + "@type": "OpenUri", + "name": "Merge PR", + "targets": [{"os": "default", "uri": "https://github.com/squad/squad/pull/23"}] + }] +}) +``` + +**Result:** Brady sees the completion notification, reviews the PR, and merges. + +## Anti-Patterns + +**DO NOT notify for:** +- Routine progress updates ("Started working on X", "Finished step 1 of 5") +- Problems that can be resolved by spawning another agent ("I don't know the answer, but McManus might") +- Redundant notifications (if already blocked on the same issue, don't re-notify unless the situation changes) +- Low-priority issues that can wait until the next sync session + +**DO NOT spam:** +- If you've already sent a notification about a specific blocker, DO NOT send another until the blocker is resolved or changes +- Use judgment: if the human is in an active session with you, prefer in-terminal responses over external notifications + +**DO NOT assume delivery:** +- If the notification tool call fails, log the failure and continue gracefully +- The coordinator will still prompt the human via the terminal as a fallback + +**DO NOT send sensitive data:** +- Notifications may pass through third-party services (Teams, iMessage, webhooks) +- Do NOT include credentials, secrets, or sensitive user data in notification messages +- Link to GitHub artifacts instead of embedding raw data + +## Integration with Human Team Members + +When work routes to a human team member (not an AI agent), send a BLOCKED notification on their behalf: + +``` +๐Ÿšซ BLOCKED โ€” {Your Name} assigned work to {Human} + +Task: {Brief task summary} + +{Human} needs to {action required}. + +Link: {GitHub issue or context} + +โ€” {Your Name} {Your Emoji} ({Your Role}) ยท Squad ยท {repo} +``` + +**Example:** +``` +๐Ÿšซ BLOCKED โ€” Keaton assigned work to Sarah + +Task: Design review for homepage redesign + +Sarah needs to approve the visual direction before components can be implemented. + +Link: https://github.com/squad/squad/issues/42 + +โ€” Keaton ๐Ÿ—๏ธ (Lead) ยท Squad ยท squad/squad +``` + +## Logging Notification Attempts + +Every notification attempt (success or failure) should be logged to `.ai-team/notifications/log.jsonl` (append-only): + +```json +{"timestamp": "2026-02-11T10:30:00Z", "agent": "Keaton", "type": "BLOCKED", "message": "Use REST or GraphQL...", "tool": "send_teams_message", "status": "success"} +{"timestamp": "2026-02-11T10:45:00Z", "agent": "McManus", "type": "ERROR", "message": "DATABASE_URL missing", "tool": "send_imessage", "status": "failed", "error": "Recipient not configured"} +``` + +This log is useful for: +- Debugging notification delivery issues +- Retrospectives (how often are agents blocked?) +- Auditing (when did the human receive the ping?) + +## Configuration (Optional) + +Squad does not require configuration to use this skill, but consumers can add optional settings to `.ai-team/team.md` under a `[notifications]` section: + +```markdown +## Notifications + +- **Enabled:** true +- **Complete notifications:** false (opt-in) +- **Ralph escalation:** false (opt-in โ€” Ralph sends notifications for stale work) +- **Log file:** `.ai-team/notifications/log.jsonl` +``` + +If no configuration exists, assume notifications are enabled with COMPLETE and Ralph escalation OFF. + +## Testing This Skill + +To verify this skill works: + +1. **Configure an MCP server** (Teams, iMessage, or webhook) in your Copilot environment +2. **Spawn an agent** and trigger a blocker: "Keaton, design the API but ask me before choosing REST or GraphQL" +3. **Verify notification arrival:** Check your Teams channel, iMessage, or webhook endpoint +4. **Test graceful degradation:** Disable the MCP server, trigger a blocker, verify the agent logs the notification attempt and continues + +## Summary + +This skill enables agents to feel like remote coworkers โ€” they ping you when they need you. Notifications are urgent, agent-branded, action-oriented, and platform-agnostic. Squad teaches the pattern; the consumer brings the delivery mechanism. + +**Key takeaway:** Notify when work stops without human input. Compose messages that let humans triage from their phone. Degrade gracefully when no notification tools exist. diff --git a/.ai-team/team.md b/.ai-team/team.md index 513a43f43..1e3e8a73e 100644 --- a/.ai-team/team.md +++ b/.ai-team/team.md @@ -21,6 +21,19 @@ | [Kobayashi](https://en.wikipedia.org/wiki/The_Usual_Suspects) | Git & Release Engineer | `.ai-team/agents/kobayashi/charter.md` | โœ… Active | | [Redfoot](https://en.wikipedia.org/wiki/The_Usual_Suspects) | Graphic Designer | `.ai-team/agents/redfoot/charter.md` | โœ… Active | | Scribe | Session Logger | `.ai-team/agents/scribe/charter.md` | ๐Ÿ“‹ Silent | +| Ralph | Work Monitor | โ€” | ๐Ÿ”„ Monitor | + + + +| Name | Role | Charter | Status | +|------|------|---------|--------| +| @copilot | Coding Agent | โ€” | ๐Ÿค– Coding Agent | + +### Capabilities + +๐ŸŸข Good fit: Bug fixes, test coverage, lint fixes, dependency updates, small features, scaffolding, doc fixes +๐ŸŸก Needs review: Medium features with clear specs, refactoring with tests, API additions +๐Ÿ”ด Not suitable: Architecture decisions, multi-system design, ambiguous requirements, security-critical changes ## Project Context diff --git a/.github/agents/squad.agent.md b/.github/agents/squad.agent.md index a3dff9d6b..c9f293f74 100644 --- a/.github/agents/squad.agent.md +++ b/.github/agents/squad.agent.md @@ -1,5 +1,5 @@ --- -name: Squad +name: Squad (v0.0.0-source) description: "Your AI team. Describe what you're building, get a team of specialists that live in your repo." version: "0.0.0-source" --- @@ -207,7 +207,7 @@ The routing table determines **WHO** handles work. After routing, use Response M | Issues/backlog request ("pull issues", "show backlog", "work on #N") | Follow GitHub Issues Mode (see that section) | | PRD intake ("here's the PRD", "read the PRD at X", pastes spec) | Follow PRD Mode (see that section) | | Human member management ("add Brady as PM", routes to human) | Follow Human Team Members (see that section) | -| Ralph commands ("Ralph, go", "keep working", "Ralph, status", "Ralph, idle") | Follow Ralph โ€” Work Monitor (see that section) | +| Ralph commands ("Ralph, go", "keep working", "Ralph, status", "Ralph, idle", "Ralph, check every N minutes") | Follow Ralph โ€” Work Monitor (see that section) | | General work request | Check routing.md, spawn best match + any anticipatory agents | | Quick factual question | Answer directly (no spawn) | | Ambiguous | Pick the most likely agent; say who you chose | @@ -905,7 +905,7 @@ prompt: | 6. **Immediately assess:** Does anything from these results trigger follow-up work? If so, launch follow-up agents NOW โ€” don't wait for the user to ask. Keep the pipeline moving. -7. **Ralph check:** If Ralph is active (see Ralph โ€” Work Monitor), after chaining any follow-up work, IMMEDIATELY run Ralph's work-check cycle (Step 1). Do NOT stop. Do NOT wait for user input. Ralph keeps the pipeline moving until the board is clear. +7. **Ralph check:** If Ralph is active (see Ralph โ€” Work Monitor), after chaining any follow-up work, IMMEDIATELY run Ralph's work-check cycle (Step 1). Do NOT stop. Do NOT wait for user input. Ralph keeps the pipeline moving until the board is clear โ€” then enters idle-watch polling mode to catch new work. ### Ceremonies @@ -1337,7 +1337,7 @@ Before connecting to a GitHub repository, verify that the `gh` CLI is available Ralph is a built-in squad member whose job is keeping tabs on work. Like Scribe tracks decisions, **Ralph tracks and drives the work queue**. Ralph is always on the roster โ€” not cast from a universe โ€” and has one job: make sure the team never sits idle when there's work to do. -**โšก CRITICAL BEHAVIOR: When Ralph is active, the coordinator MUST NOT stop and wait for user input between work items. Ralph runs a continuous loop โ€” scan for work, do the work, scan again, repeat โ€” until the board is empty or the user explicitly says "idle" or "stop". This is not optional. If work exists, keep going.** +**โšก CRITICAL BEHAVIOR: When Ralph is active, the coordinator MUST NOT stop and wait for user input between work items. Ralph runs a continuous loop โ€” scan for work, do the work, scan again, repeat โ€” until the board is empty or the user explicitly says "idle" or "stop". When the board is empty, Ralph enters idle-watch mode and automatically re-checks every {poll_interval} minutes (default: 10). This is not optional. If work exists, keep going. If the board clears, keep watching.** ### Roster Entry @@ -1354,7 +1354,8 @@ Ralph always appears in `team.md`: | "Ralph, go" / "Ralph, start monitoring" | Activate Ralph's work-check loop | | "Keep working" / "Work until done" | Activate Ralph | | "Ralph, status" / "What's on the board?" / "How's the backlog?" | Run one work-check cycle, report results, don't loop | -| "Ralph, idle" / "Take a break" / "Stop monitoring" | Deactivate Ralph, stop looping | +| "Ralph, check every N minutes" / "Ralph, poll every N minutes" | Set the idle-watch polling interval (e.g., "Ralph, check every 30 minutes") | +| "Ralph, idle" / "Take a break" / "Stop monitoring" | Fully deactivate Ralph โ€” stop looping AND stop idle-watch polling | | "Ralph, scope: just issues" / "Ralph, skip CI" | Adjust what Ralph monitors this session | ### Work-Check Cycle @@ -1387,7 +1388,7 @@ gh pr list --state open --draft --json number,title,author,labels,checks --limit | **Review feedback** | PR has `CHANGES_REQUESTED` review | Route feedback to PR author agent to address | | **CI failures** | PR checks failing | Notify assigned agent to fix, or create a fix issue | | **Approved PRs** | PR approved, CI green, ready to merge | Merge and close related issue | -| **No work found** | All clear | Report: "๐Ÿ“‹ Board is clear. Ralph is idling." | +| **No work found** | All clear | Enter idle-watch: "๐Ÿ“‹ Board is clear. Ralph is watching โ€” next check in {poll_interval} minutes. (say 'Ralph, idle' to stop)" | **Step 3 โ€” Act on highest-priority item:** - Process one category at a time, highest priority first (untriaged > assigned > CI failures > review feedback > approved PRs) @@ -1408,12 +1409,38 @@ After every 3-5 rounds, pause and report before continuing: **Do NOT ask for permission to continue.** Just report and keep going. The user must explicitly say "idle" or "stop" to break the loop. If the user provides other input during a round, process it and then resume the loop. +### Idle-Watch Mode + +When Ralph clears the board (no work found), he does **not** fully stop. Instead, he enters **idle-watch** mode: + +1. Report: "๐Ÿ“‹ Board is clear. Ralph is watching โ€” next check in {poll_interval} minutes. (say 'Ralph, idle' to stop)" +2. Wait {poll_interval} minutes (default: 10) +3. Re-run the full work-check cycle (Step 1) +4. If work is found โ†’ resume the active loop (scan โ†’ act โ†’ scan) +5. If still no work โ†’ report and wait another {poll_interval} minutes +6. Repeat indefinitely until the user says "Ralph, idle" / "stop" or the session ends + +**Configuring the interval:** +- The user can say "Ralph, check every N minutes" at any time (during active mode, idle-watch, or before activation) +- Examples: "Ralph, check every 5 minutes", "Ralph, poll every 30 minutes" +- The interval applies to idle-watch only โ€” when actively processing work, Ralph still scans immediately after each batch + +**Idle-watch vs. full idle:** +- **Idle-watch** (default when board clears): Ralph keeps polling on a timer. New work is picked up automatically. +- **Full idle** (explicit "Ralph, idle" / "stop"): Ralph fully deactivates. No polling. User must say "Ralph, go" to restart. + +``` +๐Ÿ“‹ Board is clear. Ralph is watching โ€” next check in 10 minutes. + (say "Ralph, idle" to fully stop) +``` + ### Ralph State Ralph's state is session-scoped (not persisted to disk): -- **Active/idle** โ€” whether the loop is running +- **Active/idle/watching** โ€” whether the loop is running, fully stopped, or in idle-watch polling mode - **Round count** โ€” how many check cycles completed - **Scope** โ€” what categories to monitor (default: all) +- **Poll interval** โ€” minutes between idle-watch checks (default: 10, configurable via "Ralph, check every N minutes") - **Stats** โ€” issues closed, PRs merged, items processed this session ### Ralph on the Board @@ -1441,9 +1468,13 @@ After the coordinator's step 6 ("Immediately assess: Does anything trigger follo 3. Follow-up work assessed โ†’ more agents if needed 4. Ralph scans GitHub again (Step 1) โ†’ IMMEDIATELY, no pause 5. More work found โ†’ repeat from step 2 -6. No more work โ†’ "๐Ÿ“‹ Board is clear. Ralph is idling." +6. No more work โ†’ Ralph enters **idle-watch mode**: "๐Ÿ“‹ Board is clear. Ralph is watching โ€” next check in {poll_interval} minutes." +7. After {poll_interval} minutes, Ralph automatically re-runs Step 1 +8. New work found โ†’ resume active loop from step 2 +9. Still no work โ†’ remain in idle-watch, check again after another {poll_interval} minutes +10. User says "Ralph, idle" / "stop" โ†’ fully deactivate (exit idle-watch too) -**Ralph does NOT ask "should I continue?" โ€” Ralph KEEPS GOING.** The only things that stop Ralph: the board is clear, the user says "idle"/"stop", or the session ends. +**Ralph does NOT ask "should I continue?" โ€” Ralph KEEPS GOING.** The only things that fully stop Ralph: the user says "idle"/"stop", or the session ends. A clear board does NOT stop Ralph โ€” it puts him into idle-watch polling mode. | References PR feedback, review comments, or changes requested on a PR | Spawn agent to address PR review feedback | | "merge PR #N" / "merge it" (when a PR was discussed in the last 2-3 turns) | Merge the PR via `gh pr merge` | diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 7bfa98a32..000000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,46 +0,0 @@ -# Copilot Coding Agent โ€” Squad Instructions - -You are working on a project that uses **Squad**, an AI team framework. When picking up issues autonomously, follow these guidelines. - -## Team Context - -Before starting work on any issue: - -1. Read `.ai-team/team.md` for the team roster, member roles, and your capability profile. -2. Read `.ai-team/routing.md` for work routing rules. -3. If the issue has a `squad:{member}` label, read that member's charter at `.ai-team/agents/{member}/charter.md` to understand their domain expertise and coding style โ€” work in their voice. - -## Capability Self-Check - -Before starting work, check your capability profile in `.ai-team/team.md` under the **Coding Agent โ†’ Capabilities** section. - -- **๐ŸŸข Good fit** โ€” proceed autonomously. -- **๐ŸŸก Needs review** โ€” proceed, but note in the PR description that a squad member should review. -- **๐Ÿ”ด Not suitable** โ€” do NOT start work. Instead, comment on the issue: - ``` - ๐Ÿค– This issue doesn't match my capability profile (reason: {why}). Suggesting reassignment to a squad member. - ``` - -## Branch Naming - -Use the squad branch convention: -``` -squad/{issue-number}-{kebab-case-slug} -``` -Example: `squad/42-fix-login-validation` - -## PR Guidelines - -When opening a PR: -- Reference the issue: `Closes #{issue-number}` -- If the issue had a `squad:{member}` label, mention the member: `Working as {member} ({role})` -- If this is a ๐ŸŸก needs-review task, add to the PR description: `โš ๏ธ This task was flagged as "needs review" โ€” please have a squad member review before merging.` -- Follow any project conventions in `.ai-team/decisions.md` - -## Decisions - -If you make a decision that affects other team members, write it to: -``` -.ai-team/decisions/inbox/copilot-{brief-slug}.md -``` -The Scribe will merge it into the shared decisions file. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index d966a30df..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,288 +0,0 @@ -name: Release - -# Two-phase release pipeline: -# Phase 1 ("preview") โ€” Tests, validates, builds filtered product files, pushes to `preview` branch. -# Phase 2 ("ship") โ€” Pushes preview content to main, tags, creates GitHub Release, verifies. -# -# Brady eyeballs the preview branch between phases. Nothing ships until he says go. - -on: - workflow_dispatch: - inputs: - action: - description: 'Release phase' - required: true - type: choice - options: - - preview - - ship - version: - description: 'Release version (e.g. 0.2.0) โ€” must match package.json' - required: true - type: string - -permissions: - contents: write - -# โ”€โ”€ Shared product-file allowlist (used by both preview and ship) โ”€โ”€ -# Defined as env vars so both jobs reference the same list. -env: - # Space-separated; parsed into bash arrays in steps that need them - KEEP_FILES: "index.js package.json README.md LICENSE CHANGELOG.md .gitignore .npmignore .gitattributes .github/agents/squad.agent.md" - KEEP_DIRS: "templates docs" - -jobs: - # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - # Phase 1: Preview โ€” test, validate, build preview branch - # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - - # โ”€โ”€ Gate: tests must pass before anything ships โ”€โ”€ - test: - name: Test on dev - if: github.event.inputs.action == 'preview' - runs-on: ubuntu-latest - steps: - - name: Checkout dev - uses: actions/checkout@v4 - with: - ref: dev - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.x' - - - name: Run tests - run: npm test - - # โ”€โ”€ Build preview branch โ”€โ”€ - preview: - name: Build preview branch - if: github.event.inputs.action == 'preview' - needs: test - runs-on: ubuntu-latest - steps: - - name: Checkout full repo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: dev - - - name: Validate version - id: version - run: | - VERSION="${{ github.event.inputs.version }}" - PKG_VERSION=$(node -p "require('./package.json').version") - if [ "$VERSION" != "$PKG_VERSION" ]; then - echo "::error::Version mismatch: requested=$VERSION, package.json=$PKG_VERSION" - exit 1 - fi - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "tag=v$VERSION" >> $GITHUB_OUTPUT - echo "โœ“ Version validated: $VERSION" - - - name: Build product file staging area - run: | - read -ra KEEP_FILES_ARR <<< "$KEEP_FILES" - read -ra KEEP_DIRS_ARR <<< "$KEEP_DIRS" - - STAGING=$(mktemp -d) - - for f in "${KEEP_FILES_ARR[@]}"; do - if [ -f "$f" ]; then - mkdir -p "$STAGING/$(dirname "$f")" - cp "$f" "$STAGING/$f" - fi - done - - for d in "${KEEP_DIRS_ARR[@]}"; do - if [ -d "$d" ]; then - cp -r "$d" "$STAGING/$d" - fi - done - - echo "โ”€โ”€ Staged product files โ”€โ”€" - find "$STAGING" -type f | sort - echo "STAGING=$STAGING" >> $GITHUB_ENV - - - name: Push to preview branch - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Switch to preview (create if it doesn't exist) - git checkout preview 2>/dev/null || git checkout --orphan preview - - # Remove everything in the working tree - git rm -rf . > /dev/null 2>&1 || true - rm -rf * - - # Copy staged product files into working tree - cp -r "$STAGING"/. . - - # Stage all product files - git add -A - - # Commit (always โ€” even if content matches, the preview commit message is informational) - if git diff --cached --quiet; then - echo "No changes vs. current preview โ€” content is identical" - else - git commit -m "preview: v${{ steps.version.outputs.version }}" - fi - - git push origin preview --force - echo "โœ“ Preview branch pushed โ€” ready for review" - echo "" - echo " git checkout preview # to inspect locally" - echo " Run 'ship' action when ready to release" - - # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - # Phase 2: Ship โ€” push preview โ†’ main, tag, GitHub Release - # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - - ship: - name: Ship preview to main - if: github.event.inputs.action == 'ship' - runs-on: ubuntu-latest - steps: - - name: Checkout full repo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: preview - - - name: Validate version - id: version - run: | - VERSION="${{ github.event.inputs.version }}" - PKG_VERSION=$(node -p "require('./package.json').version") - if [ "$VERSION" != "$PKG_VERSION" ]; then - echo "::error::Version mismatch: requested=$VERSION, package.json=$PKG_VERSION" - exit 1 - fi - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "tag=v$VERSION" >> $GITHUB_OUTPUT - echo "โœ“ Version validated: $VERSION" - - - name: Validate preview contains only product files - run: | - read -ra KEEP_FILES_ARR <<< "$KEEP_FILES" - read -ra KEEP_DIRS_ARR <<< "$KEEP_DIRS" - - echo "โ”€โ”€ Checking preview branch content โ”€โ”€" - FAIL=0 - while IFS= read -r file; do - ALLOWED=0 - for f in "${KEEP_FILES_ARR[@]}"; do - if [ "$file" = "$f" ]; then ALLOWED=1; break; fi - done - if [ "$ALLOWED" = "0" ]; then - for d in "${KEEP_DIRS_ARR[@]}"; do - if [[ "$file" == "$d/"* ]]; then ALLOWED=1; break; fi - done - fi - if [ "$ALLOWED" = "0" ]; then - echo "::error::Unexpected file on preview branch: $file" - FAIL=1 - fi - done < <(git ls-files) - - if [ "$FAIL" = "1" ]; then - echo "::error::Preview branch contains non-product files. Aborting." - exit 1 - fi - echo "โœ“ Preview branch contains only product files" - - - name: Push to main - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Switch to main (create if it doesn't exist) - git checkout main 2>/dev/null || git checkout --orphan main - - # Remove everything in the working tree - git rm -rf . > /dev/null 2>&1 || true - rm -rf * - - # Copy preview content into working tree - git checkout preview -- . - - # Stage all product files - git add -A - - # Only commit if there are changes - if git diff --cached --quiet; then - echo "No changes to commit โ€” main is already up to date" - else - git commit -m "release: v${{ steps.version.outputs.version }}" - fi - - # Tag the release commit on main - git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}" - - - name: Push main and tag - run: | - git push origin main - git push origin "${{ steps.version.outputs.tag }}" - - - name: Get previous tag - id: prev_tag - run: | - PREV=$(git tag --sort=-creatordate | grep '^v' | sed -n '2p') - echo "prev_tag=${PREV:-}" >> $GITHUB_OUTPUT - - - name: Create GitHub Release - uses: actions/github-script@v7 - env: - VERSION: ${{ steps.version.outputs.version }} - TAG: ${{ steps.version.outputs.tag }} - PREV_TAG: ${{ steps.prev_tag.outputs.prev_tag }} - with: - script: | - const tag = process.env.TAG; - const version = process.env.VERSION; - const prevTag = process.env.PREV_TAG; - - const body = [ - `## Install`, - '```bash', - `npx github:bradygaster/squad`, - '```', - '', - `## Upgrade`, - '```bash', - `npx github:bradygaster/squad upgrade`, - '```', - '', - `## Pin this version`, - '```bash', - `npx github:bradygaster/squad#${tag}`, - '```', - ].join('\n'); - - await github.rest.repos.createRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - tag_name: tag, - name: `Squad ${tag}`, - body: body, - draft: false, - prerelease: version.startsWith('0.'), - generate_release_notes: true, - }); - - # โ”€โ”€ Verify: confirm npx resolution works โ”€โ”€ - verify: - name: Verify release - needs: ship - runs-on: ubuntu-latest - steps: - - name: Wait for GitHub propagation - run: sleep 15 - - - name: Verify npx resolves - run: | - mkdir -p /tmp/verify-release && cd /tmp/verify-release - npx -y github:bradygaster/squad --version - echo "โœ“ Release verified" diff --git a/.github/workflows/squad-issue-assign.yml b/.github/workflows/squad-issue-assign.yml deleted file mode 100644 index 01632a5d8..000000000 --- a/.github/workflows/squad-issue-assign.yml +++ /dev/null @@ -1,133 +0,0 @@ -name: Squad Issue Assign - -on: - issues: - types: [labeled] - -permissions: - issues: write - contents: read - -jobs: - assign-work: - # Only trigger on squad:{member} labels (not the base "squad" label) - if: startsWith(github.event.label.name, 'squad:') - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Identify assigned member and trigger work - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const issue = context.payload.issue; - const label = context.payload.label.name; - - // Extract member name from label (e.g., "squad:ripley" โ†’ "ripley") - const memberName = label.replace('squad:', '').toLowerCase(); - - // Read team roster to find the member - const teamFile = '.ai-team/team.md'; - if (!fs.existsSync(teamFile)) { - core.warning('No .ai-team/team.md found โ€” cannot assign work'); - return; - } - - const content = fs.readFileSync(teamFile, 'utf8'); - const lines = content.split('\n'); - - // Check if @copilot auto-assign is enabled - const copilotAutoAssign = content.includes(''); - - // Check if this is a coding agent assignment - const isCopilotAssignment = memberName === 'copilot'; - - let assignedMember = null; - if (isCopilotAssignment) { - assignedMember = { name: '@copilot', role: 'Coding Agent' }; - } else { - let inMembersTable = false; - for (const line of lines) { - if (line.startsWith('## Members')) { - inMembersTable = true; - continue; - } - if (inMembersTable && line.startsWith('## ')) { - break; - } - if (inMembersTable && line.startsWith('|') && !line.includes('---') && !line.includes('Name')) { - const cells = line.split('|').map(c => c.trim()).filter(Boolean); - if (cells.length >= 2 && cells[0].toLowerCase() === memberName) { - assignedMember = { name: cells[0], role: cells[1] }; - break; - } - } - } - } - - if (!assignedMember) { - core.warning(`No member found matching label "${label}"`); - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: `โš ๏ธ No squad member found matching label \`${label}\`. Check \`.ai-team/team.md\` for valid member names.` - }); - return; - } - - // Auto-assign @copilot if enabled and this is a copilot assignment - if (isCopilotAssignment && copilotAutoAssign) { - try { - await github.rest.issues.addAssignees({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - assignees: ['copilot'] - }); - core.info(`Auto-assigned @copilot to issue #${issue.number}`); - } catch (err) { - core.warning(`Could not auto-assign @copilot: ${err.message}`); - } - } - - // Post assignment acknowledgment - let comment; - if (isCopilotAssignment) { - const autoAssignNote = copilotAutoAssign - ? `@copilot has been assigned and will pick this up automatically.` - : `Assign @copilot on this issue to start autonomous work.`; - - comment = [ - `### ๐Ÿค– Routed to @copilot (Coding Agent)`, - '', - `**Issue:** #${issue.number} โ€” ${issue.title}`, - '', - autoAssignNote, - '', - `> The coding agent will create a \`copilot/*\` branch and open a draft PR.`, - `> Review the PR as you would any team member's work.`, - ].join('\n'); - } else { - comment = [ - `### ๐Ÿ“‹ Assigned to ${assignedMember.name} (${assignedMember.role})`, - '', - `**Issue:** #${issue.number} โ€” ${issue.title}`, - '', - `${assignedMember.name} will pick this up in the next Copilot session.`, - '', - `> **For Copilot coding agent:** If enabled, this issue will be worked automatically.`, - `> Otherwise, start a Copilot session and say:`, - `> \`${assignedMember.name}, work on issue #${issue.number}\``, - ].join('\n'); - } - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: comment - }); - - core.info(`Issue #${issue.number} assigned to ${assignedMember.name} (${assignedMember.role})`); diff --git a/.github/workflows/squad-triage.yml b/.github/workflows/squad-triage.yml deleted file mode 100644 index fb1c3e19c..000000000 --- a/.github/workflows/squad-triage.yml +++ /dev/null @@ -1,246 +0,0 @@ -name: Squad Triage - -on: - issues: - types: [labeled] - -permissions: - issues: write - contents: read - -jobs: - triage: - if: github.event.label.name == 'squad' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Triage issue via Lead agent - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const issue = context.payload.issue; - - // Read team roster to find the Lead and all members - const teamFile = '.ai-team/team.md'; - if (!fs.existsSync(teamFile)) { - core.warning('No .ai-team/team.md found โ€” cannot triage'); - return; - } - - const content = fs.readFileSync(teamFile, 'utf8'); - const lines = content.split('\n'); - - // Check if @copilot is on the team - const hasCopilot = content.includes('๐Ÿค– Coding Agent'); - const copilotAutoAssign = content.includes(''); - - // Parse @copilot capability profile - let goodFitKeywords = []; - let needsReviewKeywords = []; - let notSuitableKeywords = []; - - if (hasCopilot) { - // Extract capability tiers from team.md - const goodFitMatch = content.match(/๐ŸŸข\s*Good fit[^:]*:\s*(.+)/i); - const needsReviewMatch = content.match(/๐ŸŸก\s*Needs review[^:]*:\s*(.+)/i); - const notSuitableMatch = content.match(/๐Ÿ”ด\s*Not suitable[^:]*:\s*(.+)/i); - - if (goodFitMatch) { - goodFitKeywords = goodFitMatch[1].toLowerCase().split(',').map(s => s.trim()); - } else { - goodFitKeywords = ['bug fix', 'test coverage', 'lint', 'format', 'dependency update', 'small feature', 'scaffolding', 'doc fix', 'documentation']; - } - if (needsReviewMatch) { - needsReviewKeywords = needsReviewMatch[1].toLowerCase().split(',').map(s => s.trim()); - } else { - needsReviewKeywords = ['medium feature', 'refactoring', 'api endpoint', 'migration']; - } - if (notSuitableMatch) { - notSuitableKeywords = notSuitableMatch[1].toLowerCase().split(',').map(s => s.trim()); - } else { - notSuitableKeywords = ['architecture', 'system design', 'security', 'auth', 'encryption', 'performance']; - } - } - - const members = []; - let inMembersTable = false; - for (const line of lines) { - if (line.startsWith('## Members')) { - inMembersTable = true; - continue; - } - if (inMembersTable && line.startsWith('## ')) { - break; - } - if (inMembersTable && line.startsWith('|') && !line.includes('---') && !line.includes('Name')) { - const cells = line.split('|').map(c => c.trim()).filter(Boolean); - if (cells.length >= 2 && cells[0] !== 'Scribe') { - members.push({ - name: cells[0], - role: cells[1] - }); - } - } - } - - // Read routing rules - const routingFile = '.ai-team/routing.md'; - let routingContent = ''; - if (fs.existsSync(routingFile)) { - routingContent = fs.readFileSync(routingFile, 'utf8'); - } - - // Find the Lead - const lead = members.find(m => - m.role.toLowerCase().includes('lead') || - m.role.toLowerCase().includes('architect') || - m.role.toLowerCase().includes('coordinator') - ); - - if (!lead) { - core.warning('No Lead role found in team roster โ€” cannot triage'); - return; - } - - // Build triage context - const memberList = members.map(m => - `- **${m.name}** (${m.role}) โ†’ label: \`squad:${m.name.toLowerCase()}\`` - ).join('\n'); - - // Determine best assignee based on issue content and routing - const issueText = `${issue.title}\n${issue.body || ''}`.toLowerCase(); - - let assignedMember = null; - let triageReason = ''; - let copilotTier = null; - - // First, evaluate @copilot fit if enabled - if (hasCopilot) { - const isNotSuitable = notSuitableKeywords.some(kw => issueText.includes(kw)); - const isGoodFit = !isNotSuitable && goodFitKeywords.some(kw => issueText.includes(kw)); - const isNeedsReview = !isNotSuitable && !isGoodFit && needsReviewKeywords.some(kw => issueText.includes(kw)); - - if (isGoodFit) { - copilotTier = 'good-fit'; - assignedMember = { name: '@copilot', role: 'Coding Agent' }; - triageReason = '๐ŸŸข Good fit for @copilot โ€” matches capability profile'; - } else if (isNeedsReview) { - copilotTier = 'needs-review'; - assignedMember = { name: '@copilot', role: 'Coding Agent' }; - triageReason = '๐ŸŸก Routing to @copilot (needs review) โ€” a squad member should review the PR'; - } else if (isNotSuitable) { - copilotTier = 'not-suitable'; - // Fall through to normal routing - } - } - - // If not routed to @copilot, use keyword-based routing - if (!assignedMember) { - for (const member of members) { - const role = member.role.toLowerCase(); - if ((role.includes('frontend') || role.includes('ui')) && - (issueText.includes('ui') || issueText.includes('frontend') || - issueText.includes('css') || issueText.includes('component') || - issueText.includes('button') || issueText.includes('page') || - issueText.includes('layout') || issueText.includes('design'))) { - assignedMember = member; - triageReason = 'Issue relates to frontend/UI work'; - break; - } - if ((role.includes('backend') || role.includes('api') || role.includes('server')) && - (issueText.includes('api') || issueText.includes('backend') || - issueText.includes('database') || issueText.includes('endpoint') || - issueText.includes('server') || issueText.includes('auth'))) { - assignedMember = member; - triageReason = 'Issue relates to backend/API work'; - break; - } - if ((role.includes('test') || role.includes('qa') || role.includes('quality')) && - (issueText.includes('test') || issueText.includes('bug') || - issueText.includes('fix') || issueText.includes('regression') || - issueText.includes('coverage'))) { - assignedMember = member; - triageReason = 'Issue relates to testing/quality work'; - break; - } - if ((role.includes('devops') || role.includes('infra') || role.includes('ops')) && - (issueText.includes('deploy') || issueText.includes('ci') || - issueText.includes('pipeline') || issueText.includes('docker') || - issueText.includes('infrastructure'))) { - assignedMember = member; - triageReason = 'Issue relates to DevOps/infrastructure work'; - break; - } - } - } - - // Default to Lead if no routing match - if (!assignedMember) { - assignedMember = lead; - triageReason = 'No specific domain match โ€” assigned to Lead for further analysis'; - } - - const isCopilot = assignedMember.name === '@copilot'; - const assignLabel = isCopilot ? 'squad:copilot' : `squad:${assignedMember.name.toLowerCase()}`; - - // Add the member-specific label - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - labels: [assignLabel] - }); - - // Auto-assign @copilot if enabled - if (isCopilot && copilotAutoAssign) { - try { - await github.rest.issues.addAssignees({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - assignees: ['copilot'] - }); - } catch (err) { - core.warning(`Could not auto-assign @copilot: ${err.message}`); - } - } - - // Build copilot evaluation note - let copilotNote = ''; - if (hasCopilot && !isCopilot) { - if (copilotTier === 'not-suitable') { - copilotNote = `\n\n**@copilot evaluation:** ๐Ÿ”ด Not suitable โ€” issue involves work outside the coding agent's capability profile.`; - } else { - copilotNote = `\n\n**@copilot evaluation:** No strong capability match โ€” routed to squad member.`; - } - } - - // Post triage comment - const comment = [ - `### ๐Ÿ—๏ธ Squad Triage โ€” ${lead.name} (${lead.role})`, - '', - `**Issue:** #${issue.number} โ€” ${issue.title}`, - `**Assigned to:** ${assignedMember.name} (${assignedMember.role})`, - `**Reason:** ${triageReason}`, - copilotTier === 'needs-review' ? `\nโš ๏ธ **PR review recommended** โ€” a squad member should review @copilot's work on this one.` : '', - copilotNote, - '', - `---`, - '', - `**Team roster:**`, - memberList, - hasCopilot ? `- **@copilot** (Coding Agent) โ†’ label: \`squad:copilot\`` : '', - '', - `> To reassign, remove the current \`squad:*\` label and add the correct one.`, - ].filter(Boolean).join('\n'); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: comment - }); - - core.info(`Triaged issue #${issue.number} โ†’ ${assignedMember.name} (${assignLabel})`); diff --git a/.github/workflows/sync-squad-labels.yml b/.github/workflows/sync-squad-labels.yml deleted file mode 100644 index 67b730732..000000000 --- a/.github/workflows/sync-squad-labels.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: Sync Squad Labels - -on: - push: - paths: - - '.ai-team/team.md' - workflow_dispatch: - -permissions: - issues: write - contents: read - -jobs: - sync-labels: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Parse roster and sync labels - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const teamFile = '.ai-team/team.md'; - - if (!fs.existsSync(teamFile)) { - core.info('No .ai-team/team.md found โ€” skipping label sync'); - return; - } - - const content = fs.readFileSync(teamFile, 'utf8'); - const lines = content.split('\n'); - - // Parse the Members table for agent names - const members = []; - let inMembersTable = false; - for (const line of lines) { - if (line.startsWith('## Members')) { - inMembersTable = true; - continue; - } - if (inMembersTable && line.startsWith('## ')) { - break; - } - if (inMembersTable && line.startsWith('|') && !line.includes('---') && !line.includes('Name')) { - const cells = line.split('|').map(c => c.trim()).filter(Boolean); - if (cells.length >= 2 && cells[0] !== 'Scribe') { - members.push({ - name: cells[0], - role: cells[1] - }); - } - } - } - - core.info(`Found ${members.length} squad members: ${members.map(m => m.name).join(', ')}`); - - // Check if @copilot is on the team - const hasCopilot = content.includes('๐Ÿค– Coding Agent'); - - // Define label color palette for squad labels - const SQUAD_COLOR = '6366f1'; - const MEMBER_COLOR = '3b82f6'; - const COPILOT_COLOR = '10b981'; - - // Ensure the base "squad" triage label exists - const labels = [ - { name: 'squad', color: SQUAD_COLOR, description: 'Squad triage inbox โ€” Lead will assign to a member' } - ]; - - for (const member of members) { - labels.push({ - name: `squad:${member.name.toLowerCase()}`, - color: MEMBER_COLOR, - description: `Assigned to ${member.name} (${member.role})` - }); - } - - // Add @copilot label if coding agent is on the team - if (hasCopilot) { - labels.push({ - name: 'squad:copilot', - color: COPILOT_COLOR, - description: 'Assigned to @copilot (Coding Agent) for autonomous work' - }); - } - - // Sync labels (create or update) - for (const label of labels) { - try { - await github.rest.issues.getLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: label.name - }); - // Label exists โ€” update it - await github.rest.issues.updateLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: label.name, - color: label.color, - description: label.description - }); - core.info(`Updated label: ${label.name}`); - } catch (err) { - if (err.status === 404) { - // Label doesn't exist โ€” create it - await github.rest.issues.createLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: label.name, - color: label.color, - description: label.description - }); - core.info(`Created label: ${label.name}`); - } else { - throw err; - } - } - } - - core.info(`Label sync complete: ${labels.length} labels synced`); diff --git a/README.md b/README.md index b05d7c074..98b4b05da 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ [![Status](https://img.shields.io/badge/status-experimental-blueviolet)](#status) [![Platform](https://img.shields.io/badge/platform-GitHub%20Copilot-blue)](#how-it-works) +๐Ÿ“ฃ **[Join the Squad Community](docs/community.md)** โ€” meet contributors, see deployments, share your work. + --- ## What is Squad? @@ -30,13 +32,25 @@ git init npx github:bradygaster/squad ``` -### 3. Open Copilot and go +### 3. Authenticate with GitHub (for Issues, PRs, and Ralph) + +```bash +gh auth login +``` + +If you plan to use [Project Boards](docs/features/project-boards.md), add the `project` scope: + +```bash +gh auth refresh -s project +``` + +### 4. Open Copilot and go ``` copilot ``` -Select **Squad** from the `/agents` list, then: +Select **Squad (vX.Y.Z)** from the `/agents` list, then: ``` I'm starting a new project. Set up the team. @@ -304,6 +318,8 @@ The coordinator checks for open `squad:{member}` issues at session start and wil npx github:bradygaster/squad ``` +> **Appears to hang?** npm resolves `github:` packages via `git+ssh://`. If no SSH agent is running, git prompts for your key passphrase โ€” but npm's progress spinner hides the prompt. Fix: start your SSH agent first (`ssh-add`), or run with `npx --progress=false github:bradygaster/squad` to reveal the prompt. See [Troubleshooting](docs/scenarios/troubleshooting.md) for more. + See [Quick Start](#quick-start) for the full walkthrough. ### Upgrade @@ -323,7 +339,9 @@ This overwrites `squad.agent.md`, `.ai-team-templates/`, and squad workflow file - **Experimental** โ€” API and file formats may change between versions - **Node 22+** โ€” requires Node.js 22.0.0 or later (`engines` field enforced) - **GitHub Copilot CLI** โ€” Squad runs on GitHub Copilot; no other runtimes are supported +- **`gh` CLI required** โ€” GitHub Issues, PRs, Ralph, and Project Boards all need `gh auth login`. Project Boards additionally require `gh auth refresh -s project` - **Knowledge grows with use** โ€” the first session is the least capable; agents improve as they accumulate history +- **SSH agent required for install** โ€” `npx github:bradygaster/squad` resolves via `git+ssh://`. If no SSH agent is running, npm's progress spinner hides git's passphrase prompt, making install appear frozen. Fix: start your SSH agent first (`ssh-add`), or use `npx --progress=false github:bradygaster/squad`. See [#30](https://github.com/bradygaster/squad/issues/30) --- diff --git a/docs/README.md b/docs/README.md index d5d36ba43..71f8b4117 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,14 +9,33 @@ Public-facing documentation for Squad. GitHub Pages ready. ## Feature Reference -- [Export & Import](features/export-import.md) โ€” Portable team snapshots +### Core +- [Team Setup](features/team-setup.md) โ€” Init mode, first session, team creation +- [Work Routing](features/routing.md) โ€” How work gets assigned to agents +- [Parallel Execution](features/parallel-execution.md) โ€” Background vs sync, fan-out +- [Response Modes](features/response-modes.md) โ€” Tiered response speed/depth +- [Memory System](features/memory.md) โ€” How agents learn and remember +- [Directives](features/directives.md) โ€” Capturing team rules and preferences +- [Reviewer Protocol](features/reviewer-protocol.md) โ€” Rejection lockout and revision routing + +### Workflow - [GitHub Issues Mode](features/github-issues.md) โ€” Issue-driven development - [PRD Mode](features/prd-mode.md) โ€” Product requirements decomposition +- [Labels & Triage](features/labels.md) โ€” go:/release:/type:/priority: taxonomy +- [Ralph โ€” Work Monitor](features/ralph.md) โ€” Autonomous backlog processing +- [Project Boards](features/project-boards.md) โ€” GitHub Projects V2 integration + +### Team - [Human Team Members](features/human-team-members.md) โ€” Mixed AI/human teams +- [@copilot Coding Agent](features/copilot-coding-agent.md) โ€” Autonomous issue agent - [Skills System](features/skills.md) โ€” Earned knowledge with confidence lifecycle - [Ceremonies](features/ceremonies.md) โ€” Team meetings and rituals -- [Response Modes](features/response-modes.md) โ€” Tiered response speed/depth -- [Memory System](features/memory.md) โ€” How agents learn and remember +- [Notifications](features/notifications.md) โ€” Ping via Teams/MCP + +### Infrastructure +- [Per-Agent Model Selection](features/model-selection.md) โ€” Cost-first model routing +- [Git Worktrees](features/worktrees.md) โ€” Multi-branch team state +- [Export & Import](features/export-import.md) โ€” Portable team snapshots ## Walkthroughs @@ -25,8 +44,28 @@ Public-facing documentation for Squad. GitHub Pages ready. ## Scenarios +### Getting Started - [Starting a New Project](scenarios/new-project.md) โ€” Greenfield setup - [Adding to an Existing Repo](scenarios/existing-repo.md) โ€” Drop Squad into existing code +- [Mid-Project Onboarding](scenarios/mid-project.md) โ€” Adding Squad halfway through - [Upgrading Squad](scenarios/upgrading.md) โ€” Update to the latest version -- [Moving a Team](scenarios/team-portability.md) โ€” Export and import between repos + +### Team Management +- [Solo Developer](scenarios/solo-dev.md) โ€” Is Squad overkill for one person? +- [Mixed Human + AI Team](scenarios/team-of-humans.md) โ€” Humans and agents working together +- [Keeping Your Squad](scenarios/keep-my-squad.md) โ€” Persistence across projects +- [Combining Old Squads](scenarios/multiple-squads.md) โ€” Cherry-picking from multiple teams + +### Project Types +- [Large Codebases](scenarios/large-codebase.md) โ€” Will Squad choke on a big repo? +- [Monorepos](scenarios/monorepo.md) โ€” Multiple services, one squad +- [Open Source Projects](scenarios/open-source.md) โ€” Triage, contributors, community + +### Operations - [Issue-Driven Development](scenarios/issue-driven-dev.md) โ€” End-to-end issue workflow +- [CI/CD Integration](scenarios/ci-cd-integration.md) โ€” Squad + GitHub Actions +- [Moving a Team](scenarios/team-portability.md) โ€” Export and import between repos +- [Team State Storage](scenarios/team-state-storage.md) โ€” Gitignore, submodules, branches, and more +- [Model Selection Strategies](scenarios/switching-models.md) โ€” Budget vs quality tradeoffs +- [Privacy & Security](scenarios/private-repos.md) โ€” What stays private +- [Disaster Recovery](scenarios/disaster-recovery.md) โ€” When things go wrong diff --git a/docs/community.md b/docs/community.md new file mode 100644 index 000000000..16639d597 --- /dev/null +++ b/docs/community.md @@ -0,0 +1,67 @@ +# Squad Community + +Squad is built by contributors who believe in democratizing multi-agent development. This page recognizes everyone who shapes the project โ€” through code, feedback, ideas, and engagement. + +## Project Metrics + +[![GitHub stars](https://img.shields.io/github/stars/bradygaster/squad?style=flat-square&logo=github)](https://github.com/bradygaster/squad/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/bradygaster/squad?style=flat-square&logo=github)](https://github.com/bradygaster/squad/network/members) +[![GitHub issues](https://img.shields.io/github/issues/bradygaster/squad?style=flat-square&logo=github)](https://github.com/bradygaster/squad/issues) +[![GitHub pull requests](https://img.shields.io/github/issues-pr/bradygaster/squad?style=flat-square&logo=github)](https://github.com/bradygaster/squad/pulls) + +## How to Contribute + +We welcome contributions in all forms: + +### Report Issues +Found a bug, have a feature request, or want to discuss an idea? [Open an issue](https://github.com/bradygaster/squad/issues). + +### Submit a Pull Request +Ready to contribute code? [Check out the open issues](https://github.com/bradygaster/squad/issues) and submit a PR. + +### Join the Discussion +Have questions, want to share how you're using Squad, or discuss the roadmap? [Start a discussion](https://github.com/bradygaster/squad/discussions). + +### External Deployments & Case Studies +Deploy Squad on your project and share your experience. These real-world deployments inform our roadmap and help the community learn from each other. + +## Contributors + +This section recognizes people who have contributed to Squad through code, feedback, deployments, and community engagement. + +### Core Team + +- **Brady** ([@bradygaster](https://github.com/bradygaster)) โ€” Project founder, architecture and vision + +### Community Contributors + +We recognize contributions including: +- Issue reports and feature requests +- Pull requests and code reviews +- Real-world deployments and case studies +- Feedback and community engagement +- Content (blog posts, videos, documentation) + +## Special Recognition + +### Early Deployments + +- **Shayne Boyer** ([@spboyer](https://github.com/spboyer)) โ€” First external deployment on a Next.js project. Introduced the `squad:` label convention for GitHub-native routing. + +### Video Coverage + +- **Jeff Fritz** ([@csharpfritz](https://github.com/csharpfritz)) โ€” ["Introducing your AI Dev Team Squad with GitHub Copilot"](https://www.youtube.com/watch?v=TXcL-te7ByY). First public technical deep-dive video demonstrating Squad in action. + +## Giving Back + +If you're using Squad, consider: +- Starring the repository โ€” helps others discover the project +- Sharing your experience in an issue or discussion +- Contributing improvements back to the community +- Showcasing your deployment or use case + +## Contact & Support + +- **Issues & Feature Requests:** [GitHub Issues](https://github.com/bradygaster/squad/issues) +- **Discussion & Questions:** [GitHub Discussions](https://github.com/bradygaster/squad/discussions) +- **Security Issues:** Report privately via GitHub Security Advisory diff --git a/docs/features/ceremonies.md b/docs/features/ceremonies.md index 0811dc1bb..6386d83b0 100644 --- a/docs/features/ceremonies.md +++ b/docs/features/ceremonies.md @@ -89,3 +89,35 @@ The ceremony remains enabled for future tasks. - Retros produce decisions that get written to `decisions.md` โ€” they improve future work, not just diagnose the current failure. - Ceremony config lives in `.ai-team/ceremonies.md`. You can edit it directly if you prefer. - Ceremonies work well with [human team members](human-team-members.md) โ€” add a human as a participant for approval gates. + +## Sample Prompts + +``` +run a design review before we start +``` + +Manually triggers a design review ceremony for the current task. + +``` +run a retro on why those tests failed +``` + +Starts a retrospective to analyze test failures and capture learnings. + +``` +add a ceremony for security reviews +``` + +Creates a custom ceremony type with its own triggers and participants. + +``` +skip the design review for this quick fix +``` + +Bypasses the design review ceremony for the current task only. + +``` +disable automatic retros +``` + +Turns off auto-triggering for retrospectives while keeping the ceremony defined. diff --git a/docs/features/copilot-coding-agent.md b/docs/features/copilot-coding-agent.md index 6c97fd1a8..04787ea54 100644 --- a/docs/features/copilot-coding-agent.md +++ b/docs/features/copilot-coding-agent.md @@ -181,3 +181,35 @@ This file is **upgraded automatically** when you run `squad upgrade` and `@copil - Use auto-assign for repos where you want fully autonomous issue processing. - The coding agent works great alongside [issue-driven development](../scenarios/issue-driven-dev.md) โ€” label issues `squad` and the Lead + @copilot handle the rest. - @copilot's PRs go through normal review โ€” treat them like any team member's work. + +## Sample Prompts + +``` +add copilot to the squad with auto-assign enabled +``` + +Adds @copilot to the roster and configures automatic issue assignment. + +``` +what's copilot's capability profile? +``` + +Shows which task types are marked as good fit, needs review, or not suitable for @copilot. + +``` +reassign issue #42 from copilot to Kane +``` + +Routes an issue away from @copilot to a different squad member. + +``` +bump refactoring to good fit for copilot +``` + +Updates the capability profile to mark refactoring tasks as automatically routable to @copilot. + +``` +review copilot's PR on #56 +``` + +Spawns the appropriate squad member to review @copilot's pull request. diff --git a/docs/features/directives.md b/docs/features/directives.md new file mode 100644 index 000000000..98d5aad9d --- /dev/null +++ b/docs/features/directives.md @@ -0,0 +1,160 @@ +# Directives + +A directive is a preference, rule, or constraint the team remembers across sessions. When you say "always do X" or "never do Y", Squad captures it as a directive, writes it to the decisions inbox, and the Scribe merges it into `.ai-team/decisions.md` โ€” the team's permanent memory. + +## How Directives Work + +1. **Signal Word Detection** โ€” The coordinator listens for: "always", "never", "from now on", "remember to", "don't", "make sure to". +2. **Capture** โ€” Directive is written to `.ai-team/decisions/inbox/{timestamp}-{brief-slug}.md`. +3. **Scribe Merge** โ€” Scribe consolidates inbox files into `decisions.md` during the next coordination cycle. +4. **Agent Awareness** โ€” All agents read `decisions.md` before starting work. Directives shape behavior. + +## Signal Words + +| Phrase | Example | +|--------|---------| +| "always" | "Always use TypeScript strict mode" | +| "never" | "Never commit directly to main" | +| "from now on" | "From now on, prefix all commits with the issue number" | +| "remember to" | "Remember to run tests before pushing" | +| "don't" | "Don't use var โ€” only let and const" | +| "make sure to" | "Make sure to document all public APIs" | + +## Directive Scope + +Directives can apply to: + +- **Coding style** โ€” Formatting, naming conventions, language features +- **Tool preferences** โ€” Linters, formatters, test runners +- **Workflow rules** โ€” Branch naming, commit messages, PR templates +- **Scope constraints** โ€” "Don't touch legacy/ directory", "Only work on v2 features" +- **Review requirements** โ€” "Always have Lead review security changes" + +## Examples + +> "Always use single quotes for strings in TypeScript" + +**Captured:** +```markdown +# Single Quotes for Strings +Date: 2024-01-15 +Scope: TypeScript code + +Use single quotes for string literals. Avoid double quotes unless escaping is required. +``` + +> "Never deploy on Fridays" + +**Captured:** +```markdown +# No Friday Deploys +Date: 2024-01-15 +Scope: Release process + +Do not trigger production deploys on Fridays. Schedule for Monday-Thursday only. +``` + +> "From now on, all API endpoints need integration tests" + +**Captured:** +```markdown +# API Integration Test Coverage +Date: 2024-01-15 +Scope: Testing + +Every new API endpoint requires at least one integration test covering the happy path and one error case. +``` + +## Decisions Inbox + +New directives land in `.ai-team/decisions/inbox/` as individual files: + +``` +.ai-team/decisions/inbox/ +โ”œโ”€โ”€ 2024-01-15-1420-single-quotes.md +โ”œโ”€โ”€ 2024-01-15-1435-no-friday-deploys.md +โ””โ”€โ”€ 2024-01-15-1450-api-test-coverage.md +``` + +The Scribe periodically consolidates these into `decisions.md`: + +```markdown +# Team Decisions + +## Coding Style + +### Single Quotes for Strings +Use single quotes for string literals in TypeScript. Avoid double quotes unless escaping is required. + +## Testing + +### API Integration Test Coverage +Every new API endpoint requires at least one integration test covering the happy path and one error case. + +## Release Process + +### No Friday Deploys +Do not trigger production deploys on Fridays. Schedule for Monday-Thursday only. +``` + +## Directive Conflicts + +When a new directive contradicts an existing one: + +1. **Scribe detects conflict** โ€” Checks for semantic overlap during merge. +2. **User prompt** โ€” "New directive conflicts with existing rule: {old rule}. Replace, merge, or skip?" +3. **Resolution** โ€” Scribe updates `decisions.md` based on your choice. + +## Viewing Directives + +> "Show me the team directives" + +Coordinator displays `decisions.md` content. + +> "What's our rule on testing?" + +Coordinator searches `decisions.md` for testing-related directives. + +## Removing Directives + +> "Remove the no-Friday-deploy rule" + +Scribe edits `decisions.md` and removes that section. + +Or edit `.ai-team/decisions.md` directly. + +## Agent Directive Compliance + +Agents are not hard-constrained by directives โ€” they're context-aware guidelines. If an agent violates a directive: + +- **Reviewer rejection** โ€” Lead or Tester flags it during review. +- **User feedback** โ€” You say "this violates our style rule" and the agent revises. + +Directives shape behavior but don't replace code review or linting. + +## Sample Prompts + +``` +Always use Prettier with single quotes and no semicolons +``` +Creates a coding style directive. All agents will format code accordingly. + +``` +Never use `any` type in TypeScript โ€” always define explicit types +``` +Establishes a type safety directive. Agents will avoid `any` and use proper types. + +``` +From now on, all commit messages must follow Conventional Commits format +``` +Sets a workflow directive. Agents will format commits as `feat:`, `fix:`, `docs:`, etc. + +``` +Remember to update the CHANGELOG.md for every user-facing change +``` +Creates a release process directive. Agents will add changelog entries when appropriate. + +``` +Make sure all security-related PRs are reviewed by Lead before merging +``` +Establishes a review requirement. Coordinator will route security PRs to Lead for approval. diff --git a/docs/features/export-import.md b/docs/features/export-import.md index cfa644d93..e05cb9a14 100644 --- a/docs/features/export-import.md +++ b/docs/features/export-import.md @@ -76,3 +76,35 @@ Imported agents bring their skills and general knowledge without assuming your p - The export file is JSON โ€” you can inspect it to see exactly what your team knows. - Imported agents retain their names and universe. They won't be renamed. - Commit your `.ai-team/` directory after importing so the team is available to everyone who clones the repo. + +## Sample Prompts + +``` +export the current team +``` + +Creates a `squad-export.json` snapshot of the entire team in the current directory. + +``` +import squad-export.json into this repo +``` + +Imports a team snapshot into the current project's `.ai-team/` directory. + +``` +what was included in that export? +``` + +Shows a summary of what data was captured in the most recent export file. + +``` +export just the team state, not the full history +``` + +Creates a lightweight export with agent charters and skills but minimal history. + +``` +import with --force and archive the current team +``` + +Overwrites the existing `.ai-team/` directory after archiving it as a backup. diff --git a/docs/features/github-issues.md b/docs/features/github-issues.md index 682481dac..9522d6ea4 100644 --- a/docs/features/github-issues.md +++ b/docs/features/github-issues.md @@ -111,3 +111,35 @@ Squad refreshes the backlog and shows remaining open issues. - You don't need to assign issues to specific agents โ€” Squad routes based on domain expertise. - If `gh` isn't authenticated, Squad will tell you. Run `gh auth login` first. - See [GitHub Issues Walkthrough](../tour-github-issues.md) for a step-by-step tour. + +## Sample Prompts + +``` +connect to bradygaster/squad +``` + +Links Squad to a GitHub repository for issue-driven development. + +``` +show the backlog +``` + +Fetches and displays all open issues from the connected repository. + +``` +work on issue #23 +``` + +Routes the issue to the appropriate agent who creates a branch, implements, and opens a PR. + +``` +work on all issues labeled "bug" +``` + +Processes multiple issues in parallel based on label filtering. + +``` +what's left in the backlog? +``` + +Refreshes the issue list and shows remaining open work items. diff --git a/docs/features/human-team-members.md b/docs/features/human-team-members.md index 97f6cb7d8..0f159148a 100644 --- a/docs/features/human-team-members.md +++ b/docs/features/human-team-members.md @@ -69,3 +69,35 @@ Their entry moves to `.ai-team/agents/_alumni/`. They can be re-added later. - Use human members for approval gates โ€” design review, compliance, final sign-off. - Human members work well alongside [ceremonies](ceremonies.md) โ€” add a human as a required participant in a design review ceremony. - You're the relay. Squad can't message humans directly โ€” it tells you, and you coordinate. + +## Sample Prompts + +``` +add Maria as security reviewer +``` + +Adds a human team member with a specific review responsibility. + +``` +route this auth work to Jordan for approval +``` + +Assigns a task to a human team member for external handling. + +``` +Jordan approved the design โ€” we can proceed +``` + +Unblocks work that was waiting on human input. + +``` +who's on the roster? +``` + +Shows all team members including both AI agents and human members. + +``` +remove Sarah from the team +``` + +Moves a human team member to the alumni list. diff --git a/docs/features/labels.md b/docs/features/labels.md new file mode 100644 index 000000000..f7601c2dc --- /dev/null +++ b/docs/features/labels.md @@ -0,0 +1,131 @@ +# Label Taxonomy + +Squad uses a structured, namespaced label system to drive workflow automation. Labels are not just tags โ€” they're the state machine. Five namespaces define issue lifecycle, priority, ownership, and release targeting. + +## The Five Namespaces + +| Namespace | Purpose | Values | Mutual Exclusivity | +|-----------|---------|--------|-------------------| +| `go:` | Verdict โ€” yes/no/needs-research | `go:yes`, `go:no`, `go:needs-research` | โœ… One per issue | +| `release:` | Release target | `release:v0.4.0`, `release:v0.5.0`, `release:backlog` | โœ… One per issue | +| `type:` | Issue category | `type:feature`, `type:bug`, `type:spike`, `type:docs`, `type:chore`, `type:epic` | โœ… One per issue | +| `priority:` | Urgency level | `priority:p0`, `priority:p1`, `priority:p2` | โœ… One per issue | +| `squad:{member}` | Agent assignment | `squad:fenster`, `squad:mcmanus`, `squad:hockney` | โŒ Can have multiple (pair work) | + +## Mutual Exclusivity Rules + +Within `go:`, `release:`, `type:`, and `priority:` namespaces, **only one label is allowed**. Applying a second label in the same namespace auto-removes the first. + +Example: +- Issue has `go:needs-research` +- You apply `go:yes` +- Result: `go:needs-research` removed, `go:yes` applied + +The `squad:{member}` namespace allows **multiple labels** for collaborative work: +- `squad:fenster` + `squad:hockney` = pair programming or handoff + +## Workflow Automation + +Labels drive four automation layers: + +### 1. Enforcement (Mutual Exclusivity) + +GitHub Actions workflow `label-enforcement.yml` watches for label changes. If multiple labels from the same namespace are applied, it removes all but the most recent. + +### 2. Sync (Cross-Namespace Consistency) + +Some label changes trigger cascading updates: +- `go:no` applied โ†’ auto-adds `release:backlog`, removes other release targets +- `priority:p0` applied โ†’ ensures `go:yes` is set (p0 implies approved) + +### 3. Triage (Auto-Assignment) + +Ralph (work monitor) uses labels to route work: +- `squad:fenster` โ†’ Fenster picks it up +- No `squad:*` + `type:bug` โ†’ Routes to Tester or Lead based on routing.md +- `go:needs-research` โ†’ Routes to Lead for investigation + +### 4. Heartbeat (Periodic Check) + +The `squad-heartbeat.yml` workflow runs every 30 minutes and: +- Finds issues with `squad` label but no `squad:{member}` โ†’ auto-triages +- Finds `go:yes` + `squad:{member}` but no assignee โ†’ spawns agent +- Finds stale `go:needs-research` (>7 days) โ†’ escalates to Lead + +## State Machine Flow + +``` +New issue โ†’ squad label โ†’ Triage + โ†“ + Lead assigns go:* + type:* + priority:* + โ†“ + go:yes โ†’ squad:{member} assigned + โ†“ + Agent works โ†’ Draft PR + โ†“ + Review โ†’ Approved + โ†“ + Merge โ†’ Issue closed +``` + +## Adding Labels + +Labels are created automatically during `init` or `upgrade`. To add custom labels: + +```bash +gh label create "squad:designer" --color "0366d6" --description "Work assigned to Designer" +``` + +Or via the GitHub UI: Issues โ†’ Labels โ†’ New label + +## Label Colors + +Squad uses a consistent color scheme: + +| Namespace | Color | Hex | +|-----------|-------|-----| +| `go:` | Green (yes), Red (no), Yellow (research) | `#0e8a16`, `#d73a4a`, `#fbca04` | +| `release:` | Blue | `#0366d6` | +| `type:` | Purple | `#6f42c1` | +| `priority:` | Orange (p0), Yellow (p1), Gray (p2) | `#d93f0b`, `#fbca04`, `#d4c5f9` | +| `squad:{member}` | Teal | `#008672` | + +## Querying by Label + +```bash +# All approved features for v0.4.0 +gh issue list --label "go:yes,release:v0.4.0,type:feature" + +# All p0 bugs assigned to Fenster +gh issue list --label "priority:p0,type:bug,squad:fenster" + +# All issues needing research +gh issue list --label "go:needs-research" +``` + +## Sample Prompts + +``` +Mark issue #42 as approved for v0.4.0 +``` +Applies `go:yes` and `release:v0.4.0` labels. Removes any conflicting labels. + +``` +Change issue #15 from needs-research to no +``` +Updates verdict: removes `go:needs-research`, applies `go:no`, adds `release:backlog`. + +``` +Assign issue #28 to Fenster and Hockney for pair work +``` +Applies `squad:fenster` and `squad:hockney` labels. Both agents can pick it up. + +``` +List all p0 features approved for the next release +``` +Queries: `priority:p0 + type:feature + go:yes + release:{current milestone}`. + +``` +Show me all issues in the backlog +``` +Filters for `release:backlog` or `go:no` labels. diff --git a/docs/features/memory.md b/docs/features/memory.md index ca03fbb2d..3a54b45e5 100644 --- a/docs/features/memory.md +++ b/docs/features/memory.md @@ -102,3 +102,35 @@ Skills differ from decisions โ€” decisions are project policies ("use PostgreSQL - If an agent keeps making the same mistake, check `decisions.md` โ€” the relevant convention might be missing. - You can edit `decisions.md` and `history.md` files directly. They're plain Markdown. - The first session is always the least capable. Give the team a few sessions to build up context. + +## Sample Prompts + +``` +what does Kane remember about the authentication system? +``` + +Queries a specific agent's personal history for relevant context. + +``` +show me the team decisions about API design +``` + +Searches the shared decisions.md file for a particular topic. + +``` +what happened in the last session? +``` + +Reviews session history and recent agent learnings. + +``` +always use single quotes in TypeScript +``` + +Adds a directive to the shared decisions that all agents will follow. + +``` +search past decisions for database choices +``` + +Finds historical decisions related to a specific topic or keyword. diff --git a/docs/features/model-selection.md b/docs/features/model-selection.md index c37465270..f33382d47 100644 --- a/docs/features/model-selection.md +++ b/docs/features/model-selection.md @@ -59,3 +59,35 @@ Tell the coordinator what you want: - `"use opus for this"` โ€” one-off premium - `"always use haiku"` โ€” session-wide cost savings - `"use gpt-5.2-codex for Fenster"` โ€” agent-specific override + +## Sample Prompts + +``` +use opus for this architecture work +``` + +Override to premium model for a single high-stakes task. + +``` +always use haiku to save costs +``` + +Set session-wide preference for the cheapest model tier. + +``` +what model did Kane use for that last task? +``` + +Check which model was actually used for a completed task. + +``` +use gpt-5.2-codex for all backend work +``` + +Set a specific model for tasks in a particular domain. + +``` +switch back to automatic model selection +``` + +Clear any session-wide overrides and return to task-aware auto-selection. diff --git a/docs/features/notifications.md b/docs/features/notifications.md new file mode 100644 index 000000000..0799b573f --- /dev/null +++ b/docs/features/notifications.md @@ -0,0 +1,393 @@ +# Squad Pings You + +Your squad can send you instant messages when they need your input. Leave your terminal, get pinged on your phone. + +--- + +## How It Works + +Squad ships zero notification infrastructure. Instead, it uses **skills** โ€” reusable knowledge files โ€” to teach agents when and how to ping you. You bring your own notification delivery by configuring an MCP notification server in your Copilot environment. + +The flow: +1. **Skill** (`human-notification`) tells agents when to ping โ€” blocked waiting for input, decision needed, error hit, work complete +2. **Agent** calls the skill, which invokes your configured MCP server +3. **Your MCP server** (Teams, iMessage, Discord, webhook, etc.) sends the actual message to your device + +This means Squad works with any notification service. Pick your favorite messaging platform, configure it once, and your squad has a direct line to you. + +--- + +## Quick Start: Teams (Simplest Path) + +### Option A: Teams Incoming Webhook (No Auth Setup) + +Teams webhooks are the fastest setup โ€” just a URL. + +1. **In Teams, create a channel for your squad:** + - Create a new Team called "My Squads" (or reuse an existing one) + - Add a channel, e.g., `#squad-myproject` + +2. **Set up the webhook:** + - Right-click the channel โ†’ "Manage channel" โ†’ "Connectors" + - Search "Incoming Webhook" โ†’ "Configure" + - Give it a name (e.g., "Squad Notifications") + - Copy the webhook URL + +3. **Configure Squad:** + - Create or edit `.vscode/mcp.json` in your workspace: + ```json + { + "mcpServers": { + "notifications": { + "command": "node", + "args": ["path/to/teams-webhook-mcp.js"], + "env": { + "TEAMS_WEBHOOK_URL": "https://outlook.webhook.office.com/webhookb2/..." + } + } + } + } + ``` + +4. **Use it:** + - Start a Squad session with `copilot squad` + - When an agent needs input, your Teams channel lights up + +### Option B: Microsoft's Official Teams MCP Server (Full Auth) + +For integration with your Azure tenant and full Teams API access: + +1. **Register an Azure AD app:** + - Go to https://portal.azure.com โ†’ "Azure Active Directory" โ†’ "App registrations" + - New registration: name it "Squad Notifications" + - Copy the **Application (client) ID** + +2. **Set up credentials:** + - "Certificates & secrets" โ†’ "New client secret" + - Copy the secret value + +3. **Grant permissions:** + - "API permissions" โ†’ "Add a permission" โ†’ "Microsoft Graph" + - Add `Chat.Send`, `ChannelMessage.Send` + - Grant admin consent + +4. **Configure Squad:** + - Install Microsoft's Teams MCP server: https://github.com/microsoft/IF-MCP-Server-for-Microsoft-Teams + - Configure in `.vscode/mcp.json`: + ```json + { + "mcpServers": { + "teams": { + "command": "node", + "args": ["path/to/teams-mcp.js"], + "env": { + "AZURE_CLIENT_ID": "your-client-id", + "AZURE_CLIENT_SECRET": "your-secret", + "AZURE_TENANT_ID": "your-tenant-id" + } + } + } + } + ``` + +--- + +## Quick Start: iMessage (Mac Only) + +iMessage is built into macOS. If you're on a Mac, this is the fastest personal setup. + +1. **Check requirements:** + - macOS with Messages.app + - Copilot running on the same Mac + - System allows Copilot to control Messages (grant permission when prompted) + +2. **Install the iMessage MCP server:** + - Get it from https://mcpmarket.com/server/imessage + - Follow its setup steps + +3. **Configure Squad:** + - Edit `.vscode/mcp.json`: + ```json + { + "mcpServers": { + "imessage": { + "command": "node", + "args": ["path/to/imessage-mcp.js"], + "env": { + "IMESSAGE_TARGET": "your-phone-number-or-email" + } + } + } + } + ``` + +4. **Test:** + - Start a Squad session + - When agents need input, it appears in Messages on your phone + +**Limitation:** iMessage only works on Mac. If you use Windows, Linux, or CI environments, use Teams or webhook instead. + +--- + +## Quick Start: Discord + +Discord is flexible and works everywhere (web, mobile, desktop). + +### Option A: Using mcp-notifications (Simplest) + +https://github.com/zudsniper/mcp-notifications supports Discord, Slack, Teams, and custom webhooks. + +1. **Get your Discord webhook:** + - In Discord, right-click a channel โ†’ "Edit channel" โ†’ "Integrations" โ†’ "Webhooks" + - "New Webhook" โ†’ name it "Squad" + - Copy the webhook URL + +2. **Configure Squad:** + ```json + { + "mcpServers": { + "notifications": { + "command": "node", + "args": ["path/to/mcp-notifications.js"], + "env": { + "DISCORD_WEBHOOK_URL": "https://discord.com/api/webhooks/..." + } + } + } + } + ``` + +### Option B: Using Discord Official MCP + +For more advanced Discord integrations, search Discord's MCP marketplace. + +--- + +## Quick Start: Custom Webhook + +For any HTTP endpoint (custom service, Zapier, IFTTT, etc.): + +1. **Get your webhook URL** from your service + +2. **Use mcp-notifications or build a thin wrapper:** + ```json + { + "mcpServers": { + "notifications": { + "command": "node", + "args": ["path/to/webhook-mcp.js"], + "env": { + "WEBHOOK_URL": "https://your-service.com/notify" + } + } + } + } + ``` + +3. **Your endpoint receives POST:** + ```json + { + "agent": "Keaton", + "message": "Blocked: waiting for your decision on architecture approach", + "context": { + "reason": "decision_needed", + "issue": "123", + "link": "https://github.com/..." + } + } + ``` + +--- + +## What Triggers a Notification + +Agents ping you when: + +| Trigger | Example | +|---------|---------| +| **Blocked on input** | "Keaton needs your decision on which API approach to use (Issue #42)" | +| **Decision needed** | "Verbal hit a design choice and needs your call on error handling strategy" | +| **Error hit** | "McManus got an authentication error and needs credentials for the staging API" | +| **Work complete** | "Fenster finished the test suite โ€” 142 tests passing, 3 flaky (check the logs)" | +| **Review feedback** | "Your PR review on #78 needs a response before Keaton can merge" | + +You control which triggers send notifications (see Configuration below). + +--- + +## Notification Format + +Notifications are **agent-branded, context-rich, and actionable.** + +Example notification message: + +``` +๐Ÿ—๏ธ Keaton needs your input + +Blocked: Design decision required for API error handling strategy. +Follow the conversation in Issue #42. + +โ†’ Review issue: github.com/myorg/myrepo/issues/42 +``` + +Another example: + +``` +โœ… Fenster finished the test suite + +142 tests passing. 3 marked as flaky โ€” review them in the terminal output. + +Session still running. Come back to the terminal to decide next steps. +``` + +**Anatomy:** +- **Agent emoji + name** โ€” who pinged you (matches your squad's cast) +- **Context** โ€” why (decision, blocked, complete, etc.) +- **What to do** โ€” specific action (check issue, review logs, come back to terminal) +- **Link** โ€” clickable GitHub issue, PR, or breadcrumb to your session + +--- + +## Configuration + +### Choosing What Triggers Notifications + +By default, agents ping on all triggers. To be selective, set environment variables: + +```json +{ + "mcpServers": { + "notifications": { + "env": { + "NOTIFY_BLOCKED": "true", + "NOTIFY_DECISION": "true", + "NOTIFY_ERROR": "false", + "NOTIFY_COMPLETE": "false" + } + } + } +} +``` + +This is useful if you only care about being pinged when blocked (not for every decision or completion). + +### Quiet Hours (Optional) + +If your MCP server supports it, configure quiet hours to suppress notifications during off-hours: + +```json +{ + "env": { + "QUIET_HOURS_START": "18:00", + "QUIET_HOURS_END": "09:00", + "QUIET_HOURS_TZ": "America/New_York" + } +} +``` + +During quiet hours, notifications queue locally and are batched into a morning digest instead of waking you up. + +### Testing Your Setup + +To test without running a full Squad session: + +```bash +# Once your MCP server is configured, trigger a test notification: +copilot squad test-notification --agent Keaton --reason blocked +``` + +This fires a sample notification through your configured server so you can verify delivery and formatting. + +--- + +## Troubleshooting + +### Notifications aren't arriving + +1. **Verify the MCP server is running:** + - Check your `.vscode/mcp.json` syntax + - Restart Copilot + +2. **Check the webhook URL:** + - Paste the URL in your browser (or `curl`). If it 404s, the webhook is invalid or expired. + - For Teams/Discord webhooks, regenerate them if they're old + +3. **Verify environment variables:** + - Ensure all secrets (API keys, webhook URLs) are set in your shell before starting Copilot + - Copilot reads `.vscode/mcp.json` at startup โ€” changes require a restart + +4. **Check agent logs:** + - In your Squad session, ask agents to log the notification call: `check the human-notification skill logs` + - This surfaces any errors from the MCP server + +### Notifications are too frequent + +Use the `NOTIFY_*` environment variables (see Configuration above) to disable notifications for non-critical triggers like `NOTIFY_COMPLETE` or `NOTIFY_DECISION`. + +### Wrong channel or user receiving notifications + +- **Teams webhook:** Ensure the webhook points to the correct channel +- **iMessage:** Verify the `IMESSAGE_TARGET` phone number or email matches your device +- **Discord:** Double-check the webhook URL points to your intended channel + +### "MCP server failed to start" + +1. Ensure the MCP server command in `.vscode/mcp.json` points to a valid executable +2. Check that all `env` variables are set and accessible +3. Review the Copilot startup logs for the actual error + +--- + +## Architecture Notes + +The `human-notification` skill lives in `.ai-team/skills/squad-human-notification/SKILL.md`. Agents read it before working and decide whether to ping you. You can edit the skill directly if you want to: + +- Add custom notification logic for your team +- Change when agents decide to ping (e.g., always notify on errors) +- Add metadata to notifications (e.g., priority levels) + +For advanced use cases, you can also: + +- Create a custom MCP server that combines multiple notification channels (Teams + Slack) +- Route notifications based on agent and trigger type (errors to you, completions to your manager) +- Add intelligent rate limiting (don't ping for 30 minutes if already pinged once) + +--- + +## See Also + +- [Skills System](./skills.md) โ€” learn how skills encode reusable knowledge +- [Copilot Environment Setup](../guide.md) โ€” how to configure `.vscode/mcp.json` +- [Model Selection](./model-selection.md) โ€” customize agent behavior per role + +## Sample Prompts + +``` +configure Teams webhook for notifications +``` + +Guides you through setting up Microsoft Teams as the notification channel. + +``` +test my notification setup +``` + +Sends a sample notification to verify your MCP server configuration is working. + +``` +disable completion notifications +``` + +Configures the notification system to only ping on blocks and errors, not completions. + +``` +what's my current notification status? +``` + +Shows which notification triggers are enabled and what channel is configured. + +``` +set quiet hours from 6pm to 9am +``` + +Configures the notification system to queue messages during off-hours instead of sending immediately. diff --git a/docs/features/parallel-execution.md b/docs/features/parallel-execution.md new file mode 100644 index 000000000..d870a1020 --- /dev/null +++ b/docs/features/parallel-execution.md @@ -0,0 +1,153 @@ +# Parallel Execution + +Squad runs agents in parallel whenever possible. The fan-out pattern launches all independent agents simultaneously, waits for results, then proceeds โ€” no sequential bottlenecks unless data dependencies or reviewer gates require them. + +## How Parallel Execution Works + +When the coordinator receives work: + +1. **Dependency Analysis** โ€” Check if tasks have data dependencies (A needs output from B). +2. **Fan-Out** โ€” Launch all independent agents in parallel using `mode: "background"`. +3. **Wait** โ€” Coordinator polls agent status until all complete. +4. **Collect** โ€” Aggregate results, check for errors, route to next step. + +### Example: Feature Implementation + +> "Implement user authentication: API endpoints, frontend form, tests, and documentation" + +Coordinator spawns **4 agents in parallel**: +- Backend โ†’ API endpoints +- Frontend โ†’ Login/signup form +- Tester โ†’ Integration tests +- DevRel โ†’ Auth documentation + +All work simultaneously. No agent waits for another unless there's a code dependency. + +## Background vs Sync Mode + +| Mode | When to Use | Behavior | +|------|-------------|----------| +| `background` | Independent work, no data dependencies | Agent runs in parallel, coordinator polls for completion | +| `sync` | Data dependency (one agent needs output from another) | Agent runs sequentially, coordinator waits | +| `sync` | Reviewer gate (Lead must approve before continuing) | Agent runs, coordinator waits for review decision | + +### Background Mode + +Used for **fan-out parallelism**: + +``` +Coordinator โ†’ [Agent1, Agent2, Agent3] (background) + โ†“ โ†“ โ†“ + Result1 Result2 Result3 + โ†“ โ†“ โ†“ + Coordinator collects all +``` + +Agents don't see each other's output until the coordinator collects and synthesizes. + +### Sync Mode + +Used for **dependencies and gates**: + +``` +Coordinator โ†’ Agent1 (sync) โ†’ Result1 + โ†“ + Coordinator โ†’ Agent2 (sync, uses Result1) โ†’ Result2 + โ†“ + Coordinator โ†’ Reviewer (sync, gates next step) +``` + +Each step blocks until the previous completes. + +## Eager Execution Philosophy + +Squad's default is **eager parallelism** โ€” launch everything that can run, let the coordinator handle synchronization. Benefits: + +- **Faster throughput** โ€” No artificial sequencing. +- **Better resource utilization** โ€” Multiple agents saturate available compute. +- **Resilient to blocking** โ€” If one agent stalls, others keep working. + +Trade-off: Increased API cost (multiple agents running simultaneously). If cost is a concern, tell the coordinator: + +> "Work sequentially to save costs" + +Coordinator switches to sync mode for all agents. + +## Deadlock Avoidance + +When agents have circular dependencies: + +- **Agent A** needs output from **Agent B** +- **Agent B** needs output from **Agent A** + +The coordinator detects the cycle during dependency analysis and prompts: + +``` +โš ๏ธ Circular dependency detected: A โ†” B +Choose resolution: +1. Run A first, then B +2. Run B first, then A +3. Redesign to remove dependency +``` + +## Reviewer Gates + +Some tasks require **sequential review**: + +1. Agent writes code โ†’ Draft PR +2. Lead reviews โ†’ Approves or rejects +3. If approved โ†’ Merge and close +4. If rejected โ†’ Reassign or escalate (agent is **locked out**) + +This is a **sync gate** โ€” the next step cannot proceed until the reviewer completes. + +## Parallel Execution Logs + +The coordinator logs parallel execution in `.ai-team/orchestration-log/`: + +``` +[2024-01-15 14:30:00] FAN-OUT: Spawning 4 agents (Backend, Frontend, Tester, DevRel) +[2024-01-15 14:30:15] AGENT: Backend started (background) +[2024-01-15 14:30:16] AGENT: Frontend started (background) +[2024-01-15 14:30:17] AGENT: Tester started (background) +[2024-01-15 14:30:18] AGENT: DevRel started (background) +[2024-01-15 14:35:42] COLLECT: Backend completed (success) +[2024-01-15 14:36:10] COLLECT: Frontend completed (success) +[2024-01-15 14:36:55] COLLECT: DevRel completed (success) +[2024-01-15 14:38:20] COLLECT: Tester completed (success) +[2024-01-15 14:38:21] FAN-IN: All agents complete +``` + +## Parallel Limits + +The coordinator respects concurrency limits to avoid rate limits or resource exhaustion: + +- **Default:** 5 agents in parallel +- **Adjustable:** `"Run at most 3 agents at once"` โ†’ Coordinator batches work in groups of 3 + +## Sample Prompts + +``` +Build the new dashboard feature โ€” everyone work in parallel +``` +Coordinator spawns all relevant agents (Frontend, Backend, Tester, DevRel) simultaneously. + +``` +Implement the API first, then write tests โ€” do it sequentially +``` +Forces sync mode: Backend runs, completes, then Tester starts. + +``` +Work on issues #12, #15, and #18 at the same time +``` +Spawns 3 agents in parallel, one per issue. Assumes no dependencies between issues. + +``` +Run at most 2 agents at once to save costs +``` +Sets concurrency limit. Coordinator batches work: runs 2, waits for completion, runs next 2. + +``` +Why is Tester waiting? Show me the dependency graph. +``` +Coordinator explains why Tester is blocked (e.g., waiting for Backend to finish implementation). diff --git a/docs/features/prd-mode.md b/docs/features/prd-mode.md index 8a5437d7b..600b7a1cb 100644 --- a/docs/features/prd-mode.md +++ b/docs/features/prd-mode.md @@ -71,3 +71,35 @@ Work already completed isn't undone. Only the remaining backlog changes. - The Lead handles decomposition โ€” you don't need to break down the spec yourself. - Dependencies are respected automatically. You won't see an agent start on a dependent task before its prerequisite is done. - Combine with [GitHub Issues Mode](github-issues.md) to create GitHub issues from work items. + +## Sample Prompts + +``` +read the PRD at docs/product-spec.md and break it into work items +``` + +Ingests a product requirements document and creates a prioritized, dependency-tracked backlog. + +``` +show me the work items +``` + +Displays the current backlog with priorities, assignments, and dependencies. + +``` +the PRD has been updated โ€” re-read docs/product-spec.md +``` + +Re-ingests the PRD and adjusts the backlog based on changes without undoing completed work. + +``` +start working on approved P0 items +``` + +Begins parallel execution of all high-priority work items with no blockers. + +``` +which work items are blocked right now? +``` + +Shows which tasks are waiting on dependencies or other blocking conditions. diff --git a/docs/features/project-boards.md b/docs/features/project-boards.md new file mode 100644 index 000000000..679cf3a4b --- /dev/null +++ b/docs/features/project-boards.md @@ -0,0 +1,143 @@ +# Project Boards + +Squad integrates with GitHub Projects V2 for visual workflow tracking. Boards are **one-way projections** of the label-based state machine โ€” labels are the source of truth, boards visualize it. Squad uses the `gh project` CLI (GraphQL-only) for board operations. + +## Prerequisites + +GitHub Projects V2 access requires the `project` scope: + +```bash +gh auth refresh -s project +``` + +Verify: + +```bash +gh auth status +``` + +You should see `โœ“ Token scopes: repo, project, workflow` (or similar). + +## How It Works + +Squad treats labels as the state machine and boards as a **read-mostly visualization**: + +1. **Labels drive state** โ€” Issue gets `go:yes` + `squad:fenster` โ†’ state changes to "In Progress". +2. **Board updates** โ€” Squad syncs label changes to the project board automatically. +3. **Board changes propagate** โ€” If you drag an issue to "Done" on the board, Squad applies the corresponding label (`status:done`). + +Labels are authoritative. Boards reflect labels, not the other way around. + +## Board Structure + +Squad's default board has 5 columns matching issue lifecycle: + +| Column | Label State | Description | +|--------|-------------|-------------| +| **Backlog** | `go:no` or `release:backlog` | Not approved or deferred | +| **Needs Research** | `go:needs-research` | Lead is investigating feasibility | +| **Ready** | `go:yes`, no `squad:*` | Approved, awaiting assignment | +| **In Progress** | `go:yes` + `squad:{member}` | Agent actively working | +| **Done** | Issue closed | Completed and merged | + +## Creating a Board + +> "Create a project board for this repository" + +Squad runs: + +```bash +gh project create --owner {org} --title "Squad Board" --format "Board" +``` + +Then adds the 5 default columns and syncs all existing issues based on their labels. + +## Syncing Labels to Board + +Squad's `sync-board.yml` workflow runs: +- **On label change** โ€” Issue labeled `go:yes` โ†’ moves to "Ready" column +- **On issue close** โ†’ moves to "Done" column +- **On PR merge** โ†’ linked issue moves to "Done" +- **On schedule** (every 30 min) โ€” full board resync to catch any drift + +### Manual Sync + +```bash +gh project item-list --owner {org} --project {project-id} +# For each item, check label state and update column +``` + +## Board-to-Label Sync + +When you manually move an issue on the board: + +1. **Board webhook triggers** โ€” GitHub sends `projects_v2_item.moved` event +2. **Squad workflow runs** โ€” Reads new column, infers label change +3. **Labels update** โ€” Applies appropriate `go:*`, `squad:*`, or `status:*` label + +Example: +- Drag issue from "Backlog" to "Ready" โ†’ Squad applies `go:yes` +- Drag issue from "Ready" to "In Progress" โ†’ Squad prompts: "Assign to which member?" then applies `squad:{member}` + +## Board CLI Commands + +| Command | What it does | +|---------|--------------| +| `gh project list --owner {org}` | List all projects in org/repo | +| `gh project view {id}` | Show project board layout | +| `gh project item-add {id} --url {issue-url}` | Add issue to board | +| `gh project item-delete {id} --item-id {item}` | Remove issue from board | +| `gh project field-list {id}` | List custom fields (Status, Priority, etc.) | + +**Note:** `gh project` uses GraphQL, not REST. All operations are against the Projects V2 API. + +## Custom Fields + +You can add custom fields to the board (Assignee, Priority, Release): + +```bash +gh project field-create {id} --name "Priority" --data-type "SINGLE_SELECT" --options "P0,P1,P2" +``` + +Squad syncs these from labels: +- `priority:p0` โ†’ Board "Priority" field = "P0" +- `release:v0.4.0` โ†’ Board "Release" field = "v0.4.0" + +## Current Status + +GitHub Projects V2 integration is **planned for v0.4.0**. Current capabilities: + +- โœ… Label-based state machine (fully implemented) +- โœ… CLI access via `gh project` (prerequisite met) +- ๐Ÿšง Automated board sync workflows (in development) +- ๐Ÿšง Bidirectional sync (board โ†’ labels) (in development) +- โŒ Custom field mapping (not yet implemented) + +You can manually use `gh project` commands now. Full automation arrives in v0.4.0. + +## Sample Prompts + +``` +Create a project board for Squad work +``` +Initializes a new GitHub Projects V2 board with default columns and syncs existing issues. + +``` +Move issue #42 to In Progress +``` +Updates board column and applies `squad:{member}` label (prompts for member if not set). + +``` +Sync all issues to the project board +``` +Re-scans all open issues, updates board columns based on current label state. + +``` +Add a custom Priority field to the board +``` +Creates a custom field on the project board and maps it to `priority:*` labels. + +``` +Show me the board status โ€” how many issues in each column? +``` +Queries the project board and displays issue count per column (Backlog, Ready, In Progress, Done). diff --git a/docs/features/ralph.md b/docs/features/ralph.md index 1de2bae15..1cc75ece9 100644 --- a/docs/features/ralph.md +++ b/docs/features/ralph.md @@ -2,6 +2,42 @@ Ralph is a built-in squad member whose job is keeping tabs on work. Like Scribe tracks decisions, **Ralph tracks and drives the work queue**. He's always on the roster โ€” not cast from a universe โ€” and has one job: make sure the team never sits idle when there's work to do. +## Prerequisites + +Ralph requires access to GitHub Issues and Pull Requests via the `gh` CLI. **A GitHub PAT (Personal Access Token) with Classic scope is required.** + +### Why PAT Classic? + +The default `GITHUB_TOKEN` provided by Copilot does not have sufficient scopes to read and write GitHub Issues and PRs. Ralph needs to: +- List and read issues +- Create and update issue labels and assignments +- Read and interact with pull requests +- Report on CI status + +### Setup + +1. **Create a PAT Classic token:** + - Go to https://github.com/settings/tokens + - Click "Generate new token (classic)" + - Select scopes: `repo` and `project` (full access to repositories and projects) + - Copy the token + +2. **Authenticate with `gh`:** + ```bash + gh auth login + ``` + - Select "GitHub.com" + - Select "HTTPS" for protocol + - When asked "Authenticate Git with your GitHub credentials?", answer "Yes" + - Choose "Paste an authentication token" and paste your PAT Classic token + +3. **Verify authentication:** + ```bash + gh auth status + ``` + +Once authenticated, Ralph can monitor your repository's issues and PRs. + ## How It Works Once activated, Ralph continuously checks for pending work โ€” open issues, draft PRs, review feedback, CI failures โ€” and keeps the squad moving through the backlog without manual nudges. @@ -14,9 +50,9 @@ When you're in a Copilot session, Ralph self-chains the coordinator's work loop: 2. Ralph checks GitHub for more: untriaged issues, assigned-but-unstarted items, draft PRs, failing CI 3. Work found โ†’ triage, assign, spawn agents 4. Results collected โ†’ Ralph checks again **immediately** โ€” no pause, no asking permission -5. Board clear โ†’ Ralph idles +5. Board clear โ†’ Ralph enters **idle-watch** โ€” polls every 10 minutes (configurable) for new work -**Ralph never stops on his own while work remains.** He keeps cycling through the backlog until every issue is closed, every PR is merged, and CI is green. The only things that stop Ralph: the board is clear, you say "idle", or the session ends. +**Ralph never stops on his own while work remains.** He keeps cycling through the backlog until every issue is closed, every PR is merged, and CI is green. When the board clears, Ralph doesn't fully stop โ€” he enters idle-watch mode and periodically checks for new work. The only things that fully stop Ralph: you say "idle"/"stop", or the session ends. ### Between Sessions (GitHub Actions Heartbeat) @@ -36,7 +72,8 @@ This creates a fully autonomous loop for `@copilot` โ€” heartbeat triages โ†’ as | "Ralph, go" / "Ralph, start monitoring" | Activates the work-check loop | | "Keep working" / "Work until done" | Activates Ralph | | "Ralph, status" / "What's on the board?" | Runs one check cycle, reports results | -| "Ralph, idle" / "Take a break" | Stops the loop | +| "Ralph, check every N minutes" | Sets the idle-watch polling interval (e.g., "Ralph, check every 30 minutes") | +| "Ralph, idle" / "Take a break" | Fully stops the loop and idle-watch polling | | "Ralph, scope: just issues" | Monitors only issues, skips PRs/CI | ## What Ralph Monitors @@ -61,7 +98,43 @@ Ralph doesn't run silently forever. Every 3-5 rounds, Ralph reports and **keeps Continuing... (say "Ralph, idle" to stop) ``` -Ralph does **not** ask permission to continue โ€” he keeps working. The only things that stop Ralph: the board is clear, you say "idle"/"stop", or the session ends. +Ralph does **not** ask permission to continue โ€” he keeps working. The only things that fully stop Ralph: you say "idle"/"stop", or the session ends. A clear board puts Ralph into idle-watch mode, not full stop. + +## Idle-Watch Mode + +When the board clears, Ralph doesn't fully stop. He enters **idle-watch** โ€” a polling mode that automatically re-checks for new work on a timer. + +``` +๐Ÿ“‹ Board is clear. Ralph is watching โ€” next check in 10 minutes. + (say "Ralph, idle" to fully stop) +``` + +### How it works + +1. Board clears โ†’ Ralph enters idle-watch +2. After {poll_interval} minutes (default: 10), Ralph re-scans GitHub +3. New work found โ†’ resumes the active work loop automatically +4. Still no work โ†’ waits another {poll_interval} minutes and checks again +5. Repeats until you say "Ralph, idle" or the session ends + +### Configuring the interval + +You can adjust the polling interval at any time: + +| What you say | Interval | +|---|---| +| "Ralph, check every 5 minutes" | 5 min | +| "Ralph, check every 15 minutes" | 15 min | +| "Ralph, poll every 30 minutes" | 30 min | + +The default is **10 minutes**. The interval only affects idle-watch โ€” when actively processing work, Ralph scans immediately after each batch. + +### Idle-watch vs. full idle + +| Mode | Behavior | How to enter | +|---|---|---| +| **Idle-watch** | Polls for new work every N minutes | Automatic when board clears | +| **Full idle** | Completely stopped, no polling | Say "Ralph, idle" or "stop" | ## Ralph's Board View @@ -100,7 +173,39 @@ on: ## Notes -- Ralph is session-scoped โ€” his state (active/idle, round count, stats) resets each session +- Ralph is session-scoped โ€” his state (active/idle/watching, round count, poll interval, stats) resets each session - Ralph appears on the roster like Scribe: `| Ralph | Work Monitor | โ€” | ๐Ÿ”„ Monitor |` - Ralph is exempt from universe casting โ€” always "Ralph" - The heartbeat workflow is the between-session complement to in-session Ralph + +## Sample Prompts + +``` +Ralph, go โ€” start monitoring and process the backlog until it's clear +``` + +Activates Ralph's self-chaining work loop to continuously process all pending work. + +``` +Ralph, status +``` + +Runs a single check cycle and shows the current board state without activating the work loop. + +``` +Ralph, check every 5 minutes +``` + +Changes the idle-watch polling interval from the default 10 minutes to 5 minutes. + +``` +Ralph, scope: just issues +``` + +Configures Ralph to monitor only issues and skip PRs and CI status checks. + +``` +Ralph, idle +``` + +Fully stops Ralph's work loop and idle-watch polling until manually reactivated. diff --git a/docs/features/response-modes.md b/docs/features/response-modes.md index ec14bfa81..15a1c3e23 100644 --- a/docs/features/response-modes.md +++ b/docs/features/response-modes.md @@ -83,3 +83,35 @@ You don't need to specify a mode. When uncertain, the coordinator biases toward - "Team, ..." prompts typically trigger Full mode. - Direct-named agent prompts ("Kane, ...") typically trigger Standard mode. - Response times depend on the Copilot platform. The numbers above are approximate. + +## Sample Prompts + +``` +force lightweight mode for this quick fix +``` + +Explicitly requests a reduced-context spawn for a simple task. + +``` +what port does the API run on? +``` + +Quick factual question that triggers Direct mode with no agent spawn. + +``` +Kane, do a thorough analysis of the auth system +``` + +Requests Standard mode with full context load for complex work. + +``` +what response mode was used for that last task? +``` + +Checks which mode the coordinator selected for the previous request. + +``` +Team, rebuild the authentication system end-to-end +``` + +Multi-domain prompt that triggers Full mode with parallel agent spawns. diff --git a/docs/features/reviewer-protocol.md b/docs/features/reviewer-protocol.md new file mode 100644 index 000000000..7c6a9272b --- /dev/null +++ b/docs/features/reviewer-protocol.md @@ -0,0 +1,142 @@ +# Reviewer Rejection Protocol + +When a reviewer (Lead, Tester) rejects an agent's work, the agent is **locked out** from self-revising. This prevents endless fix-retry loops and forces human oversight or escalation. The protocol ensures rejected work doesn't slip through without proper review. + +## How It Works + +1. **Agent submits work** โ€” Creates draft PR, requests review from Lead or Tester. +2. **Reviewer evaluates** โ€” Checks code quality, test coverage, adherence to directives. +3. **Reviewer decision:** + - **Approve** โ†’ PR merges, issue closes, agent unlocked. + - **Request changes** โ†’ Agent is **locked out**, work routes to another agent or escalates. + +## Strict Lockout + +Once a reviewer rejects work, the **original agent cannot revise their own submission**. This is a hard constraint: + +- Agent A writes code โ†’ Lead rejects +- Agent A **cannot** fix and resubmit +- Coordinator must **reassign** to Agent B or **escalate** to user + +### Why Lockout? + +Without lockout: +- Agent A writes buggy code +- Lead rejects: "This has race conditions" +- Agent A fixes, resubmits +- Lead rejects again: "Still broken" +- Agent A fixes, resubmits +- Infinite loop, no progress + +With lockout: +- Agent A writes buggy code +- Lead rejects: "This has race conditions" +- Agent A **locked out** +- Coordinator assigns Agent B (fresh perspective) or escalates to user +- Work gets done or human intervenes + +## Reassign vs. Escalate + +When rejection happens, coordinator has two options: + +| Option | When to Use | How It Works | +|--------|-------------|--------------| +| **Reassign** | Another agent has the skill | Route work to different squad member with relevant expertise | +| **Escalate** | No other agent fits, or multiple rejections | Notify user, ask for manual intervention or guidance | + +### Reassign Example + +1. Fenster (Frontend) writes a React component โ†’ Lead rejects: "Accessibility issues" +2. Fenster locked out +3. Coordinator checks skills: Hockney (Frontend) has accessibility expertise +4. Work reassigned to Hockney +5. Hockney fixes and resubmits + +### Escalate Example + +1. Backend writes API logic โ†’ Tester rejects: "Integration tests fail" +2. Backend locked out +3. Coordinator reassigns to Core Dev โ†’ Core Dev also fails review +4. Core Dev locked out +5. **All agents exhausted** โ†’ Coordinator escalates to user: "Issue #42 rejected twice. Need guidance or manual fix." + +## Lockout Scope and Duration + +| Scope | Duration | +|-------|----------| +| **Task-specific** | Lockout applies to the specific PR/issue, not all work | +| **Session-persistent** | Lockout survives session restarts (stored in `.ai-team/orchestration-log/`) | +| **Clearable** | User can manually unlock: "Unlock Fenster for issue #42" | + +An agent locked out of issue #42 can still work on issue #43, #44, etc. Lockout is not a global ban. + +## Deadlock Handling + +If **all capable agents are locked out**: + +1. Coordinator detects deadlock: no available agents for work. +2. Coordinator escalates to user: "All agents locked out for issue #42. Options: 1) Manual fix, 2) Unlock an agent and provide guidance, 3) Close as won't-fix." +3. User chooses resolution. + +This prevents the team from getting stuck in a state where no one can proceed. + +## Reviewer Authority + +Only **designated reviewers** can lock out agents: + +| Reviewer | Authority | Scope | +|----------|-----------|-------| +| **Lead** | Code quality, architecture, security | All code submissions | +| **Tester** | Test coverage, correctness | Test-related changes | +| **User (you)** | Final arbiter | Can override any decision | + +Other agents (Frontend, Backend, DevRel) cannot lock out peers. + +## Unlocking an Agent + +> "Unlock Fenster for issue #42" + +Coordinator clears the lockout. Fenster can now revise the PR. Use this when: + +- Reviewer feedback was unclear, you've provided better guidance +- Agent legitimately misunderstood requirements +- External factors (API change, dependency update) invalidated the original rejection + +## Lockout Logs + +Lockouts are recorded in `.ai-team/orchestration-log/`: + +``` +[2024-01-15 15:45:30] REVIEW: Lead rejected PR #12 (author: Fenster) +[2024-01-15 15:45:31] LOCKOUT: Fenster locked out for issue #42 +[2024-01-15 15:45:35] REASSIGN: Issue #42 โ†’ Hockney (accessibility expertise) +[2024-01-15 16:20:10] REVIEW: Lead approved PR #13 (author: Hockney) +[2024-01-15 16:20:11] UNLOCK: Fenster unlocked (issue #42 resolved) +``` + +## Sample Prompts + +``` +Lead, review PR #15 +``` +Triggers review. Lead evaluates code and either approves (merge + unlock) or rejects (lockout original author). + +``` +Why is Fenster locked out? +``` +Coordinator explains: "Fenster was locked out for issue #42 after Lead rejected PR #15 due to security concerns." + +``` +Unlock Fenster for issue #42 โ€” I've given him better guidance +``` +Clears lockout. Fenster can now revise the PR with your additional context. + +``` +Reassign issue #42 from Fenster to Hockney +``` +Manual reassignment. Fenster remains locked out, Hockney takes over the work. + +``` +Escalate issue #42 to me โ€” the team is stuck +``` +Coordinator notifies you of deadlock or repeated rejections. You provide manual intervention or guidance. diff --git a/docs/features/routing.md b/docs/features/routing.md new file mode 100644 index 000000000..360ac060c --- /dev/null +++ b/docs/features/routing.md @@ -0,0 +1,147 @@ +# Work Routing + +The coordinator decides who handles each piece of work using a three-layer routing system: named routing (explicit assignments), domain routing (pattern matching), and skill-aware routing (capability checking). The goal: get work to the right agent without manual triage overhead. + +## Routing Strategies + +### 1. Named Routing + +You explicitly name who should do the work: + +> "Fenster, fix the login validation bug" + +Coordinator assigns directly to Fenster. No lookup required. + +### 2. Domain Routing + +The coordinator checks `.ai-team/routing.md` for pattern matches: + +```markdown +## Routing Table + +| Pattern | Owner | Reason | +|---------|-------|--------| +| `src/api/**` | Backend | API implementation | +| `src/components/**/*.tsx` | Frontend | React components | +| `*.test.ts` | Tester | Test files | +| `docs/**` | DevRel | Documentation | +| `package.json`, `tsconfig.json` | Lead | Config changes | +``` + +When work involves `src/api/auth.ts`, it routes to Backend automatically. + +### 3. Skill-Aware Routing + +If no domain match, the coordinator checks `.ai-team/skills/` for capability fit: + +```markdown +# authentication.md +Members with authentication expertise: +- Backend (OAuth, JWT, session management) +- Lead (security review, architecture) +``` + +Work tagged with authentication routes to Backend or Lead based on task type (implementation vs. review). + +## The Routing Table + +`.ai-team/routing.md` is the canonical routing manifest. It's structured as: + +```markdown +# Work Routing + +Default assignments for common patterns. + +## Routing Table + +| Pattern | Owner | Reason | +|---------|-------|--------| +| `src/frontend/**` | Frontend | UI implementation | +| `src/backend/**` | Backend | Server logic | +| `*.test.js` | Tester | Test coverage | +| `README.md`, `docs/**` | DevRel | User-facing docs | +| `.github/workflows/**` | Lead | CI/CD config | + +## Fallback + +If no match: route to Lead for triage. +``` + +## Adding Routing Rules + +Tell the coordinator: + +> "From now on, route all database migrations to Backend" + +Coordinator adds to routing.md: + +```markdown +| `migrations/**`, `*.sql` | Backend | Database schema changes | +``` + +Or edit `.ai-team/routing.md` directly. + +## Routing Ambiguity + +When multiple patterns match: + +1. **Most specific wins** โ€” `src/api/auth.ts` matches both `src/api/**` and `src/**`, but `src/api/**` is more specific. +2. **Named > Domain > Skill** โ€” Explicit assignment always overrides pattern matching. +3. **Fallback to Lead** โ€” If no clear owner, route to Lead for triage. + +## Issue Label Routing + +GitHub issues with `squad:{member}` labels route directly: + +- `squad:fenster` โ†’ Fenster picks it up +- `squad:mcmanus` โ†’ McManus handles it +- No `squad:*` label โ†’ Coordinator triages and assigns + +Ralph (the work monitor) uses this to auto-assign based on routing rules. + +## Multi-Agent Work + +Some tasks require multiple agents: + +> "Fenster, implement the API. Hockney, write the tests." + +Coordinator spawns both agents in parallel. They work independently and coordinate via the shared `.ai-team/` state. + +## Routing Logs + +The coordinator logs routing decisions to `.ai-team/orchestration-log/`: + +``` +[2024-01-15 14:23:10] ROUTE: Issue #42 โ†’ Backend (pattern: src/api/**) +[2024-01-15 14:24:05] ROUTE: Issue #43 โ†’ Lead (no match, fallback) +[2024-01-15 14:25:30] ROUTE: "Fenster, fix bug" โ†’ Fenster (named) +``` + +Useful for debugging why work went to a specific agent. + +## Sample Prompts + +``` +Route all CSS files to Frontend +``` +Adds a routing rule: `*.css` โ†’ Frontend. + +``` +Who handles authentication work? +``` +Coordinator checks routing.md and skills/authentication.md, reports the responsible agent(s). + +``` +From now on, McManus reviews all user-facing documentation before merge +``` +Creates a routing rule + directive: docs/** routes to McManus for review. + +``` +Why did issue #42 go to Backend? +``` +Coordinator explains the routing decision based on pattern match or skill fit. + +``` +Fenster, implement the new search API. Hockney, write integration tests for it. +``` +Named routing to two agents. Both spawn in parallel. diff --git a/docs/features/skills.md b/docs/features/skills.md index 790c6f066..ffb9189e6 100644 --- a/docs/features/skills.md +++ b/docs/features/skills.md @@ -80,3 +80,35 @@ After successfully setting up a CI pipeline, an agent might create: - Starter skills (`squad-*`) are overwritten on upgrade. Earned skills are never touched. - Skills are shared across the whole team โ€” any agent can read any skill. - You can manually edit skill files if you want to seed knowledge (e.g., paste your team's existing conventions into a `SKILL.md`). + +## Sample Prompts + +``` +list all skills +``` + +Shows all skill files in `.ai-team/skills/` with confidence levels for earned skills. + +``` +what's the confidence level for the CI skill? +``` + +Checks how battle-tested a specific earned skill is. + +``` +create a skill for our deployment process +``` + +Manually creates a new skill file and guides you through documenting the pattern. + +``` +which skills have low confidence? +``` + +Finds recently-created skills that haven't been validated across multiple contexts yet. + +``` +bump the testing skill to high confidence +``` + +Manually increases the confidence level after successful repeated use. diff --git a/docs/features/team-setup.md b/docs/features/team-setup.md new file mode 100644 index 000000000..6e58be910 --- /dev/null +++ b/docs/features/team-setup.md @@ -0,0 +1,111 @@ +# Team Setup & Init Mode + +When you first run Squad in a repository, it doesn't impose a team โ€” it proposes one. The init flow analyzes your project, suggests roles and members, waits for your confirmation, then creates the `.ai-team/` directory structure and installs the crew. + +## How Init Works + +1. **Discovery** โ€” Squad scans your repository: language distribution, file structure, test frameworks, dependencies, existing workflows. +2. **Proposal** โ€” Based on what it finds, Squad proposes a team roster with 3-7 members and their roles. +3. **Confirmation** โ€” You review the proposal and can accept as-is, add members, remove members, or change roles. +4. **Creation** โ€” Squad writes `.ai-team/team.md`, creates agent directories under `.ai-team/agents/{member}/`, and sets up the coordinator. + +### File Structure Created + +``` +.ai-team/ +โ”œโ”€โ”€ team.md # Team roster +โ”œโ”€โ”€ routing.md # Work routing rules +โ”œโ”€โ”€ decisions.md # Team memory (directives) +โ”œโ”€โ”€ decisions/inbox/ # Pending decision writes +โ”œโ”€โ”€ agents/ +โ”‚ โ”œโ”€โ”€ {member1}/ +โ”‚ โ”‚ โ”œโ”€โ”€ charter.md # Role, skills, voice +โ”‚ โ”‚ โ””โ”€โ”€ context.md # Agent-specific notes +โ”‚ โ”œโ”€โ”€ {member2}/ +โ”‚ โ”‚ โ””โ”€โ”€ charter.md +โ”‚ โ””โ”€โ”€ ... +โ”œโ”€โ”€ skills/ +โ”‚ โ”œโ”€โ”€ {skill1}.md # Skill definitions +โ”‚ โ””โ”€โ”€ ... +โ”œโ”€โ”€ log/ # Execution logs +โ”œโ”€โ”€ orchestration-log/ # Coordinator state +โ””โ”€โ”€ casting/ # Universe assignments +``` + +## Customizing During Init + +| What you say | What happens | +|--------------|--------------| +| "Accept" / "Looks good" | Creates team as proposed | +| "Add a designer" | Adds a designer role to the roster | +| "Remove the tester" | Drops tester from the team | +| "Change backend to Rust specialist" | Adjusts role focus for that member | +| "Make Fenster the frontend lead" | Assigns specific name to role | + +## Customizing After Init + +You can modify `.ai-team/team.md` directly or ask the coordinator: + +> "Add a security specialist to the team" + +The coordinator will: +1. Cast a new member from the universe +2. Create their agent directory and charter +3. Update `team.md` and `routing.md` + +> "Remove McManus from the team" + +The coordinator will: +1. Remove the member from `team.md` +2. Archive their agent directory (moves to `.ai-team/agents/.archived/{member}/`) +3. Update routing rules + +## Default Team Composition + +For most projects, Squad proposes: + +| Role | When Included | +|------|--------------| +| **Lead** | Always โ€” triages, reviews, unblocks | +| **Core Dev** | Always โ€” main implementation | +| **Tester** | If tests exist or `package.json`/`pyproject.toml` has test deps | +| **DevRel** | If README exists or docs/ present | +| **Frontend** | If React/Vue/Svelte/Angular detected | +| **Backend** | If API routes, database code, or server framework detected | +| **Scribe** | Always โ€” decision logger | + +## Upgrade vs. Init + +| Command | When to Use | +|---------|------------| +| `init` | First-time setup in a new repository | +| `upgrade` | Existing `.ai-team/` โ€” updates templates, adds new members, migrates config | + +Running `init` on an existing Squad repository prompts for upgrade mode automatically. + +## Sample Prompts + +``` +Start a new Squad team for this project +``` +Triggers init mode. Squad analyzes the repository and proposes a team. + +``` +Add a database specialist to the team +``` +Adds a new member post-init. Coordinator casts from universe, creates charter, updates routing. + +``` +Remove the designer role โ€” we don't need it +``` +Removes a team member. Archives their directory and updates team.md. + +``` +Show me the current team roster +``` +Displays team.md with all members, roles, and capabilities. + +``` +Change the tester to focus on integration tests instead of unit tests +``` +Updates the tester's charter to adjust their focus area and expertise. diff --git a/docs/features/worktrees.md b/docs/features/worktrees.md new file mode 100644 index 000000000..93ab21c12 --- /dev/null +++ b/docs/features/worktrees.md @@ -0,0 +1,178 @@ +# Git Worktree Awareness + +Squad supports git worktrees โ€” multiple working directories for the same repository. Two strategies: **worktree-local** (each worktree has its own `.ai-team/` state) and **main-checkout** (shared state across all worktrees). The coordinator resolves team root based on your choice. + +## What Are Worktrees? + +Git worktrees let you check out multiple branches simultaneously: + +```bash +git worktree add ../project-feature-a feature-a +git worktree add ../project-feature-b feature-b +``` + +Now you have: +- `project/` (main branch) +- `project-feature-a/` (feature-a branch) +- `project-feature-b/` (feature-b branch) + +All share the same `.git/` database but have separate working directories. + +## Worktree Strategies + +### 1. Worktree-Local (Independent State) + +Each worktree has its own `.ai-team/` directory. Agents in one worktree don't see state from another. + +**When to use:** +- Multiple features in parallel with **different teams** +- Experimental branches where you want isolated Squad config +- Different team compositions per worktree (e.g., frontend-only team in one, backend-only in another) + +**Structure:** +``` +project/ +โ”œโ”€โ”€ .git/ +โ””โ”€โ”€ .ai-team/ # Main worktree team + +project-feature-a/ +โ”œโ”€โ”€ .git -> ../project/.git/ +โ””โ”€โ”€ .ai-team/ # Feature A team (independent) + +project-feature-b/ +โ”œโ”€โ”€ .git -> ../project/.git/ +โ””โ”€โ”€ .ai-team/ # Feature B team (independent) +``` + +**Setup:** +```bash +cd project-feature-a +# Initialize Squad in this worktree +gh copilot "Initialize Squad for this worktree" +``` + +### 2. Main-Checkout (Shared State) + +All worktrees share the `.ai-team/` directory from the main checkout. Agents across worktrees see the same team, decisions, and routing rules. + +**When to use:** +- Same team working on multiple branches +- Coordinated work where agents need shared context +- Parallel feature development by the same squad + +**Structure:** +``` +project/ +โ”œโ”€โ”€ .git/ +โ””โ”€โ”€ .ai-team/ # Shared by all worktrees + +project-feature-a/ +โ”œโ”€โ”€ .git -> ../project/.git/ +โ””โ”€โ”€ .ai-team -> ../project/.ai-team/ # Symlink + +project-feature-b/ +โ”œโ”€โ”€ .git -> ../project/.git/ +โ””โ”€โ”€ .ai-team -> ../project/.ai-team/ # Symlink +``` + +**Setup:** +```bash +cd project-feature-a +ln -s ../project/.ai-team .ai-team +``` + +Or tell Squad: `"Use the main worktree's team"` โ€” Squad creates the symlink automatically. + +## Coordinator Team Root Resolution + +When Squad starts in a worktree, the coordinator resolves team root: + +1. **Check for `.ai-team/` in current directory** โ€” If exists and is not a symlink, use worktree-local strategy. +2. **Check if `.ai-team/` is a symlink** โ€” If yes, follow symlink to main checkout, use main-checkout strategy. +3. **Scan parent worktrees** โ€” If no `.ai-team/` found, search `../` for main worktree with `.ai-team/`. +4. **Prompt for strategy** โ€” If ambiguous, ask: "Use worktree-local or main-checkout?" + +## Merge Driver for Append-Only Files + +Squad uses `merge=union` for append-only log files to avoid conflicts across worktrees: + +**.gitattributes:** +``` +.ai-team/log/* merge=union +.ai-team/orchestration-log/* merge=union +.ai-team/decisions/inbox/* merge=union +``` + +This ensures log entries from different worktrees don't conflict when merged back to main. + +## Worktree-Aware Commands + +When using main-checkout strategy: + +| Command | Behavior | +|---------|----------| +| `"Show team roster"` | Reads shared `team.md` from main worktree | +| `"Add a directive"` | Writes to shared `decisions/inbox/` in main worktree | +| `"Who's working on issue #42?"` | Checks orchestration log in main worktree (sees all agents across worktrees) | +| `"Initialize Squad"` | Prompts: "Use main worktree's team or create new?" | + +## When to Use Which Strategy + +| Scenario | Strategy | Reason | +|----------|----------|--------| +| **Parallel features, same team** | Main-checkout | Shared context, coordinated work | +| **Experimental branch, isolated team** | Worktree-local | No cross-contamination | +| **Hotfix branch + feature branch** | Main-checkout | Same squad, need shared decisions | +| **Multiple teams in same repo** | Worktree-local | Different roles, different directives | +| **Solo dev, multiple branches** | Main-checkout | No need for duplicate state | + +## Switching Strategies + +You can convert between strategies: + +### Worktree-Local โ†’ Main-Checkout + +```bash +cd project-feature-a +rm -rf .ai-team +ln -s ../project/.ai-team .ai-team +``` + +Or: `"Convert this worktree to use main team"` + +### Main-Checkout โ†’ Worktree-Local + +```bash +cd project-feature-a +rm .ai-team # Remove symlink +cp -r ../project/.ai-team .ai-team # Copy state +``` + +Or: `"Give this worktree its own Squad team"` + +## Sample Prompts + +``` +Initialize Squad in this worktree with a separate team +``` +Creates worktree-local `.ai-team/` directory. Team is independent from main worktree. + +``` +Use the main worktree's Squad team +``` +Creates symlink to main worktree's `.ai-team/`. All state is shared. + +``` +Which worktrees have active Squad teams? +``` +Scans all worktrees linked to this repository, reports which have `.ai-team/` directories. + +``` +Show me the team roster for the main worktree +``` +Resolves main worktree path, reads `team.md` from there (useful when in a feature worktree). + +``` +Convert this worktree to use the main team +``` +Removes worktree-local `.ai-team/` and creates symlink to main worktree's `.ai-team/`. diff --git a/docs/guide.md b/docs/guide.md index b2ddd5ab6..44c58dd96 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -2,12 +2,25 @@ ## What Is Squad? -Squad gives you an AI development team through GitHub Copilot CLI. You describe what you're building. Squad proposes a team of specialists โ€” lead, frontend, backend, tester โ€” that live in your repo as files. Each agent runs in its own context window, reads its own knowledge, and writes back what it learned. They persist across sessions, share decisions, and get better the more you use them. +Squad gives you an AI development team through GitHub Copilot. You describe what you're building. Squad proposes a team of specialists โ€” lead, frontend, backend, tester โ€” that live in your repo as files. Each agent runs in its own context window, reads its own knowledge, and writes back what it learned. They persist across sessions, share decisions, and get better the more you use them. It is not a chatbot wearing hats. Each team member is spawned as a real sub-agent with its own tools, its own memory, and its own area of expertise. --- +## Supported Platforms + +Squad is designed for **GitHub Copilot CLI** and ships with full support for that environment. + +**Current state:** +- โœ… **GitHub Copilot CLI** โ€” fully supported. This is the primary platform. Uses the stable `task` tool for sub-agent spawning. +- ๐Ÿšง **VS Code Copilot** โ€” partial support tracked in [#10](https://github.com/bradygaster/squad/issues/10). VS Code uses a different tool (`runSubagent`) that doesn't yet support Squad's parallel execution model (`mode: "background"`) or typed agent selection. +- โŒ **Other platforms** โ€” Visual Studio, JetBrains IDEs, and other runtimes are not supported. + +If you're using VS Code, Squad will run but with limitations. Follow [#10](https://github.com/bradygaster/squad/issues/10) for cross-client support progress. + +--- + ## Installation ```bash @@ -16,11 +29,48 @@ npx github:bradygaster/squad **Requirements:** - Node.js 22+ -- GitHub Copilot CLI (the `copilot` command) +- GitHub Copilot (CLI, VS Code, Visual Studio, or Coding Agent) - A git repository (Squad stores team state in `.ai-team/`) +- **`gh` CLI** โ€” required for GitHub Issues, PRs, Ralph, and Project Boards ([install](https://cli.github.com/)) This copies `squad.agent.md` into `.github/agents/` and installs templates into `.ai-team-templates/`. Your actual team (`.ai-team/`) is created at runtime when you first talk to Squad. +**Note:** When you select Squad from the agent picker, you'll see the version number in the name (e.g., "Squad (v0.3.0)"). This helps you confirm which version is installed. + +### GitHub CLI Authentication + +Squad uses the `gh` CLI for all GitHub API operations โ€” issues, PRs, labels, project boards, and Ralph's work monitoring. You must authenticate before using any of these features. + +**Quick start:** + +```bash +gh auth login +``` + +Choose **GitHub.com**, **HTTPS**, and authenticate with your browser or a Personal Access Token (PAT Classic). + +**Verify it worked:** + +```bash +gh auth status +``` + +**Additional scopes** โ€” some features require scopes beyond the default: + +| Feature | Required Scope | Command | +|---------|---------------|---------| +| Issues, PRs, Ralph | `repo` (included by default) | โ€” | +| Project Boards | `project` | `gh auth refresh -s project` | + +The `gh auth refresh` command adds scopes to your existing token โ€” it takes about 10 seconds and you only need to do it once. + +**Troubleshooting:** + +- **"gh: command not found"** โ€” Install the GitHub CLI from https://cli.github.com/ +- **"HTTP 401" or "authentication required"** โ€” Run `gh auth login` to re-authenticate +- **Project board commands fail** โ€” Run `gh auth refresh -s project` to add the `project` scope +- **"Resource not accessible by integration"** โ€” Your token may lack the `repo` scope. Re-authenticate with a PAT Classic that has `repo` and `project` scopes + --- ## How Teams Form (Init Mode) @@ -379,7 +429,7 @@ The coordinator uses 6.6% of its window. A 12-week veteran agent uses 4.5% โ€” b - **Silent success bug** โ€” approximately 7โ€“10% of background agent spawns complete all their file writes but return no text response. This is a platform-level issue. Squad detects it by checking the filesystem for work product and reports what it finds. Work is not lost. - **Platform latency** โ€” response times depend on the Copilot platform. Complex multi-agent tasks take 40โ€“60 seconds. Simple questions are answered in 2โ€“3 seconds. - **Node 22+** โ€” requires Node.js 22.0.0 or later. -- **GitHub Copilot CLI only** โ€” no other runtimes are supported. +- **GitHub Copilot required** โ€” Squad works across Copilot hosts (CLI, VS Code, Visual Studio, Coding Agent). - **First session is the least capable** โ€” agents improve as they accumulate history. Give it a few sessions before judging. --- diff --git a/docs/sample-prompts.md b/docs/sample-prompts.md index 388757de8..328152efe 100644 --- a/docs/sample-prompts.md +++ b/docs/sample-prompts.md @@ -725,3 +725,201 @@ Create a custom ceremony called "Demo Day" where each agent presents what they b ``` Schedule a retro after every third session automatically. ``` + +--- + +## v0.3.0 Feature Prompts + +Quick prompts that exercise specific v0.3.0 features. Use these to try out individual capabilities. + +--- + +### Ralph โ€” Work Monitor + +``` +Enable Ralph to watch the team's work. Start monitoring background task execution. +``` + +``` +Check Ralph's status โ€” show me what the team is currently working on and task queue depth. +``` + +``` +Ralph, configure idle-watch mode. Alert me if an agent hasn't made progress for more than 10 minutes. +``` + +``` +Scope Ralph's monitoring to just the backend agent. Ignore frontend for now. +``` + +``` +Show me Ralph's activity log for the past hour โ€” what tasks completed, what failed, what's queued? +``` + +--- + +### Per-Agent Model Selection + +``` +Override the model for the backend agent โ€” use Claude Opus for complex database design instead of the default. +``` + +``` +Run this feature with a cheaper model to save costs. Use GPT-4 Mini for the frontend work. +``` + +``` +Bump the Lead's model to Claude Opus for this session. We need better reasoning for architecture decisions. +``` + +``` +The frontend agent just used Haiku for the styling work. Show me what model was used. +``` + +``` +Set up model rotation: use Opus for design reviews, Sonnet for implementation, Haiku for tests. +``` + +--- + +### @copilot Coding Agent + +``` +Add @copilot to the team as the coding specialist. Auto-assign code generation and refactoring to them. +``` + +``` +Configure @copilot to handle all TypeScript work. Route TypeScript issues directly to them. +``` + +``` +Show me @copilot's capabilities. What can they do and what do they need human review on? +``` + +``` +@copilot just finished the component refactor. Review their work before I merge. +``` + +``` +Remove @copilot from the team. We're doing code review manually going forward. +``` + +--- + +### Labels & Triage + +``` +Add priority labels to all open issues. What's critical vs. nice-to-have? +``` + +``` +Show me the triage status for issue #42. Who said what about the verdict? +``` + +``` +Change the verdict on issue #8 from "blocked" to "ready-to-start" โ€” the dependency is resolved. +``` + +``` +Tag issues for the v1.0 release. Show me what's targeted for the next milestone. +``` + +``` +Set priority: mark frontend bugs as P1, documentation updates as P3. +``` + +--- + +### Directives + +``` +Set a coding style preference: prefer functional components over class components in React. +``` + +``` +Add a scope constraint: don't touch authentication logic without explicit approval from the Lead. +``` + +``` +Set a process rule: all pull requests must have a code review before merging. +``` + +``` +Show me the team's current directives. What rules are we following? +``` + +``` +Update the documentation preference: use JSDoc for all public functions with @param and @return tags. +``` + +--- + +### Parallel Execution + +``` +Start these three tasks in parallel: implement the API endpoint, write tests, and update docs. +``` + +``` +Run this work in sync mode โ€” I want real-time output instead of background execution. +``` + +``` +Check the status of my background agents. Which tasks completed and which are still running? +``` + +``` +The frontend and backend agents are working in parallel. Show me their progress separately. +``` + +``` +Cancel the background task for the database migration โ€” we're taking a different approach. +``` + +--- + +### Reviewer Protocol + +``` +Request a code review from Alex before this PR merges. They're our database expert. +``` + +``` +The reviewer rejected my changes. Show me their feedback and what needs to be fixed. +``` + +``` +Reassign the PR review to Jordan โ€” the original reviewer is busy with another task. +``` + +``` +I've addressed the review feedback. Re-request approval from the reviewer. +``` + +``` +Show me all PRs waiting for review. Who's blocking and when did they last respond? +``` + +--- + +### Worktree Awareness + +``` +I'm working in a git worktree. Update the team root path so commands run in the right directory. +``` + +``` +Switch to a different worktree strategy โ€” we're rotating who works on what branch. +``` + +``` +Show me the team root location. Confirm we're pointing at the right working directory. +``` + +``` +The worktree was deleted. Recover the team state and pick a new working directory. +``` + +``` +I need to work on multiple features in parallel using worktrees. Help me set up the team for that workflow. +``` diff --git a/docs/scenarios/ci-cd-integration.md b/docs/scenarios/ci-cd-integration.md new file mode 100644 index 000000000..3d1fc99c8 --- /dev/null +++ b/docs/scenarios/ci-cd-integration.md @@ -0,0 +1,211 @@ +# Squad in CI/CD Pipelines + +Using Squad with GitHub Actions. Label-driven automation, heartbeat workflows, and autonomous issue processing. + +--- + +## 1. The Heartbeat Workflow โ€” Ralph Between Sessions + +Ralph (the manager agent) runs periodically via GitHub Actions to handle housekeeping between Copilot sessions: + +- Triage new issues +- Apply squad labels based on routing rules +- Check for stale branches +- Archive old decisions + +The workflow is in `.github/workflows/ralph-heartbeat.yml` and runs every 6 hours. + +**You don't have to do anything** โ€” it's installed automatically when you run `npx github:bradygaster/squad`. + +```yaml +name: Ralph Heartbeat +on: + schedule: + - cron: '0 */6 * * *' # Every 6 hours + workflow_dispatch: + +jobs: + heartbeat: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run Ralph + run: npx github:bradygaster/squad heartbeat +``` + +Ralph reads `.ai-team/routing.md`, looks at open issues, and applies labels: + +``` +Issue #42: "Add Stripe payment integration" + โ†’ squad:morpheus (backend work, routed to Morpheus) + โ†’ type:feature + โ†’ priority:high +``` + +Now when you open Copilot, you see issues pre-triaged. + +--- + +## 2. Label-Driven Automation + +Squad uses GitHub labels to drive workflows: + +**Routing labels** (auto-applied by Ralph): +- `squad:neo` โ€” routed to Neo (Lead) +- `squad:trinity` โ€” routed to Trinity (Frontend Dev) +- `squad:morpheus` โ€” routed to Morpheus (Backend Dev) +- `squad:tank` โ€” routed to Tank (Tester) + +**Control labels**: +- `go:neo` โ€” tells Copilot to auto-assign this issue to Neo +- `go:trinity` โ€” auto-assign to Trinity +- `go:morpheus` โ€” auto-assign to Morpheus +- `go:tank` โ€” auto-assign to Tank + +**Type labels** (for filtering): +- `type:feature` +- `type:bug` +- `type:refactor` +- `type:docs` + +**Priority labels**: +- `priority:critical` +- `priority:high` +- `priority:medium` +- `priority:low` + +**Release labels**: +- `release:next` โ€” include in the next release +- `release:backlog` โ€” not scheduled yet + +Ralph applies `squad:*` and `type:*` labels automatically. You apply `go:*` labels manually when you want autonomous processing. + +--- + +## 3. @copilot Auto-Assign for Autonomous Issue Processing + +When you add a `go:*` label to an issue, the `@copilot` automation picks it up: + +1. Ralph labels issue #42 with `squad:morpheus` (backend work) +2. You review the issue and add `go:morpheus` (approval to proceed) +3. GitHub Actions triggers the `@copilot` workflow +4. Copilot session spawns Morpheus to handle the issue +5. Morpheus reads the issue, implements the feature, opens a PR +6. PR is tagged for human review + +**This is autonomous issue processing.** You don't open Copilot manually โ€” the workflow does. + +Workflow file: `.github/workflows/copilot-auto-assign.yml`: + +```yaml +name: Copilot Auto-Assign +on: + issues: + types: [labeled] + +jobs: + auto-assign: + if: startsWith(github.event.label.name, 'go:') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Extract agent name + id: agent + run: echo "agent=${LABEL#go:}" >> $GITHUB_OUTPUT + env: + LABEL: ${{ github.event.label.name }} + - name: Spawn Copilot session + run: | + copilot --agent squad --message "${{ steps.agent.outputs.agent }}, handle issue #${{ github.event.issue.number }}" +``` + +**Note:** This workflow requires GitHub Actions to have access to your Copilot session. See GitHub's docs for `gh copilot` in Actions. + +--- + +## 4. What You CAN'T Do: Agents Can't Run in Actions (Yet) + +**Squad agents require a live Copilot session.** They can't run in a GitHub Actions runner without Copilot CLI access. + +This means: + +โŒ You **can't** run `Squad, build the feature` inside a GitHub Actions workflow +โœ… You **can** use Ralph to triage and label issues +โœ… You **can** trigger Copilot sessions via Actions (if you have `gh copilot` access) +โŒ You **can't** have agents autonomously merge PRs without human approval (by design) + +--- + +## 5. Sample Workflow: Issue Filed โ†’ Triage โ†’ Assign โ†’ Build โ†’ Review + +1. **User files issue** #42: "Add Stripe payment integration" +2. **Ralph (heartbeat)** runs, reads routing rules, applies `squad:morpheus` and `type:feature` +3. **You review** the issue, decide it's good, add `go:morpheus` label +4. **GitHub Actions** triggers Copilot auto-assign workflow +5. **Copilot spawns Morpheus** to handle issue #42 +6. **Morpheus builds** the Stripe integration, writes tests, opens PR #43 +7. **Neo (Lead) reviews** PR #43, approves or requests changes +8. **You merge** PR #43 after human review + +Steps 2, 4, 5, 6, 7 are **automated**. You only do steps 3 and 8. + +--- + +## 6. Workflow Templates Ship with Squad + +When you run `npx github:bradygaster/squad`, these workflow templates are installed: + +- `.ai-team-templates/ralph-heartbeat.yml` โ†’ Ralph runs every 6 hours +- `.ai-team-templates/copilot-auto-assign.yml` โ†’ Triggers Copilot on `go:*` labels +- `.ai-team-templates/pr-review-reminder.yml` โ†’ Reminds you of open PRs needing review + +To activate them: + +```bash +cp .ai-team-templates/*.yml .github/workflows/ +git add .github/workflows/ +git commit -m "Enable Squad workflows" +git push +``` + +Now they're live. + +--- + +## 7. Sample Prompts for CI-Adjacent Workflows + +**Trigger Ralph manually:** + +```bash +npx github:bradygaster/squad heartbeat +``` + +**Check what Ralph would do (dry run):** + +```bash +npx github:bradygaster/squad heartbeat --dry-run +``` + +**Have agents work on labeled issues:** + +``` +> Team, review all open issues labeled squad:morpheus and tell me +> which ones are ready to work on. +``` + +**Autonomous issue pickup:** + +``` +> Ralph, triage the 10 newest issues and apply squad labels. +> If any are ready to start, let me know. +``` + +--- + +## Tips + +- **Ralph is your assistant between sessions.** It triages issues, applies labels, and keeps things organized while you're not in Copilot. +- **`go:*` labels mean "approved to proceed."** Don't add them to every issue โ€” only the ones you've reviewed and want agents to handle autonomously. +- **Agents still need human review.** PRs created by agents should be reviewed by a human before merging. +- **Workflows are templates.** Customize `.ai-team-templates/` to match your CI/CD setup, then copy to `.github/workflows/`. +- **Heartbeat frequency is configurable.** Edit `ralph-heartbeat.yml` to change from every 6 hours to daily, hourly, etc. diff --git a/docs/scenarios/disaster-recovery.md b/docs/scenarios/disaster-recovery.md new file mode 100644 index 000000000..cf9c6a7cb --- /dev/null +++ b/docs/scenarios/disaster-recovery.md @@ -0,0 +1,276 @@ +# Disaster Recovery โ€” When Things Go Wrong + +Recovery scenarios: deleted `.ai-team/`, bad agent code, confused squad, upgrade issues. + +--- + +## 1. "I accidentally deleted `.ai-team/`" + +**Solution:** It's in Git. Restore it. + +```bash +git checkout .ai-team/ +``` + +If you haven't committed `.ai-team/` yet, it's gone. Rebuild: + +```bash +npx github:bradygaster/squad +``` + +Start from scratch. If you exported your squad before, import the export: + +```bash +npx github:bradygaster/squad import squad-export-2025-07-15.zip +``` + +**Prevention:** Commit `.ai-team/` early. Don't let it stay uncommitted for long. + +--- + +## 2. "An agent wrote bad code" + +**What happened:** Morpheus implemented a feature, but it has a bug. Michael (the Lead) didn't catch it during review. + +**Solution:** Use the reviewer rejection protocol. + +``` +> Michael, review Morpheus's latest commit. There's a bug in the +> payment validation logic. +``` + +``` +๐Ÿ—๏ธ Michael โ€” reviewing Morpheus's commit + +Issue found: Payment validation allows negative amounts. + +Rejected. Morpheus, fix the validation to reject negative amounts. +``` + +Morpheus fixes it: + +``` +๐Ÿ”ง Morpheus โ€” fixing payment validation to reject negative amounts +``` + +Alternatively, have a **different agent** fix it: + +``` +> Sonny, fix the payment validation bug Morpheus introduced. +> It's allowing negative amounts. +``` + +Sonny reads the code, fixes the issue, commits. + +**Prevention:** Use code review. Michael should always review code before it lands. + +--- + +## 3. "An agent made a wrong decision" + +**What happened:** Neo decided to use REST when GraphQL was the better choice. The decision is logged in `.ai-team/decisions.md`. + +**Solution:** Add a directive to override it. + +``` +> Team, I'm overriding Neo's decision from last session. We're using +> GraphQL, not REST. The client needs flexible queries. Document this. +``` + +``` +๐Ÿ“‹ Scribe โ€” logged decision override + +### 2025-07-15: Using GraphQL instead of REST +**By:** You (overriding Neo's recommendation) +**What:** API will use GraphQL, not REST +**Why:** Client needs flexible queries, REST would require too many endpoints + +Neo's previous recommendation archived. +``` + +Agents now read the new decision and build accordingly. + +**Prevention:** Review major decisions before agents implement them. Use the Lead as a sounding board, not a dictator. + +--- + +## 4. "My squad is confused after a bad session" + +**What happened:** Agents learned incorrect information during a session. Now they're making mistakes. + +**Solution:** Have the Scribe archive old learnings and start fresh. + +``` +> Scribe, archive agent histories from the last session. We made +> mistakes and I don't want agents repeating them. +``` + +``` +๐Ÿ“‹ Scribe โ€” archiving recent session histories + +Moved to .ai-team/history-archive/: + - Neo's session from 2025-07-14 + - Morpheus's session from 2025-07-14 + - Trinity's session from 2025-07-14 + +Agents now only have context from earlier sessions. +``` + +Agents **forget** the bad session. They still have their long-term skills and decisions. + +**Prevention:** End sessions if agents are going in the wrong direction. Don't let them accumulate bad context. + +--- + +## 5. "I want to start over completely" + +**Solution:** Delete `.ai-team/` and reinstall. + +```bash +rm -rf .ai-team/ +npx github:bradygaster/squad +``` + +``` +Squad is ready. What are you building? +``` + +You're back to day one. Clean slate. + +**Prevention:** Only do this if the squad is truly beyond repair. Usually archiving histories (above) is enough. + +--- + +## 6. "Upgrade broke something" + +**What happened:** You upgraded Squad to a new version, and now something doesn't work. + +**Solution:** Squad upgrades **never touch** `.ai-team/`. The issue is likely in: + +1. **Workflow templates** โ€” check `.ai-team-templates/` +2. **Squad agent definition** โ€” check `.github/agents/squad.agent.md` +3. **Model configuration** โ€” check `.ai-team/model-config.json` + +Roll back the Squad agent definition: + +```bash +git checkout HEAD^ .github/agents/squad.agent.md +``` + +Or reinstall the previous version: + +```bash +npx github:bradygaster/squad@0.1.5 +``` + +**Your team's knowledge is safe.** `.ai-team/` is untouched. + +**Prevention:** Check the CHANGELOG before upgrading. If the upgrade is major, test in a branch first. + +--- + +## 7. "An agent is stuck in a loop" + +**What happened:** Tank keeps writing the same failing test over and over. + +**Solution:** Stop the agent manually. + +``` +> Tank, stop. The test is failing because of a known issue in the +> test environment, not the code. Skip this test for now. +``` + +If the agent doesn't stop: + +``` +> Scribe, pause Tank's work. I need to fix the test environment first. +``` + +Or just close the Copilot session (Ctrl+C) and start a new one. + +**Prevention:** If a test is flaky, tell agents to skip it until the environment is fixed. + +--- + +## 8. "Skills are outdated or wrong" + +**What happened:** A skill file in `.ai-team/skills/` contains outdated information. Agents are following bad advice. + +**Solution:** Edit or delete the skill file. + +```bash +# Edit the skill +code .ai-team/skills/auth-rate-limiting.md + +# Or delete it +rm .ai-team/skills/auth-rate-limiting.md +git add .ai-team/skills/ +git commit -m "Remove outdated auth rate limiting skill" +``` + +**Prevention:** Review skills periodically. If your patterns change, update the skills. + +--- + +## 9. "Decisions.md is a mess" + +**What happened:** `.ai-team/decisions.md` has 200 entries and it's hard to find anything. + +**Solution:** Archive old decisions. + +``` +> Scribe, archive decisions older than 3 months. Move them to +> .ai-team/decisions-archive.md. +``` + +``` +๐Ÿ“‹ Scribe โ€” archiving old decisions + +Moved 87 decisions older than 2025-04-01 to decisions-archive.md. +decisions.md now contains only recent decisions. +``` + +Agents still have access to archived decisions if they need them, but the main file is cleaner. + +**Prevention:** Periodically archive old decisions. Keep `decisions.md` focused on recent, relevant choices. + +--- + +## 10. "I can't tell which agent did what" + +**What happened:** Multiple agents worked on the same feature, and the commit history is tangled. + +**Solution:** Check agent histories. + +``` +> Show me Neo's history for the last session. +``` + +``` +๐Ÿ—๏ธ Neo โ€” session history 2025-07-15 + +Tasks: + - Reviewed architecture for the payment feature + - Rejected Morpheus's first implementation (missing validation) + - Approved Morpheus's second implementation + +Decisions made: + - Use Stripe Checkout instead of raw Payment Intents + - Store payment metadata in the orders table +``` + +Each agent logs what they did in their `history.md`. + +**Prevention:** Agents automatically log their work. You don't have to do anything. + +--- + +## Tips + +- **`.ai-team/` is in Git.** If you delete it, restore from Git. If it's uncommitted, it's gone. +- **Code review catches bad agent code.** Use the Lead to review before merging. +- **Override bad decisions with directives.** If an agent made the wrong call, tell the team the correct one. +- **Archive confused histories.** If a session went badly, archive the learnings so agents forget. +- **Upgrades don't touch `.ai-team/`.** Your team's knowledge is safe across upgrades. +- **Edit skill files directly.** They're just markdown. If a skill is wrong, fix it or delete it. +- **Agent histories are the audit log.** Check them to see what each agent did. diff --git a/docs/scenarios/keep-my-squad.md b/docs/scenarios/keep-my-squad.md new file mode 100644 index 000000000..3ef88676c --- /dev/null +++ b/docs/scenarios/keep-my-squad.md @@ -0,0 +1,221 @@ +# Keeping Your Squad Across Many Projects + +Squad persistence and portability. Your squad remembers skills, casting, and knowledge. Take them everywhere. + +--- + +## 1. Your Squad Remembers + +After working on a project for a few weeks, your squad has learned: + +- **Skills** โ€” patterns, conventions, best practices (23 skill files in `.ai-team/skills/`) +- **Decisions** โ€” architectural choices, why you picked X over Y (`.ai-team/decisions.md`) +- **Histories** โ€” project-specific context each agent accumulated (`.ai-team/agents/{name}/history.md`) +- **Casting state** โ€” the chosen agent names, roles, universe (`.ai-team/casting-state.json`) + +All of this lives in `.ai-team/`. Commit it, and anyone who clones your repo gets the full team. + +--- + +## 2. Export Your Squad + +When you finish a project or want to take your squad to a new one: + +```bash +cd ~/projects/finished-saas-app +npx github:bradygaster/squad export +``` + +``` +๐Ÿ“ฆ Exporting squad to squad-export-2025-07-15.zip + +โœ… Export complete: squad-export-2025-07-15.zip + +Contains: + - Roster (5 agents) + - Charters (4 agent charters) + - Skills (23 skills โ€” portable knowledge) + - Decisions (architectural decisions) + - Histories (project-specific context removed) + - Casting state (agent names, universe) +``` + +**Important:** The export **removes project-specific details** from histories. What remains is **portable knowledge** โ€” skills, decisions, patterns. Not "we use PostgreSQL in this repo," but "always validate input with Zod." + +--- + +## 3. Import Your Squad Into a New Project + +Start a new project: + +```bash +mkdir ~/projects/new-mobile-app +cd ~/projects/new-mobile-app +git init +npx github:bradygaster/squad +``` + +When Squad asks what you're building: + +``` +> Import my squad from squad-export-2025-07-15.zip +``` + +``` +โœ… Squad imported + +Your team: + ๐Ÿ—๏ธ Neo โ€” Lead + โš›๏ธ Trinity โ€” Frontend Dev + ๐Ÿ”ง Morpheus โ€” Backend Dev + ๐Ÿงช Tank โ€” Tester + ๐Ÿ“‹ Scribe โ€” (silent) + +23 skills loaded +47 decisions loaded +Agent histories loaded (generic knowledge only) + +Your squad is ready. What's the project? +``` + +Now describe the new project: + +``` +> This is a React Native app for tracking fitness goals. +> TypeScript, Expo, Firebase backend. +``` + +Agents already know: + +- TypeScript conventions (from skills) +- Testing patterns (from skills) +- Decision-making norms (from decisions) +- Their own specialties (from histories) + +But they **don't** know the old project's code structure โ€” that was stripped from the export. + +--- + +## 4. What Carries Over vs What Doesn't + +### โœ… Portable knowledge (carries over): + +- **Skills** โ€” generic patterns ("always rate-limit auth endpoints") +- **Decisions** โ€” architectural reasoning ("why we chose WebSockets over polling") +- **Casting state** โ€” agent names, universe theme +- **Agent roles** โ€” who does what + +### โŒ Project-specific details (stripped): + +- "The users table has 12 columns" +- "The API is at /server/routes/" +- "We use Prisma with PostgreSQL" +- File paths, module names, specific code references + +This is intentional. Skills are **reusable**. Project details are **not**. + +--- + +## 5. Version Upgrades Don't Touch `.ai-team/` + +When Squad releases a new version: + +```bash +npx github:bradygaster/squad@latest +``` + +``` +๐Ÿ”„ Upgrading Squad from v0.1.5 to v0.2.0 + +โœ… .github/agents/squad.agent.md (updated to v0.2.0) +โœ… .ai-team-templates/ (new workflow templates) +โœ… .gitattributes (merge=union rules verified) + +โš ๏ธ Your .ai-team/ directory was NOT modified. + Your team's memory, skills, and decisions are untouched. +``` + +Upgrades only change: + +- The Squad agent definition (`.github/agents/squad.agent.md`) +- Workflow templates (`.ai-team-templates/`) +- The installer itself + +Your **team's knowledge is safe**. + +--- + +## 6. Git Commit Means Everyone Gets the Team + +You commit `.ai-team/`: + +```bash +git add .ai-team/ +git commit -m "Add Squad team with 3 weeks of accumulated knowledge" +git push +``` + +A teammate clones the repo: + +```bash +git clone https://github.com/yourname/new-mobile-app.git +cd new-mobile-app +copilot +``` + +They select **Squad** from `/agents`. The full team loads instantly โ€” same agents, same skills, same knowledge. + +No re-training. No setup. The squad is **in the repo**. + +--- + +## 7. Long-Lived Squads + +Some squads persist across multiple projects over months or years: + +1. **Start project A** โ€” squad learns TypeScript, React, testing conventions +2. **Export** โ†’ `squad-export-v1.zip` +3. **Start project B** โ€” import the squad, they already know TypeScript patterns +4. **Squad learns Firebase** โ€” new skills accumulated +5. **Export** โ†’ `squad-export-v2.zip` +6. **Start project C** โ€” import v2, squad now knows TypeScript + Firebase +7. **Squad learns GraphQL** โ€” more skills +8. **Export** โ†’ `squad-export-v3.zip` + +Your squad becomes **more valuable over time**. Each project adds to their knowledge. + +--- + +## 8. Sample Prompts for Long-Lived Squads + +**Starting a new project with an experienced squad:** + +``` +> This is a new e-commerce site. You've worked on 3 projects with me +> before, so you know our TypeScript conventions and testing patterns. +> Use what you know. +``` + +**After a project ends:** + +``` +> Export the squad. We're taking everything we learned here to the +> next project. +``` + +**Mid-project knowledge checkpoint:** + +``` +> Scribe, review what the team has learned so far. Which skills and +> decisions are generic enough to carry to other projects? +``` + +--- + +## Tips + +- **Export often.** At the end of each project or after a major milestone, export your squad. It's your team backup. +- **Generic skills are gold.** Skills like "always validate input" are reusable everywhere. Project-specific notes like "our API is at /api/v2" are not. +- **Casting state persists.** If your team is Neo, Trinity, Morpheus, they stay that way across projects. Consistent names build familiarity. +- **Import, don't rebuild.** Starting fresh every project wastes the knowledge you've accumulated. Always import your latest squad export. +- **Your squad gets smarter.** After 5 projects, your squad has seen more patterns than most junior developers. diff --git a/docs/scenarios/large-codebase.md b/docs/scenarios/large-codebase.md new file mode 100644 index 000000000..ce3466aa4 --- /dev/null +++ b/docs/scenarios/large-codebase.md @@ -0,0 +1,208 @@ +# Squad on Large Codebases + +How Squad handles scale. Agents work in their own 200K context windows. Routing ensures only the right agent looks at code. + +--- + +## 1. The Scale Problem + +Large codebases overwhelm most AI tools: + +- **500K+ lines of code** โ€” can't fit in a single context window +- **Hundreds of files** โ€” loading everything is slow and expensive +- **Deep module trees** โ€” agents get lost in the structure +- **Multiple services** โ€” monorepos with 10+ services + +Squad doesn't try to load everything. Instead, **each agent gets its own 200K token context window**, and **routing ensures only the right agent works on relevant code**. + +--- + +## 2. Each Agent Has Its Own Context Window + +When you give a task: + +``` +> Team, add a payment processing feature. +``` + +Squad spawns multiple agents **in parallel**, each with their own context: + +``` +๐Ÿ—๏ธ Neo โ€” 200K token context (reviewing architecture) +โš›๏ธ Trinity โ€” 200K token context (exploring frontend payment UI) +๐Ÿ”ง Morpheus โ€” 200K token context (building backend payment API) +๐Ÿงช Tank โ€” 200K token context (writing payment tests) +``` + +**Each agent's context is isolated.** Trinity doesn't load backend code. Morpheus doesn't load frontend components. They only read what's relevant to their task. + +Your **codebase size doesn't matter** โ€” agents aren't loading all 500K lines. + +--- + +## 3. Routing Directs Work to the Right Agent + +Routing rules in `.ai-team/routing.md` keep agents focused: + +```markdown +# Routing Rules + +**Frontend changes** โ†’ Trinity +**Backend API work** โ†’ Morpheus +**Database migrations** โ†’ Morpheus +**UI component changes** โ†’ Trinity +**Test writing** โ†’ Tank +**Architecture decisions** โ†’ Neo +``` + +When you say: + +``` +> Fix the checkout button styling +``` + +The coordinator routes to Trinity. **Only Trinity** looks at frontend code. Morpheus and Tank don't load any of it. + +When you say: + +``` +> Add a Stripe webhook handler +``` + +The coordinator routes to Morpheus. **Only Morpheus** looks at backend code. + +This is how Squad scales โ€” **selective loading**, not brute-force context. + +--- + +## 4. History Summarization Keeps Memories Manageable + +After 10 sessions, agent histories can grow large. The Scribe **archives old learnings** to keep histories focused: + +``` +๐Ÿ“‹ Scribe โ€” archiving agent histories + +Old learnings moved to .ai-team/history-archive/: + - Neo's session logs from June + - Trinity's session logs from July + +Current histories now cover the last 3 sessions only. +Skills extracted from old sessions remain in .ai-team/skills/. +``` + +Agents don't forget โ€” they just move old details to the archive. **Generic knowledge becomes skills**, and **specific session logs are archived**. + +--- + +## 5. Skills Encode Patterns โ€” No Rediscovery + +After an agent solves a problem, it writes a skill file: + +`.ai-team/skills/stripe-webhook-verification.md`: + +```markdown +# Stripe Webhook Verification + +Always verify webhook signatures using the Stripe SDK. + +Example: +const sig = req.headers['stripe-signature']; +const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret); +``` + +Next time **any agent** handles Stripe webhooks, they read this skill first. No rediscovery. No re-exploration. + +Over time, your `.ai-team/skills/` directory becomes a **compressed knowledge base** โ€” 50 skill files instead of 10,000 lines of history. + +--- + +## 6. Be Explicit About Scope on Huge Repos + +On truly massive codebases (monorepos with 10+ services), help agents focus: + +``` +> Team, we're working in the payment-service directory only. +> Ignore the other services for now. +``` + +``` +๐Ÿ“‹ Scribe โ€” scope limited to payment-service/ directory + +Agents will focus on: + payment-service/src/ + payment-service/tests/ + payment-service/package.json +``` + +Or route by service in `.ai-team/routing.md`: + +```markdown +**Payment service work** โ†’ Morpheus +**Notification service work** โ†’ Linus +**Auth service work** โ†’ Rusty +``` + +Each agent becomes a **service owner**. + +--- + +## 7. Sample Prompts for Large Codebases + +**Initial exploration:** + +``` +> Team, this is a 600K-line monorepo with 8 microservices. +> Each of you, explore the service relevant to your role. +> Don't try to read everything โ€” focus on your domain. +``` + +**Scoped task assignment:** + +``` +> Morpheus, add a retry mechanism to the payment processor. +> Only touch payment-service/. Don't explore other services. +``` + +**Routing-based work:** + +``` +> Team, add real-time notifications. Trinity handles the frontend +> notification UI, Linus handles the notification-service backend. +> Stay in your respective directories. +``` + +**Agent memory check:** + +``` +> Morpheus, what do you know about the payment service architecture? +``` + +If Morpheus's answer is stale or incomplete: + +``` +> Morpheus, re-explore the payment service. It's been refactored. +``` + +--- + +## 8. Workaround: Use File Paths in Prompts + +If agents are getting lost in a huge codebase, give explicit file paths: + +``` +> Morpheus, refactor src/services/payment/stripe-adapter.ts. +> Don't touch anything else. +``` + +Agents load only the specified file and its immediate dependencies. + +--- + +## Tips + +- **Each agent has 200K tokens.** Even a 1M-line codebase isn't a problem โ€” agents only load what's relevant. +- **Routing prevents over-exploration.** Route frontend work to frontend agents, backend to backend agents. Don't let everyone explore everything. +- **Skills are compressed knowledge.** After 5 sessions, your team has 30 skill files that encode months of learning. Agents read skills in seconds. +- **History archiving happens automatically.** The Scribe moves old session logs to the archive, keeping current histories lean. +- **Be explicit on monorepos.** In a 10-service monorepo, tell agents which service they're working on. Don't let them wander. +- **Agent context is isolated.** Frontend agents don't load backend code. Backend agents don't load frontend code. This is the key to scaling. diff --git a/docs/scenarios/mid-project.md b/docs/scenarios/mid-project.md new file mode 100644 index 000000000..09478a100 --- /dev/null +++ b/docs/scenarios/mid-project.md @@ -0,0 +1,243 @@ +# Adding Squad Mid-Project + +Never too late to add Squad. Agents discover what's there, learn your patterns, and get up to speed in 2โ€“3 sessions. + +--- + +## 1. You're Halfway Through โ€” Is It Too Late? + +No. Squad is designed for **existing codebases**. Whether you're 3 weeks in or 3 years in, agents adapt. + +You don't have to start from scratch. You don't have to rewrite anything. Install Squad, let agents explore, and keep building. + +--- + +## 2. Install Squad + +```bash +cd ~/projects/halfway-done-app +npx github:bradygaster/squad +``` + +``` +โœ… .github/agents/squad.agent.md (v0.2.0) +โœ… .ai-team-templates/ +โœ… .ai-team/skills/ (starter skills) +โœ… .ai-team/ceremonies.md +โœ… .gitattributes (merge=union rules) + +Squad is ready. +``` + +--- + +## 3. Open Copilot and Describe What Exists + +```bash +copilot +``` + +Select **Squad** from `/agents`. Describe the project **as it is today**, not as you originally planned it: + +``` +> This is an e-commerce platform. We're 4 months into development. +> React frontend, Django backend, PostgreSQL database. +> We've built user auth, product catalog, and shopping cart. +> We're halfway through the checkout flow. +``` + +Squad proposes a team: + +``` +Here's your team: + +๐Ÿ—๏ธ Michael โ€” Lead Scope, decisions, code review +โš›๏ธ Fredo โ€” Frontend Dev React, UI components +๐Ÿ”ง Sonny โ€” Backend Dev Django, PostgreSQL, APIs +๐Ÿงช Tom โ€” Tester Tests, edge cases +๐Ÿ“‹ Scribe โ€” (silent) Memory, decisions, session logs + +Look right? +``` + +--- + +## 4. Let Agents Explore What's Already There + +Before giving new tasks, let agents discover the codebase: + +``` +> Team, review the codebase and tell me what you find. +``` + +Agents explore in parallel: + +``` +๐Ÿ—๏ธ Michael โ€” reviewing overall architecture +โš›๏ธ Fredo โ€” exploring frontend structure and component patterns +๐Ÿ”ง Sonny โ€” exploring backend: models, views, API endpoints +๐Ÿงช Tom โ€” reviewing test suite and coverage +``` + +Results come back: + +``` +๐Ÿ—๏ธ Michael โ€” Architecture overview: + Monorepo with /frontend and /backend directories. + React 18 with TypeScript, Django 4.2 with DRF. + 15 API endpoints, 47 React components, 123 tests (~68% coverage). + Auth uses JWT tokens via djangorestframework-simplejwt. + +โš›๏ธ Fredo โ€” Frontend findings: + Component structure: /components/{domain}/{ComponentName}/ + State management: React Context (no Redux or Zustand). + Each component has a .tsx, .module.css, and .test.tsx. + Shopping cart state is in CartContext.tsx. + +๐Ÿ”ง Sonny โ€” Backend findings: + Django apps: users, products, cart, orders (checkout is incomplete). + Models use Django ORM, migrations in /backend/migrations/. + API uses DRF viewsets with token auth. + Incomplete: order creation, payment integration. + +๐Ÿงช Tom โ€” Test suite: + Jest for frontend (87 tests), pytest for backend (36 tests). + Missing: checkout flow tests, payment mocking. + Coverage gaps in the cart and orders apps. +``` + +These findings are written to agent histories. Agents now know your project structure. + +--- + +## 5. Feed Conventions and Decisions You've Already Made + +Agents discovered the code structure, but they don't know **why** you made certain choices: + +``` +> Here are conventions we've established: +> - All API endpoints use DRF viewsets, no function-based views. +> - Frontend components are grouped by domain (user, product, cart, checkout). +> - We use Zod for form validation on the frontend. +> - All database changes go through Django migrations, no raw SQL. +> - Payment integration will use Stripe (not implemented yet). +``` + +``` +๐Ÿ“‹ Scribe โ€” logged 5 directives + +These conventions are now in decisions.md. All agents will follow them. +``` + +--- + +## 6. Agents Learn Fast โ€” 2-3 Sessions + +After the initial exploration and 2โ€“3 real tasks, agents are up to speed: + +- **Session 1:** Exploration โ€” agents map the codebase +- **Session 2:** First task โ€” agents implement a feature, learn your patterns +- **Session 3:** Second task โ€” agents already know the structure, make fewer mistakes + +By session 3, agents are making decisions that align with your existing code style without you having to explain. + +--- + +## 7. Start with a Real Task + +Now give a task: + +``` +> Sonny, finish the checkout flow. We need an order creation endpoint +> that validates the cart, calculates total, and saves the order to +> the database. No payment integration yet. +``` + +``` +๐Ÿ”ง Sonny โ€” building order creation endpoint + +Sonny is reading existing cart and product models before starting. +``` + +Sonny knows: +- The Django app structure (from exploration) +- The ORM patterns (from exploration) +- The DRF viewset convention (from your directives) + +No guessing. He builds it correctly on the first try. + +--- + +## 8. Use the Lead to Review What's Already There + +If you're unsure about code quality in the existing codebase: + +``` +> Michael, review the cart app. Are there issues I should know about? +``` + +``` +๐Ÿ—๏ธ Michael โ€” reviewing cart app + +Issues found: + - CartItem model doesn't enforce quantity > 0 + - add_to_cart view doesn't check if product is in stock + - Cart total calculation isn't atomic โ€” race condition risk + +Recommendations: + - Add model-level validation for quantity + - Add stock check in add_to_cart view + - Use database transactions for cart operations +``` + +Michael just gave you a code review of code **you already wrote**. Now you can fix it or add it to the backlog. + +--- + +## 9. Sample Prompts for Mid-Project Onboarding + +**Initial exploration:** + +``` +> Team, explore the codebase. We're 4 months in, so there's a lot here. +> Focus on understanding the architecture, conventions, and what's complete. +``` + +**Feed existing conventions:** + +``` +> We have conventions I need to tell you about. All components use +> TypeScript strict mode. All API calls go through the apiClient +> utility in /frontend/lib/api.ts. Never use any or unknown types. +``` + +**Identify technical debt:** + +``` +> Michael, review the codebase and identify areas of technical debt +> or code that needs refactoring. +``` + +**Continue unfinished work:** + +``` +> Sonny, the previous developer started the payment integration but +> didn't finish. Review /backend/payments/ and tell me what's missing. +``` + +**Backfill tests:** + +``` +> Tom, we're at 68% test coverage. Review the codebase and identify +> the highest-risk areas that need tests. +``` + +--- + +## Tips + +- **Start with exploration, not implementation.** Let agents map the codebase before giving tasks. They'll make fewer mistakes. +- **Feed conventions explicitly.** Agents can discover file structure, but they can't discover team norms. Tell them: "We always X," "We never Y." +- **Use the Lead to audit existing code.** Michael can review code that was written before Squad was added. +- **Skills accumulate fast.** After 2โ€“3 sessions, agents know your patterns. By session 5, they're as good as a developer who's been on the project for weeks. +- **Never too late.** Squad works on 3-week projects and 3-year projects. Agents adapt to what's there. diff --git a/docs/scenarios/monorepo.md b/docs/scenarios/monorepo.md new file mode 100644 index 000000000..cb4445a7a --- /dev/null +++ b/docs/scenarios/monorepo.md @@ -0,0 +1,266 @@ +# Squad in Monorepos + +One squad per monorepo, not per service. Add specialists per domain, route work to the right agent. + +--- + +## 1. The Monorepo Challenge + +You have a monorepo with 8 services: + +``` +monorepo/ +โ”œโ”€โ”€ services/ +โ”‚ โ”œโ”€โ”€ auth-service/ +โ”‚ โ”œโ”€โ”€ payment-service/ +โ”‚ โ”œโ”€โ”€ notification-service/ +โ”‚ โ”œโ”€โ”€ api-gateway/ +โ”‚ โ”œโ”€โ”€ analytics-service/ +โ”‚ โ”œโ”€โ”€ user-service/ +โ”‚ โ”œโ”€โ”€ product-service/ +โ”‚ โ””โ”€โ”€ order-service/ +โ”œโ”€โ”€ shared/ +โ”‚ โ”œโ”€โ”€ types/ +โ”‚ โ”œโ”€โ”€ utils/ +โ”‚ โ””โ”€โ”€ config/ +โ””โ”€โ”€ infra/ +``` + +Do you need 8 squads (one per service)? **No. One squad with specialists.** + +--- + +## 2. One Squad, Multiple Specialists + +Tell Squad about your monorepo structure: + +``` +> I'm building a microservices platform in a monorepo. We have 8 services: +> auth, payments, notifications, API gateway, analytics, users, products, +> and orders. I need specialists for each service domain. +``` + +``` +Here's your team: + +๐Ÿ—๏ธ Michael โ€” Lead Scope, decisions, code review +๐Ÿ” Fredo โ€” Auth Specialist Auth service, JWT, sessions +๐Ÿ’ณ Sonny โ€” Payments Dev Payment service, Stripe, billing +๐Ÿ“ง Tom โ€” Notifications Notification service, email, SMS +๐ŸŒ Kay โ€” Gateway Dev API gateway, routing, rate limiting +๐Ÿ“Š Luca โ€” Analytics Dev Analytics service, tracking, metrics +๐Ÿ‘ค Vito โ€” User Service User service, profiles, preferences +๐Ÿ“ฆ Clemenza โ€” Products Dev Product service, catalog, inventory +๐Ÿ›’ Tessio โ€” Orders Dev Order service, checkout, fulfillment +๐Ÿงช Hagen โ€” Tester Tests across all services +๐Ÿ“‹ Scribe โ€” (silent) Memory, decisions, session logs + +Look right? I can adjust if you want fewer specialists. +``` + +That's a **10-agent team** (9 active + Scribe). You can trim it if you want: + +``` +> That's too many. Let's have 3 domain specialists: backend (auth, payments, +> users), frontend (gateway, notifications), and infra (analytics, products, +> orders). Plus a Lead and Tester. +``` + +--- + +## 3. Routing Rules Direct Work to the Right Specialist + +Edit `.ai-team/routing.md`: + +```markdown +# Routing Rules + +**Auth service work** โ†’ Fredo +**Payment service work** โ†’ Sonny +**Notification service work** โ†’ Tom +**API gateway work** โ†’ Kay +**Analytics service work** โ†’ Luca +**User service work** โ†’ Vito +**Product service work** โ†’ Clemenza +**Order service work** โ†’ Tessio + +**Shared utilities** โ†’ Michael (Lead decides who takes it) +**Infrastructure changes** โ†’ Michael +**Cross-service refactoring** โ†’ Michael +**Testing** โ†’ Hagen +``` + +Now when you give a task: + +``` +> Add two-factor authentication to the auth service. +``` + +The coordinator routes to Fredo (auth specialist). **Only Fredo** loads the auth service code. + +``` +> Add Stripe subscription management to the payment service. +``` + +Routes to Sonny (payments specialist). + +--- + +## 4. Worktree Awareness โ€” Multiple Services Simultaneously + +You can work on multiple services at once: + +``` +> Team, we're adding a loyalty points feature. This spans three services: +> users (store points balance), orders (award points on purchase), +> and products (display points earned per product). +``` + +Squad decomposes and routes: + +``` +๐Ÿ—๏ธ Michael โ€” coordinating cross-service feature +๐Ÿ‘ค Vito โ€” adding points balance to user service +๐Ÿ›’ Tessio โ€” awarding points in order service +๐Ÿ“ฆ Clemenza โ€” displaying points in product service +๐Ÿงช Hagen โ€” writing integration tests across services +``` + +All four work in parallel, each in their own service directory. + +--- + +## 5. Skills That Span Services + +Some patterns apply **across all services**: + +`.ai-team/skills/service-logging-pattern.md`: + +```markdown +# Service Logging Pattern + +All services use structured logging with Winston. + +Log format: +{ + "timestamp": "ISO 8601", + "service": "service-name", + "level": "info|warn|error", + "message": "human-readable message", + "context": { /* additional fields */ } +} + +Every service must log: +- Request IDs for tracing +- User IDs (if authenticated) +- Error stack traces +``` + +This skill is read by **all agents**, regardless of which service they're working on. Consistent logging across the monorepo. + +`.ai-team/skills/inter-service-communication.md`: + +```markdown +# Inter-Service Communication + +Services communicate via HTTP REST APIs (synchronous) or RabbitMQ messages +(asynchronous events). + +Rules: +- Never import code from another service +- Use the service's public API only +- All inter-service calls must have timeouts and retries +- Use circuit breakers for downstream failures +``` + +Agents know: **don't tightly couple services**. + +--- + +## 6. Shared Code in `/shared` + +The `/shared` directory has utilities, types, and config used by all services: + +``` +> Kay, refactor the rate limiting utility in /shared/utils/rate-limit.ts. +> This is used by 5 services, so be careful. +``` + +``` +๐ŸŒ Kay โ€” refactoring rate limiting utility in /shared + +Kay is checking which services import this utility before changing it. +``` + +Kay knows changes to `/shared` affect multiple services. + +--- + +## 7. Sample Prompts for Monorepo Workflows + +**Cross-service feature:** + +``` +> Team, we're adding real-time notifications. This requires: +> notification-service (WebSocket server), api-gateway (WebSocket proxy), +> and user-service (notification preferences). Split the work. +``` + +**Service-specific task:** + +``` +> Sonny, add support for Stripe payment intents in the payment service. +> Don't touch other services. +``` + +**Shared utility change:** + +``` +> Michael, we need to update the /shared/types/User.ts type. +> This affects auth, users, and orders services. Coordinate the change. +``` + +**Infrastructure change:** + +``` +> All services need to switch from Winston to Pino for logging. +> Team, update each service. Use the same Pino config across all services. +``` + +**Integration test:** + +``` +> Hagen, write an integration test for the checkout flow. It spans +> orders, payments, and notifications services. +``` + +**Explore a new service:** + +``` +> Clemenza, review the product service. We haven't touched it in weeks. +> Tell me what's there and what needs work. +``` + +--- + +## 8. One Squad, Not Eight + +**Why one squad instead of one per service?** + +- **Shared knowledge.** Patterns that span services (logging, auth, error handling) are encoded once in skills. +- **Cross-service coordination.** Michael (the Lead) sees the whole monorepo, not just one service. +- **Fewer exports/imports.** You don't have to export/import squads between services. +- **Consistent conventions.** All services follow the same patterns because the same agents work on them. + +If you had 8 separate squads, they'd diverge. One squad keeps the monorepo aligned. + +--- + +## Tips + +- **One squad per monorepo.** Add specialists per service, but keep them in one team. +- **Routing rules are critical.** Route work to the right specialist so agents don't wander across services. +- **Skills that span services are gold.** Logging, error handling, API conventions โ€” document them once, use everywhere. +- **Shared code needs careful handling.** Changes to `/shared` affect multiple services. Route those to the Lead. +- **Agents become service owners.** After a few sessions, each specialist knows their service deeply. +- **Cross-service features need coordination.** Use the Lead to decompose features that span services, then route to specialists. diff --git a/docs/scenarios/multiple-squads.md b/docs/scenarios/multiple-squads.md new file mode 100644 index 000000000..5a3583aa6 --- /dev/null +++ b/docs/scenarios/multiple-squads.md @@ -0,0 +1,162 @@ +# Combining Knowledge from Multiple Squads + +You have 3 repos with trained squads. You're starting a new project and want the best of all of them. + +--- + +## 1. The Reality: One Full Squad at a Time + +Squad's import system brings in a complete team โ€” roster, charters, histories, skills, decisions. You can only import one full squad cleanly. + +**But** you can cherry-pick skills and knowledge manually. + +--- + +## 2. Export from Each Repository + +In each repo with a trained squad: + +```bash +cd ~/projects/saas-app +npx github:bradygaster/squad export +``` + +``` +๐Ÿ“ฆ Exporting squad to squad-export-2025-07-15.zip +โœ… Export complete: squad-export-2025-07-15.zip + +Contains: + - Roster (5 agents) + - Charters (4 agent charters) + - Skills (23 skills) + - Decisions + - Histories (project-specific context removed) +``` + +Repeat for your other repos: + +```bash +cd ~/projects/mobile-app +npx github:bradygaster/squad export +# Produces: squad-export-2025-07-15-1.zip + +cd ~/projects/api-gateway +npx github:bradygaster/squad export +# Produces: squad-export-2025-07-15-2.zip +``` + +You now have three export archives. + +--- + +## 3. Import the Most Relevant Squad + +Pick the squad whose domain knowledge is closest to your new project. + +```bash +cd ~/projects/new-platform +git init +npx github:bradygaster/squad +``` + +``` +> Import a squad from squad-export-saas-app.zip +``` + +``` +โœ… Squad imported + 5 agents, 23 skills, 47 decisions, histories loaded + +Your team is ready. +``` + +This squad is now your baseline. + +--- + +## 4. Cherry-Pick Skills from Other Squads + +You can't import a second full squad without conflicts, but you **can** manually copy individual skill files. + +Extract the other two exports and copy skill files: + +```bash +# Extract the mobile-app squad export +unzip squad-export-mobile-app.zip -d /tmp/mobile-squad + +# Copy specific skills you want +cp /tmp/mobile-squad/.ai-team/skills/react-native-debugging.md .ai-team/skills/ +cp /tmp/mobile-squad/.ai-team/skills/mobile-testing-patterns.md .ai-team/skills/ +``` + +Repeat for the API gateway squad: + +```bash +unzip squad-export-api-gateway.zip -d /tmp/gateway-squad + +cp /tmp/gateway-squad/.ai-team/skills/rate-limiting-patterns.md .ai-team/skills/ +cp /tmp/gateway-squad/.ai-team/skills/auth-middleware-testing.md .ai-team/skills/ +``` + +Skills are standalone markdown files. Agents load them automatically. + +--- + +## 5. Manually Merge History Insights (Optional) + +If another squad learned something critical that isn't in a skill file, you can manually append it to an agent's history. + +Open `.ai-team/agents/{agent-name}/history.md` and add the knowledge as a session entry: + +```markdown +## Session: 2025-07-15 + +### Context from previous squad (API Gateway project) +- GraphQL resolvers should always validate auth before query execution +- Rate limiting uses token bucket algorithm with Redis backing store +- Circuit breaker pattern wraps all downstream API calls +``` + +This becomes part of the agent's memory. + +--- + +## 6. Tell Agents About Cross-Project Knowledge + +When you give your first task, reference the knowledge you brought in: + +``` +> Team, we've combined learnings from three previous projects: +> the SaaS app, the mobile app, and the API gateway. +> You have skills from all three. The SaaS patterns are your baseline, +> but we've also imported mobile testing strategies and gateway +> rate-limiting patterns. Use them. +``` + +``` +๐Ÿ“‹ Scribe โ€” logged cross-project context +``` + +Agents now know they have hybrid knowledge. + +--- + +## 7. Alternative: Use --force for Full Reimport (Destructive) + +If you want to **replace** your imported squad with a different one: + +```bash +npx github:bradygaster/squad import squad-export-mobile-app.zip --force +``` + +This **overwrites** the existing squad. Use only if you're sure. + +--- + +## Tips + +- **One full import, then cherry-pick.** Import the squad with the closest domain match, then manually copy skills from the others. +- **Skills are modular.** Each skill file is independent. Copy the ones you need, ignore the rest. +- **Histories are context-heavy.** Don't import histories from unrelated projects โ€” they contain project-specific details that will confuse agents. +- **Decisions can be manually merged.** If another squad made architectural decisions you want to preserve, copy them into `.ai-team/decisions.md` as new entries. +- **Skill files are the cleanest transfer.** They're generic, portable, and immediately useful across projects. diff --git a/docs/scenarios/open-source.md b/docs/scenarios/open-source.md new file mode 100644 index 000000000..144f56341 --- /dev/null +++ b/docs/scenarios/open-source.md @@ -0,0 +1,259 @@ +# Squad for Open Source Projects + +Autonomous issue triage, community contributor support, and architectural knowledge sharing. + +--- + +## 1. The Open Source Maintainer Problem + +You maintain an open source project. Issues pile up. PRs from new contributors need guidance. Questions repeat. Triaging takes hours. + +Squad helps: +- **Triage incoming issues** automatically +- **Guide contributors** with documented patterns +- **Handle good-first-issue tasks** autonomously +- **Keep architecture decisions visible** in `.ai-team/decisions.md` + +--- + +## 2. Install Squad and Set Up Triage + +```bash +cd ~/projects/my-open-source-lib +npx github:bradygaster/squad +``` + +Enable the Ralph heartbeat workflow: + +```bash +cp .ai-team-templates/ralph-heartbeat.yml .github/workflows/ +git add .github/workflows/ralph-heartbeat.yml +git commit -m "Enable Squad auto-triage" +git push +``` + +Ralph now runs every 6 hours, reading new issues and applying labels: + +``` +Issue #142: "Add support for custom themes" + โ†’ squad:trinity (frontend work) + โ†’ type:feature + โ†’ priority:medium + +Issue #143: "Documentation typo in README" + โ†’ squad:scribe (docs work) + โ†’ type:docs + โ†’ priority:low + โ†’ good-first-issue +``` + +--- + +## 3. Community Contributors File Issues, Squad Triages + +A contributor files an issue: + +``` +Issue #144: "Add TypeScript type definitions" +``` + +Ralph (heartbeat workflow) reads the issue, applies: +- `squad:morpheus` (backend/tooling work) +- `type:feature` +- `priority:high` +- `good-first-issue` (if it's suitable) + +You review triaged issues and add `go:morpheus` if you approve. + +--- + +## 4. @copilot Picks Up Good-First-Issue Tasks Autonomously + +Enable the auto-assign workflow: + +```bash +cp .ai-team-templates/copilot-auto-assign.yml .github/workflows/ +git add .github/workflows/copilot-auto-assign.yml +git commit -m "Enable Squad auto-assign" +git push +``` + +When you add `go:morpheus` to issue #144, GitHub Actions triggers: + +``` +GitHub Actions โ†’ Copilot session spawns Morpheus +Morpheus reads issue #144 โ†’ implements TypeScript definitions +Morpheus opens PR #145 โ†’ "Add TypeScript type definitions" +``` + +You review PR #145, approve, merge. Issue #144 closed. + +**The contributor filed the issue. Squad handled it.** + +--- + +## 5. Skills Document Your Project's Patterns + +After Squad works on your project for a few weeks, `.ai-team/skills/` becomes a **living contributor guide**: + +`.ai-team/skills/testing-conventions.md`: + +```markdown +# Testing Conventions + +All new features must include tests. Use Jest for unit tests. + +Test file naming: `{module}.test.ts` +Test structure: describe โ†’ it blocks +Mock external dependencies with `jest.mock()` +``` + +Contributors can **read this file** to understand your testing norms. No need to repeat it in every PR review. + +`.ai-team/skills/api-design-patterns.md`: + +```markdown +# API Design Patterns + +All API endpoints follow RESTful conventions: +- GET for read operations +- POST for create +- PUT for full update +- PATCH for partial update +- DELETE for removal + +Use HTTP status codes correctly: +- 200 OK for success +- 201 Created for resource creation +- 400 Bad Request for invalid input +- 404 Not Found for missing resources +- 500 Internal Server Error for server issues +``` + +**These skills are contributor documentation** that stays up to date because agents use them. + +--- + +## 6. Decisions.md is Your Architecture Decision Record (ADR) + +`.ai-team/decisions.md` becomes your **public ADR**: + +```markdown +### 2025-07-10: Use esbuild instead of Webpack +**By:** Neo +**What:** Migrated build system from Webpack to esbuild +**Why:** 10x faster builds, simpler config, better DX for contributors + +### 2025-07-12: Stick with CommonJS for now +**By:** Neo +**What:** Not migrating to ESM yet +**Why:** Too many compatibility issues with downstream tools + Will revisit in 6 months + +### 2025-07-15: Use Zod for runtime validation +**By:** Morpheus +**What:** All API input validation uses Zod schemas +**Why:** Type-safe, composable, generates TypeScript types +``` + +Contributors see **why you made decisions**, not just what the code does. + +--- + +## 7. Export Your Squad for Forks + +When someone forks your project, they can **import your squad**: + +```bash +npx github:bradygaster/squad export +``` + +Share `squad-export-{date}.zip` in your repo's releases or documentation. + +Forkers import it: + +```bash +git clone https://github.com/forker/my-lib-fork.git +cd my-lib-fork +npx github:bradygaster/squad import squad-export-2025-07-15.zip +``` + +Now they have **your team's knowledge** โ€” skills, decisions, conventions. They're not starting from scratch. + +--- + +## 8. Sample Prompts for Open Source Workflows + +**Triage a batch of issues:** + +``` +> Ralph, triage the 15 newest issues. Apply squad labels based on +> routing rules. Flag any that are duplicates or need clarification. +``` + +**Check which issues are ready for autonomous work:** + +``` +> Show me all issues labeled good-first-issue and squad:morpheus. +> Which ones are clear enough for Morpheus to handle autonomously? +``` + +**Autonomous issue processing:** + +``` +> Issue #152 is labeled go:morpheus. Morpheus, implement the feature, +> write tests, and open a PR. +``` + +**Generate contributor documentation from skills:** + +``` +> Scribe, create a CONTRIBUTING.md file based on our accumulated +> skills and conventions. Include testing patterns, code style, +> and PR guidelines. +``` + +**Review contributor PRs:** + +``` +> Neo, review PR #160 from @contributor. Check if it follows our +> conventions (skills, decisions). If not, suggest changes. +``` + +**Handle a repeat question:** + +``` +> Issue #175 is asking how to add a custom validator again. +> Scribe, write a skill file for this so we can point future +> contributors to it. +``` + +--- + +## 9. Label Your Repo as Squad-Enabled + +Add a badge to your README: + +```markdown +## Contributing + +This project uses [Squad](https://github.com/bradygaster/squad) for AI-assisted development. + +- **Triaging:** Issues are auto-labeled by Squad's Ralph agent +- **Patterns:** See `.ai-team/skills/` for coding conventions +- **Decisions:** See `.ai-team/decisions.md` for architectural rationale +- **Import the squad:** `npx github:bradygaster/squad import squad-export.zip` +``` + +Contributors know what to expect. + +--- + +## Tips + +- **Ralph triages issues for you.** Run the heartbeat workflow every 6 hours to auto-label new issues. +- **Skills are living contributor docs.** As your squad learns, `.ai-team/skills/` becomes a knowledge base contributors can read. +- **Decisions.md is your ADR.** Architectural decisions are visible and explained, not hidden in Git history. +- **Export your squad for forks.** Forkers get your team's accumulated knowledge โ€” skills, conventions, decisions. +- **good-first-issue + go:* = autonomous processing.** Mark issues as safe to auto-process, and Squad handles them. +- **Agents don't merge without approval.** PRs created by agents still require human review before merging. diff --git a/docs/scenarios/private-repos.md b/docs/scenarios/private-repos.md new file mode 100644 index 000000000..6b8039567 --- /dev/null +++ b/docs/scenarios/private-repos.md @@ -0,0 +1,201 @@ +# Squad on Private Repositories โ€” Privacy & Security + +Squad runs entirely in your Copilot session. Nothing leaves your machine except what Copilot already does. + +--- + +## 1. Where Squad Runs + +Squad is a **local agent** that runs in your GitHub Copilot CLI session. It doesn't phone home. It doesn't send data to a Squad server. It doesn't use external APIs. + +When you run: + +```bash +copilot +``` + +And select **Squad** from the `/agents` list, Squad runs **on your machine** using Copilot's infrastructure. + +**What this means:** +- Your code stays local +- Squad sees what Copilot already sees (your repo, your files) +- No additional data transmission beyond Copilot's standard operation +- No Squad-specific telemetry or tracking + +--- + +## 2. What's Stored in `.ai-team/` + +Squad writes everything to `.ai-team/` in your repository: + +``` +.ai-team/ +โ”œโ”€โ”€ team.md # Roster (agent names, roles) +โ”œโ”€โ”€ routing.md # Work routing rules +โ”œโ”€โ”€ decisions.md # Architectural decisions +โ”œโ”€โ”€ casting-state.json # Agent names, universe theme +โ”œโ”€โ”€ skills/ # Generic best practices (23 files) +โ””โ”€โ”€ agents/ + โ”œโ”€โ”€ neo/ + โ”‚ โ”œโ”€โ”€ charter.md # Neo's role definition + โ”‚ โ””โ”€โ”€ history.md # Neo's accumulated knowledge + โ”œโ”€โ”€ trinity/ + โ”‚ โ”œโ”€โ”€ charter.md + โ”‚ โ””โ”€โ”€ history.md + โ””โ”€โ”€ ... +``` + +**You control what's committed.** If you don't want agent histories in your repo, add them to `.gitignore`: + +```gitignore +.ai-team/agents/*/history.md +``` + +Now histories stay local. Charters, skills, and decisions are still committed. + +--- + +## 3. Agent Histories May Contain Project-Specific Info + +Agent histories (`history.md`) log what agents learned during sessions: + +```markdown +## Session: 2025-07-15 + +### What I learned +- The users table has columns: id, email, created_at, role +- Auth middleware is in /server/middleware/auth.ts +- Passwords are hashed with bcrypt, salt rounds = 12 +``` + +This is **project-specific knowledge**. If your repo is private and you want to keep it that way, **review histories before sharing exports**. + +--- + +## 4. Skills Are Generic โ€” Safe to Share + +Skill files in `.ai-team/skills/` are **intentionally generic**: + +`.ai-team/skills/auth-rate-limiting.md`: + +```markdown +# Authentication Endpoints Must Be Rate-Limited + +When building user-facing auth flows (login, registration, password reset, +email verification), always add rate limiting to prevent brute force attacks. + +Use a token bucket or sliding window algorithm. Store counters in Redis +or an in-memory cache with TTL. +``` + +No project-specific details. No code references. No file paths. + +**Skills are safe to share publicly.** They're best practices, not secrets. + +--- + +## 5. Exporting Your Squad โ€” What's Included + +When you run: + +```bash +npx github:bradygaster/squad export +``` + +The export includes: + +โœ… Roster (agent names, roles) +โœ… Charters (agent role definitions) +โœ… Skills (generic best practices) +โœ… Decisions (architectural reasoning) +โœ… Histories โ€” **with project-specific details removed** +โœ… Casting state (agent names, universe) + +**Squad strips project-specific info** from histories during export. What remains is **portable knowledge**: + +- "Always validate input with Zod" โœ… +- "The API is at /server/routes/api.ts" โŒ (removed) + +The export is **safe to share** with other projects or teammates, but **review it first** if you're paranoid. + +--- + +## 6. Labels and Workflows Use Standard GitHub APIs + +Squad's GitHub Actions workflows (Ralph heartbeat, auto-assign) use GitHub's public APIs: + +- **Issue labeling** โ€” uses the GitHub Issues API with your repo's auth token +- **PR creation** โ€” uses the GitHub Pull Requests API +- **Workflow dispatch** โ€” uses the GitHub Actions API + +No third-party services. No external webhooks. Just GitHub talking to GitHub. + +**Your GitHub token permissions matter.** If your repo is private, make sure the token used by Actions has the appropriate permissions (`issues:write`, `pull_requests:write`). + +--- + +## 7. What Squad DOESN'T Do + +โŒ Send code to a Squad server +โŒ Use external APIs for processing +โŒ Transmit telemetry or usage data +โŒ Store your team's knowledge in a cloud service +โŒ Require an account or API key (beyond your GitHub Copilot license) + +Squad is **entirely local**. It's a GitHub Copilot agent, not a standalone service. + +--- + +## 8. Private Repo Checklist + +If your repository is private and you're security-conscious: + +- [ ] **Review `.ai-team/agents/*/history.md`** โ€” make sure no secrets or sensitive details are logged +- [ ] **Add `history.md` to `.gitignore`** if you don't want histories committed +- [ ] **Review exports before sharing** โ€” check `squad-export-*.zip` for project-specific details +- [ ] **Audit `.ai-team/decisions.md`** โ€” remove any decisions that reference internal systems or secrets +- [ ] **Use GitHub token permissions wisely** โ€” don't give Actions more permissions than needed +- [ ] **Skills are public-safe** โ€” feel free to share `.ai-team/skills/` publicly + +--- + +## 9. Sample Prompts for Privacy-Conscious Usage + +**Check what's in histories:** + +``` +> Scribe, show me what's in Neo's history. Are there any secrets +> or sensitive project details? +``` + +**Clean up histories before export:** + +``` +> Scribe, review all agent histories and remove any references to +> internal APIs, tokens, or database schemas before I export. +``` + +**Exclude histories from Git:** + +``` +> Add .ai-team/agents/*/history.md to .gitignore. I don't want +> agent histories committed. +``` + +**Audit decisions:** + +``` +> Show me all decisions in decisions.md. I want to check for +> anything we shouldn't share publicly. +``` + +--- + +## Tips + +- **Squad runs in Copilot, not on a remote server.** Your code stays on your machine. +- **Review histories before exporting.** They may contain project-specific details you don't want to share. +- **Skills are generic by design.** They're safe to share publicly. +- **Use `.gitignore` for sensitive files.** If you don't want histories committed, exclude them. +- **GitHub Actions workflows use your repo's auth.** Make sure token permissions are scoped correctly. +- **No external services.** Squad doesn't phone home or send telemetry. diff --git a/docs/scenarios/solo-dev.md b/docs/scenarios/solo-dev.md new file mode 100644 index 000000000..7ee498726 --- /dev/null +++ b/docs/scenarios/solo-dev.md @@ -0,0 +1,158 @@ +# Squad for Solo Developers + +Squad is actually GREAT for solo devs. You get a code reviewer, tester, and architect you'd never have otherwise. + +--- + +## 1. Why Squad Works for Solo Devs + +When you're working alone: + +- **No code reviews.** Bugs land in production because no one else looked. +- **No testing discipline.** You skip tests when you're in a hurry. +- **No second opinion.** Architectural decisions go unchallenged. + +Squad gives you a **Lead who reviews everything**, a **tester who catches edge cases**, and **specialists who know their domain**. You're one person, but you have a team that remembers everything. + +--- + +## 2. Start Small: 3 Agents Instead of 5 + +You don't need a full 5-agent team as a solo dev. Customize the roster: + +``` +> I'm a solo developer building a Python API. I want a small team: +> a Lead for code review, one backend dev, and a tester. No frontend dev. +``` + +``` +Here's your team: + +๐Ÿ—๏ธ Michael โ€” Lead Code review, scope, decisions +๐Ÿ”ง Fredo โ€” Backend Dev Python, FastAPI, database work +๐Ÿงช Kay โ€” Tester Tests, edge cases, quality +๐Ÿ“‹ Scribe โ€” (silent) Memory, decisions, session logs + +Look right? +``` + +Lean team. Just what you need. + +--- + +## 3. The Reviewer Protocol Catches Bugs + +When you give a task to an agent: + +``` +> Fredo, add user registration with email verification. +``` + +Fredo builds it. **Then Michael (the Lead) automatically reviews the code.** + +``` +๐Ÿ—๏ธ Michael โ€” reviewing Fredo's user registration implementation + +Issues found: + - Email validation regex allows invalid TLDs + - Verification tokens aren't rate-limited โ€” brute force risk + - No test for expired token edge case + +Rejected. Fredo, address these issues. +``` + +This is the safety net you don't have as a solo dev. Michael catches issues before they land. + +--- + +## 4. Skills Accumulate โ€” You Don't Repeat Mistakes + +After Michael rejects Fredo's code for missing rate limiting, **it gets encoded as a skill**: + +`.ai-team/skills/auth-rate-limiting.md`: + +```markdown +# Authentication Endpoints Must Be Rate-Limited + +When building user-facing auth flows (login, registration, password reset, +email verification), always add rate limiting to prevent brute force attacks. + +Use a token bucket or sliding window algorithm. Store counters in Redis +or an in-memory cache with TTL. +``` + +Next time any agent builds an auth feature, they read this skill first. The mistake doesn't happen again. + +--- + +## 5. You're Solo, But Your Team Remembers Everything + +As a solo dev, you juggle dozens of context switches. Squad doesn't forget: + +- **Decisions** are logged. "Why did I use PostgreSQL instead of MongoDB?" โ€” check `.ai-team/decisions.md`. +- **Skills** capture patterns. "How do I structure FastAPI routes?" โ€” check `.ai-team/skills/`. +- **Histories** track what each agent learned. Fredo knows your database schema after one session. + +You get back to a project after 3 weeks, and the team is still up to speed. + +--- + +## 6. Workflow: Solo Dev + Squad + +``` +> Fredo, add a /users endpoint with pagination and filtering. +``` + +Fredo builds it. Michael reviews. Kay writes tests. + +``` +๐Ÿ”ง Fredo โ€” building /users endpoint with pagination and filtering +๐Ÿ—๏ธ Michael โ€” reviewing Fredo's implementation +๐Ÿงช Kay โ€” writing tests for /users endpoint +``` + +All three work in parallel. You give one prompt, get three agents. + +When it's done: + +``` +โœ… /users endpoint implemented +โœ… Code review passed (minor refactor for query optimization) +โœ… 8 tests written (pagination, filtering, edge cases) +``` + +You're a solo dev, but you shipped like a team. + +--- + +## 7. Use the Lead as a Sounding Board + +``` +> Michael, I'm deciding between REST and GraphQL for this API. +> It's a read-heavy app with a mobile client. Thoughts? +``` + +``` +๐Ÿ—๏ธ Michael โ€” evaluating REST vs GraphQL for your use case + +REST pros: Simple, cacheable, mobile SDKs abundant +GraphQL pros: Flexible queries, reduces round trips + +For a read-heavy app with a mobile client, I'd lean REST. +You get better HTTP caching (CDN, browser, mobile OS), +simpler mobile integration, and fewer surprises at scale. + +If your mobile app needs highly dynamic queries, revisit GraphQL. +``` + +Michael's not always right, but having a second opinion is invaluable. + +--- + +## Tips + +- **Start with 3โ€“4 agents, not 5.** As a solo dev, you don't need a frontend and backend specialist if you're only building one layer. +- **The Lead is your reviewer.** Even if you don't delegate tasks, use Michael to review your own code before committing. +- **Skills are YOUR documentation.** After 10 sessions, your `.ai-team/skills/` directory is a custom knowledge base about your project. +- **Agents work while you're thinking.** Give a vague task ("explore auth options"), and agents research in parallel while you handle something else. +- **You get a testing discipline.** Kay writes tests you'd skip. Over time, your coverage goes up without extra effort. diff --git a/docs/scenarios/switching-models.md b/docs/scenarios/switching-models.md new file mode 100644 index 000000000..20a21ccb8 --- /dev/null +++ b/docs/scenarios/switching-models.md @@ -0,0 +1,216 @@ +# Switching AI Models โ€” Budget vs Quality + +Model selection strategies for different needs. Squad supports 16 models with fallback chains. + +--- + +## 1. The Default: Cost-First Strategy + +Squad's default model configuration prioritizes cost-effectiveness: + +- **Non-code tasks** (planning, triage, decisions) โ†’ `claude-haiku-4.5` (fast, cheap) +- **Code tasks** (implementation, refactoring) โ†’ `claude-sonnet-4.5` (balanced quality/cost) +- **Code review** (critical analysis) โ†’ `claude-sonnet-4.5` + +This is optimized for **everyday use** โ€” good quality without burning your API budget. + +--- + +## 2. Budget Mode: Always Use Haiku + +If you're cost-sensitive or working on a small project: + +``` +> Switch the entire team to claude-haiku-4.5 for all tasks. +``` + +``` +โœ… Model configuration updated + +All agents now use claude-haiku-4.5 (fast/cheap tier) + +Agents will be faster but may need more guidance on complex tasks. +``` + +This is written to `.ai-team/model-config.json`: + +```json +{ + "default": "claude-haiku-4.5", + "overrides": {} +} +``` + +Now every agent uses Haiku for everything. Faster responses, lower cost, slightly less nuanced reasoning. + +--- + +## 3. Quality Mode: Use Opus for Critical Work + +If you're working on architecture, security, or high-stakes features: + +``` +> Use claude-opus-4.6 for Neo (the Lead) and claude-sonnet-4.5 +> for everyone else. +``` + +``` +โœ… Model configuration updated + +Neo (Lead) โ†’ claude-opus-4.6 (premium tier) +All other agents โ†’ claude-sonnet-4.5 (standard tier) + +Neo will give higher-quality code reviews and architectural guidance. +``` + +This is written to `.ai-team/model-config.json`: + +```json +{ + "default": "claude-sonnet-4.5", + "overrides": { + "neo": "claude-opus-4.6" + } +} +``` + +Neo gets the premium model for code reviews and decisions. Everyone else stays on Sonnet. + +--- + +## 4. Per-Agent Overrides + +You can set different models for different roles: + +``` +> Configure models like this: +> Neo (Lead) โ†’ opus (best quality for code review) +> Trinity (Frontend) โ†’ sonnet (balanced) +> Morpheus (Backend) โ†’ sonnet (balanced) +> Tank (Tester) โ†’ haiku (tests don't need premium reasoning) +``` + +``` +โœ… Model configuration updated + +Neo โ†’ claude-opus-4.6 (premium) +Trinity โ†’ claude-sonnet-4.5 (standard) +Morpheus โ†’ claude-sonnet-4.5 (standard) +Tank โ†’ claude-haiku-4.5 (fast/cheap) +``` + +Tank doesn't need Opus to write tests. Neo does need it for code reviews. Balanced spend. + +--- + +## 5. The 16-Model Catalog + +Squad supports these models (as of v0.2.0): + +**Premium tier** (highest quality, highest cost): +- `claude-opus-4.6` โ€” latest Opus, best reasoning +- `claude-opus-4.6-fast` โ€” Opus with faster response time +- `claude-opus-4.5` โ€” previous Opus generation + +**Standard tier** (balanced quality/cost): +- `claude-sonnet-4.5` โ€” current default for code tasks +- `claude-sonnet-4` โ€” previous Sonnet generation +- `gemini-3-pro-preview` โ€” Google's latest +- `gpt-5.3-codex` โ€” OpenAI Codex, code-specialized +- `gpt-5.2-codex` +- `gpt-5.2` +- `gpt-5.1-codex-max` +- `gpt-5.1-codex` +- `gpt-5.1` +- `gpt-5` + +**Fast/cheap tier** (fast responses, lower cost): +- `claude-haiku-4.5` โ€” current default for non-code tasks +- `gpt-5.1-codex-mini` โ€” smaller Codex model +- `gpt-5-mini` +- `gpt-4.1` + +**Note:** Model availability depends on your GitHub Copilot subscription tier. + +--- + +## 6. Fallback Chains + +If a model is unavailable, Squad falls back to the next tier: + +``` +claude-opus-4.6 โ†’ claude-sonnet-4.5 โ†’ claude-haiku-4.5 +``` + +If Opus is unavailable (rate limit, quota), Squad automatically uses Sonnet. If Sonnet is unavailable, it falls back to Haiku. + +You don't have to configure this โ€” it's automatic. + +--- + +## 7. When to Use Which Model + +**Use Haiku (`claude-haiku-4.5`) when:** +- Writing tests +- Running triage or planning tasks +- Generating boilerplate code +- Refactoring (simple renames, restructuring) +- You're on a budget and speed matters more than depth + +**Use Sonnet (`claude-sonnet-4.5`) when:** +- Writing feature code +- Implementing APIs or UI components +- Refactoring with logic changes +- Most everyday development tasks + +**Use Opus (`claude-opus-4.6`) when:** +- Code review (the Lead should catch subtle bugs) +- Architectural decisions +- Security-sensitive code +- Complex debugging +- Critical features where quality trumps cost + +--- + +## 8. Sample Prompts for Model Configuration + +**Check current model configuration:** + +``` +> What models is the team using? +``` + +**Switch everyone to budget mode:** + +``` +> Switch all agents to haiku. We're prototyping, speed matters +> more than perfection. +``` + +**Use premium for the Lead only:** + +``` +> Neo should use opus for code reviews. Everyone else stays on sonnet. +``` + +**Temporary override for a specific task:** + +``` +> Morpheus, use opus for this security-critical auth implementation. +``` + +**Reset to defaults:** + +``` +> Reset model configuration to Squad's defaults. +``` + +--- + +## Tips + +- **Default is fine for most projects.** Haiku for planning, Sonnet for code. You don't need to change it. +- **Use Opus for the Lead.** Code reviews benefit most from premium reasoning. Opus catches edge cases Sonnet misses. +- **Haiku is underrated for tests.** Test writing doesn't require deep reasoning โ€” Haiku is fast and accurate enough. +- **Per-agent overrides are cheap.** Put Opus on the Lead, Haiku on the Tester, Sonnet on everyone else. Balanced budget. +- **Model config is in `.ai-team/model-config.json`.** Commit it so your team uses the same models. diff --git a/docs/scenarios/team-of-humans.md b/docs/scenarios/team-of-humans.md new file mode 100644 index 000000000..0528bcfd4 --- /dev/null +++ b/docs/scenarios/team-of-humans.md @@ -0,0 +1,226 @@ +# Squad Alongside a Team of Human Developers + +Mixed AI + human teams. AI agents work, humans review. Route decisions to humans, let AI handle implementation. + +--- + +## 1. Add Human Members to the Roster + +Tell Squad about your human team members: + +``` +> Add two human developers to the roster: +> Sarah (senior backend engineer) and Jamal (frontend lead). +> They're not AI agents, they're on my team. +``` + +``` +โœ… Added human members: + ๐Ÿ‘ค Sarah โ€” Senior Backend Engineer + ๐Ÿ‘ค Jamal โ€” Frontend Lead + +Humans appear in the roster but don't get charters. +Work can be routed to them via routing rules. +``` + +Squad adds them to `.ai-team/team.md`: + +```markdown +## Human Team Members + +- **Sarah** โ€” Senior Backend Engineer +- **Jamal** โ€” Frontend Lead +``` + +--- + +## 2. Routing Rules for Mixed Teams + +Edit `.ai-team/routing.md` to route work to humans: + +```markdown +# Routing Rules + +**Backend architecture decisions** โ†’ Sarah (human) +**Frontend architectural changes** โ†’ Jamal (human) +**Payment integration work** โ†’ Sarah (human) +**UI component library changes** โ†’ Jamal (human) + +**Backend implementation tasks** โ†’ Morpheus (AI agent) +**Frontend implementation tasks** โ†’ Trinity (AI agent) +**Code review** โ†’ Neo (AI agent) +**Testing** โ†’ Tank (AI agent) +``` + +Now when you give a task: + +``` +> Team, we need to add a real-time notification system. +> This is a big architectural change. +``` + +The coordinator sees "architectural change" and routes to humans: + +``` +๐Ÿ“‹ Scribe โ€” routing architectural decision to Sarah and Jamal + +โธ๏ธ Coordinator paused. Waiting for Sarah and Jamal to decide on + the notification architecture (WebSockets vs Server-Sent Events + vs polling). Resume with their decision. +``` + +The AI agents **don't start implementation** until the humans decide. + +--- + +## 3. Humans Decide, AI Implements + +Sarah and Jamal discuss and decide: WebSockets via Socket.IO. + +You relay the decision: + +``` +> Sarah and Jamal decided on WebSockets using Socket.IO. +> Morpheus, implement the backend. Trinity, integrate on the frontend. +``` + +``` +๐Ÿ”ง Morpheus โ€” building WebSocket server with Socket.IO +โš›๏ธ Trinity โ€” integrating Socket.IO client in React components + +Both agents are reading Sarah and Jamal's decision from decisions.md. +``` + +Scribe logs the decision: + +```markdown +### 2025-07-15: Real-time notifications via WebSockets +**By:** Sarah, Jamal +**What:** Use Socket.IO for real-time notifications +**Why:** Need bi-directional communication, Socket.IO has better mobile client support than raw WebSockets +``` + +AI agents read this before starting. They know the humans already decided. + +--- + +## 4. AI Agents Work, Humans Review PRs + +Agents create pull requests. Humans review them. + +``` +๐Ÿ—๏ธ Neo โ€” submitting PR #47: WebSocket notification system + +PR includes: + - Backend: Socket.IO server integration + - Frontend: React component with socket connection + - Tests: 12 new tests for connection lifecycle + - Docs: Socket.IO event protocol + +Requesting review from Sarah and Jamal. +``` + +Sarah and Jamal review the PR on GitHub. If they request changes, relay that back: + +``` +> Sarah flagged an issue in PR #47: the socket reconnection logic +> doesn't handle token expiration. Morpheus, fix it. +``` + +``` +๐Ÿ”ง Morpheus โ€” fixing socket reconnection to handle token expiration +``` + +Morpheus pushes a fix. The humans approve. Merge. + +--- + +## 5. Pausing the Coordinator + +When work routes to a human, the coordinator **pauses** โ€” it doesn't guess what the human will decide. + +``` +> Team, should we migrate from REST to GraphQL? +``` + +``` +๐Ÿ“‹ Scribe โ€” routing API architecture decision to Sarah + +โธ๏ธ Coordinator paused. This is a significant architectural change. + Waiting for Sarah's input before proceeding. +``` + +You ask Sarah. She says no, stick with REST. + +``` +> Sarah said no, we're staying with REST. Document that. +``` + +``` +๐Ÿ“‹ Scribe โ€” logged decision + +### 2025-07-15: Staying with REST +**By:** Sarah +**What:** Not migrating to GraphQL +**Why:** Current REST API works well, migration cost isn't justified +``` + +--- + +## 6. Use Agents for the Tedious Work + +Humans handle high-level decisions and code review. Agents handle implementation, testing, and grunt work. + +``` +> Tank, we just merged PR #47. Run the full test suite and check +> for regressions. If you find any, fix them. +``` + +``` +๐Ÿงช Tank โ€” running full test suite + Checking for regressions after WebSocket integration... +``` + +Tank finds a broken test, fixes it, commits. Sarah doesn't have to. + +--- + +## 7. Sample Prompts for Mixed Teams + +**Route a decision to a human:** + +``` +> This payment gateway change is sensitive. Route it to Sarah +> for approval before implementing. +``` + +**Delegate implementation after human approval:** + +``` +> Sarah approved the Stripe integration plan. Morpheus, implement it. +> Follow the plan Sarah outlined in issue #23. +``` + +**Have an agent assist a human:** + +``` +> Jamal is working on the new dashboard UI. Trinity, help him by +> building the data-fetching hooks and TypeScript types. +``` + +**Agent-led PR, human review:** + +``` +> Neo, create a PR for the caching layer work. Assign it to Sarah +> for review. +``` + +--- + +## Tips + +- **Humans in the roster, not as agents.** Humans don't get charters or histories, but they appear in routing rules. +- **Use routing rules to protect critical paths.** Route payment logic, security changes, and architectural decisions to humans. +- **Agents don't guess.** If a task routes to a human, the coordinator pauses until you relay the human's decision. +- **Agents make PRs, humans review.** Preserve your team's code review culture โ€” agents submit work for approval, not direct commits. +- **Agents handle the tedious stuff.** Test writing, linting fixes, refactoring โ€” offload it to agents so humans focus on high-value work. diff --git a/docs/scenarios/team-state-storage.md b/docs/scenarios/team-state-storage.md new file mode 100644 index 000000000..a2dbe4057 --- /dev/null +++ b/docs/scenarios/team-state-storage.md @@ -0,0 +1,329 @@ +# Keeping Your Squad Where You Want It + +Your `.ai-team/` directory contains everythingโ€”team rosters, skills, decisions, agent histories. The question isn't whether to track it, but *how* and *where* to track it. Here are the real options, with honest tradeoffs. + +--- + +## 1. Committed to Main (The Default) + +**What it is:** `.ai-team/` is tracked in git, committed alongside your code. Anyone who clones the repo gets the full team with all accumulated knowledge. + +```bash +git add .ai-team/ +git commit -m "Add Squad team" +``` + +### Pros + +- **Simplest setup.** No configuration, no branching strategy. +- **Portable.** Clone the repo anywhere, and the team knowledge travels with it. +- **Shared context.** Every collaborator sees the same team definitions, skills, and decisions. +- **Git history.** You can trace how decisions evolved, view old skills, recover deleted files. +- **GitHub Actions work out of the box.** Workflows (heartbeat, triage, label sync) access `.ai-team/` immediately. + +### Cons + +- **PR noise.** Every team changeโ€”new skill, updated decision, agent historyโ€”shows up in PR diffs. Some people find this distracting. +- **`decisions.md` grows.** Over time, your decisions file accumulates hundreds of entries. Git history is there, but the current file gets long. +- **Some orgs don't allow it.** Enterprise policies sometimes forbid AI artifacts in source repositories. Check before you commit. + +### When to Use This + +- Solo dev or small team, private repo. +- Open source projectโ€”your contributors should see how the team works. +- You want maximum portability and zero configuration. + +--- + +## 2. Gitignored (Local-Only) + +**What it is:** Add `.ai-team/` to `.gitignore`. Team state lives locally on each dev machine, never committed. + +```bash +echo ".ai-team/" >> .gitignore +git add .gitignore +git commit -m "Gitignore squad team state" +``` + +### Pros + +- **Zero repo noise.** No PR diffs, no git history clutter. +- **No policy concerns.** Enterprise orgs with AI artifact policies sleep easy. +- **Clean main branch.** Code and team are completely separated. + +### Cons + +- **Team knowledge is not portable.** If you delete `.ai-team/`, it's gone. No git history to recover it. +- **Collaborators don't share state.** Your teammate clones the repo and gets a fresh, empty `.ai-team/`. Their team doesn't match yours. +- **No git history for recovery.** You can't `git log` to find an old decision or see when a skill was added. +- **โš ๏ธ GitHub Actions workflows can't access `.ai-team/`.** Actions only see committed files. Triage routing rules in `team.md` won't work in CI/CD. (Label sync and other API-based workflows still function, but the team-based routing logic is silent.) + +### When to Use This + +- Team doesn't need shared state (unlikely for Squad). +- Enterprise policy strictly forbids AI artifacts in repos. +- You're experimenting and don't want to commit yet. + +--- + +## 3. Separate Branch (e.g., `squad-state`) + +**What it is:** Keep `.ai-team/` on a dedicated branch (`squad-state`, `team-config`, etc.), not on `main`. Use `git worktree` to mount it locally. + +### Setup + +```bash +# Create and push the squad-state branch (if it doesn't exist) +git checkout --orphan squad-state +git rm -rf . +echo "# Squad State Branch\nThis branch tracks .ai-team/ configuration." > README.md +git add README.md +git commit -m "Initial squad-state branch" +git push origin squad-state + +# Back on main +git checkout main + +# Mount squad-state in a worktree +git worktree add .ai-team-worktree squad-state +ln -s .ai-team-worktree/.ai-team .ai-team +git add .gitignore +echo ".ai-team-worktree/" >> .gitignore +git commit -m "Add squad worktree" +``` + +On Windows: + +```bash +# Use mklink instead of ln -s (requires admin or Developer Mode) +git worktree add .ai-team-worktree squad-state +mklink /D .ai-team .ai-team-worktree\.ai-team +``` + +### Pros + +- **Clean main branch.** `.ai-team/` never appears in `main` or in PR diffs. +- **Full git history.** The `squad-state` branch has complete history of all team changes. +- **Shareable with collaborators.** They can check out `squad-state` and pull your team setup. +- **GitHub Actions can access it.** Workflows can check out both `main` and `squad-state` if needed. + +### Cons + +- **Complex setup.** Requires knowledge of `git worktree` and branch management. +- **Merge conflicts.** If multiple people work on `squad-state` simultaneously, conflicts happen. +- **Worktree management overhead.** You need to remember to update the worktree, and it can get stale. +- **Collaborators must set up the worktree.** They can't just clone; they need to run the setup commands. + +### When to Use This + +- Team that values clean main branch but wants shared team state. +- You want full git history of team evolution but don't want PR noise. +- You're already comfortable with `git worktree` or branching strategies. + +--- + +## 4. Git Submodule + +**What it is:** `.ai-team/` as a separate Git repository, added as a submodule to your main repo. + +### Setup + +```bash +# Create a separate repository for your squad (e.g., on GitHub) +# Then add it as a submodule +git submodule add https://github.com/you/my-squad-state .ai-team +git commit -m "Add squad state as submodule" +git push +``` + +Collaborators clone with: + +```bash +git clone --recurse-submodules https://github.com/you/my-project +``` + +Or after cloning normally: + +```bash +git submodule init +git submodule update +``` + +### Pros + +- **Completely separate history.** The submodule repo has its own git log, independent of your main project. +- **Shareable across repos.** Use the same submodule in multiple projects. +- **Clean main branch.** `.ai-team/` is external; no PR diffs in your project. +- **Full git features.** Submodule repo has branches, tags, and full history. + +### Cons + +- **Submodules are complex.** Widely disliked by the git community. Conflicts, merge issues, and confusion are common. +- **Everyone must remember `--recurse-submodules`.** Collaborators who forget get an empty `.ai-team/` directory. +- **CI/CD needs extra setup.** Your workflows must initialize submodules explicitly: + ```bash + git submodule init && git submodule update + ``` +- **Updating the submodule can cause conflicts.** If two people push to the submodule simultaneously, merging back is painful. + +### When to Use This + +- You're already using submodules elsewhere in your org (they're familiar with the pain). +- You want to share the same squad configuration across 3+ repositories. +- Your team is comfortable with advanced git workflows. + +**Honest take:** Submodules work, but the git community almost universally dislikes them. They're powerful tools for specific use cases, but most teams regret using them. Only reach for submodules if you truly need them. + +--- + +## 5. Symlink to External Directory + +**What it is:** Keep `.ai-team/` somewhere else on your filesystem (e.g., `~/my-squads/my-project-squad/`), then symlink it into your repo. + +### Setup + +On macOS/Linux: + +```bash +mkdir -p ~/my-squads/my-project-squad +ln -s ~/my-squads/my-project-squad .ai-team +``` + +On Windows (requires admin or Developer Mode): + +```bash +mkdir C:\Users\you\my-squads\my-project-squad +mklink /D .ai-team C:\Users\you\my-squads\my-project-squad +``` + +Add `.ai-team` to `.gitignore`: + +```bash +echo ".ai-team" >> .gitignore +``` + +### Pros + +- **Share state across repos.** Point multiple projects to the same squad directory. +- **No git noise.** The symlink itself isn't tracked; `.ai-team/` is ignored. +- **Maximum flexibility.** You can move the squad, reorganize it, or swap it out. + +### Cons + +- **Not portable.** Symlinks are machine-specific. Collaborators need the exact same filesystem layout or the symlink breaks. +- **Windows compatibility is fragile.** Symlinks on Windows require admin privileges or Developer Mode; many orgs disable this. +- **Easy to break.** If the external directory is deleted, the symlink points to nothing. +- **No git history.** Team state changes aren't tracked in your project repo; you're on your own for backups. + +### When to Use This + +- You maintain multiple repositories with the same squad. +- Everyone on your team has the same filesystem layout (rare in practice). +- You're on macOS/Linux and control your development environment. + +**Caveat:** This breaks for most teams sharing code. Collaborators' symlinks will be broken, external contractors can't participate, and CI/CD usually fails. + +--- + +## 6. Dev Branch Only (The Squad Project's Own Approach) + +**What it is:** `.ai-team/` is committed, but *only* on dev/feature branches. On `main`, it's gitignored. When you create a feature branch, you remove `.ai-team/` from `.gitignore` so the team travels with your work. + +### Setup + +On `main`: + +```bash +echo ".ai-team/" >> .gitignore +git add .gitignore +git commit -m "Ignore squad team on main" +``` + +When you start a feature branch: + +```bash +git checkout -b feature/my-feature +git rm .ai-team/ # if it exists from a previous branch +# Remove .ai-team/ from .gitignore +git edit .gitignore +# (remove the .ai-team/ line) +git add .gitignore +git commit -m "Track squad team on this branch" +``` + +Agents work with the full `.ai-team/` context while you develop. When you merge back to `main`, the PR shows the `.ai-team/` changes, but `main` stays clean. + +### Pros + +- **Clean main branch.** `main` is pure code, no squad artifacts. +- **Full context on feature branches.** Agents have the team history while you work. +- **Git history preserved.** Team changes are committed on feature branches and visible in git log. +- **Collaborators get team state.** Anyone checking out your feature branch gets `.ai-team/`. +- **GitHub Actions can work both ways.** On `main`, workflows use GitHub API (label sync, heartbeat). On feature branches, they can use team-based routing if needed. + +### Cons + +- **Merge conflicts when syncing branches.** If `main` has `.ai-team/` gitignored but your branch commits it, merging is messy. +- **Easy to forget the pattern.** Developers forget to remove `.ai-team/` from `.gitignore` when creating feature branches (or forget to add it back when switching back to `main`). +- **PR diffs include team changes.** PRs from feature branches show all `.ai-team/` modifications, which some teams find noisy. + +### When to Use This + +- Small team that's aware of the pattern. +- You want clean main but team context on feature branches. +- You're OK with remembering to toggle `.gitignore` per branch. + +--- + +## Decision Matrix + +| Scenario | Option | Why | +|----------|--------|-----| +| Solo dev, private repo | **1. Committed** | Simplest, portable, full history | +| Team, shared state, no PR concerns | **1. Committed** | Everyone gets same team | +| Team, clean main, no Actions workflows | **2. Gitignored** | No policy issues, no PR noise | +| Team, clean main, need Actions workflows | **3. Separate Branch** | Full history, shared state, Actions can access it | +| Multiple repos, same squad | **4. Submodule** or **5. Symlink** | Submodule if you need git; symlink if portable | +| Enterprise, AI artifact policy | **2. Gitignored** or **4. Submodule** | Keep AI stuff out of main repo | +| Open source | **1. Committed** | Contributors should see how the team works | + +--- + +## Tips + +- **GitHub Actions and Gitignored `.ai-team/`:** If you choose option 2 (gitignore), remember that Actions workflows see committed files only. Label sync and heartbeat workflows (which use GitHub API) still work. But `squad.agent.md` triage rules won't see `.ai-team/decisions.md` during automated runs. Workaround: Copy critical decisions to a committed file or pass them as workflow env vars. +- **Merge conflicts on `decisions.md`:** If multiple people are committing to `.ai-team/` at the same time, `decisions.md` and agent histories conflict frequently. Use the `.gitattributes merge=union` rules that Squad sets up. Check the file after merge to ensure it looks reasonable. +- **Backup your team.** If you're gitignoring `.ai-team/`, make sure you have backups. A deleted `.ai-team/` directory with no git history is gone forever. +- **Communicate the pattern to your team.** Whatever you choose, document it. Add a line to your `CONTRIBUTING.md` or `README.md` explaining where the squad lives and how to interact with it. +- **Start simple, migrate later.** Commit `.ai-team/` initially (option 1). If PR noise becomes a real problem, migrate to option 2 or 3. Changing strategies later is possible but requires care. + +--- + +## Sample Prompts + +Use these prompts with Squad to implement specific strategies: + +- **"Keep .ai-team/ out of my main branch."** + - Directs you toward option 3 (separate branch) or option 6 (dev-only). + +- **"I want to share my squad across three repos without duplicating the team state."** + - Points to option 4 (submodule) or option 5 (symlink). + +- **"Add .ai-team to .gitignore but make sure GitHub Actions can still route based on team.md."** + - Hybrid: gitignore but keep a committed `squad-routing.md` that Actions reads. + +- **"My enterprise doesn't allow AI artifacts in the main repository."** + - Option 2 (gitignore) or option 4 (submodule in a separate org-controlled repo). + +- **"I deleted .ai-team by accident. How do I recover it?"** + - If committed: `git checkout HEAD~5 .ai-team/` (restore from history). + - If gitignored: No recovery from git. Restore from backup or rebuild the team. + +--- + +## See Also + +- **[Adding Squad to an Existing Repo](existing-repo.md)** โ€” How to integrate Squad into a project with existing code. +- **[Squad for Solo Developers](solo-dev.md)** โ€” Building alone? Here's how Squad becomes your team. +- **[Multiple Squads](multiple-squads.md)** โ€” Managing more than one AI team. +- **[Team Portability](team-portability.md)** โ€” Moving your squad to a new repo or machine. diff --git a/docs/scenarios/troubleshooting.md b/docs/scenarios/troubleshooting.md new file mode 100644 index 000000000..906fc4f98 --- /dev/null +++ b/docs/scenarios/troubleshooting.md @@ -0,0 +1,124 @@ +# Troubleshooting + +Common issues and fixes for Squad installation and usage. + +--- + +## `npx github:bradygaster/squad` appears to hang + +**Problem:** Running the install command shows a frozen npm spinner. Nothing happens. + +**Cause:** npm resolves `github:` package specifiers via `git+ssh://git@github.com/...`. If no SSH agent is running (or your key isn't loaded), git prompts for your passphrase on the TTY โ€” but npm's progress spinner overwrites the prompt, making it invisible. This is an npm TTY handling issue, not a Squad bug. + +**Fix (choose one):** + +1. **Start your SSH agent first** (recommended): + ```bash + eval "$(ssh-agent -s)" + ssh-add + ``` + Then re-run `npx github:bradygaster/squad`. + +2. **Disable npm's progress spinner** to reveal the prompt: + ```bash + npx --progress=false github:bradygaster/squad + ``` + +3. **Use HTTPS instead of SSH** by configuring git: + ```bash + git config --global url."https://github.com/".insteadOf git@github.com: + ``` + +**Reference:** [#30](https://github.com/bradygaster/squad/issues/30) + +--- + +## `gh` CLI not authenticated + +**Problem:** GitHub Issues, PRs, Ralph, or Project Boards commands fail with authentication errors. + +**Cause:** The `gh` CLI isn't logged in, or is missing required scopes. + +**Fix:** + +1. Log in: + ```bash + gh auth login + ``` + +2. If using Project Boards, add the `project` scope: + ```bash + gh auth refresh -s project + ``` + +3. Verify: + ```bash + gh auth status + ``` + +--- + +## Node.js version too old + +**Problem:** `npx github:bradygaster/squad` fails with an engine compatibility error, or Squad behaves unexpectedly. + +**Cause:** Squad requires Node.js 22.0.0 or later (enforced via `engines` in `package.json`). + +**Fix:** + +```bash +node --version +``` + +If below v22, upgrade Node.js: +- **nvm (macOS/Linux):** `nvm install 22 && nvm use 22` +- **nvm-windows:** `nvm install 22 && nvm use 22` +- **Direct download:** [nodejs.org](https://nodejs.org/) + +--- + +## Squad agent not appearing in Copilot + +**Problem:** After install, `squad` doesn't show up in the `/agents` list in GitHub Copilot. + +**Cause:** The `.github/agents/squad.agent.md` file may not have been created, or Copilot hasn't refreshed its agent list. + +**Fix:** + +1. Verify the file exists: + ```bash + ls .github/agents/squad.agent.md + ``` + If missing, re-run `npx github:bradygaster/squad`. + +2. Restart your Copilot session โ€” close and reopen the terminal or editor. + +--- + +## Upgrade doesn't change anything + +**Problem:** Running `npx github:bradygaster/squad upgrade` completes but nothing changes. + +**Cause:** You may already be on the latest version, or npm cached an old version. + +**Fix:** + +1. Check current version in `.github/agents/squad.agent.md` (frontmatter `version:` field). + +2. Clear npm cache and retry: + ```bash + npx --yes github:bradygaster/squad upgrade + ``` + +--- + +## Windows-specific issues + +**Problem:** Path errors or file operations fail on Windows. + +**Cause:** Some shell commands assume Unix-style paths. + +**Fix:** Squad's core uses `path.join()` for all file operations and is Windows-safe. If you see path issues: +- Use PowerShell or Git Bash (not cmd.exe) +- Ensure git is in your PATH +- Ensure `gh` CLI is in your PATH diff --git a/docs/scenarios/upgrading.md b/docs/scenarios/upgrading.md index 2a8a41aab..4fb1df61a 100644 --- a/docs/scenarios/upgrading.md +++ b/docs/scenarios/upgrading.md @@ -57,22 +57,36 @@ Example: upgrading to v0.2.0 creates `.ai-team/skills/` if it doesn't already ex ## Version Stamping -`squad.agent.md` is version-stamped on install and upgrade. You can check your installed version: +`squad.agent.md` is version-stamped on install and upgrade. The version appears in two places: -```bash -npx github:bradygaster/squad --version -``` +### 1. Agent Name (Visible in UI) +The version is displayed in the agent picker across all Copilot hosts (VS Code, CLI, Visual Studio): + +```yaml +name: Squad (vX.Y.Z) ``` -0.2.0 -``` -Or look at the frontmatter in `.github/agents/squad.agent.md`: +When you select agents in Copilot, you'll see **"Squad (vX.Y.Z)"** in the dropdown โ€” making it immediately clear which version you're running. + +### 2. Version Field (For Reference) + +The frontmatter also includes a standalone version field: ```yaml -version: "0.2.0" +version: "X.Y.Z" ``` +### 3. CLI Check + +You can also check your installed version from the command line: + +```bash +npx github:bradygaster/squad --version +``` + +The output will show your installed version (e.g., `X.Y.Z`). + --- ## Already Up to Date diff --git a/docs/tips-and-tricks.md b/docs/tips-and-tricks.md new file mode 100644 index 000000000..a59c7d336 --- /dev/null +++ b/docs/tips-and-tricks.md @@ -0,0 +1,634 @@ +# Tips and Tricks for Managing Your Squad + +Real patterns from using Squad effectively. These are techniques that work. + +--- + +## Effective Prompt Patterns + +### 1. Be Specific About Scope + +Good prompts describe the boundary, not just the task. + +``` +โŒ "Build the auth system" +โœ… "Build JWT authentication for login/logout/refresh. Sessions stored in Redis. + Passwords hashed with bcrypt. No OAuth yet โ€” that's phase 2." +``` + +The second one tells the team: what's in, what's out, what's coming. Agents don't have to guess or ask. + +### 2. Name the Team Roster in Your Spec + +If you need specialized agents, say so in the prompt. + +``` +I'm building a data pipeline that: +- Reads CSV files and validates schema (Backend handles I/O) +- Transforms data with custom rules (Data Specialist handles logic) +- Loads into PostgreSQL with migration tracking (Backend handles schema) +- Generates reports as HTML dashboards (Frontend handles UI) + +I need Backend, a Data Specialist (who knows ETL patterns), and Frontend. +Set up the team and start with the data validation layer. +``` + +This creates exactly the team you need instead of defaulting to the generic roster. + +### 3. Use "Team" When Parallel Work Matters + +``` +> Team, build the login page. +``` + +This spawns frontend (UI), backend (endpoints), tester (test cases), and lead (architecture) โ€” all at once. They divide the work naturally. + +For sequential work, name the agent: + +``` +> Dallas (Frontend), build the dashboard layout first. +> When you're done, Kane (Backend) will add the data binding. +``` + +### 4. Stack Decisions in Your Prompt + +Decisions made early prevent agents from asking questions later. + +``` +> Here are the rules for this sprint: +> - Always use TypeScript strict mode +> - Component file names are PascalCase, never kebab-case +> - All exports are named (no default exports) +> - React hooks only, no class components +> +> Frontend team, build the form components. These rules are permanent. +``` + +These go into `decisions.md` automatically. Future agents read them before working. + +### 5. Use Bullet Points for Multi-Part Tasks + +Agents process lists better than paragraphs. + +``` +โŒ "We need to update the user model to include profile fields like bio and avatar + and we should also add validation for those fields and write tests." + +โœ… "Update the user model: + - Add bio (string, 500 char max) + - Add avatar (string, URL) + - Add phoneNumber (string, optional, E.164 format) + - Validate all fields + - Write test cases for validation edge cases" +``` + +--- + +## When to Use Direct Commands vs Team Requests + +### Use Direct Commands (Name an Agent) + +When the work is **sequential** or **highly specialized**. + +``` +> Keaton, review this PR for architectural fit. +``` + +| Use Case | Example | Why | +|----------|---------|-----| +| Code review | "Keaton, review the auth endpoints" | Only the lead does design review | +| Specialized skill | "Felix, optimize the database queries" | The performance expert works alone | +| Fix a specific mistake | "Dallas, fix the button styling" | Don't spawn the whole team for one file | +| Unblock someone | "Kane, help Lambert debug the test failure" | Point conversation between two agents | + +### Use Team Requests (Say "Team") + +When the work is **parallel** or **cross-functional**. + +``` +> Team, build the checkout flow. +``` + +| Use Case | Example | Why | +|----------|---------|-----| +| New feature | "Team, build the search feature" | Frontend, backend, tests all start together | +| Sprint planning | "Team, plan the next two weeks" | Lead scopes, backend estimates, tester defines test cases | +| Problem-solving | "Team, we have a performance problem โ€” investigate" | Frontend measures, backend profiles, infra checks caching | +| Iteration round | "Team, fix the feedback from the design review" | Multiple people can tackle different issues in parallel | + +### Use General Requests (No Name) + +When you don't care who handles it, or when it's context-dependent. + +``` +> Add error logging to the API. +``` + +Squad routes this intelligently. Could be backend, could be ops, depends on team. + +--- + +## Getting the Most Out of Parallel Work + +### 1. Wait for Work to Complete Before Following Up + +Squad agents chain their own work. When you give a task, **don't interrupt**. + +``` +You: "Team, build the login page." + [Squad spawns frontend, backend, tester, lead] + [Frontend finishes UI, backend finishes endpoints, tester writes test cases] + + [Test failures show up โ†’ backend picks them up automatically] + [Tester finds edge cases โ†’ backend fixes them โ†’ tester re-runs] + + [5 minutes later, everything is done] +``` + +If you jump in after 2 minutes with "Did you test the form submission?", you break the chain. Let it finish. + +### 2. Check the Work Log, Not the Output + +When agents finish a batch, read the logs, not the code. + +``` +> What did the team just do? +``` + +This asks Scribe to summarize. You'll see: +- What was built +- What decisions were made +- What's left to do +- What surprised them + +Much faster than reading 5 agent outputs. + +### 3. Run Ralph When the Board is Full + +If you have a backlog of issues or PRs, let Ralph process them. + +``` +> Ralph, go +``` + +Ralph will: +1. Triage untriaged issues +2. Assign to team members +3. Spawn agents to work through them +4. Report progress every 3-5 rounds +5. Keep going until the board is clear + +You can keep using the team for urgent work while Ralph grinds through the backlog. + +### 4. Use Parallel Decision-Making + +Agents can write decisions in parallel (they go to `/decisions/inbox/`). Scribe merges them. + +``` +You: "Frontend team, decide on component structure. + Backend team, decide on API versioning. + Both write your decisions to decisions.md. Don't wait for each other." + +[Frontend writes decision about component structure] +[Backend writes decision about API versioning] +[Both decisions merge automatically via Scribe] +[Every agent reads both before the next task] +``` + +This prevents "we decided different things" surprises. + +--- + +## Tips for Working with Ralph (Work Monitor) + +### 1. Activate Ralph When You Have Backlog + +Ralph is most useful when you have open issues. + +``` +> Ralph, start monitoring +``` + +Ralph will: +- Check GitHub Issues for untriaged work +- Ask the Lead to triage +- Assign issues to team members +- Spawn agents to work through them +- Report every 3 rounds + +### 2. Give Ralph a Scope If Needed + +By default, Ralph monitors issues, PRs, and CI. + +``` +> Ralph, scope: just issues +``` + +Useful when: +- You're in the middle of a PR and don't want Ralph to merge it yet +- You only care about triaging issues, not closing them +- You want to focus on one type of work + +### 3. Ralph Reports Automatically Every 3-5 Rounds + +Don't ask for status โ€” Ralph tells you. + +``` +๐Ÿ”„ Ralph: Round 3 complete. + โœ… 2 issues closed, 1 PR merged + ๐Ÿ“‹ 3 items remaining: #42, #45, PR #12 + Continuing... (say "Ralph, idle" to stop) +``` + +When you see this, you can: +- Let Ralph keep working (he will) +- Say "Ralph, idle" to stop +- Jump in with a different task +- Check a specific issue + +### 4. Use Ralph Between Sessions + +The `squad-heartbeat` workflow runs every 30 minutes (or on your schedule). + +Ralph will: +- Triage new issues +- Assign them to team members +- Trigger `@copilot` if you have the coding agent enabled + +This means your squad works even when you're not at the keyboard. + +### 5. Check Ralph's Status Before Wrapping Up + +``` +> Ralph, status +``` + +Ralph does one check and reports: + +``` +๐Ÿ“Š Board Status: + ๐Ÿ”ด Untriaged: 0 issues need triage + ๐ŸŸก In Progress: 1 issue assigned, 0 draft PRs + ๐ŸŸข Ready: 0 PRs approved + โœ… Done: 7 issues closed this session +``` + +If the board is clean, you can wrap up. If there's work, start Ralph for the next session. + +--- + +## Managing Decisions and Team Memory + +### 1. Set Permanent Rules Early + +The first or second session, establish conventions. + +``` +> Here are the permanent rules for this team: +> - Always use TypeScript strict mode +> - Component naming: PascalCase (never kebab-case) +> - All exports are named exports (no defaults) +> - Test coverage must be > 80% +> - PR must have at least one review before merge +``` + +These go to `decisions.md`. Every agent reads them before working. **You only have to say them once.** + +### 2. Use User Directives for "Never Again" Lessons + +When an agent makes a mistake, turn it into a directive. + +``` +> Never use inline styles. Use CSS classes instead. +> Always validate user input on the backend, not just the frontend. +> Never commit environment variables to git. +``` + +These get stored as directives and agents follow them automatically in future sessions. + +### 3. Check decisions.md When Agents Disagree + +If Frontend does something one way and Backend does it another way, the decision is usually missing. + +``` +Agent A: "I used kebab-case for the file names" +Agent B: "I used PascalCase for the file names" + +[You check .ai-team/decisions.md] +[No decision about file naming conventions] + +> Here's the permanent rule: all component files are PascalCase. +``` + +Now it's in the shared brain. Next agent to work on components will see this. + +### 4. Archive Outdated Decisions + +When a decision no longer applies, move it to a "Superseded" section. + +You can edit `.ai-team/decisions.md` directly: + +```markdown +## Superseded Decisions + +- **File naming (v1)**: "All files kebab-case" โ€” SUPERSEDED by PascalCase convention in v2 +- **API versioning (v1)**: "Use URL paths for versioning" โ€” SUPERSEDED by headers-based versioning + +## Active Decisions +... +``` + +Agents know to ignore "Superseded" sections. + +### 5. Let Scribe Handle Decision Merging + +Agents write decisions to `/decisions/inbox/`, Scribe merges them into `/decisions.md`. + +You don't have to manually merge. Just ask: + +``` +> Scribe, merge pending decisions +``` + +Scribe will: +- Read all files in `/decisions/inbox/` +- Merge them into the canonical `decisions.md` +- Deduplicate overlaps +- Clean up the inbox + +This happens automatically in mature teams, but you can force it anytime. + +### 6. Personal History Files Build Over Time + +Each agent's `.ai-team/agents/{name}/history.md` grows with every session. Check it when an agent seems lost. + +``` +[Dallas's history shows] +- React expertise: hooks, context, performance patterns +- Knowledge of routing: react-router v6 +- Knows about the design system: established in session 3 +- Familiar with the component structure: 50+ components in src/components/ +``` + +If an agent keeps asking "where are the components?", their history might not have the right info. Edit it directly or remind them: + +``` +> Dallas, your last 5 sessions were all in the same component library. +> Check your history.md for the path. +``` + +--- + +## Common Pitfalls and How to Avoid Them + +### Pitfall 1: Vague Scope = Agents Ask Questions Instead of Building + +**Problem:** "Build the API" โ€” unclear what endpoints, what data model, what auth. + +**Solution:** Be specific. Agents will ask if unclear, but clarity upfront saves rounds. + +``` +โœ… "Build a REST API for a recipe app. Endpoints: /recipes (list, create), + /recipes/:id (get, update, delete), /recipes/:id/ingredients (list, add). + Auth via JWT. Database: PostgreSQL." +``` + +### Pitfall 2: Interrupting Parallel Work + +**Problem:** You give a task to the team, then jump in after 2 minutes with a follow-up question. + +**Solution:** Let parallel work finish. Squad agents chain automatically. Your interruption breaks the chain. + +``` +โŒ You: "Team, build the checkout page" + [2 minutes later] + You: "Did you test the payment flow yet?" + +โœ… You: "Team, build the checkout page" + [Wait for them to finish] + You: "What did you build?" +``` + +### Pitfall 3: Forgetting That Decisions Persist + +**Problem:** You set a rule in session 1, forget about it, contradict it in session 5. + +**Solution:** Read `decisions.md` at the start of every session, or ask Scribe: + +``` +> Scribe, remind me of the permanent rules. +``` + +### Pitfall 4: Not Using Ralph on a Full Backlog + +**Problem:** You have 10 open issues, but you keep working on small tasks manually. + +**Solution:** Use Ralph for the backlog, stay focused on urgent work. + +``` +> Ralph, start monitoring. I'm going to focus on the payment bug. +``` + +Ralph handles the backlog, you handle the critical path. + +### Pitfall 5: Too Many Agents at Once + +**Problem:** You spawn a huge team and context gets confusing. + +**Solution:** Start small. 4-5 agents is a good team. Add specialists only when needed. + +``` +โœ… "Start with Lead, Frontend, Backend, Tester. If we need DevOps later, we'll add them." + +โŒ "I want Lead, Frontend, Backend, Tester, DevOps, Data Engineer, Designer, and a Scribe." +``` + +### Pitfall 6: Lost Work Because You Didn't Commit `.ai-team/` + +**Problem:** You deleted the repo and lost all your team knowledge. + +**Solution:** **Commit `.ai-team/` to git.** It's permanent team memory. + +```bash +git add .ai-team/ +git commit -m "Add squad team state" +git push +``` + +Now anyone who clones the repo gets your team with all their learned knowledge. + +### Pitfall 7: Agents Stuck on the Same Mistake + +**Problem:** An agent keeps making the same error even though you fixed it in session 3. + +**Solution:** The decision might not be in `decisions.md`. Add it. + +``` +> Agent keeps importing with `require` instead of `import`. +> Here's the rule: Always use ES6 import/export syntax. +``` + +This goes to `decisions.md`. Next time that agent works, they'll read it. + +### Pitfall 8: Ralph Running Out of Work Too Quietly + +**Problem:** Ralph finishes all the work but doesn't tell you, so you think he's still working. + +**Solution:** Ralph reports every 3-5 rounds. If you don't see a report in a while, ask: + +``` +> Ralph, status +``` + +Ralph will check once and report. If the board is empty, you know you're done. + +--- + +## Advanced Patterns + +### Pattern 1: Decision First, Implementation Second + +Before any agent writes code, the team agrees on the design. + +``` +> Team, design the user model. Don't code yet. +> Frontend, what fields do you need? Backend, what do you need to persist? +> Tester, what are the validation edge cases? +> Write your decisions to decisions.md. + +[Team agrees on the design] + +> Team, now build it. +``` + +This prevents "we built different things" surprises. + +### Pattern 2: Run Two Parallel Teams on One Repo + +If you have a large project, you can run one team on one feature, another team on another. + +``` +Squad 1: "Team A, build the admin dashboard. You own features/admin/." +Squad 2: "Team B, build the mobile app. You own features/mobile/." + +[Both teams work in parallel] +[Shared decisions in .ai-team/decisions.md prevent conflicts] +``` + +Requires good routing rules and clear ownership, but it works. + +### Pattern 3: Spike โ†’ Decision โ†’ Build + +For hard problems, do a spike first. + +``` +> Keaton (Lead), do a spike on authentication patterns for this stack. +> Spend 30 minutes exploring. Write your findings to a decision. + +[Keaton researches, writes decision about auth strategy] + +> Team, now build the auth system using the strategy Keaton decided. +``` + +This prevents agents from building the wrong thing. + +### Pattern 4: Post-Mortem Decisions + +When something goes wrong, capture the lesson. + +``` +> The API is returning user passwords in the response. This was a mistake. +> Here's the rule going forward: Never include password fields in API responses. +``` + +This prevents it from happening again. + +--- + +## Prompts You Can Copy + +### Getting Started + +``` +I'm building [brief description]. Set up the team. +Stack: [language, framework, database] +Key requirements: +- [requirement 1] +- [requirement 2] +- [requirement 3] +``` + +### Asking for Status + +``` +What did the team accomplish last session? Any blockers? +``` + +### Parallel Work on Different Features + +``` +Team, I want you to work on two things in parallel: + +Feature A (Frontend + Backend): +- [spec] + +Feature B (Backend + Tester): +- [spec] + +Divide the team. Start both immediately. +``` + +### Spike Before Building + +``` +Keaton, do a 20-minute spike on [problem]. +Research [specific areas]. +Write a decision with your recommendation. +When you're done, tell me what you learned. +``` + +### Closing a Phase + +``` +Team, we're closing the MVP phase. +Keaton, what's the current architecture? +Kane, what's left to do on the backend? +Dallas, what UX work is pending? +Lambert, what tests are missing? + +Write your summary to history.md. +``` + +--- + +## Session Flow Template + +A typical high-performing session: + +1. **Start:** Open Copilot, say "Team" or name an agent +2. **Set context:** Describe the work (scope, decisions, rules) +3. **Parallel execution:** Let agents work (don't interrupt) +4. **Check logs:** Ask Scribe what happened while you were reading code +5. **Next round:** Based on what Scribe told you, give follow-up work or start Ralph +6. **Wrap up:** Ask Ralph for status, commit `.ai-team/`, go home + +**Time to productive work: usually < 2 minutes.** + +--- + +## Reference: Who Does What + +When you're unsure who to ask: + +| Task | Ask | Why | +|------|-----|-----| +| Architecture review | Lead (Keaton) | Design decisions are the lead's job | +| Fix a feature | The assigned agent | They know the context | +| Debug a test | Tester + Backend | Usually a logic error or missing setup | +| Design decision | Team (parallel) | All perspectives needed | +| Code review | Lead | Final arbiter | +| What happened last session? | Scribe | Scribe tracks everything | +| What's on the backlog? | Ralph | Ralph monitors the board | +| New decision | Any agent can propose, Scribe merges | Decisions are shared | +| Edit decisions.md | You or Scribe | Plain markdown, editable anytime | + diff --git a/index.js b/index.js index ecc2641a7..525a7a798 100644 --- a/index.js +++ b/index.js @@ -468,8 +468,13 @@ const isUpgrade = cmd === 'upgrade'; // Stamp version into squad.agent.md after copying function stampVersion(filePath) { - const content = fs.readFileSync(filePath, 'utf8'); - fs.writeFileSync(filePath, content.replace('version: "0.0.0-source"', `version: "${pkg.version}"`)); + let content = fs.readFileSync(filePath, 'utf8'); + // Replace version field + content = content.replace(/^version:\s*"[^"]*"/m, `version: "${pkg.version}"`); + // Replace version in name field to show in agent picker UI + // Handles both "Squad" and "Squad (vX.Y.Z)" formats + content = content.replace(/^name:\s*Squad(?:\s*\([^)]*\))?$/m, `name: Squad (v${pkg.version})`); + fs.writeFileSync(filePath, content); } // Read version from squad.agent.md frontmatter diff --git a/templates/workflows/squad-heartbeat.yml b/templates/workflows/squad-heartbeat.yml index a76f07f9d..a0b1b3ba1 100644 --- a/templates/workflows/squad-heartbeat.yml +++ b/templates/workflows/squad-heartbeat.yml @@ -113,7 +113,25 @@ jobs: } } - // 3. Find open PRs that need attention + // 3. Find squad issues missing triage verdict (no go:* label) + const missingVerdict = squadIssues.filter(issue => { + const labels = issue.labels.map(l => l.name); + return !labels.some(l => l.startsWith('go:')); + }); + + // 4. Find go:yes issues missing release target + const goYesIssues = squadIssues.filter(issue => { + const labels = issue.labels.map(l => l.name); + return labels.includes('go:yes') && !labels.some(l => l.startsWith('release:')); + }); + + // 4b. Find issues missing type: label + const missingType = squadIssues.filter(issue => { + const labels = issue.labels.map(l => l.name); + return !labels.some(l => l.startsWith('type:')); + }); + + // 5. Find open PRs that need attention const { data: openPRs } = await github.rest.pulls.list({ owner: context.repo.owner, repo: context.repo.repo, @@ -133,6 +151,15 @@ jobs: if (unstarted.length > 0) { summary.push(`๐ŸŸก **${unstarted.length} assigned issue(s)** have no assignee`); } + if (missingVerdict.length > 0) { + summary.push(`โšช **${missingVerdict.length} issue(s)** missing triage verdict (no \`go:\` label)`); + } + if (goYesIssues.length > 0) { + summary.push(`โšช **${goYesIssues.length} approved issue(s)** missing release target (no \`release:\` label)`); + } + if (missingType.length > 0) { + summary.push(`โšช **${missingType.length} issue(s)** missing \`type:\` label`); + } if (squadPRs.length > 0) { const drafts = squadPRs.filter(pr => pr.draft).length; const ready = squadPRs.length - drafts; diff --git a/templates/workflows/squad-label-enforce.yml b/templates/workflows/squad-label-enforce.yml new file mode 100644 index 000000000..633d220df --- /dev/null +++ b/templates/workflows/squad-label-enforce.yml @@ -0,0 +1,181 @@ +name: Squad Label Enforce + +on: + issues: + types: [labeled] + +permissions: + issues: write + contents: read + +jobs: + enforce: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Enforce mutual exclusivity + uses: actions/github-script@v7 + with: + script: | + const issue = context.payload.issue; + const appliedLabel = context.payload.label.name; + + // Namespaces with mutual exclusivity rules + const EXCLUSIVE_PREFIXES = ['go:', 'release:', 'type:', 'priority:']; + + // Skip if not a managed namespace label + if (!EXCLUSIVE_PREFIXES.some(p => appliedLabel.startsWith(p))) { + core.info(`Label ${appliedLabel} is not in a managed namespace โ€” skipping`); + return; + } + + const allLabels = issue.labels.map(l => l.name); + + // Handle go: namespace (mutual exclusivity) + if (appliedLabel.startsWith('go:')) { + const otherGoLabels = allLabels.filter(l => + l.startsWith('go:') && l !== appliedLabel + ); + + if (otherGoLabels.length > 0) { + // Remove conflicting go: labels + for (const label of otherGoLabels) { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + name: label + }); + core.info(`Removed conflicting label: ${label}`); + } + + // Post update comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `๐Ÿท๏ธ Triage verdict updated โ†’ \`${appliedLabel}\`` + }); + } + + // Auto-apply release:backlog if go:yes and no release target + if (appliedLabel === 'go:yes') { + const hasReleaseLabel = allLabels.some(l => l.startsWith('release:')); + if (!hasReleaseLabel) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['release:backlog'] + }); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `๐Ÿ“‹ Marked as \`release:backlog\` โ€” assign a release target when ready.` + }); + + core.info('Applied release:backlog for go:yes issue'); + } + } + + // Remove release: labels if go:no + if (appliedLabel === 'go:no') { + const releaseLabels = allLabels.filter(l => l.startsWith('release:')); + if (releaseLabels.length > 0) { + for (const label of releaseLabels) { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + name: label + }); + core.info(`Removed release label from go:no issue: ${label}`); + } + } + } + } + + // Handle release: namespace (mutual exclusivity) + if (appliedLabel.startsWith('release:')) { + const otherReleaseLabels = allLabels.filter(l => + l.startsWith('release:') && l !== appliedLabel + ); + + if (otherReleaseLabels.length > 0) { + // Remove conflicting release: labels + for (const label of otherReleaseLabels) { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + name: label + }); + core.info(`Removed conflicting label: ${label}`); + } + + // Post update comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `๐Ÿท๏ธ Release target updated โ†’ \`${appliedLabel}\`` + }); + } + } + + // Handle type: namespace (mutual exclusivity) + if (appliedLabel.startsWith('type:')) { + const otherTypeLabels = allLabels.filter(l => + l.startsWith('type:') && l !== appliedLabel + ); + + if (otherTypeLabels.length > 0) { + for (const label of otherTypeLabels) { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + name: label + }); + core.info(`Removed conflicting label: ${label}`); + } + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `๐Ÿท๏ธ Issue type updated โ†’ \`${appliedLabel}\`` + }); + } + } + + // Handle priority: namespace (mutual exclusivity) + if (appliedLabel.startsWith('priority:')) { + const otherPriorityLabels = allLabels.filter(l => + l.startsWith('priority:') && l !== appliedLabel + ); + + if (otherPriorityLabels.length > 0) { + for (const label of otherPriorityLabels) { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + name: label + }); + core.info(`Removed conflicting label: ${label}`); + } + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `๐Ÿท๏ธ Priority updated โ†’ \`${appliedLabel}\`` + }); + } + } + + core.info(`Label enforcement complete for ${appliedLabel}`); diff --git a/templates/workflows/squad-triage.yml b/templates/workflows/squad-triage.yml index fb1c3e19c..0aa53c9aa 100644 --- a/templates/workflows/squad-triage.yml +++ b/templates/workflows/squad-triage.yml @@ -193,6 +193,14 @@ jobs: labels: [assignLabel] }); + // Apply default triage verdict + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['go:needs-research'] + }); + // Auto-assign @copilot if enabled if (isCopilot && copilotAutoAssign) { try { diff --git a/templates/workflows/sync-squad-labels.yml b/templates/workflows/sync-squad-labels.yml index 67b730732..3ae1ff5a4 100644 --- a/templates/workflows/sync-squad-labels.yml +++ b/templates/workflows/sync-squad-labels.yml @@ -63,6 +63,36 @@ jobs: const MEMBER_COLOR = '3b82f6'; const COPILOT_COLOR = '10b981'; + // Define go: and release: labels (static) + const GO_LABELS = [ + { name: 'go:yes', color: '0E8A16', description: 'Ready to implement' }, + { name: 'go:no', color: 'B60205', description: 'Not pursuing' }, + { name: 'go:needs-research', color: 'FBCA04', description: 'Needs investigation' } + ]; + + const RELEASE_LABELS = [ + { name: 'release:v0.4.0', color: '0052CC', description: 'Targeted for v0.4.0' }, + { name: 'release:v0.5.0', color: '1D76DB', description: 'Targeted for v0.5.0' }, + { name: 'release:v0.6.0', color: '5319E7', description: 'Targeted for v0.6.0' }, + { name: 'release:v1.0.0', color: '6F42C1', description: 'Targeted for v1.0.0' }, + { name: 'release:backlog', color: 'C5DEF5', description: 'Not yet targeted' } + ]; + + const TYPE_LABELS = [ + { name: 'type:feature', color: 'D4C5F9', description: 'New capability' }, + { name: 'type:bug', color: 'D73A4A', description: 'Something broken' }, + { name: 'type:spike', color: 'F9D0C4', description: 'Research/investigation โ€” produces a plan, not code' }, + { name: 'type:docs', color: 'C5DEF5', description: 'Documentation work' }, + { name: 'type:chore', color: 'BFD4F2', description: 'Maintenance, refactoring, cleanup' }, + { name: 'type:epic', color: 'B60205', description: 'Parent issue that decomposes into sub-issues' } + ]; + + const PRIORITY_LABELS = [ + { name: 'priority:p0', color: 'B60205', description: 'Blocking release' }, + { name: 'priority:p1', color: 'D93F0B', description: 'This sprint' }, + { name: 'priority:p2', color: 'FBCA04', description: 'Next sprint' } + ]; + // Ensure the base "squad" triage label exists const labels = [ { name: 'squad', color: SQUAD_COLOR, description: 'Squad triage inbox โ€” Lead will assign to a member' } @@ -85,6 +115,12 @@ jobs: }); } + // Add go:, release:, type:, and priority: labels + labels.push(...GO_LABELS); + labels.push(...RELEASE_LABELS); + labels.push(...TYPE_LABELS); + labels.push(...PRIORITY_LABELS); + // Sync labels (create or update) for (const label of labels) { try { diff --git a/test/index.test.js b/test/index.test.js deleted file mode 100644 index 54921752d..000000000 --- a/test/index.test.js +++ /dev/null @@ -1,1392 +0,0 @@ -const { describe, it, beforeEach, afterEach } = require('node:test'); -const assert = require('node:assert/strict'); -const fs = require('fs'); -const path = require('path'); -const os = require('os'); -const { execSync } = require('child_process'); - -const ROOT = path.resolve(__dirname, '..'); -const INDEX = path.join(ROOT, 'index.js'); -const PKG = require(path.join(ROOT, 'package.json')); - -function runInit(cwd) { - return execSync(`node "${INDEX}"`, { cwd, encoding: 'utf8', env: { ...process.env } }); -} - -function runCmd(cwd, args) { - return execSync(`node "${INDEX}" ${args}`, { cwd, encoding: 'utf8', env: { ...process.env } }); -} - -function runCmdStatus(cwd, args) { - try { - const stdout = execSync(`node "${INDEX}" ${args}`, { cwd, encoding: 'utf8', env: { ...process.env } }); - return { stdout, exitCode: 0 }; - } catch (err) { - return { stdout: err.stdout || '', stderr: err.stderr || '', exitCode: err.status }; - } -} - -// --- copyRecursive unit tests --- - -describe('copyRecursive', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-copy-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - // We can't require copyRecursive directly (no module.exports), so we - // replicate it here for isolated unit testing of the algorithm. - function copyRecursive(src, target) { - if (fs.statSync(src).isDirectory()) { - fs.mkdirSync(target, { recursive: true }); - for (const entry of fs.readdirSync(src)) { - copyRecursive(path.join(src, entry), path.join(target, entry)); - } - } else { - fs.mkdirSync(path.dirname(target), { recursive: true }); - fs.copyFileSync(src, target); - } - } - - it('copies a single file', () => { - const src = path.join(tmpDir, 'src'); - const dest = path.join(tmpDir, 'dest'); - fs.mkdirSync(src); - fs.writeFileSync(path.join(src, 'file.txt'), 'hello'); - - copyRecursive(path.join(src, 'file.txt'), path.join(dest, 'file.txt')); - assert.equal(fs.readFileSync(path.join(dest, 'file.txt'), 'utf8'), 'hello'); - }); - - it('copies nested directories and preserves file contents', () => { - const src = path.join(tmpDir, 'src'); - const dest = path.join(tmpDir, 'dest'); - - // Create nested structure: src/a/b/deep.txt, src/root.md - fs.mkdirSync(path.join(src, 'a', 'b'), { recursive: true }); - fs.writeFileSync(path.join(src, 'root.md'), '# Root'); - fs.writeFileSync(path.join(src, 'a', 'mid.json'), '{"key":"value"}'); - fs.writeFileSync(path.join(src, 'a', 'b', 'deep.txt'), 'deep content'); - - copyRecursive(src, dest); - - assert.equal(fs.readFileSync(path.join(dest, 'root.md'), 'utf8'), '# Root'); - assert.equal(fs.readFileSync(path.join(dest, 'a', 'mid.json'), 'utf8'), '{"key":"value"}'); - assert.equal(fs.readFileSync(path.join(dest, 'a', 'b', 'deep.txt'), 'utf8'), 'deep content'); - }); - - it('copies an empty directory', () => { - const src = path.join(tmpDir, 'src'); - const dest = path.join(tmpDir, 'dest'); - fs.mkdirSync(src); - - copyRecursive(src, dest); - assert.ok(fs.existsSync(dest)); - assert.equal(fs.readdirSync(dest).length, 0); - }); - - it('preserves binary file contents', () => { - const src = path.join(tmpDir, 'src'); - const dest = path.join(tmpDir, 'dest'); - fs.mkdirSync(src); - - const buf = Buffer.from([0x00, 0x01, 0xFF, 0xFE, 0x89, 0x50]); - fs.writeFileSync(path.join(src, 'bin.dat'), buf); - - copyRecursive(src, dest); - const result = fs.readFileSync(path.join(dest, 'bin.dat')); - assert.deepEqual(result, buf); - }); -}); - -// --- Init happy path --- - -describe('init into empty directory', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-init-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('creates .github/agents/squad.agent.md', () => { - runInit(tmpDir); - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - assert.ok(fs.existsSync(agentFile), 'squad.agent.md should exist'); - - // Content should match the source but with version stamped - const source = fs.readFileSync(path.join(ROOT, '.github', 'agents', 'squad.agent.md'), 'utf8'); - const actual = fs.readFileSync(agentFile, 'utf8'); - const pkg = require(path.join(ROOT, 'package.json')); - const expected = source.replace('version: "0.0.0-source"', `version: "${pkg.version}"`); - assert.equal(actual, expected); - }); - - it('stamps version into squad.agent.md', () => { - runInit(tmpDir); - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - const content = fs.readFileSync(agentFile, 'utf8'); - const pkg = require(path.join(ROOT, 'package.json')); - assert.ok(content.includes(`version: "${pkg.version}"`), 'should contain stamped version'); - assert.ok(!content.includes('0.0.0-source'), 'should not contain source placeholder'); - }); - - it('creates .ai-team-templates/ with all template files', () => { - runInit(tmpDir); - const templatesDir = path.join(tmpDir, '.ai-team-templates'); - assert.ok(fs.existsSync(templatesDir), '.ai-team-templates/ should exist'); - - // Every file/dir in templates/ should be copied - const sourceFiles = fs.readdirSync(path.join(ROOT, 'templates')); - const destFiles = fs.readdirSync(templatesDir); - assert.deepEqual(destFiles.sort(), sourceFiles.sort()); - - // Spot-check: content matches for files (skip directories) - for (const file of sourceFiles) { - const srcPath = path.join(ROOT, 'templates', file); - if (fs.statSync(srcPath).isDirectory()) continue; - const expected = fs.readFileSync(srcPath, 'utf8'); - const actual = fs.readFileSync(path.join(templatesDir, file), 'utf8'); - assert.equal(actual, expected, `template ${file} content should match`); - } - }); - - it('creates drop-box directories', () => { - runInit(tmpDir); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'decisions', 'inbox')), - 'decisions/inbox should exist'); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'orchestration-log')), - 'orchestration-log should exist'); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'casting')), - 'casting should exist'); - }); - - it('creates .ai-team/skills/ with starter skills on init', () => { - runInit(tmpDir); - const skillsDir = path.join(tmpDir, '.ai-team', 'skills'); - assert.ok(fs.existsSync(skillsDir), '.ai-team/skills/ should exist'); - assert.ok(fs.existsSync(path.join(skillsDir, 'squad-conventions', 'SKILL.md')), - 'squad-conventions/SKILL.md should be copied as starter skill'); - }); - - it('starter skill content matches source template', () => { - runInit(tmpDir); - const expected = fs.readFileSync( - path.join(ROOT, 'templates', 'skills', 'squad-conventions', 'SKILL.md'), 'utf8'); - const actual = fs.readFileSync( - path.join(tmpDir, '.ai-team', 'skills', 'squad-conventions', 'SKILL.md'), 'utf8'); - assert.equal(actual, expected, 'starter skill content should match source'); - }); - - it('outputs success messages', () => { - const output = runInit(tmpDir); - assert.ok(output.includes('squad.agent.md'), 'should mention squad.agent.md'); - assert.ok(output.includes('.ai-team-templates'), 'should mention templates'); - assert.ok(output.includes('Squad is ready'), 'should print ready message'); - }); -}); - -// --- Re-init (idempotency) --- - -describe('re-init into existing directory', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-reinit-')); - // First init - runInit(tmpDir); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('skips squad.agent.md when it already exists', () => { - // Modify the agent file so we can verify it's NOT overwritten - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - fs.writeFileSync(agentFile, 'user-customized content'); - - const output = runInit(tmpDir); - assert.ok(output.includes('already exists'), 'should report skipping'); - - const content = fs.readFileSync(agentFile, 'utf8'); - assert.equal(content, 'user-customized content', 'should NOT overwrite user file'); - }); - - it('skips .ai-team-templates/ when it already exists', () => { - // Add a user file to templates dir - const userFile = path.join(tmpDir, '.ai-team-templates', 'user-custom.md'); - fs.writeFileSync(userFile, 'custom content'); - - const output = runInit(tmpDir); - assert.ok(output.includes('already exists'), 'should report skipping templates'); - - // User file should still be there - assert.ok(fs.existsSync(userFile), 'user custom file should survive re-init'); - }); - - it('drop-box directories still exist after re-init', () => { - runInit(tmpDir); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'decisions', 'inbox'))); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'orchestration-log'))); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'casting'))); - }); - - it('does not corrupt existing drop-box contents', () => { - // Put a file in inbox before re-init - const inboxFile = path.join(tmpDir, '.ai-team', 'decisions', 'inbox', 'test-decision.md'); - fs.writeFileSync(inboxFile, '# Test Decision'); - - runInit(tmpDir); - - assert.ok(fs.existsSync(inboxFile), 'inbox file should survive'); - assert.equal(fs.readFileSync(inboxFile, 'utf8'), '# Test Decision'); - }); - - it('does not overwrite existing skills on re-init', () => { - // Add a user skill before re-init - const userSkillDir = path.join(tmpDir, '.ai-team', 'skills', 'my-custom-skill'); - fs.mkdirSync(userSkillDir, { recursive: true }); - fs.writeFileSync(path.join(userSkillDir, 'SKILL.md'), '# My Custom Skill'); - - runInit(tmpDir); - - // User skill should survive - assert.ok(fs.existsSync(path.join(userSkillDir, 'SKILL.md')), 'user skill should survive re-init'); - assert.equal(fs.readFileSync(path.join(userSkillDir, 'SKILL.md'), 'utf8'), '# My Custom Skill'); - }); -}); - -// --- Flag tests --- - -describe('flags and subcommands', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-flags-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('--version prints version from package.json', () => { - const result = runCmdStatus(tmpDir, '--version'); - assert.equal(result.exitCode, 0, 'should exit 0'); - assert.equal(result.stdout.trim(), PKG.version); - }); - - it('-v works as alias for --version', () => { - const result = runCmdStatus(tmpDir, '-v'); - assert.equal(result.exitCode, 0, 'should exit 0'); - assert.equal(result.stdout.trim(), PKG.version); - }); - - it('--help prints usage information', () => { - const result = runCmdStatus(tmpDir, '--help'); - assert.equal(result.exitCode, 0, 'should exit 0'); - assert.ok(result.stdout.includes('squad'), 'should mention squad'); - assert.ok(result.stdout.includes('Usage'), 'should include Usage'); - assert.ok(result.stdout.includes('upgrade'), 'should mention upgrade command'); - }); - - it('-h works as alias for --help', () => { - const result = runCmdStatus(tmpDir, '-h'); - assert.equal(result.exitCode, 0, 'should exit 0'); - assert.ok(result.stdout.includes('Usage'), 'should include Usage'); - }); - - it('help subcommand prints usage information', () => { - const result = runCmdStatus(tmpDir, 'help'); - assert.equal(result.exitCode, 0, 'should exit 0'); - assert.ok(result.stdout.includes('Usage'), 'should include Usage'); - assert.ok(result.stdout.includes('Commands'), 'should list commands'); - }); -}); - -// --- Upgrade path tests --- - -describe('upgrade subcommand', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-upgrade-')); - // Initial install first - runInit(tmpDir); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('overwrites squad.agent.md with latest version', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - // Simulate user having an older version - fs.writeFileSync(agentFile, '---\nversion: "0.0.1"\n---\nold version content'); - - runCmd(tmpDir, 'upgrade'); - - const source = fs.readFileSync(path.join(ROOT, '.github', 'agents', 'squad.agent.md'), 'utf8'); - const actual = fs.readFileSync(agentFile, 'utf8'); - const pkg = require(path.join(ROOT, 'package.json')); - const expected = source.replace('version: "0.0.0-source"', `version: "${pkg.version}"`); - assert.equal(actual, expected, 'squad.agent.md should match source with version stamped after upgrade'); - }); - - it('overwrites .ai-team-templates/ with latest versions', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - // Simulate older version so upgrade proceeds - fs.writeFileSync(agentFile, '---\nversion: "0.0.1"\n---\nold'); - - const templatesDir = path.join(tmpDir, '.ai-team-templates'); - // Modify a template file (not a directory) to simulate old version - const templateFiles = fs.readdirSync(templatesDir).filter(f => - fs.statSync(path.join(templatesDir, f)).isFile() - ); - assert.ok(templateFiles.length > 0, 'should have template files'); - fs.writeFileSync(path.join(templatesDir, templateFiles[0]), 'old template content'); - - runCmd(tmpDir, 'upgrade'); - - // All template files should match source (skip directories) - const sourceFiles = fs.readdirSync(path.join(ROOT, 'templates')); - for (const file of sourceFiles) { - const srcPath = path.join(ROOT, 'templates', file); - if (fs.statSync(srcPath).isDirectory()) continue; - const expected = fs.readFileSync(srcPath, 'utf8'); - const actual = fs.readFileSync(path.join(templatesDir, file), 'utf8'); - assert.equal(actual, expected, `template ${file} should match source after upgrade`); - } - }); - - it('does NOT touch .ai-team/ directory', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - // Simulate older version so upgrade proceeds - fs.writeFileSync(agentFile, '---\nversion: "0.0.1"\n---\nold'); - - // Add user state to .ai-team/ - const userFile = path.join(tmpDir, '.ai-team', 'decisions', 'inbox', 'user-decision.md'); - fs.writeFileSync(userFile, '# My Important Decision'); - const castingFile = path.join(tmpDir, '.ai-team', 'casting', 'my-cast.json'); - fs.writeFileSync(castingFile, '{"agent":"test"}'); - - runCmd(tmpDir, 'upgrade'); - - // User state must survive - assert.ok(fs.existsSync(userFile), 'inbox decision should survive upgrade'); - assert.equal(fs.readFileSync(userFile, 'utf8'), '# My Important Decision'); - assert.ok(fs.existsSync(castingFile), 'casting file should survive upgrade'); - assert.equal(fs.readFileSync(castingFile, 'utf8'), '{"agent":"test"}'); - }); - - it('outputs upgrade confirmation messages', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - // Simulate older version so upgrade proceeds - fs.writeFileSync(agentFile, '---\nversion: "0.0.1"\n---\nold'); - - const output = runCmd(tmpDir, 'upgrade'); - assert.ok(output.includes('upgraded'), 'should mention upgraded'); - assert.ok(output.includes('untouched') || output.includes('safe'), - 'should confirm .ai-team/ is safe'); - }); -}); - -// --- Error handling tests --- - -describe('error handling', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-err-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('fatal() exits with code 1 on error', () => { - // Run index.js from a fake root missing source files ฮ“ร‡รถ triggers source validation fatal() - const fakeRoot = path.join(tmpDir, 'fake-pkg'); - fs.mkdirSync(fakeRoot); - fs.copyFileSync(INDEX, path.join(fakeRoot, 'index.js')); - fs.copyFileSync(path.join(ROOT, 'package.json'), path.join(fakeRoot, 'package.json')); - - const target = path.join(tmpDir, 'target'); - fs.mkdirSync(target); - - try { - execSync(`node "${path.join(fakeRoot, 'index.js')}"`, { - cwd: target, encoding: 'utf8', stdio: 'pipe' - }); - assert.fail('should have thrown'); - } catch (err) { - assert.equal(err.status, 1, 'fatal() should exit with code 1'); - assert.ok(err.stderr.includes('missing') || err.stderr.includes('corrupted'), - 'should mention missing/corrupted source'); - } - }); - - it('missing source files produce clean error message', () => { - // Same approach: fake package root without .github/agents/squad.agent.md - const fakeRoot = path.join(tmpDir, 'fake-pkg2'); - fs.mkdirSync(fakeRoot); - fs.copyFileSync(INDEX, path.join(fakeRoot, 'index.js')); - fs.copyFileSync(path.join(ROOT, 'package.json'), path.join(fakeRoot, 'package.json')); - - const target = path.join(tmpDir, 'target2'); - fs.mkdirSync(target); - - try { - execSync(`node "${path.join(fakeRoot, 'index.js')}"`, { - cwd: target, encoding: 'utf8', stdio: 'pipe' - }); - assert.fail('should have thrown'); - } catch (err) { - // Error message should be human-readable, not a raw stack trace - assert.ok(err.stderr.includes('squad.agent.md') || err.stderr.includes('installation'), - 'error should reference the missing file or installation'); - // Should NOT contain raw stack trace - assert.ok(!err.stderr.includes(' at '), 'should not include stack trace'); - } - }); - - it('exits with code 0 on successful init', () => { - const result = runCmdStatus(tmpDir, ''); - assert.equal(result.exitCode, 0, 'should exit 0 on success'); - }); - - it('exits with code 0 on successful upgrade', () => { - runInit(tmpDir); - const result = runCmdStatus(tmpDir, 'upgrade'); - assert.equal(result.exitCode, 0, 'upgrade should exit 0 on success'); - }); -}); - -// --- Ralph tests --- - -describe('Ralph โ€” Work Monitor', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-ralph-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('roster template includes Ralph', () => { - const roster = fs.readFileSync(path.join(ROOT, 'templates', 'roster.md'), 'utf8'); - assert.ok(roster.includes('Ralph'), 'roster template should include Ralph'); - assert.ok(roster.includes('Work Monitor'), 'roster template should include Work Monitor role'); - assert.ok(roster.includes('๐Ÿ”„'), 'roster template should include ๐Ÿ”„ badge'); - }); - - it('init creates team.md with Ralph on roster', () => { - runInit(tmpDir); - const teamFile = path.join(tmpDir, '.ai-team', 'team.md'); - // team.md is created from roster template which now includes Ralph - const templateContent = fs.readFileSync(path.join(ROOT, 'templates', 'roster.md'), 'utf8'); - assert.ok(templateContent.includes('Ralph'), 'roster template should have Ralph'); - }); - - it('heartbeat workflow is copied on init', () => { - runInit(tmpDir); - const heartbeatPath = path.join(tmpDir, '.github', 'workflows', 'squad-heartbeat.yml'); - assert.ok(fs.existsSync(heartbeatPath), 'squad-heartbeat.yml should be created on init'); - }); - - it('heartbeat workflow contains Ralph reference', () => { - const heartbeat = fs.readFileSync( - path.join(ROOT, 'templates', 'workflows', 'squad-heartbeat.yml'), 'utf8' - ); - assert.ok(heartbeat.includes('Ralph'), 'heartbeat workflow should reference Ralph'); - assert.ok(heartbeat.includes('Auto-Triage'), 'heartbeat workflow should have auto-triage'); - }); - - it('heartbeat workflow has schedule trigger', () => { - const heartbeat = fs.readFileSync( - path.join(ROOT, 'templates', 'workflows', 'squad-heartbeat.yml'), 'utf8' - ); - assert.ok(heartbeat.includes('schedule'), 'heartbeat should have schedule trigger'); - assert.ok(heartbeat.includes('cron'), 'heartbeat should have cron expression'); - }); - - it('heartbeat workflow has event triggers', () => { - const heartbeat = fs.readFileSync( - path.join(ROOT, 'templates', 'workflows', 'squad-heartbeat.yml'), 'utf8' - ); - assert.ok(heartbeat.includes('issues'), 'heartbeat should trigger on issues'); - assert.ok(heartbeat.includes('pull_request'), 'heartbeat should trigger on PRs'); - assert.ok(heartbeat.includes('workflow_dispatch'), 'heartbeat should support manual trigger'); - }); - - it('upgrade refreshes heartbeat workflow', () => { - runInit(tmpDir); - const heartbeatPath = path.join(tmpDir, '.github', 'workflows', 'squad-heartbeat.yml'); - // Write a dummy to simulate old version - fs.writeFileSync(heartbeatPath, '# old heartbeat'); - runCmd(tmpDir, 'upgrade'); - const content = fs.readFileSync(heartbeatPath, 'utf8'); - assert.ok(content.includes('Ralph'), 'upgrade should refresh heartbeat workflow'); - }); - - it('agent.md includes Ralph section', () => { - const agentMd = fs.readFileSync( - path.join(ROOT, '.github', 'agents', 'squad.agent.md'), 'utf8' - ); - assert.ok(agentMd.includes('Ralph โ€” Work Monitor'), 'agent.md should have Ralph section'); - assert.ok(agentMd.includes('Ralph is always "Ralph"'), 'agent.md should exempt Ralph from casting'); - }); - - it('agent.md includes Ralph in routing signals', () => { - const agentMd = fs.readFileSync( - path.join(ROOT, '.github', 'agents', 'squad.agent.md'), 'utf8' - ); - assert.ok( - agentMd.includes('Ralph commands'), - 'routing signals should include Ralph commands' - ); - }); - - it('agent.md includes Ralph check after follow-up work', () => { - const agentMd = fs.readFileSync( - path.join(ROOT, '.github', 'agents', 'squad.agent.md'), 'utf8' - ); - assert.ok( - agentMd.includes('Ralph check'), - 'agent.md should have Ralph check after agent work completes' - ); - }); -}); - -// --- Workflow copy tests --- - -describe('squad workflow files', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-workflows-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('creates squad workflow files in .github/workflows/ on init', () => { - runInit(tmpDir); - const workflowsDir = path.join(tmpDir, '.github', 'workflows'); - assert.ok(fs.existsSync(workflowsDir), '.github/workflows/ should exist'); - - const expectedWorkflows = ['sync-squad-labels.yml', 'squad-triage.yml', 'squad-issue-assign.yml']; - for (const file of expectedWorkflows) { - assert.ok(fs.existsSync(path.join(workflowsDir, file)), `${file} should exist`); - } - }); - - it('workflow file contents match source templates', () => { - runInit(tmpDir); - const workflowsDir = path.join(tmpDir, '.github', 'workflows'); - const sourceDir = path.join(ROOT, 'templates', 'workflows'); - - const sourceFiles = fs.readdirSync(sourceDir).filter(f => f.endsWith('.yml')); - for (const file of sourceFiles) { - const expected = fs.readFileSync(path.join(sourceDir, file), 'utf8'); - const actual = fs.readFileSync(path.join(workflowsDir, file), 'utf8'); - assert.equal(actual, expected, `workflow ${file} content should match source`); - } - }); - - it('skips existing workflow files on re-init', () => { - runInit(tmpDir); - const workflowFile = path.join(tmpDir, '.github', 'workflows', 'sync-squad-labels.yml'); - fs.writeFileSync(workflowFile, 'user-customized workflow'); - - const output = runInit(tmpDir); - assert.ok(output.includes('already exists'), 'should report skipping'); - - const content = fs.readFileSync(workflowFile, 'utf8'); - assert.equal(content, 'user-customized workflow', 'should NOT overwrite user workflow'); - }); - - it('overwrites workflow files on upgrade', () => { - runInit(tmpDir); - const workflowFile = path.join(tmpDir, '.github', 'workflows', 'sync-squad-labels.yml'); - fs.writeFileSync(workflowFile, 'old workflow content'); - - // Simulate an older installed version so upgrade doesn't short-circuit - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - fs.writeFileSync(agentFile, 'version: "0.0.1"\nold agent content'); - - runCmd(tmpDir, 'upgrade'); - - const expected = fs.readFileSync(path.join(ROOT, 'templates', 'workflows', 'sync-squad-labels.yml'), 'utf8'); - const actual = fs.readFileSync(workflowFile, 'utf8'); - assert.equal(actual, expected, 'workflow should match source after upgrade'); - }); - - it('upgrade output mentions workflow files', () => { - runInit(tmpDir); - - // Simulate an older installed version so upgrade doesn't short-circuit - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - fs.writeFileSync(agentFile, 'version: "0.0.1"\nold agent content'); - - const output = runCmd(tmpDir, 'upgrade'); - assert.ok(output.includes('workflow'), 'should mention workflows in upgrade output'); - }); -}); - -// --- Edge case tests --- - -describe('edge cases', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-edge-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('re-init skips existing files and reports it', () => { - // First init - runInit(tmpDir); - // Second init should skip - const output = runInit(tmpDir); - assert.ok(output.includes('already exists'), 'should report files already exist'); - // Files should still be valid - assert.ok(fs.existsSync(path.join(tmpDir, '.github', 'agents', 'squad.agent.md'))); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team-templates'))); - }); - - it('exit code is 0 on re-init', () => { - runInit(tmpDir); - const result = runCmdStatus(tmpDir, ''); - assert.equal(result.exitCode, 0, 're-init should exit 0'); - }); -}); - -// --- Smart upgrade with migrations --- - -describe('smart upgrade ฮ“ร‡รถ version delta', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-smart-')); - runInit(tmpDir); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('reports version delta when upgrading from older version', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - fs.writeFileSync(agentFile, '---\nversion: "0.0.1"\n---\nold content'); - - const output = runCmd(tmpDir, 'upgrade'); - assert.ok(output.includes('upgraded'), 'should mention upgraded'); - assert.ok(output.includes('0.0.1'), 'should mention old version'); - assert.ok(output.includes(PKG.version), 'should mention new version'); - }); - - it('reports "Already up to date" when versions match', () => { - // After init, squad.agent.md has current version stamped - const output = runCmd(tmpDir, 'upgrade'); - assert.ok(output.includes('Already up to date'), 'should say already up to date'); - assert.ok(output.includes(PKG.version), 'should mention current version'); - }); - - it('treats missing version header as unknown', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - fs.writeFileSync(agentFile, '---\nname: Squad\n---\nno version header'); - - const output = runCmd(tmpDir, 'upgrade'); - assert.ok(output.includes('unknown'), 'should report upgrading from unknown'); - assert.ok(output.includes(PKG.version), 'should mention new version'); - }); - - it('exits cleanly when already up to date', () => { - const result = runCmdStatus(tmpDir, 'upgrade'); - assert.equal(result.exitCode, 0, 'should exit 0'); - assert.ok(result.stdout.includes('Already up to date'), 'should say already up to date'); - }); -}); - -describe('smart upgrade ฮ“ร‡รถ migrations', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-migr-')); - runInit(tmpDir); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('creates .ai-team/skills/ directory on upgrade', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - fs.writeFileSync(agentFile, '---\nversion: "0.0.1"\n---\nold'); - - runCmd(tmpDir, 'upgrade'); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'skills')), - '.ai-team/skills/ should be created by migration'); - }); - - it('migrations are idempotent ฮ“ร‡รถ running upgrade twice does not error', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - fs.writeFileSync(agentFile, '---\nversion: "0.0.1"\n---\nold'); - runCmd(tmpDir, 'upgrade'); - - // Second upgrade ฮ“ร‡รถ now versions match, hits "already up to date" path - // which still runs migrations. Should not error. - const result = runCmdStatus(tmpDir, 'upgrade'); - assert.equal(result.exitCode, 0, 'second upgrade should exit 0'); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'skills')), - '.ai-team/skills/ should still exist'); - }); - - it('skips migrations for versions already past', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - // Simulate upgrading from a version PAST the migration version - fs.writeFileSync(agentFile, '---\nversion: "99.0.0"\n---\nfuture'); - - // 99.0.0 != pkg.version so it will do full upgrade, and migrations - // run against oldVersion=99.0.0 ฮ“ร‡รถ 0.2.0 is NOT > 99.0.0, so migration is skipped. - // Note: skills dir already exists from init (created in init flow), but the - // migration itself is correctly skipped based on version comparison. - runCmd(tmpDir, 'upgrade'); - // The dir exists (from init), but the migration was skipped ฮ“ร‡รถ verify upgrade succeeds - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'skills')), - '.ai-team/skills/ should exist (created during init)'); - }); - - it('runs migrations even on "already up to date" path', () => { - const agentFile = path.join(tmpDir, '.github', 'agents', 'squad.agent.md'); - // The file already has pkg.version from init. Skills dir already exists from init. - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'skills')), - 'skills should exist from init'); - - // The "already up to date" path runs migrations against oldVersion=pkg.version - // and 0.2.0 > pkg.version only if pkg.version < 0.2.0. - // Current pkg.version is 0.1.0, so 0.2.0 > 0.1.0 is true ฮ“รฅร† migration runs. - const output = runCmd(tmpDir, 'upgrade'); - assert.ok(output.includes('Already up to date'), 'should be up to date'); - assert.ok(fs.existsSync(path.join(tmpDir, '.ai-team', 'skills')), - '.ai-team/skills/ should still exist after migration on up-to-date path'); - }); -}); - -// --- squad.agent.md prompt content validation (PR #2 features) --- - -describe('squad.agent.md prompt content', () => { - const agentMd = fs.readFileSync(path.join(ROOT, '.github', 'agents', 'squad.agent.md'), 'utf8'); - - describe('GitHub Issues Mode', () => { - it('contains the GitHub Issues Mode section', () => { - assert.ok(agentMd.includes('## GitHub Issues Mode'), 'missing ## GitHub Issues Mode section'); - }); - - it('contains prerequisites for gh CLI', () => { - assert.ok(agentMd.includes('gh --version'), 'missing gh CLI detection'); - assert.ok(agentMd.includes('gh auth status'), 'missing gh auth check'); - }); - - it('contains issue trigger table', () => { - assert.ok(agentMd.includes('"pull issues from {owner/repo}"'), 'missing pull issues trigger'); - assert.ok(agentMd.includes('"work on issue #N"'), 'missing work on issue trigger'); - assert.ok(agentMd.includes('"merge PR #N"'), 'missing merge PR trigger'); - }); - - it('contains Issue Source storage format', () => { - assert.ok(agentMd.includes('## Issue Source'), 'missing ## Issue Source section in team.md format'); - }); - - it('documents the branch naming convention', () => { - assert.ok(agentMd.includes('squad/{issue-number}-{slug}'), 'missing branch naming convention'); - }); - - it('documents PR submission with issue linking', () => { - assert.ok(agentMd.includes('Closes #'), 'missing Closes # issue linking in PR flow'); - }); - - it('documents PR review handling', () => { - assert.ok(agentMd.includes('PR REVIEW FEEDBACK'), 'missing PR review feedback spawn prompt'); - }); - - it('documents PR merge flow', () => { - assert.ok(agentMd.includes('gh pr merge'), 'missing gh pr merge command'); - }); - - it('references standard After Agent Work flow', () => { - assert.ok(agentMd.includes('After Agent Work flow'), 'missing reference to standard After Agent Work flow in issue lifecycle'); - }); - - it('mentions worktree interaction for parallel issues', () => { - assert.ok(agentMd.includes('worktree') || agentMd.includes('Worktree'), 'missing worktree guidance in issue lifecycle'); - }); - }); - - describe('PRD Mode', () => { - it('contains the PRD Mode section', () => { - assert.ok(agentMd.includes('## PRD Mode'), 'missing ## PRD Mode section'); - }); - - it('contains PRD trigger table', () => { - assert.ok(agentMd.includes('"here\'s the PRD"'), 'missing PRD trigger phrase'); - assert.ok(agentMd.includes('"read the PRD at {path}"'), 'missing file path trigger'); - }); - - it('documents PRD storage in team.md', () => { - assert.ok(agentMd.includes('## PRD'), 'missing ## PRD section in team.md format'); - }); - - it('documents Lead agent decomposition', () => { - assert.ok(agentMd.includes('Decompose PRD into work items'), 'missing PRD decomposition prompt'); - }); - - it('documents work item format', () => { - assert.ok(agentMd.includes('WI-{number}'), 'missing work item ID format'); - }); - - it('includes decomposition guidelines', () => { - assert.ok(agentMd.includes('Decomposition guidelines'), 'missing decomposition guidelines'); - }); - - it('documents mid-project PRD updates', () => { - assert.ok(agentMd.includes('Mid-Project PRD Updates'), 'missing mid-project PRD update section'); - }); - }); - - describe('Human Team Members', () => { - it('contains the Human Team Members section', () => { - assert.ok(agentMd.includes('## Human Team Members'), 'missing ## Human Team Members section'); - }); - - it('contains human trigger table', () => { - assert.ok(agentMd.includes('"add {Name} as {role}"'), 'missing add human trigger'); - assert.ok(agentMd.includes('"I\'m on the team as {role}"'), 'missing self-add trigger'); - }); - - it('documents the human badge', () => { - assert.ok(agentMd.includes('๐Ÿ‘ค Human'), 'missing ๐Ÿ‘ค Human badge'); - }); - - it('documents differences from AI agents', () => { - assert.ok(agentMd.includes('How Humans Differ from AI Agents'), 'missing human vs AI comparison'); - }); - - it('documents routing to humans with pause behavior', () => { - assert.ok(agentMd.includes("This one's for {Name}"), 'missing human routing pause message'); - }); - - it('documents non-dependent work continues', () => { - assert.ok(agentMd.includes('Non-dependent work continues'), 'missing continuation guidance for human blocks'); - }); - - it('documents stale reminder', () => { - assert.ok(agentMd.includes('Still waiting on {Name}'), 'missing stale reminder message'); - }); - - it('documents human reviewer integration', () => { - assert.ok(agentMd.includes('Human Members and the Reviewer Rejection Protocol'), 'missing human reviewer integration section'); - }); - - it('shows multiple humans example', () => { - assert.ok(agentMd.includes('Multiple Humans'), 'missing multiple humans section'); - }); - }); - - describe('Init Mode integration', () => { - it('asks about PRD after team setup', () => { - assert.ok(agentMd.includes('Do you have a PRD or spec document?'), 'missing PRD question'); - }); - - it('asks about GitHub issues after team setup', () => { - assert.ok(agentMd.includes('Is there a GitHub repo with issues I should pull from?'), 'missing issues question'); - }); - - it('asks about human members after team setup', () => { - assert.ok(agentMd.includes('Are any humans joining the team?'), 'missing humans question'); - }); - - it('documents post-setup input sources', () => { - assert.ok(agentMd.includes('Post-setup input sources'), 'missing post-setup input sources step'); - }); - }); - - describe('Routing table integration', () => { - it('includes GitHub Issues routing signal', () => { - assert.ok(agentMd.includes('Follow GitHub Issues Mode'), 'missing issues routing signal'); - }); - - it('includes PRD routing signal', () => { - assert.ok(agentMd.includes('Follow PRD Mode'), 'missing PRD routing signal'); - }); - - it('includes Human Members routing signal', () => { - assert.ok(agentMd.includes('Follow Human Team Members'), 'missing human members routing signal'); - }); - }); -}); - -// --- Export subcommand tests --- - -describe('export subcommand', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-export-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - function setupSquad(dir) { - // Create minimal squad structure with team.md - const aiTeam = path.join(dir, '.ai-team'); - fs.mkdirSync(path.join(aiTeam, 'casting'), { recursive: true }); - fs.mkdirSync(path.join(aiTeam, 'agents', 'fenster'), { recursive: true }); - fs.mkdirSync(path.join(aiTeam, 'agents', 'keaton'), { recursive: true }); - fs.mkdirSync(path.join(aiTeam, 'skills', 'testing'), { recursive: true }); - fs.writeFileSync(path.join(aiTeam, 'team.md'), '# My Squad'); - - // Casting files - fs.writeFileSync(path.join(aiTeam, 'casting', 'registry.json'), JSON.stringify({ agents: ['fenster'] })); - fs.writeFileSync(path.join(aiTeam, 'casting', 'policy.json'), JSON.stringify({ universe: 'usual-suspects' })); - fs.writeFileSync(path.join(aiTeam, 'casting', 'history.json'), JSON.stringify({ snapshots: [] })); - - // Agent files - fs.writeFileSync(path.join(aiTeam, 'agents', 'fenster', 'charter.md'), '# Fenster Charter'); - fs.writeFileSync(path.join(aiTeam, 'agents', 'fenster', 'history.md'), '# Fenster History'); - fs.writeFileSync(path.join(aiTeam, 'agents', 'keaton', 'charter.md'), '# Keaton Charter'); - - // Skill file - fs.writeFileSync(path.join(aiTeam, 'skills', 'testing', 'SKILL.md'), '# Testing Skill'); - } - - it('produces valid JSON', () => { - setupSquad(tmpDir); - runCmd(tmpDir, 'export'); - const exportFile = path.join(tmpDir, 'squad-export.json'); - assert.ok(fs.existsSync(exportFile), 'squad-export.json should exist'); - const manifest = JSON.parse(fs.readFileSync(exportFile, 'utf8')); - assert.equal(manifest.version, '1.0'); - assert.equal(manifest.squad_version, PKG.version); - assert.ok(manifest.exported_at, 'should have exported_at timestamp'); - }); - - it('includes casting state', () => { - setupSquad(tmpDir); - runCmd(tmpDir, 'export'); - const manifest = JSON.parse(fs.readFileSync(path.join(tmpDir, 'squad-export.json'), 'utf8')); - assert.deepEqual(manifest.casting.registry, { agents: ['fenster'] }); - assert.deepEqual(manifest.casting.policy, { universe: 'usual-suspects' }); - assert.deepEqual(manifest.casting.history, { snapshots: [] }); - }); - - it('includes agent charters and histories', () => { - setupSquad(tmpDir); - runCmd(tmpDir, 'export'); - const manifest = JSON.parse(fs.readFileSync(path.join(tmpDir, 'squad-export.json'), 'utf8')); - assert.equal(manifest.agents.fenster.charter, '# Fenster Charter'); - assert.equal(manifest.agents.fenster.history, '# Fenster History'); - assert.equal(manifest.agents.keaton.charter, '# Keaton Charter'); - assert.equal(manifest.agents.keaton.history, undefined, 'keaton has no history.md'); - }); - - it('includes skills if they exist', () => { - setupSquad(tmpDir); - runCmd(tmpDir, 'export'); - const manifest = JSON.parse(fs.readFileSync(path.join(tmpDir, 'squad-export.json'), 'utf8')); - assert.equal(manifest.skills.length, 1); - assert.equal(manifest.skills[0], '# Testing Skill'); - }); - - it('exports with --out to custom path', () => { - setupSquad(tmpDir); - const customPath = path.join(tmpDir, 'custom', 'my-export.json'); - fs.mkdirSync(path.join(tmpDir, 'custom'), { recursive: true }); - runCmd(tmpDir, `export --out "${customPath}"`); - assert.ok(fs.existsSync(customPath), 'custom export file should exist'); - const manifest = JSON.parse(fs.readFileSync(customPath, 'utf8')); - assert.equal(manifest.version, '1.0'); - }); - - it('fails gracefully when no squad exists', () => { - const result = runCmdStatus(tmpDir, 'export'); - assert.equal(result.exitCode, 1, 'should exit 1 when no squad'); - assert.ok(result.stderr.includes('No squad found'), 'should mention no squad found'); - }); - - it('outputs success and warning messages', () => { - setupSquad(tmpDir); - const output = runCmd(tmpDir, 'export'); - assert.ok(output.includes('Exported squad to'), 'should confirm export'); - assert.ok(output.includes('Review agent histories'), 'should warn about histories'); - }); - - it('handles missing casting files gracefully', () => { - const aiTeam = path.join(tmpDir, '.ai-team'); - fs.mkdirSync(path.join(aiTeam, 'casting'), { recursive: true }); - fs.writeFileSync(path.join(aiTeam, 'team.md'), '# Squad'); - // No casting JSON files, no agents, no skills - - runCmd(tmpDir, 'export'); - const manifest = JSON.parse(fs.readFileSync(path.join(tmpDir, 'squad-export.json'), 'utf8')); - assert.deepEqual(manifest.casting, {}); - assert.deepEqual(manifest.agents, {}); - assert.deepEqual(manifest.skills, []); - }); - - it('help text mentions export command', () => { - const result = runCmdStatus(tmpDir, 'help'); - assert.ok(result.stdout.includes('export'), 'help should mention export'); - }); -}); - -// --- Import subcommand tests --- - -describe('import subcommand', () => { - let tmpDir; - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-import-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - function createExportFile(dir, overrides) { - const manifest = { - version: '1.0', - exported_at: '2026-02-09T12:00:00.000Z', - squad_version: '0.1.0', - casting: { - registry: { agents: ['fenster', 'keaton'] }, - policy: { universe: 'usual-suspects' }, - history: { snapshots: [] } - }, - agents: { - fenster: { - charter: '# Fenster Charter\nCore developer.', - history: '# Project Context\n\n## Learnings\n\n### Runtime Architecture\n- No runtime\n\n### Key File Paths\n- index.js\n\n๐Ÿ“Œ Team update: something happened' - }, - keaton: { - charter: '# Keaton Charter\nLead architect.', - history: '# Project Context\n\n## Learnings\n\n### Windows Compatibility\n- path.join everywhere' - } - }, - skills: [ - '---\nname: testing\n---\n# Testing Skill\nHow to test things.', - '---\nname: code-review\n---\n# Code Review Skill\nHow to review code.' - ], - ...overrides - }; - const filePath = path.join(dir, 'squad-export.json'); - fs.writeFileSync(filePath, JSON.stringify(manifest, null, 2)); - return filePath; - } - - it('imports from valid export file and creates .ai-team/ structure', () => { - const exportFile = createExportFile(tmpDir); - const targetDir = path.join(tmpDir, 'target'); - fs.mkdirSync(targetDir); - - runCmd(targetDir, `import "${exportFile}"`); - - // Verify directory structure - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team')), '.ai-team/ should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'casting')), 'casting/ should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'agents', 'fenster')), 'agents/fenster/ should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'agents', 'keaton')), 'agents/keaton/ should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'decisions', 'inbox')), 'decisions/inbox/ should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'orchestration-log')), 'orchestration-log/ should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'log')), 'log/ should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'skills')), 'skills/ should exist'); - - // Verify casting files - const registry = JSON.parse(fs.readFileSync(path.join(targetDir, '.ai-team', 'casting', 'registry.json'), 'utf8')); - assert.deepEqual(registry, { agents: ['fenster', 'keaton'] }); - - // Verify agent charters - const charter = fs.readFileSync(path.join(targetDir, '.ai-team', 'agents', 'fenster', 'charter.md'), 'utf8'); - assert.equal(charter, '# Fenster Charter\nCore developer.'); - - // Verify skills - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'skills', 'testing', 'SKILL.md')), 'testing skill should exist'); - assert.ok(fs.existsSync(path.join(targetDir, '.ai-team', 'skills', 'code-review', 'SKILL.md')), 'code-review skill should exist'); - - // Verify empty project-specific files - assert.equal(fs.readFileSync(path.join(targetDir, '.ai-team', 'decisions.md'), 'utf8'), ''); - assert.equal(fs.readFileSync(path.join(targetDir, '.ai-team', 'team.md'), 'utf8'), ''); - }); - - it('fails with clear error when squad exists and no --force', () => { - const exportFile = createExportFile(tmpDir); - const targetDir = path.join(tmpDir, 'target'); - fs.mkdirSync(path.join(targetDir, '.ai-team'), { recursive: true }); - - const result = runCmdStatus(targetDir, `import "${exportFile}"`); - assert.equal(result.exitCode, 1, 'should exit 1'); - assert.ok(result.stderr.includes('already exists') || result.stderr.includes('--force'), - 'should mention --force'); - }); - - it('archives existing squad with --force', () => { - const exportFile = createExportFile(tmpDir); - const targetDir = path.join(tmpDir, 'target'); - const aiTeam = path.join(targetDir, '.ai-team'); - fs.mkdirSync(path.join(aiTeam, 'agents', 'old-agent'), { recursive: true }); - fs.writeFileSync(path.join(aiTeam, 'agents', 'old-agent', 'charter.md'), '# Old Agent'); - - runCmd(targetDir, `import "${exportFile}" --force`); - - // Old squad should be archived - const entries = fs.readdirSync(targetDir); - const archives = entries.filter(e => e.startsWith('.ai-team-archive-')); - assert.equal(archives.length, 1, 'should have exactly one archive'); - - // Archive should contain old agent - const archiveDir = path.join(targetDir, archives[0]); - assert.ok(fs.existsSync(path.join(archiveDir, 'agents', 'old-agent', 'charter.md')), - 'old agent should be in archive'); - - // New squad should be imported - assert.ok(fs.existsSync(path.join(aiTeam, 'agents', 'fenster', 'charter.md')), - 'new agent should exist after import'); - }); - - it('round-trip: init ฮ“รฅร† export ฮ“รฅร† import preserves agents', () => { - // Init a squad - const srcDir = path.join(tmpDir, 'source'); - fs.mkdirSync(srcDir); - runInit(srcDir); - - // Add agents to make it a real squad - const aiTeam = path.join(srcDir, '.ai-team'); - fs.writeFileSync(path.join(aiTeam, 'team.md'), '# My Squad'); - fs.mkdirSync(path.join(aiTeam, 'agents', 'testbot'), { recursive: true }); - fs.writeFileSync(path.join(aiTeam, 'agents', 'testbot', 'charter.md'), '# Testbot\nI test things.'); - fs.writeFileSync(path.join(aiTeam, 'agents', 'testbot', 'history.md'), '# Learnings\n\n## Learnings\n\nSome knowledge here.'); - - // Export - runCmd(srcDir, 'export'); - const exportFile = path.join(srcDir, 'squad-export.json'); - assert.ok(fs.existsSync(exportFile), 'export file should exist'); - - // Import into new directory - const destDir = path.join(tmpDir, 'dest'); - fs.mkdirSync(destDir); - runCmd(destDir, `import "${exportFile}"`); - - // Verify agent charter preserved - const charter = fs.readFileSync(path.join(destDir, '.ai-team', 'agents', 'testbot', 'charter.md'), 'utf8'); - assert.equal(charter, '# Testbot\nI test things.', 'charter should match'); - - // Verify agent history exists with import marker - const history = fs.readFileSync(path.join(destDir, '.ai-team', 'agents', 'testbot', 'history.md'), 'utf8'); - assert.ok(history.includes('Imported from'), 'history should have import marker'); - assert.ok(history.includes('Some knowledge here'), 'history should contain original knowledge'); - }); - - it('fails gracefully with missing file', () => { - const result = runCmdStatus(tmpDir, 'import nonexistent.json'); - assert.equal(result.exitCode, 1, 'should exit 1'); - assert.ok(result.stderr.includes('not found'), 'should mention file not found'); - }); - - it('fails gracefully with invalid JSON', () => { - const badFile = path.join(tmpDir, 'bad.json'); - fs.writeFileSync(badFile, 'not valid json {{{'); - - const result = runCmdStatus(tmpDir, `import "${badFile}"`); - assert.equal(result.exitCode, 1, 'should exit 1'); - assert.ok(result.stderr.includes('Invalid JSON'), 'should mention invalid JSON'); - }); - - it('fails gracefully with wrong version', () => { - const badFile = path.join(tmpDir, 'bad-version.json'); - fs.writeFileSync(badFile, JSON.stringify({ version: '99.0', casting: {}, agents: {}, skills: [] })); - - const result = runCmdStatus(tmpDir, `import "${badFile}"`); - assert.equal(result.exitCode, 1, 'should exit 1'); - assert.ok(result.stderr.includes('Unsupported'), 'should mention unsupported version'); - }); - - it('imported histories contain portable knowledge markers', () => { - const exportFile = createExportFile(tmpDir); - const targetDir = path.join(tmpDir, 'target'); - fs.mkdirSync(targetDir); - - runCmd(targetDir, `import "${exportFile}"`); - - const history = fs.readFileSync(path.join(targetDir, '.ai-team', 'agents', 'fenster', 'history.md'), 'utf8'); - - // Should have import marker - assert.ok(history.includes('๐Ÿ“Œ Imported from'), 'should have import marker'); - assert.ok(history.includes('Portable knowledge carried over'), 'should mention portable knowledge'); - - // Portable content should be present - assert.ok(history.includes('Runtime Architecture'), 'portable section should be present'); - - // Project-specific content should be marked - assert.ok(history.includes('Project Learnings (from import'), 'project learnings should be marked'); - assert.ok(history.includes('Key File Paths'), 'project-specific section should be in project learnings'); - }); - - it('outputs correct success messaging', () => { - const exportFile = createExportFile(tmpDir); - const targetDir = path.join(tmpDir, 'target'); - fs.mkdirSync(targetDir); - - const output = runCmd(targetDir, `import "${exportFile}"`); - assert.ok(output.includes('Imported squad from'), 'should confirm import'); - assert.ok(output.includes('fenster'), 'should list agent names'); - assert.ok(output.includes('keaton'), 'should list agent names'); - assert.ok(output.includes('2 agents'), 'should show agent count'); - assert.ok(output.includes('2 skills'), 'should show skill count'); - assert.ok(output.includes('usual-suspects'), 'should show universe'); - assert.ok(output.includes('Project-specific learnings'), 'should warn about learnings'); - assert.ok(output.includes('Next steps'), 'should show next steps'); - }); - - it('help text mentions import command', () => { - const result = runCmdStatus(tmpDir, 'help'); - assert.ok(result.stdout.includes('import'), 'help should mention import'); - }); - - it('fails when no file argument provided', () => { - const result = runCmdStatus(tmpDir, 'import'); - assert.equal(result.exitCode, 1, 'should exit 1'); - assert.ok(result.stderr.includes('Usage'), 'should show usage'); - }); -}); - -describe('copilot subcommand', () => { - let tmpDir; - - function initWithTeam(dir) { - runInit(dir); - // Init creates directories but not team.md (coordinator does that) - // Create a minimal team.md so the copilot subcommand can proceed - const teamDir = path.join(dir, '.ai-team'); - fs.mkdirSync(teamDir, { recursive: true }); - fs.writeFileSync(path.join(teamDir, 'team.md'), '# The Squad\n\n## Project Context\n\nNo context yet.\n'); - } - - beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squad-copilot-')); - }); - - afterEach(() => { - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); - - it('fails when no squad exists', () => { - const { status } = runCmdStatus(tmpDir, 'copilot'); - assert.notEqual(status, 0, 'should fail without a squad'); - }); - - it('adds @copilot to team.md with capability profile', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - const teamMd = fs.readFileSync(path.join(tmpDir, '.ai-team', 'team.md'), 'utf8'); - assert.ok(teamMd.includes('๐Ÿค– Coding Agent'), 'should have coding agent badge'); - assert.ok(teamMd.includes('@copilot'), 'should have @copilot name'); - assert.ok(teamMd.includes('๐ŸŸข Good fit'), 'should have capability profile'); - assert.ok(teamMd.includes('๐ŸŸก Needs review'), 'should have needs-review tier'); - assert.ok(teamMd.includes('๐Ÿ”ด Not suitable'), 'should have not-suitable tier'); - }); - - it('creates .github/copilot-instructions.md', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - const dest = path.join(tmpDir, '.github', 'copilot-instructions.md'); - assert.ok(fs.existsSync(dest), 'copilot-instructions.md should be created'); - const content = fs.readFileSync(dest, 'utf8'); - assert.ok(content.includes('Squad'), 'should reference Squad'); - assert.ok(content.includes('.ai-team/team.md'), 'should reference team.md'); - }); - - it('sets auto-assign when --auto-assign flag is used', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot --auto-assign'); - const teamMd = fs.readFileSync(path.join(tmpDir, '.ai-team', 'team.md'), 'utf8'); - assert.ok(teamMd.includes(''), 'should have auto-assign enabled'); - }); - - it('defaults auto-assign to false without flag', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - const teamMd = fs.readFileSync(path.join(tmpDir, '.ai-team', 'team.md'), 'utf8'); - assert.ok(teamMd.includes(''), 'should have auto-assign disabled'); - }); - - it('reports already on team if run twice', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - const out = runCmd(tmpDir, 'copilot'); - assert.ok(out.includes('already on the team'), 'should note already added'); - }); - - it('enables auto-assign on existing copilot member', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - runCmd(tmpDir, 'copilot --auto-assign'); - const teamMd = fs.readFileSync(path.join(tmpDir, '.ai-team', 'team.md'), 'utf8'); - assert.ok(teamMd.includes(''), 'should update to auto-assign'); - }); - - it('removes @copilot with --off flag', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - runCmd(tmpDir, 'copilot --off'); - const teamMd = fs.readFileSync(path.join(tmpDir, '.ai-team', 'team.md'), 'utf8'); - assert.ok(!teamMd.includes('๐Ÿค– Coding Agent'), 'should remove coding agent'); - }); - - it('does not overwrite copilot-instructions.md on upgrade when @copilot is not enabled', () => { - initWithTeam(tmpDir); - const dest = path.join(tmpDir, '.github', 'copilot-instructions.md'); - fs.mkdirSync(path.dirname(dest), { recursive: true }); - fs.writeFileSync(dest, 'user customized'); - runCmd(tmpDir, 'upgrade'); - const content = fs.readFileSync(dest, 'utf8'); - assert.equal(content, 'user customized', 'upgrade should not touch copilot-instructions.md when @copilot is not enabled'); - }); - - it('upgrades copilot-instructions.md when @copilot is enabled on the team', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - const dest = path.join(tmpDir, '.github', 'copilot-instructions.md'); - fs.writeFileSync(dest, 'old version'); - runCmd(tmpDir, 'upgrade'); - const content = fs.readFileSync(dest, 'utf8'); - assert.notEqual(content, 'old version', 'upgrade should overwrite copilot-instructions.md when @copilot is enabled'); - assert.ok(content.includes('Squad'), 'should contain latest template content'); - }); - - it('copilot-instructions.md content matches source template', () => { - initWithTeam(tmpDir); - runCmd(tmpDir, 'copilot'); - const dest = path.join(tmpDir, '.github', 'copilot-instructions.md'); - const src = path.join(ROOT, 'templates', 'copilot-instructions.md'); - const destContent = fs.readFileSync(dest, 'utf8'); - const srcContent = fs.readFileSync(src, 'utf8'); - assert.equal(destContent, srcContent, 'should copy template exactly'); - }); -});