Repository navigation
Description
Problem Statement
When users run squad init from a subfolder of a monorepo, the old behavior ran git init — creating a broken nested .git/ directory inside the subfolder. This corrupted the parent repo's view of the subfolder and caused cascading problems with workflows, upgrades, and agent resolution.
PR #944 fixes the init path (phase 1), but the full monorepo story has gaps:
- Upgrade doesn't know about monorepo layouts — it re-stamps files at CWD instead of git root
- Workflows conflict when multiple squads coexist in one repo
- Shared agent file works today but has limitations if squads need different coordinator policies
- Migration path is manual for users who already hit the bug
Related: #939 (original bug report), #944 (phase 1 fix)
Platform Constraint
Copilot custom agents (.github/agents/*.md) only resolve from the git root. This is a Copilot platform constraint — Squad cannot change it.
Implications:
| Constraint | Consequence |
|---|---|
One shared squad.agent.md at git root |
All squads share the same coordinator template |
| Coordinator is stateless | It reads team state from CWD (.squad/ directory) |
| CWD determines which squad is active | cd team-alpha && copilot loads alpha's squad; cd team-beta && copilot loads beta's squad |
This is actually a clean design — the coordinator is a router, and .squad/ is the state store. The constraint becomes a feature.
Phase 1 — Bug Fix ✅
Status: Done — PR #944
What shipped
squad initno longer runsgit initin subfolders- Agent file (
.github/agents/squad.agent.md) placed at git root, not CWD .squad/directory placed in the subfolder (CWD)- Workflows skipped in monorepo mode (with console warning explaining why)
- CWD-first
.squad/resolution baked into the coordinator template
Validation
- 20 unit tests passing
- 7 E2E scenarios validated:
- Standalone repo (baseline, no regression)
- Monorepo subfolder — first squad
- Monorepo subfolder — second squad alongside first
- No-git directory (error path)
- Git root init (same as standalone)
- Re-init in same subfolder (idempotent)
- Agent file content verification (CWD resolution present)
Phase 2 — Upgrade Awareness
Status: Not started
Problem
squad upgrade currently assumes CWD == git root. In a monorepo, it re-stamps the agent file at the wrong location and doesn't detect pre-fix damage (nested .git/ directories).
Requirements
| # | Requirement | Details |
|---|---|---|
| 2.1 | Monorepo detection in upgrade |
Detect when git root ≠ CWD; apply same path-splitting logic as init |
| 2.2 | Agent file re-stamp at git root | upgrade writes updated squad.agent.md to <git-root>/.github/agents/, not CWD |
| 2.3 | Nested .git/ detection |
Warn if CWD contains a .git/ directory that isn't the repo root (pre-fix damage) |
| 2.4 | Migration helper | squad migrate-monorepo command that automates the manual migration steps (see Migration Path below) |
Acceptance criteria
-
squad upgradefrom a monorepo subfolder updates agent file at git root -
squad upgradefrom a monorepo subfolder updates.squad/in CWD - Warning emitted when nested
.git/detected -
squad migrate-monorepomoves agent file, removes nested.git/, preserves.squad/ - Existing standalone upgrade behavior is unchanged (no regression)
Phase 3 — Multi-Squad Workflows
Status: Not started — needs design spike
Problem
GitHub Actions only reads workflow files from <repo-root>/.github/workflows/. When multiple squads coexist in one monorepo, they can't each have independent heartbeat/triage workflows without conflicts.
Options to evaluate
| Option | Approach | Pros | Cons |
|---|---|---|---|
| A. Discovery workflow | Single shared workflow discovers all .squad/ directories and iterates |
One workflow to maintain; scales automatically | Complex workflow logic; all squads share schedule |
| B. Path-filtered workflows | Heartbeat for team-alpha/**, separate for team-beta/** |
Clean separation; familiar pattern | squad init must generate path-aware workflows; manual if squads added later |
| C. Per-squad naming | squad-heartbeat-alpha.yml, squad-heartbeat-beta.yml |
Explicit; easy to debug | squad init must namespace; doesn't scale to many squads |
Additional considerations
- Squad labels: Need namespacing? E.g.,
squad:alpha:membervssquad:beta:member— or do squad labels already scope by repo convention? - Workflow skip in phase 1: Currently
squad initskips workflows entirely in monorepo mode and prints a warning. Phase 3 should remove this limitation. - Cron schedule: Should all squads share one heartbeat cadence, or can they differ?
Acceptance criteria
- Design doc produced (pick one option or hybrid)
-
squad initin monorepo generates appropriate workflow(s) - Multiple squads in one repo can run independent heartbeats without conflict
- Labels are properly namespaced (if needed)
Phase 4 — Per-Squad Coordinator Customization (If Needed)
Status: Future — may not be needed
Problem
Today one shared squad.agent.md means the coordinator behavior is identical for all squads. This works when squads only differ in team state (roster, decisions, history). It breaks if squads need:
- Different casting policies (e.g., alpha uses strict casting, beta uses relaxed)
- Different ceremony configs (e.g., alpha has weekly retros, beta doesn't)
- Different routing rules or tool restrictions
Possible solution
A squad.config.json (or similar) in each subfolder's .squad/ directory with coordinator overrides:
{
"casting": { "policy": "strict", "maxRetries": 2 },
"ceremonies": { "retro": "weekly", "standup": "daily" },
"routing": { "securityIssues": "worf", "docs": "seven" }
}The coordinator template would read this config from CWD and adjust behavior accordingly.
Non-goal
Per-squad agent files (e.g., squad-alpha.agent.md) — blocked by Copilot platform constraint. Agent files resolve from .github/agents/ by name, not by CWD.
Non-Goals
| Non-goal | Reason |
|---|---|
Named agent files per squad (squad-alpha.agent.md) |
Copilot doesn't support CWD-based agent selection; agent name is global |
| Cross-squad agent sharing | Squads are independent teams, not a federation |
| Monorepo-wide orchestration | No "meta-coordinator" that spans all squads |
| Polyrepo support | Out of scope; Squad assumes one git repo per init |
Migration Path
For users who already ran squad init in a monorepo subfolder before the fix in PR #944:
Manual steps (available now)
# 1. Navigate to the subfolder where squad was incorrectly initialized
cd my-monorepo/team-alpha
# 2. Remove the broken nested .git/
rm -rf .git
# 3. Move the agent file to git root
mkdir -p ../..github/agents
mv .github/agents/squad.agent.md ../../.github/agents/squad.agent.md
rm -rf .github # if empty after move
# 4. Keep .squad/ in place — it's already correct
ls .squad/ # roster.md, decisions.md, etc. should be here
# 5. Verify
git status # should show changes at repo root, not nested repoAutomated (phase 2)
cd my-monorepo/team-alpha
squad upgrade # or: squad migrate-monorepoTesting Strategy
| Layer | What to test | Status |
|---|---|---|
| Unit | Monorepo detection, git-root resolution, path normalization, workflow skip logic | ✅ Phase 1 |
| E2E | Standalone, monorepo subfolder, second squad, no-git, git-root, re-init, agent content | ✅ Phase 1 |
| E2E | Upgrade in monorepo, migrate-monorepo, nested .git/ detection |
⬜ Phase 2 |
| E2E | Multi-squad workflow generation, label namespacing | ⬜ Phase 3 |
| Manual | Clone PR branch → build → run squad init from various locations |
✅ Phase 1 |
Links
- squad init: Squad init should not run git init in a sub-folder of a repository (or ever) #939 — Original bug report (monorepo subfolder creates nested
.git/) - fix: monorepo subfolder support — never run git init (#939) #944 — Phase 1 implementation (init fix)
- Platform docs — Copilot custom agents resolve from
.github/agents/at git root only
Activity
fix: monorepo subfolder support — never run git init (#939)
fix: monorepo subfolder support — never run git init (#939)
github-actions commentedon Sep 10, 2026
🔄 Ralph — Auto-Triage
Assigned to: Booster
Reason: Matched routing keyword(s): cd, GitHub Actions
Source: routing-rule
github-actions commentedon Sep 10, 2026
🔄 Ralph — Auto-Triage
Assigned to: Booster
Reason: Matched routing keyword(s): cd, GitHub Actions
Source: routing-rule
github-actions commentedon Sep 11, 2026
🔄 Ralph — Auto-Triage
Assigned to: Booster
Reason: Matched routing keyword(s): cd, GitHub Actions
Source: routing-rule
github-actions commentedon Sep 11, 2026
🔄 Ralph — Auto-Triage
Assigned to: Booster
Reason: Matched routing keyword(s): cd, GitHub Actions
Source: routing-rule
github-actions commentedon Sep 11, 2026
🔄 Ralph — Auto-Triage
Assigned to: Booster
Reason: Matched routing keyword(s): cd, GitHub Actions
Source: routing-rule
github-actions commentedon Sep 11, 2026
🔄 Ralph — Auto-Triage
Assigned to: Booster
Reason: Matched routing keyword(s): cd, GitHub Actions
Source: routing-rule
github-actions commentedon Sep 13, 2026
🔄 Ralph — Auto-Triage
Assigned to: architect
Reason: No module, routing, or role keyword match — routed to Lead/Architect
Source: lead-fallback