Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
8dd7170
wip: state-backend regression fixes (Bug A,B,C,F)
May 31, 2026
0d124b9
fix(cli): runtime commands resolve externalized state paths
diberry Apr 10, 2026
09cd6c1
fix(cli,sdk): state-backend and upgrade regressions (#1163, #1185, #1…
May 31, 2026
2d9f0b4
fix(cli,sdk): address Worf gate blockers — test regression, doctor ho…
May 31, 2026
748d2be
fix(coordinator): sync .github/agents/squad.agent.md with canonical t…
May 31, 2026
d77c312
fix(template): correct state backend default from worktree to local
May 31, 2026
50ca7fe
fix(ci): normalize versions to 0.9.6-preview, fix CLI SDK dependency …
May 31, 2026
bf3d87b
fix(cli): restore >=0.9.0-0 workspace range for squad-sdk dep
May 31, 2026
7a6b013
fix(cli): correct @bradygaster/squad-sdk semver range to resolve work…
May 31, 2026
dc2b3f5
fix(sdk): warn once when git-notes config silently migrates to two-layer
Jun 2, 2026
fc40635
fix(sdk): throw in toRelative for absolute paths outside squadDir on …
Jun 2, 2026
70a3781
fix(permissions): use 'approve-once' for Copilot CLI v1.0.54+ contract
bradygaster May 29, 2026
e0291f3
test(permissions): cover approve-once contract for Copilot CLI v1.0.54+
Jun 2, 2026
cf99139
fix(upgrade): surface self-upgrade failures instead of false-success …
tamirdresher Jun 2, 2026
e2ff827
fix(hooks): install pre-commit + post-commit hooks for two-layer/orph…
tamirdresher Jun 2, 2026
e010b16
fix(upgrade): honour --state-backend and migrate working-tree state t…
tamirdresher Jun 2, 2026
b987fe6
fix(mcp): pin @bradygaster/squad-cli@<version> in mcp-config so npx d…
tamirdresher Jun 2, 2026
e291b96
fix(init): lift mutable state onto squad-state branch on fresh orphan…
tamirdresher Jun 2, 2026
8ab9a30
chore(release): bump to 0.9.6-preview.3 for combined-fixes tarball
tamirdresher Jun 2, 2026
3b44f45
fix(sync+mcp): register 'squad sync' command + insert squad_state whe…
Jun 2, 2026
a0fa7e3
fix(init): wire ensureSquadStateMcpPinned into 'squad init' too
Jun 2, 2026
e839da6
fix(combined): iter-4 end-to-end working bundle for state-backend upg…
tamirdresher Jun 2, 2026
3c01924
fix(combined): iter-5 — run-copilot wrapper + init MCP fallback + tem…
tamirdresher Jun 3, 2026
9b5f377
fix(mcp-spec): fall back to local install when pinned version unpubli…
tamirdresher Jun 3, 2026
f25e400
fix(run-copilot): use shell:false + cmd.exe shim with windowsVerbatim…
tamirdresher Jun 3, 2026
d979560
refactor(mcp-spec): simplify resolver to 2-tier (pinned npx / @inside…
tamirdresher Jun 3, 2026
1d0d4db
refactor(cli): delete run-copilot wrapper subcommand
tamirdresher Jun 3, 2026
00bde06
feat(init,upgrade): write squad_state MCP entry to ~/.copilot/mcp-con…
tamirdresher Jun 3, 2026
e00ff4b
docs(state-backends): clarify default backend is local
tamirdresher Jun 3, 2026
5562efe
chore(release): bump to 0.9.6-preview.13
tamirdresher Jun 3, 2026
9f21d03
refactor(init,upgrade): pivot squad_state MCP write to repo-root .mcp…
tamirdresher Jun 3, 2026
908a9ba
chore(release): bump to 0.9.6-preview.14
tamirdresher Jun 3, 2026
2e35beb
test(mcp-root): cover repo-root .mcp.json writer + tombstone
tamirdresher Jun 3, 2026
f8347d8
iter-9: fix non-interactive MCP trust gate — inject --yolo + --additi…
tamirdresher Jun 3, 2026
1c62800
docs: add iter-9 MCP trust gate cross-links to ralph, loop, and cli r…
tamirdresher Jun 3, 2026
5bef8f2
ci(policy): allow -preview.N and -insider.N suffix patterns in versio…
tamirdresher Jun 3, 2026
4da1183
ci(policy): allow -preview.N and -insider.N suffix patterns in versio…
tamirdresher Jun 3, 2026
bc5e81e
test(upgrade-state-backend): add 30 s timeout + clean-target regressi…
tamirdresher Jun 3, 2026
debd05c
fix(mcp): guard against undefined content in squad_state_write/append…
tamirdresher Jun 3, 2026
3f0a16d
test(iter-9): update copilot-invocation-mcp-wrap + npm-registry-fallb…
tamirdresher Jun 3, 2026
8f3208a
fix(shell): use effective state dir when resuming sessions (PR #1200 …
tamirdresher Jun 4, 2026
dab1d9e
fix(doctor): match install-hooks git-dir resolution for worktrees (PR…
tamirdresher Jun 4, 2026
55e843c
fix(types): normalize legacy 'approved' permission kind (PR #1200 rev…
tamirdresher Jun 4, 2026
3a02478
test(effective-squad-dir): stub global Squad path env vars to avoid p…
tamirdresher Jun 4, 2026
c9e5b75
test(session-store,doctor): add regression tests for stateDir and git…
tamirdresher Jun 4, 2026
14917c5
fix(sdk): state backend hardening — retry, circuit-breaker, startup v…
tamirdresher Jun 4, 2026
212365e
fix: restore backtick template literals in GitExecError test suites
tamirdresher Jun 4, 2026
d24b8ba
fix(sdk): preserve trailing newlines in OrphanBranchBackend reads
tamirdresher Jun 4, 2026
c301263
fix(sdk): anchor GitNotesBackend notes on root commit for branch-swit…
tamirdresher Jun 4, 2026
e19b4f8
ci: re-apply preview.N/insider.N version-policy without LF churn
tamirdresher Jun 4, 2026
aaec183
fix(state-backend): add notes promotion/read API and observability fo…
tamirdresher Jun 4, 2026
f35eafe
Merge branch 'dev' of https://github.com/bradygaster/squad into squad…
tamirdresher Jun 4, 2026
abd37ea
fix(sdk): add maxBuffer to git exec wrappers (B1+B2 ENOBUFS)
Jun 4, 2026
8f7e7f7
fix(sdk): add CAS to GitNotesBackend + OrphanBranchBackend writers (B4)
Jun 4, 2026
3f13cdf
fix(sdk): tokenize git args properly in gitExecMaybeMissing
Jun 4, 2026
c71ea2c
feat(cli): add 'squad notes promote' command (P0.3 A3 production caller)
tamirdresher Jun 4, 2026
7e3e8a4
feat(cli): wire promoteNotes into Ralph heartbeat (P0.3 A3 path B)
tamirdresher Jun 4, 2026
98b69ae
fix(cli): clean stale .squad/ working-branch files after upgrade (F1)
tamirdresher Jun 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-externalized-state-paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@bradygaster/squad-cli': patch
---

Fix runtime commands to correctly resolve externalized state paths
6 changes: 6 additions & 0 deletions .changeset/fix-permission-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@bradygaster/squad-sdk": patch
"@bradygaster/squad-cli": patch
---

Fix permission handler to use `approve-once` instead of deprecated `approved` kind, aligning with Copilot CLI v1.0.54+ permission contract
38 changes: 38 additions & 0 deletions .changeset/fix-state-backend-upgrade-regressions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
"@bradygaster/squad-cli": patch
"@bradygaster/squad-sdk": patch
---

Fix state-backend and upgrade regressions (#1163, #1185, #1190, #1191, #1194)

**Bug A (P0) — Permission contract mismatch** (#1191)
The Copilot SDK changed the valid permission result `kind` from `"approved"` to
`"approve-once"`. Squad was still returning `{ kind: 'approved' }`, causing all
agent sessions to fail permission checks immediately. Fixed in:
- `cli/shell/index.ts` — `approveAllPermissions` handler now returns `{ kind: 'approve-once' }`
- `adapter/types.ts` — `SquadPermissionRequestResult.kind` union includes `'approve-once'`
- `adapter/client.ts` — error hint updated to reference the correct `kind` value

**Bug B (P1) — Hard-throw in `resolveStateBackend()` when explicit backend fails** (#1185, #1190)
When a backend configured in `config.json` failed to initialize (e.g., no git repo
available), Squad threw a fatal error and refused to start. Now always warns and
falls back to `local` so operators can fix config without losing work.

**Bug C (P1) — Silent git-notes→two-layer migration** (#1163)
`normalizeBackendType()` silently mapped `'git-notes'` to `'two-layer'` with no
user notification. Now emits a `console.warn()` directing users to update their
`config.json`.

**Bug F (P3) — Windows `toRelative()` drive-letter case mismatch**
`StateBackendStorageAdapter.toRelative()` used a simple string prefix comparison
after normalizing separators. On Windows, `C:\` vs `c:\` drive-letter case
differences caused the prefix check to fail, returning full absolute paths as
git-notes keys (corruption). Now uses `path.resolve()` and case-insensitive
comparison on `process.platform === 'win32'`.

**Issue #1194 — Externalized state paths not followed by runtime commands**
Adds `effectiveSquadDir()` and `resolveStateDir()` helpers that follow the
`stateLocation: 'external'` marker in `.squad/config.json`. Updates `loop`,
`watch`, `plugin`, `doctor` commands and `shell` (lifecycle, coordinator, index)
to use the effective state dir for reading `team.md`, `routing.md`, `agents/`,
`plugins/`, and other state files.
5 changes: 5 additions & 0 deletions .changeset/iter9-non-interactive-mcp-load.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bradygaster/squad-cli": minor
---

iter-9: inject `--yolo --additional-mcp-config @.mcp.json` in all non-interactive copilot spawns; fix path regression from `.copilot/mcp-config.json` (iter-7) to `.mcp.json` (iter-8 canonical location); add fallback warning when `.mcp.json` is absent; add `--yolo` deduplication guard; document Copilot CLI 1.0.59+ folder-trust security gate
5 changes: 5 additions & 0 deletions .changeset/state-backend-hardening.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@bradygaster/squad-sdk': patch
---

State backend hardening: retry with exponential backoff for transient git errors, circuit-breaker to prevent cascading failures, read-only startup verification, and observable error surfacing replacing silent swallowing.
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@
.squad/decisions/decisions.md merge=union
# Squad: union merge for append-only team state files
.squad/rai/audit-trail.md merge=union

# Squad: pin LF for YAML to prevent CRLF<->LF flip on Windows checkouts (PR #1200 concern G)
*.yml text eol=lf
*.yaml text eol=lf
6 changes: 3 additions & 3 deletions .github/agents/squad.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ The `union` merge driver keeps all lines from both sides, which is correct for a

**On every session start:** Run `git config user.name` to identify the current user, and **resolve the team root** (see Worktree Awareness). Store the team root — all `.squad/` paths must be resolved relative to it. Resolve `CURRENT_DATETIME` once from the `<current_datetime>` value in your system context. Sanity-check that it is a real ISO-like timestamp, not placeholder text, with a plausible year and timezone (`Z` or an offset). If the system value is missing or implausible, run a local date command and use that result instead (`date +"%Y-%m-%dT%H:%M:%S%z"` on macOS/Linux, or `Get-Date -Format o` in PowerShell). Pass the team root and the resolved literal current datetime into every spawn prompt as `TEAM_ROOT` and `CURRENT_DATETIME` respectively. Never pass placeholder text for `CURRENT_DATETIME`. Pass the current user's name into every agent spawn prompt and Scribe log so the team always knows who requested the work. Check `.squad/identity/now.md` if it exists — it tells you what the team was last focused on. Update it if the focus has shifted.

**Resolve state backend:** Read `.squad/config.json` (at the resolved TEAM_ROOT) and check the `stateBackend` field. Valid values: `"worktree"` (default), `"git-notes"`, `"orphan"`, `"two-layer"`. Store as `STATE_BACKEND` and pass it into every spawn prompt. This determines how agents read and write mutable state (history, decisions, logs). Static config (charters, team.md, routing.md) always lives on disk regardless of backend. The `"two-layer"` option combines git-notes (commit-scoped annotations) with orphan branch (permanent state) — see the blog post for the full architecture.
**Resolve state backend:** Read `.squad/config.json` (at the resolved TEAM_ROOT) and check the `stateBackend` field. Valid values: `"local"` (default), `"orphan"`, `"two-layer"`. Legacy alias: `"worktree"` maps to `"local"`. Deprecated: `"git-notes"` maps to `"two-layer"` with a deprecation warning. Store as `STATE_BACKEND` and pass it into every spawn prompt. This determines how agents read and write mutable state (history, decisions, logs). Static config (charters, team.md, routing.md) always lives on disk regardless of backend. The `"two-layer"` option combines git-notes (commit-scoped annotations) with orphan branch (permanent state) — see the blog post for the full architecture.

**⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing).

Expand Down Expand Up @@ -607,8 +607,8 @@ prompt: |
0b. PRE-CHECK: Read `decisions.md` and list `decisions/inbox` with state tools. Record measurements.
1. DECISIONS ARCHIVE [HARD GATE]: If decisions.md >= 20480 bytes, archive entries older than 30 days NOW. If >= 51200 bytes, archive entries older than 7 days. Do not skip this step.
2. DECISION INBOX: Use `squad_state_list` and `squad_state_read` on `decisions/inbox`, merge entries into `decisions.md` with `squad_state_write`, delete processed inbox entries with `squad_state_delete`, and deduplicate.
3. ORCHESTRATION LOG: Write `orchestration-log/{timestamp}-{agent}.md` with `squad_state_write` per agent. Use the literal CURRENT_DATETIME value.
4. SESSION LOG: Write `log/{timestamp}-{topic}.md` with `squad_state_write`. Brief. Use the literal CURRENT_DATETIME value.
3. ORCHESTRATION LOG: Write `orchestration-log/{timestamp}-{agent}.md` with `squad_state_write` per agent. Use the literal CURRENT_DATETIME value. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms (e.g. `2026-06-02T21-15-30Z`).
4. SESSION LOG: Write `log/{timestamp}-{topic}.md` with `squad_state_write`. Brief. Use the literal CURRENT_DATETIME value. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms.
5. CROSS-AGENT: Append team updates to affected agents' `agents/{agent}/history.md` with `squad_state_append`.
6. HISTORY SUMMARIZATION [HARD GATE]: If any history.md >= 15360 bytes (15KB), summarize now.
7. GIT COMMIT: Do not commit mutable squad state. If non-state repo files changed, report them for coordinator handling.
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/squad-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -310,15 +310,15 @@ jobs:
const pkgPath = path.join('packages', dir, 'package.json');
if (!fs.existsSync(pkgPath)) continue;
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
// Allow x.y.z-preview (CONTRIBUTING.md canonical dev suffix); block all other prerelease tags
if (pkg.version && /-/.test(pkg.version) && !/^\d+\.\d+\.\d+-preview$/.test(pkg.version)) {
// Allow x.y.z, x.y.z-preview, x.y.z-preview.N, x.y.z-insider.N; block all other prerelease tags
if (pkg.version && !/^\d+\.\d+\.\d+(-(preview|insider)(\.\d+)?)?$/.test(pkg.version)) {
violations.push({ name: pkg.name, version: pkg.version, path: pkgPath });
}
}
if (violations.length > 0) {
console.error('::error::UNSANCTIONED PRERELEASE VERSION DETECTED — cannot merge to dev/main.');
violations.forEach(v => console.error(' ' + v.name + '@' + v.version + ' (' + v.path + ')'));
console.error('Fix: use x.y.z-preview (CONTRIBUTING.md) or a clean semver. Skip: add \"skip-version-check\" label.');
console.error('Fix: use X.Y.Z, X.Y.Z-preview, X.Y.Z-preview.N, or X.Y.Z-insider.N. Skip: add \"skip-version-check\" label.');
process.exit(1);
}
console.log('✅ All package versions are release versions');
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ docs/tests/screenshots/
/images/
# Squad: ignore runtime state (logs, inbox, sessions)
.squad/.scratch/

# Squad: PR-1200 picard local artifacts (do not commit)
.pr-body-new.md
.followup-issue-body.md
4 changes: 2 additions & 2 deletions .squad-templates/after-agent-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ prompt: |
2. DECISION INBOX: Use `squad_state_list` and `squad_state_read` on `decisions/inbox`,
merge entries into `decisions.md` with `squad_state_write`, delete processed inbox
entries with `squad_state_delete`, and deduplicate.
3. ORCHESTRATION LOG: Write `orchestration-log/{timestamp}-{agent}.md` with `squad_state_write` per agent. Use ISO 8601 UTC timestamp.
4. SESSION LOG: Write `log/{timestamp}-{topic}.md` with `squad_state_write`. Brief. Use ISO 8601 UTC timestamp.
3. ORCHESTRATION LOG: Write `orchestration-log/{timestamp}-{agent}.md` with `squad_state_write` per agent. Use ISO 8601 UTC timestamp. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms (e.g. `2026-06-02T21-15-30Z`).
4. SESSION LOG: Write `log/{timestamp}-{topic}.md` with `squad_state_write`. Brief. Use ISO 8601 UTC timestamp. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms.
5. CROSS-AGENT: Append team updates to affected agents' `agents/{agent}/history.md` with `squad_state_append`.
6. HISTORY SUMMARIZATION [HARD GATE]: If any history.md >= 15360 bytes (15KB), summarize now.
7. HEALTH REPORT: Log decisions.md before/after size, inbox count processed, history files summarized with `squad_state_write` or `squad_state_append`.
Expand Down
2 changes: 1 addition & 1 deletion .squad-templates/scribe-charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

After every substantial work session:

1. **Log the session** to `log/{timestamp}-{topic}.md` with `squad_state_write`:
1. **Log the session** to `log/{timestamp}-{topic}.md` with `squad_state_write` (replace `:` with `-` in `{timestamp}` so the filename is valid on all platforms, e.g. `2026-06-02T21-15-30Z`):
- Who worked
- What was done
- Decisions made
Expand Down
6 changes: 3 additions & 3 deletions .squad-templates/squad.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ The `union` merge driver keeps all lines from both sides, which is correct for a

**On every session start:** Run `git config user.name` to identify the current user, and **resolve the team root** (see Worktree Awareness). Store the team root — all `.squad/` paths must be resolved relative to it. Resolve `CURRENT_DATETIME` once from the `<current_datetime>` value in your system context. Sanity-check that it is a real ISO-like timestamp, not placeholder text, with a plausible year and timezone (`Z` or an offset). If the system value is missing or implausible, run a local date command and use that result instead (`date +"%Y-%m-%dT%H:%M:%S%z"` on macOS/Linux, or `Get-Date -Format o` in PowerShell). Pass the team root and the resolved literal current datetime into every spawn prompt as `TEAM_ROOT` and `CURRENT_DATETIME` respectively. Never pass placeholder text for `CURRENT_DATETIME`. Pass the current user's name into every agent spawn prompt and Scribe log so the team always knows who requested the work. Check `.squad/identity/now.md` if it exists — it tells you what the team was last focused on. Update it if the focus has shifted.

**Resolve state backend:** Read `.squad/config.json` (at the resolved TEAM_ROOT) and check the `stateBackend` field. Valid values: `"worktree"` (default), `"git-notes"`, `"orphan"`, `"two-layer"`. Store as `STATE_BACKEND` and pass it into every spawn prompt. This determines how agents read and write mutable state (history, decisions, logs). Static config (charters, team.md, routing.md) always lives on disk regardless of backend. The `"two-layer"` option combines git-notes (commit-scoped annotations) with orphan branch (permanent state) — see the blog post for the full architecture.
**Resolve state backend:** Read `.squad/config.json` (at the resolved TEAM_ROOT) and check the `stateBackend` field. Valid values: `"local"` (default), `"orphan"`, `"two-layer"`. Legacy alias: `"worktree"` maps to `"local"`. Deprecated: `"git-notes"` maps to `"two-layer"` with a deprecation warning. Store as `STATE_BACKEND` and pass it into every spawn prompt. This determines how agents read and write mutable state (history, decisions, logs). Static config (charters, team.md, routing.md) always lives on disk regardless of backend. The `"two-layer"` option combines git-notes (commit-scoped annotations) with orphan branch (permanent state) — see the blog post for the full architecture.

**⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing).

Expand Down Expand Up @@ -607,8 +607,8 @@ prompt: |
0b. PRE-CHECK: Read `decisions.md` and list `decisions/inbox` with state tools. Record measurements.
1. DECISIONS ARCHIVE [HARD GATE]: If decisions.md >= 20480 bytes, archive entries older than 30 days NOW. If >= 51200 bytes, archive entries older than 7 days. Do not skip this step.
2. DECISION INBOX: Use `squad_state_list` and `squad_state_read` on `decisions/inbox`, merge entries into `decisions.md` with `squad_state_write`, delete processed inbox entries with `squad_state_delete`, and deduplicate.
3. ORCHESTRATION LOG: Write `orchestration-log/{timestamp}-{agent}.md` with `squad_state_write` per agent. Use the literal CURRENT_DATETIME value.
4. SESSION LOG: Write `log/{timestamp}-{topic}.md` with `squad_state_write`. Brief. Use the literal CURRENT_DATETIME value.
3. ORCHESTRATION LOG: Write `orchestration-log/{timestamp}-{agent}.md` with `squad_state_write` per agent. Use the literal CURRENT_DATETIME value. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms (e.g. `2026-06-02T21-15-30Z`).
4. SESSION LOG: Write `log/{timestamp}-{topic}.md` with `squad_state_write`. Brief. Use the literal CURRENT_DATETIME value. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms.
5. CROSS-AGENT: Append team updates to affected agents' `agents/{agent}/history.md` with `squad_state_append`.
6. HISTORY SUMMARIZATION [HARD GATE]: If any history.md >= 15360 bytes (15KB), summarize now.
7. GIT COMMIT: Do not commit mutable squad state. If non-state repo files changed, report them for coordinator handling.
Expand Down
Loading
Loading