You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Squad state destroyed when .squad/ is gitignored and agents switch branches #643
When .squad/ is in .gitignore (common when using Squad in a repo you do not own), agent-triggered git checkout commands silently destroy all Squad state files (dashboards, agent history, decisions, orchestration logs).
Root Cause
.squad/ files are untracked. Git does not preserve untracked files during branch switches. Agents that run git checkout <branch> in the main worktree — instead of git worktree add — cause the deletion.
How We Hit This
We used Squad to triage a 78-issue backlog in Azure/azure-cli. Since we cannot commit .squad/ to that repo, we gitignored it. During live validation, an agent ran git checkout fix/ssl-branch in the main worktree. All .squad/ files were wiped — dashboards, agent charters, history, logs. This happened twice in one session.
Suggested Improvements
Detect gitignored .squad/ at init — If .squad/ matches a .gitignore rule, warn the user: "⚠️ .squad/ is gitignored. State will not survive branch switches. Consider using --external-state or committing .squad/."
Enforce worktree usage in agent prompts — The coordinator already instructs agents to use git worktree add, but there is no enforcement. Consider adding a pre-flight check or a git hook that prevents git checkout when .squad/ is untracked.
Support external state directory — For "contributor" scenarios (using Squad in repos you do not own), allow .squad/ state to live outside the repo, e.g. ~/.squad/projects/<repo-name>/. This would be immune to checkout/worktree issues.
Auto-backup before risky git ops — Before any branch switch, snapshot .squad/ to a temp location. Restore if files are missing after the operation.
Issue:#643 — Squad state destroyed when .squad/ is gitignored and agents switch branches Assigned to: FIDO (Quality Owner) Reason: Issue relates to testing/quality work
@copilot evaluation: 🔴 Not suitable — issue involves work outside the coding agent's capability profile.
🔄 Ralph status: PR #680 is a POC for StateBackend (orphan branch persistence) that would solve the root cause. Marked DO NOT MERGE, has conflicts. Also refs #678 (RFC), #498, #670. No production fix merged yet — issue remains open.
I've experienced this a number of times because I didn't want squad in my repo and .gitignored it (matching what i think is coming anyway). I also used the worktrees feature which seemed to make it happen more often. I hit numerous issues with agents force adding/committing and even pushing the commits to origin containing .squad files despite directives, trying to funnel pushes and you name it, i spent a couple of days fighting this.
I investigated using a global squad but still seemed to hit issues - maybe something to do with my mucking around.
After various discussions and threats to the coordinator (that didn't work btw), i have found something that's been working for me and wanted to share in case it guides you to a fix or some sort of workaround for people.
one point noting is that the cause of files being left in random places, for me was identified as Squad agents receiving prompts without a TEAM_ROOT and being left to discover things. They would walk the tree and fail so end up back in the repo.
anyway, moving the .squad folder outside the repo given it's .gitignore anyway should be a suitable workaround. I wanted to retain the ability to have different squads in projects so global wasn't really a good option for me anyway. my folder structure is ~/project-name-dev/.squad and ~/project-name-dev/gitrepo. i did the squad /init in the ~/project-name-dev folder iirc.
We came up with Personal Squad Solo Mode added to the squad.agent.md and a revised agent-collaboration SKILL.md which i've added below (it's a long scroll for the agent one sorry)
``
Personal Squad — Sole Squad Mode (External Repo)
Injected at line 137 just after the **spawn personal agents with: ** section
When SQUAD_PERSONAL_ROOT is set in the environment, the personal squad operates in Sole Squad Mode:
TEAM_ROOT = $SQUAD_PERSONAL_ROOT (the personal squad's git repo path)
WORKTREE_PATH = current project repo root (from git rev-parse --show-toplevel)
Ghost Protocol is OFF — there is no project .squad/ to protect
Scribe commits to the personal squad repo, not the project repo
No origin: 'personal' tags — the personal squad IS the squad
The project repo remains clean: no .squad/ directory at all
Revised team root resolution section
Three strategies for resolving the team root:
Strategy
Team root
State scope
When to use
worktree-local
Current worktree root
Branch-local — each worktree has its own .squad/ state
Feature branches that need isolated decisions and history
main-checkout
Main working tree root
Shared — all worktrees read/write the main checkout's .squad/
Single source of truth for memories, decisions, and logs across all branches
external-personal-squad
$SQUAD_PERSONAL_ROOT (separate git repo)
Shared across all project worktrees — state lives in the personal squad repo, never the project repo
Personal squad is the sole squad; project repo has no .squad/
How the Coordinator resolves the team root (on every session start):
Check SQUAD_PERSONAL_ROOT env var first. If set → use external-personal-squad strategy:
Run git rev-parse --show-toplevel to get the current worktree root.
Check if .squad/ exists at that root (fall back to .ai-team/ for repos that haven't migrated yet).
Yes → use worktree-local strategy. Team root = current worktree root.
No → use main-checkout strategy. Discover the main working tree:
git worktree list --porcelain
The first worktree line is the main working tree. Team root = that path.
The user may override the strategy at any time (e.g., "use main checkout for team state" or "keep team state in this worktree").
Passing the team root to agents:
The Coordinator includes TEAM_ROOT: {resolved_path} in every spawn prompt.
Agents resolve ALL .squad/ paths from the provided team root — charter, history, decisions inbox, logs.
Agents never discover the team root themselves. They trust the value from the Coordinator.
Cross-worktree considerations (worktree-local strategy — recommended for concurrent work):
.squad/ files are branch-local. Each worktree works independently — no locking, no shared-state races.
When branches merge into main, .squad/ state merges with them. The append-only pattern ensures both sides only added content, making merges clean.
A merge=union driver in .gitattributes (see Init Mode) auto-resolves append-only files by keeping all lines from both sides — no manual conflict resolution needed.
The Scribe commits .squad/ changes to the worktree's branch. State flows to other branches through normal git merge / PR workflow.
All worktrees share the same .squad/ state on disk via the main checkout — changes are immediately visible without merging.
Not safe for concurrent sessions. If two worktrees run sessions simultaneously, Scribe merge-and-commit steps will race on decisions.md and git index. Use only when a single session is active at a time.
Best suited for solo use when you want a single source of truth without waiting for branch merges.
The personal squad repo is completely independent of the project repo — no .squad/ in the project at all.
Multiple project worktrees all point at the same TEAM_ROOT (the personal squad repo). State is shared across all worktrees without any merging.
Safe for single-session use (one Scribe, no concurrent Scribe write races within a session).
Concurrent sessions on different machines: same caveat as main-checkout — avoid simultaneous Scribe commits to the same personal squad branch.
SQUAD_PERSONAL_ROOT must be set consistently across all worktrees in the session.
In this mode, the standard Ambient Discovery flow is skipped. All agent state, decisions, and logs live entirely in the external personal squad repo.
Revised/hacked Agent Collab Skill the cooridinator made (i haven't hit the gate yet):
`---
name: "agent-collaboration"
description: "Standard collaboration patterns for all squad agents — worktree awareness, decisions, cross-agent communication"
domain: "team-workflow"
confidence: "high"
source: "extracted from charter boilerplate — identical content in 18+ agent charters"
Context
Every agent on the team follows identical collaboration patterns for worktree awareness, decision recording, and cross-agent communication. These were previously duplicated in every charter's Collaboration section (~300 bytes × 18 agents = ~5.4KB of redundant context). Now centralized here.
The coordinator's spawn prompt already instructs agents to read decisions.md and their history.md. This skill adds the patterns for WRITING decisions and requesting help.
Patterns
Worktree Awareness
Use the TEAM ROOT path provided in your spawn prompt. All .squad/ paths are relative to this root. Never assume CWD is the repo root.
TEAM_ROOT Validation Gate ⛔ HARD GATE
Run this check BEFORE any work that reads or writes .squad/:
Is TEAM_ROOT explicitly present in your spawn prompt?
Yes → absolute path (starts with / or drive letter): proceed.
No / empty / missing: HALT immediately. Report back:
"⛔ TEAM_ROOT not set in spawn prompt — refusing to write team state. Coordinator must re-spawn with TEAM_ROOT set."
Do NOT fall back to git rev-parse --show-toplevel. Do NOT proceed with any .squad/ operations.
Why the fallback is banned: Inside a worktree, git rev-parse --show-toplevel returns the worktree root (e.g., /Users/test/projectgitrepo/projectgitrepo-1234), NOT the personal squad repo root (/Users/test/testsquadroot). Using it as a fallback silently writes team state to the wrong location and can commit squad artifacts into project branches — which is a hard violation.
Decision Recording
After making a decision that affects other team members, write it to: .squad/decisions/inbox/{your-name}-{brief-slug}.md
If you need another team member's input, say so in your response. The coordinator will bring them in. Don't try to do work outside your domain.
Reviewer Protocol
If you have reviewer authority and reject work: the original author is locked out from revising that artifact. A different agent must own the revision. State who should revise in your rejection response.
Anti-Patterns
Don't read all agent charters — you only need your own context + decisions.md
Don't write directly to .squad/decisions.md — always use the inbox drop-box
Don't modify other agents' history.md files — that's Scribe's job
Don't assume CWD is the repo root — always use TEAM ROOT
Don't fall back to git rev-parse if TEAM_ROOT is missing — halt and report instead
Don't write .squad/ files without TEAM_ROOT being an absolute path — this is how team state ends up in worktrees and project branches
`
This is addressed by PR #797 (merged to insider Apr 5) which adds \squad externalize\ — moves .squad/ state outside the working tree to a platform-specific global directory.
With external state, branch switches no longer destroy squad state because the files aren't in the working tree at all.
To use it: \squad externalize\ (moves state out) / \squad internalize\ (moves it back).
Closing as resolved by #797. If you're on insider, try \squad externalize\ and let us know if it works for your workflow.
Activity
github-actions commentedon Mar 28, 2026
📋 Assigned to EECOM (Core Dev)
Issue: #643 — Squad state destroyed when .squad/ is gitignored and agents switch branches
EECOM will pick this up in the next Copilot session.
github-actions commentedon Mar 28, 2026
📋 Assigned to FIDO (Quality Owner)
Issue: #643 — Squad state destroyed when .squad/ is gitignored and agents switch branches
FIDO will pick this up in the next Copilot session.
github-actions commentedon Mar 28, 2026
🏗️ Squad Triage — Flight (Lead)
Issue: #643 — Squad state destroyed when .squad/ is gitignored and agents switch branches
Assigned to: FIDO (Quality Owner)
Reason: Issue relates to testing/quality work
@copilot evaluation: 🔴 Not suitable — issue involves work outside the coding agent's capability profile.
Team roster:
squad:flightsquad:proceduressquad:eecomsquad:fidosquad:paosquad:capcomsquad:controlsquad:surgeonsquad:boostersquad:gncsquad:networksquad:retrosquad:incosquad:guidosquad:telemetrysquad:voxsquad:dskysquad:simssquad:handbooksquad:ralphsquad:copilotfeat(sdk): StateBackend POC — orphan branch state persistence (#678)
fix: address all 5 Copilot review findings + expand to 36 E2E tests
diberry commentedon Mar 31, 2026
🔄 Ralph status: PR #680 is a POC for StateBackend (orphan branch persistence) that would solve the root cause. Marked DO NOT MERGE, has conflicts. Also refs #678 (RFC), #498, #670. No production fix merged yet — issue remains open.
jazz127 commentedon Apr 1, 2026
I've experienced this a number of times because I didn't want squad in my repo and .gitignored it (matching what i think is coming anyway). I also used the worktrees feature which seemed to make it happen more often. I hit numerous issues with agents force adding/committing and even pushing the commits to origin containing .squad files despite directives, trying to funnel pushes and you name it, i spent a couple of days fighting this.
I investigated using a global squad but still seemed to hit issues - maybe something to do with my mucking around.
After various discussions and threats to the coordinator (that didn't work btw), i have found something that's been working for me and wanted to share in case it guides you to a fix or some sort of workaround for people.
one point noting is that the cause of files being left in random places, for me was identified as Squad agents receiving prompts without a TEAM_ROOT and being left to discover things. They would walk the tree and fail so end up back in the repo.
anyway, moving the .squad folder outside the repo given it's .gitignore anyway should be a suitable workaround. I wanted to retain the ability to have different squads in projects so global wasn't really a good option for me anyway. my folder structure is ~/project-name-dev/.squad and ~/project-name-dev/gitrepo. i did the squad /init in the ~/project-name-dev folder iirc.
We came up with Personal Squad Solo Mode added to the squad.agent.md and a revised agent-collaboration SKILL.md which i've added below (it's a long scroll for the agent one sorry)
``
Personal Squad — Sole Squad Mode (External Repo)
Injected at line 137 just after the **spawn personal agents with: ** section
When
SQUAD_PERSONAL_ROOTis set in the environment, the personal squad operates in Sole Squad Mode:TEAM_ROOT=$SQUAD_PERSONAL_ROOT(the personal squad's git repo path)WORKTREE_PATH= current project repo root (fromgit rev-parse --show-toplevel).squad/to protectorigin: 'personal'tags — the personal squad IS the squad.squad/directory at allRevised team root resolution section
Three strategies for resolving the team root:
.squad/state.squad/$SQUAD_PERSONAL_ROOT(separate git repo).squad/How the Coordinator resolves the team root (on every session start):
SQUAD_PERSONAL_ROOTenv var first. If set → use external-personal-squad strategy:TEAM_ROOT=$SQUAD_PERSONAL_ROOTWORKTREE_PATH=git rev-parse --show-toplevel(current project repo)git rev-parse --show-toplevelto get the current worktree root..squad/exists at that root (fall back to.ai-team/for repos that haven't migrated yet).worktreeline is the main working tree. Team root = that path.Passing the team root to agents:
TEAM_ROOT: {resolved_path}in every spawn prompt..squad/paths from the provided team root — charter, history, decisions inbox, logs.Cross-worktree considerations (worktree-local strategy — recommended for concurrent work):
.squad/files are branch-local. Each worktree works independently — no locking, no shared-state races..squad/state merges with them. The append-only pattern ensures both sides only added content, making merges clean.merge=uniondriver in.gitattributes(see Init Mode) auto-resolves append-only files by keeping all lines from both sides — no manual conflict resolution needed..squad/changes to the worktree's branch. State flows to other branches through normal git merge / PR workflow.Cross-worktree considerations (main-checkout strategy):
.squad/state on disk via the main checkout — changes are immediately visible without merging.decisions.mdand git index. Use only when a single session is active at a time.Cross-worktree considerations (external-personal-squad strategy):
.squad/in the project at all.TEAM_ROOT(the personal squad repo). State is shared across all worktrees without any merging.SQUAD_PERSONAL_ROOTmust be set consistently across all worktrees in the session.In this mode, the standard Ambient Discovery flow is skipped. All agent state, decisions, and logs live entirely in the external personal squad repo.
Revised/hacked Agent Collab Skill the cooridinator made (i haven't hit the gate yet):
`---
name: "agent-collaboration"
description: "Standard collaboration patterns for all squad agents — worktree awareness, decisions, cross-agent communication"
domain: "team-workflow"
confidence: "high"
source: "extracted from charter boilerplate — identical content in 18+ agent charters"
Context
Every agent on the team follows identical collaboration patterns for worktree awareness, decision recording, and cross-agent communication. These were previously duplicated in every charter's Collaboration section (~300 bytes × 18 agents = ~5.4KB of redundant context). Now centralized here.
The coordinator's spawn prompt already instructs agents to read decisions.md and their history.md. This skill adds the patterns for WRITING decisions and requesting help.
Patterns
Worktree Awareness
Use the
TEAM ROOTpath provided in your spawn prompt. All.squad/paths are relative to this root. Never assume CWD is the repo root.TEAM_ROOT Validation Gate ⛔ HARD GATE
Run this check BEFORE any work that reads or writes
.squad/:TEAM_ROOTexplicitly present in your spawn prompt?/or drive letter): proceed.Why the fallback is banned: Inside a worktree,
git rev-parse --show-toplevelreturns the worktree root (e.g.,/Users/test/projectgitrepo/projectgitrepo-1234), NOT the personal squad repo root (/Users/test/testsquadroot). Using it as a fallback silently writes team state to the wrong location and can commit squad artifacts into project branches — which is a hard violation.Decision Recording
After making a decision that affects other team members, write it to:
.squad/decisions/inbox/{your-name}-{brief-slug}.mdFormat:
Cross-Agent Communication
If you need another team member's input, say so in your response. The coordinator will bring them in. Don't try to do work outside your domain.
Reviewer Protocol
If you have reviewer authority and reject work: the original author is locked out from revising that artifact. A different agent must own the revision. State who should revise in your rejection response.
Anti-Patterns
.squad/decisions.md— always use the inbox drop-boxgit rev-parseif TEAM_ROOT is missing — halt and report instead.squad/files without TEAM_ROOT being an absolute path — this is how team state ends up in worktrees and project branches`
tamirdresher commentedon Apr 12, 2026
This is addressed by PR #797 (merged to insider Apr 5) which adds \squad externalize\ — moves .squad/ state outside the working tree to a platform-specific global directory.
With external state, branch switches no longer destroy squad state because the files aren't in the working tree at all.
To use it: \squad externalize\ (moves state out) / \squad internalize\ (moves it back).
Closing as resolved by #797. If you're on insider, try \squad externalize\ and let us know if it works for your workflow.