Repository navigation
Description
Problem
.git/info/exclude (line 9) contains:
.squad/
commented as "Squad consult mode (local only)".
This rule behaves asymmetrically, and the asymmetry is the hazard:
| File state | Behavior |
|---|---|
| Already tracked in git | Shows as modified, commits normally ✅ |
| New / untracked | Invisible to git status -uall, silently never commits ❌ |
An agent can write a file, see no error, report success, and have that file quietly die with the worktree. There is no signal at any point in the workflow.
.git/info/exclude is per-clone and not version controlled, so this is also invisible in code review and won't reproduce for other contributors — making it harder to diagnose when it does bite.
Observed impact
During the agentic-workflows audit session (2026-08-21), Scribe wrote 8 files. 3 were already tracked and committed cleanly via #1816. The other 5 were silently dropped:
.squad/log/2026-08-21T09-30-07-07-00-agentic-workflows-audit.md.squad/orchestration-log/2026-08-21T09-30-07-07-00-booster.md.squad/orchestration-log/2026-08-21T09-30-07-07-00-flight.md.squad/orchestration-log/2026-08-21T09-30-07-07-00-sims.md.squad/agents/sims/history.md(newly created — Sims had no prior history file, so this agent now has no persisted memory at all)
The sims/history.md loss is the most consequential: it isn't a missing increment, it's a missing origin.
Why this looks like a behavior change, not long-standing policy
dev currently tracks files that this rule would now prevent from ever being added:
- 4 files under
.squad/log/ - 11 files under
.squad/orchestration-log/
So these paths were previously committed as a matter of course. The exclude rule appears to have been added later, and it silently froze those directories — existing entries keep updating, new ones can never appear.
Relevant context
.squad/is tracked ondevby design and is stripped at release time bysquad-promote.yml(git rm -rf --cached --ignore-unmatch .squad/), andsquad-preview.ymlfails if.squad/is tracked on a preview branch. So committing.squad/todevdoes not leak into releases — the release path already handles it.- The
Squad File LeakageCI check (scripts/check-squad-leakage.mjs) is informational only — its header states "Exit code: always 0 (informational only — does not block merge)". It would not have caught this. - Squad's own Scribe archival-safety rules explicitly warn about this exact failure shape: "
.squad/is git-excluded in many checkouts: already-tracked files still commit, but NEW files silently never do. Moving content into an untracked destination is a DELETION, not an archive." The rules anticipated the trap; the environment still contains it.
Options to discuss
- Remove the
.squad/line from.git/info/exclude. Restores the pre-existing behavior where session logs and orchestration logs commit normally. Simplest fix, but re-opens whatever concern motivated adding it. - Narrow the rule to only the paths genuinely meant to stay local (e.g.
.squad/memory/, scratch dirs) rather than the whole tree. - Keep it and make the loss loud. Have Scribe verify with
git check-ignore -vafter each write and fail loudly when a file it just authored is unreachable to git — so silent loss becomes a visible error. - Keep it and redirect — route session/orchestration logs to a path outside the exclude, or to the session artifacts dir, and accept that they are ephemeral by design.
Worth deciding once, in the open, rather than each session rediscovering it.
Acceptance criteria
- Team decides which option (or combination) to adopt
- Decision recorded in
.squad/decisions.md - If the rule stays in any form, there is a loud failure mode — no silent drops
- Consider regenerating
.squad/agents/sims/history.md, which currently does not exist in any committed form
Raised by Flight during review of #1816, independently corroborated by the Coordinator during the same session.
Activity
bradygaster commentedon Aug 21, 2026
Additional hazard surfaced during E2E readiness assessment (Sims):
.git/info/excludeis per-clone and untracked.The consequence is worse than "new
.squad/files silently do not commit." Because this file lives in.git/and is never version-controlled, each clone and each worktree host has its own copy. That means:This makes the failure mode a ratchet:
git add -f <file>works, but only for the person who remembers, only that time. Every subsequent contributor silently reintroduces the bug.Two operational mitigations worth capturing regardless of how the underlying line is resolved:
git check-ignore -v .squad/<newfile>before assuming a newly written doc is committable.git cat-file -e <rev>:<path>is the only trustworthy confirmation the blob actually landed.Open question that should be answered before removing the line: why was
.squad/added to the exclude in the first place? If it was deliberate (e.g. keeping local agent history out of commits), blind removal trades this bug for a different one.devstill tracks 4.squad/log/and 11.squad/orchestration-log/files from before the rule existed, which suggests the exclusion is a later behavior change rather than a standing policy — but that is inference, not evidence.bradygaster commentedon Aug 21, 2026
1. Why the line exists — answered
squad consultwrote it. It is a tool artifact, not policy. Confidence: high.packages/squad-sdk/src/sharing/consult.ts:463:…where
excludeLinesis['.squad/', '.github/agents/squad.agent.md'](lines 455–461). That is byte-for-byte what is in the file, same comment, same order.Byte math closes it:
info/excludetemplateThe file contains the stock git template plus exactly that block and nothing else — no hand edits, ever.
mtime 2026-06-24 10:43:26,ctime 2026-06-15(clone time). Consult mode shipped2026-03-01(47a77aee), ~3.5 months before the write.Release pipeline: ruled out explicitly.
squad-npm-publish.yml— zero.squadreferences.squad-promote.yml:52-57— strips.squad/(git rm -rf --cached) when merging dev→preview. So.squad/tracked ondevnever reaches a release.squad-preview.yml:36-50— the gate only guards the preview branch, and promote has already stripped by then. It is satisfied today with.squad/tracked ondev..squad/decisions.md— no decision about.git/info/exclude.CONTRIBUTING.md,.gitattributes,.npmignore— nothing.scripts/check-squad-leakage.mjs— confirmedexit 0always, informational only.The release path was already correct without this line. It was never the reason.
Mechanism — how a guarded function wrote it anyway.
resolveGitExcludePath()(consult.ts:328) shellsgit rev-parse --git-path info/exclude, which from any worktree returns the shared common dir. Verified from this worktree:But the "already squadified → refuse" guard (consult.ts:396) checks the worktree-local
.squad/. Runsquad consultin a worktree that lacks.squad/and the guard passes while the write lands in the shared exclude — poisoning the main checkout and every sibling worktree in one shot. Confidence: high that consult wrote it (byte-exact); medium-high on the worktree route specifically (mechanism verified; the individual invocation isn't logged anywhere).2. Correction: 4 of the 5 lost files are not the exclude's doing
I built three isolated repos — tracked-
.gitignore-only, exclude-only, and both — and asked git which paths each hides:.gitignorealone.squad/log/…audit.md.squad/log/.squad/orchestration-log/…booster.md.squad/orchestration-log/.squad/orchestration-log/…flight.md.squad/orchestration-log/.squad/orchestration-log/…sims.md.squad/orchestration-log/.squad/agents/sims/history.md.gitignore:13-18has ignored.squad/log/and.squad/orchestration-log/since 2026-02-21 (c36e8ecc) — tracked, reviewed, repo-wide, and older than every one of the 15 tracked files in those directories (earliest add2026-02-22,f4f86683). Those files were committed with-fagainst a standing rule.So the "the exclude was added later and silently froze those directories" hypothesis is refuted. The directories were never frozen — adds continued through 2026-08-02 (
065d3021), six weeks after this machine was poisoned. That late add is itself independent proof of the per-clone split you described: a clean clone still committed those paths while this one could not.Net: removing the exclude line would have saved exactly one of the five files —
sims/history.md. The other four are working as designed by policy that predates the exclude by four months.3. Live hazard, needs flagging now
.squad/e2e/is not in.gitignorebut is hidden by the exclude. The in-flight.squad/e2e/work is squarely in the blast radius — thegit add -f+ post-commitgit cat-file -eprotocol there is necessary, not belt-and-braces.4. Recommendation
The per-clone constraint is the whole problem: anything landed in the repo cannot repair an already-poisoned clone. So the repo-side answer has to be detection, and the local edit is a separate, manual act.
.gitignorewith scoped negation.gitignorecan't express it —.squad/must stay tracked on dev, release is already handled by promote-time stripping, and ignore rules don't affect tracked files anyway. Trades a per-clone hazard for a repo-wide one.decisions.md:604bar.squad doctorcheckconsult.tsD —
squad doctorcheck. Rungit check-ignore -vagainst the state paths squad intends to write, and discriminate on the matching source: a.gitignorematch is expected policy → info; a$GIT_DIR/info/excludematch on.squad/is the anomaly → fail, with the exact repair command. This clearsdecisions.md:604because it compares two genuinely independent sources — squad's own intent (its state-path model) against git's real enforcement engine (check-ignore) — rather than reading the file it is guarding. Slots into the existingDoctorCheckshape inpackages/squad-cli/src/cli/commands/doctor.ts.Cost: doctor is opt-in; it only helps whoever runs it. Worth wiring into the operator prelude / session-init so it fires unprompted.
E — guard in
consult.ts. Refuse to add.squad/to the exclude when.squad/is already tracked (git ls-files --error-unmatch .squad/), and resolve worktree-vs-common-dir correctly. Stops all future poisoning; does nothing for already-poisoned clones — which is exactly why it pairs with D.5. The larger bug underneath this one
Four of the five losses were
.squad/log/and.squad/orchestration-log/writes into directories that have been gitignored repo-wide since February. "Scribe writes session logs to.squad/log/" is a workflow that has never worked in a clean clone. Either those paths should be un-ignored or Scribe should stop writing there and the logs should go somewhere real. That is the bigger of the two problems and it has nothing to do with.git/info/exclude. Flagging for a team decision — not filing anything.6. Local remediation (per-machine, explicitly not a fix)
Delete line 9 (
.squad/) fromC:\src\squad\.git\info\exclude, keeping.github/agents/squad.agent.md:What it might break: nothing in the release path (promote strips
.squad/, preview gate is downstream of that). The real risk is the reverse —.squad/becomes visible togit statusagain, so anygit add .-style staging can now sweep in local squad state. Given the standing "nevergit add ." rule that is acceptable, but it is a genuine behavior change on this machine.Do not run it while the
.squad/e2e/session is in flight — it changes ignore semantics underneath that work.bradygaster commentedon Aug 23, 2026
Closing as a duplicate of #1826 — not because the problem is solved, but because the investigation that started here landed the root cause there, and two issues on one defect will drift.
Your analysis in this thread is what identified the writer:
#1826 carries that forward with the piece this issue could not have: the scope defect.
resolveGitExcludePath()shellsgit rev-parse --git-path info/exclude, which from a worktree resolves to the shared common dir, while the "already squadified → refuse" guard checks the worktree-local.squad/. Sosquad consultrun in a worktree passes the guard and poisons the exclude for the main checkout and every sibling worktree. #1826 also has a live re-poisoning observation from 2026-08-22, after the lines had been manually removed the same day — which upgrades this from a historical artifact to an active bug.Where the rest of this thread's content now lives:
squad consultwriter + worktree scope defect.squad/paths be ignored at all — the policy auditReopen if there is a per-clone repair story that #1826 does not cover — noting your own point that
.git/info/excludeis untracked, so no repo-side change can fix an already-poisoned clone.Triage: 2026-08-23.