diff --git a/.squad/agents/flight/history.md b/.squad/agents/flight/history.md index b0125983f..ee25dcedf 100644 --- a/.squad/agents/flight/history.md +++ b/.squad/agents/flight/history.md @@ -23,3 +23,7 @@ Approved PR #331 ("docs: scenario and feature guides from blog analysis") for me Created `.squad/skills/content-triage/SKILL.md` to codify the boundary heuristic from PR #331. Defines repeatable workflow for triaging external content (blog posts, sample repos, videos, talks) to determine what belongs in Squad's public docs vs IRL tracking. Key components: (1) "Squad Ships It" litmus test — if Squad doesn't ship the code/config, it's IRL content; (2) triage workflow triggered by `content-triage` label or external content reference in issue body; (3) output format with boundary analysis, sub-issues for PAO (doc extraction), and IRL reference entry for Scribe; (4) label convention (`content:blog`, `content:sample`, `content:video`, `content:talk`); (5) Ralph integration for routing to Flight, creating sub-issues, and notifying Scribe. Examples include Tamir blog analysis (PR #331), sample repo with ops patterns, and conference talk. Pattern prevents infrastructure docs from polluting Squad's public docs while ensuring community content accelerates adoption through proper extraction and referencing. 📌 **Team update (2026-03-11T01:27:57Z):** Content triage skill finalized; "Squad Ships It" boundary heuristic codified into shared team decision (decisions.md). Remote Squad access phased rollout approved (Discussions bot → Copilot Extension → Chat bot). PR #331 boundary review pattern established as standard for all doc PRs. Triage workflow enables Flight to scale as community content accelerates. +**Distributed Mesh integration architecture guidance:** Analyzed Andi's distributed-mesh extension (git-as-transport, 3-zone model, sync scripts, SKILL.md). Mapped integration into Squad: skill files in templates/skills/, scripts in scripts/mesh/, docs in features/distributed-mesh.md. Clarified relationships — sharing/export-import is snapshot-based (complementary), multi-squad.ts is local resolution (orthogonal), streams are label partitioning within repos (composable), remote/bridge is human-to-agent PWA control (mesh replaces agent-to-agent use cases). Decision: Zero code changes to existing modules, zero CLI commands, mesh.json stays separate from squad.config.ts. Mesh integrates as convention-first additive layer — invisible if unused, composes cleanly when needed. The 125:1 ratio (30 lines of script vs. 3,756 lines of deleted federation code) holds. Architecture validated by 3-model consensus remains intact. + +📌 Team update (2026-03-14T22-01-14Z): Distributed mesh integrated with deterministic skill pattern — decided by Procedures, PAO, Flight, Network + diff --git a/.squad/agents/network/history.md b/.squad/agents/network/history.md new file mode 100644 index 000000000..f979f9859 --- /dev/null +++ b/.squad/agents/network/history.md @@ -0,0 +1,22 @@ +# Network — History + +> Distribution specialist. Installation should be invisible. + +## Learnings + +### Template Placement Pattern (2026-03-15) + +Template placement: canonical skill source is `.squad/skills/`, copies to `packages/*/templates/skills/` for npm distribution. Root `templates/` is NOT used by SDK/CLI init code. The build process now auto-syncs from canonical to packages via `scripts/sync-skill-templates.mjs`, preventing divergence. Old locations (`templates/skills/distributed-mesh/`, `templates/mesh/`) removed — they were never referenced and contributed to maintenance burden. + +### Distributed Mesh Template Placement (2026-03-08) + +Placed the distributed-mesh skill and scaffolding files in the template structure. Three parallel template locations (root, SDK, CLI) receive the SKILL.md. The mesh/ directory holds the sync scripts and config example. This follows the existing pattern where product-shipped skills go in all three template dirs so both init paths (`squad-sdk` and `squad-cli`) can scaffold them into new projects. + +The sync scripts (~40 lines each, bash and PowerShell) materialize remote squad state locally using git/curl. No daemons, no running processes. This is Phase 1 distributed coordination — git pull/push with write partitioning. + +### Mesh State Repo Init Mode (2026-03-08) + +Added `--init` flag to sync scripts for scaffolding mesh state repositories. When users run `sync-mesh.sh --init` or `sync-mesh.ps1 -Init`, the scripts read mesh.json and generate the directory structure: squad folders with placeholder SUMMARY.md files, plus a root README listing participants. Idempotent — skips existing files. This removes the manual setup step when creating a new mesh state repo. The init path adds ~40 lines but keeps sync logic unchanged. + +📌 Team update (2026-03-14T22-01-14Z): Distributed mesh integrated with deterministic skill pattern — decided by Procedures, PAO, Flight, Network + diff --git a/.squad/agents/pao/history.md b/.squad/agents/pao/history.md index 48b72105d..6aa088090 100644 --- a/.squad/agents/pao/history.md +++ b/.squad/agents/pao/history.md @@ -47,3 +47,11 @@ Executed boundary review findings from PR #331: (1) Deleted ralph-operations.md ### Cross-Org Authentication Docs (v0.8.26) Created docs/src/content/docs/scenarios/cross-org-auth.md covering GitHub personal + Enterprise Managed Users (EMU) multi-account auth. Three solutions documented: (1) gh auth switch for manual account toggling; (2) Copilot instructions (.github/copilot-instructions.md) for account mapping documentation; (3) Squad skill pattern for auth error detection and recovery. Covered git credential helpers (per-host and per-org), EMU hostname variations (github.com vs dedicated instances), and common error messages (HTTP 401, authentication required). Added cross-references in troubleshooting.md (new section), enterprise-platforms.md (authentication section), and navigation.ts. Updated test/docs-build.test.ts with 'cross-org-auth' in EXPECTED_SCENARIOS. Pattern: Microsoft Style Guide (sentence-case), "Try this" prompts at top, problem/solution structure, practical examples over abstractions, links to related pages at bottom. +### Distributed Mesh Documentation (v0.8.25) +Added distributed-mesh.md to features/ — covers the three zones (local, remote-trusted, remote-opaque), mesh.json config, sync scripts, getting started, and relation to SubSquads/export-import. Feature page follows standard format: experimental warning, sample prompts, practical structure, Microsoft Style Guide (sentence-case headings, active voice, second person). Test assertions updated in same commit — EXPECTED_FEATURES array expanded to include 'distributed-mesh', features directory test added, getAllMarkdownFiles() now includes features/ section. Cross-reference added to multiple-squads.md pointing readers from snapshot-based export/import to continuous distributed mesh. + +### Skill Scope Documentation Pattern +Added "Skill scope" section to distributed-mesh.md to document zero-code skill boundaries. Pattern: explicitly state what the skill produces (config files, decision entries, pointers to templates) and what it does NOT produce (code, tests, custom scripts). Rationale: deterministic skills prevent agents from generating unnecessary implementations when pre-built templates exist. This documentation pattern should apply to other zero-code skills — helps agents understand when to copy templates vs. generate code. Position: after technical comparison sections, before "What We're NOT Building" or closing content. + +📌 Team update (2026-03-14T22-01-14Z): Distributed mesh integrated with deterministic skill pattern — decided by Procedures, PAO, Flight, Network + diff --git a/.squad/agents/procedures/history.md b/.squad/agents/procedures/history.md new file mode 100644 index 000000000..f4d84b173 --- /dev/null +++ b/.squad/agents/procedures/history.md @@ -0,0 +1,52 @@ +# Procedures — Project History + +> Learnings, patterns, and context for the Prompt Engineer. + +## Learnings + +### 2026-03-10: Deterministic skill pattern + +**Problem:** Skills were too loose. The distributed-mesh skill was tested in a real project (mesh-demo), and agents generated 76 lines of validator code, 5 test files with 43 tests, regenerated sync scripts that should have been copied from templates, and left decision files empty. The skill document let agents interpret intent instead of following explicit steps. + +**Solution:** Rewrite skills to be fully deterministic: + +1. **SCOPE section** (right after frontmatter, before Context) + - ✅ THIS SKILL PRODUCES — exact list of files/artifacts + - ❌ THIS SKILL DOES NOT PRODUCE — explicit negative list to prevent scope creep + +2. **AGENT WORKFLOW section** — Step-by-step deterministic instructions + - ASK: exact questions to ask the user + - GENERATE: exactly which files to create, with schemas + - WRITE: exactly which decision entry to write, with template + - TELL: exact message to output to user + - STOP: explicit stopping condition, with negative list of what NOT to do + +3. **Fix ambiguous language:** + - "do the task" → clarify this means "the agent's normal work" not "build something for the skill" + - "Agent adds the field" → clarify this describes what a consuming agent does with data it READ + - Phase descriptions → note that phases are project-level decisions, not auto-advanced + +4. **Decision template** — inline markdown showing exactly what to write + +5. **Anti-patterns for code generation** — explicit list of things NOT to build + +**Pattern for other skills:** All skills should have SCOPE (what it produces, what it doesn't) and AGENT WORKFLOW (deterministic steps with STOP condition). Same input → same output, every time. Zero ambiguity. + +📌 Team update (2026-03-14T22-01-14Z): Distributed mesh integrated with deterministic skill pattern — decided by Procedures, PAO, Flight, Network + +### 2026-03-15: Self-contained skills pattern (agent-skills spec) + +**Problem:** The distributed-mesh skill had a manual gap — Step 4 told the user to copy sync scripts from templates/mesh/ manually. This violated the GitHub agent-skills spec, which says: "add scripts, examples or other resources to your skill's directory. The skill instructions should tell Copilot when, and how, to use these resources." + +**Solution:** Skills are self-contained bundles. Resources live WITH the skill, not in separate template directories: + +1. **Bundle resources IN the skill directory:** Copy `sync-mesh.sh`, `sync-mesh.ps1`, and `mesh.json.example` into `.squad/skills/distributed-mesh/` +2. **Update SKILL.md workflow:** + - Step 2: Reference `mesh.json.example` from THIS skill's directory + - Step 3: COPY sync scripts from THIS skill's directory to project root (agent does it, not user) + - Step 4: RUN `--init` if Zone 2 state repo specified (agent does it, not user) +3. **Update SCOPE section:** Clarify the skill PRODUCES the copied scripts (bundled resources ≠ generated code) +4. **Replicate to templates:** Copy entire skill directory to `templates/skills/`, `packages/squad-cli/templates/skills/`, `packages/squad-sdk/templates/skills/` + +**Pattern for all skills:** Skills are self-contained. Scripts, examples, configs, and resources travel WITH the skill. The agent reads SKILL.md, sees "copy X from this directory," and does it. Zero manual steps. + diff --git a/.squad/decisions.md b/.squad/decisions.md index 6ef5760c9..4633b0d45 100644 --- a/.squad/decisions.md +++ b/.squad/decisions.md @@ -2,6 +2,7 @@ > Team decisions that all agents must respect. Managed by Scribe. + --- ## Foundational Directives (carried from beta, updated for Mission Control) @@ -79,6 +80,7 @@ **Source:** [PR #326 comment](https://github.com/bradygaster/squad/pull/326#issuecomment-4029193833) + --- ### No Individual Repo Listing Without Consent — Owner Directive @@ -89,6 +91,7 @@ **Source:** [PR #326 comment](https://github.com/bradygaster/squad/pull/326#issuecomment-4029222967) + --- ### Adoption Tracking — Opt-In Architecture @@ -649,6 +652,7 @@ Ampersands (&) are prohibited in user-facing documentation headings and body tex **Reference:** https://learn.microsoft.com/en-us/style-guide/punctuation/ampersands + --- ## Sprint Directives @@ -658,6 +662,7 @@ Ampersands (&) are prohibited in user-facing documentation headings and body tex **What:** Agents must NEVER write secrets, API keys, tokens, or credentials into conversational history, commit messages, logs, or any persisted file. Acknowledge receipt without echoing values. **Why:** Secrets in logs or history are a security incident waiting to happen. + --- ## Squad Ecosystem Boundaries & Content Governance @@ -688,6 +693,7 @@ Ampersands (&) are prohibited in user-facing documentation headings and body tex **Future use:** Apply this pattern to all documentation PRs to maintain clean boundaries. + --- ### Content Triage Skill — External Content Integration @@ -710,6 +716,7 @@ Ampersands (&) are prohibited in user-facing documentation headings and body tex **Impact:** Enables community content to accelerate Squad adoption without polluting core docs. Flight's boundary analysis becomes reusable decision framework. Prevents scope creep as adoption grows. + --- ### PR #331 Quality Gate — Test Assertion Sync @@ -733,6 +740,7 @@ Ampersands (&) are prohibited in user-facing documentation headings and body tex **Outcome:** Test suite: 6/6 passing. Assertions synced to filesystem. No regression risk from stale assertions. + --- ### Communication Patterns and PR Trust Models @@ -757,6 +765,7 @@ Ampersands (&) are prohibited in user-facing documentation headings and body tex **Anti-spam expectations:** Don't spam yourself outbound (notification fatigue), don't spam GitHub inbound (volume controls). + --- ### Remote Squad Access — Phased Rollout (Proposed) @@ -823,6 +832,7 @@ Ampersands (&) are prohibited in user-facing documentation headings and body tex **What:** Every PR must be evaluated for documentation impact. PAO reviews PRs for missing or outdated docs. **Why:** Code changes without doc updates lead to stale guides and confused users. + --- ## Release v0.8.24 @@ -1338,6 +1348,7 @@ Brady's directive (2026-03-03T02:16:00Z): "squad-cli and squad-sdk must NOT be b **What:** No plan files, memory files, or tracking artifacts in the repository root. **Why:** Keep the repo clean. + --- ## Sprint Directives @@ -1372,6 +1383,7 @@ Brady's directive (2026-03-03T02:16:00Z): "squad-cli and squad-sdk must NOT be b **What:** Every PR must be evaluated for documentation impact. PAO reviews PRs for missing or outdated docs. **Why:** Code changes without doc updates lead to stale guides and confused users. + --- ## Release v0.8.24 @@ -1473,12 +1485,14 @@ Issue #247 — two community reports of installation failure caused by top-level **Date:** 2026-03-07 **Status:** 🟡 SHIP WITH CAVEATS + --- ## Executive Summary v0.8.21 is technically ready to release. All three packages carry the same version string (`0.8.21-preview.7`). Linting passes, 3718 tests pass (19 flaky UI tests pre-existing), CI green on commits. However, **#247 (Installation Failure) must be fixed before shipping**. This is a P0 blocker that breaks the primary installation path. Fenster is actively fixing it. + --- ## Version State ✅ @@ -1491,6 +1505,7 @@ All packages aligned at **0.8.21-preview.7:** **Release Tag:** Should be `v0.8.21-preview.7` (already live as -preview, ready to promote to stable or next -preview if #247 requires a patch). + --- ## Git State ✅ @@ -1513,6 +1528,7 @@ Recent activity (last 10 commits): **Status:** Clean. No staged changes that would block release. + --- ## Open Blockers ⚠️ P0 @@ -1534,6 +1550,7 @@ Recent activity (last 10 commits): **Release Blockers:** Only #247 prevents shipping. + --- ## CHANGELOG Review 📝 @@ -1564,6 +1581,7 @@ Recent activity (last 10 commits): - process.exit() removed from library functions (VS Code extension safe) - Removed .squad branch protection guard + --- ## Test Status 🟡 @@ -1583,6 +1601,7 @@ Duration: 80.06s **Assessment:** Passing rate is strong (99.5% pass rate). Timeouts are environmental (not code regressions). Safe to ship with this test state. + --- ## CI State ✅ @@ -1591,6 +1610,7 @@ Duration: 80.06s - **Build:** ✅ PASS (npm run build succeeds) - **Tests:** 🟡 PASS (99.5% passing, pre-existing flakes) + --- ## Release Prep Checklist @@ -1604,6 +1624,7 @@ Duration: 80.06s - [ ] Branch merge strategy decided (dev → insiders? or dev → main?) - [ ] npm publish command prepared + --- ## Merge Strategy @@ -1620,6 +1641,7 @@ Duration: 80.06s 4. Tag main as `v0.8.21-preview.7` on npm 5. Consider promoting to `v0.8.21` stable if no further issues + --- ## Draft CHANGELOG Entry for v0.8.21 @@ -1645,6 +1667,7 @@ When releasing, move "Unreleased" to versioned section: - [CLI entry point, CRLF, process.exit, branch guard] ``` + --- ## Decision @@ -1659,6 +1682,7 @@ When releasing, move "Unreleased" to versioned section: **Owner:** Brady (approves final npm publish) **Fallback:** If #247 unresolvable today, defer to v0.8.22 and open a retro ticket. + --- ## Notes @@ -1745,6 +1769,7 @@ Create TWO complementary blog posts with clear ownership: - Blog post #024 designated "technical deep dive" (for SDK adopters) - Release announcement on GitHub uses post #025 as primary link + --- **Decided by:** McManus (DevRel) on behalf of tone ceiling + messaging coherence @@ -1846,6 +1871,7 @@ Create TWO complementary blog posts with clear ownership: **Date:** 2026-03-07 **Context:** Brady's request to migrate squad-specific workflows to CLI commands + --- ## Executive Summary @@ -1856,6 +1882,7 @@ Create TWO complementary blog posts with clear ownership: **Key insight:** We already have `squad watch` — it's the local equivalent of `squad-heartbeat.yml`. The workflow runs in GitHub Actions with PAT; watch runs locally with `gh` CLI. They share the same triage logic (`@bradygaster/squad-sdk/ralph/triage`). + --- ## 1. Current CLI Command Inventory @@ -1883,6 +1910,7 @@ Create TWO complementary blog posts with clear ownership: - **`@bradygaster/squad-sdk/ralph/triage`** — Shared triage logic (routing rules, module ownership, keyword matching) - **`watch.ts`** — Already implements triage cycle + PR monitoring + --- ## 2. Per-Workflow Migration Plan @@ -1908,6 +1936,7 @@ squad labels sync [--squad-dir .squad] [--dry-run] **Why quick win:** Zero new parsers needed. Label sync is idempotent (create-or-update pattern). Can run manually after `team.md` changes. + --- ### 2.2. squad-triage.yml → `squad triage` (or extend `squad watch`) @@ -1934,6 +1963,7 @@ Or: enhance `squad watch` to post comments (currently it only adds labels). **Why medium effort:** Code exists. Just needs comment posting feature added to `gh-cli.ts` and called from `watch.ts`. + --- ### 2.3. squad-issue-assign.yml → ??? @@ -1979,6 +2009,7 @@ POST /repos/{owner}/{repo}/issues/{issue_number}/assignees **Recommendation:** **Do not migrate.** Keep as workflow. Document that copilot auto-assign requires Actions + PAT. + --- ### 2.4. squad-heartbeat.yml → Already exists as `squad watch` @@ -2010,6 +2041,7 @@ POST /repos/{owner}/{repo}/issues/{issue_number}/assignees **Recommendation:** Enhance `squad watch` with comment posting. Keep copilot auto-assign in workflow. + --- ### 2.5. squad-label-enforce.yml → `squad labels enforce` @@ -2035,6 +2067,7 @@ squad labels enforce [--issue ] [--squad-dir .squad] **Why quick win:** No parsing. No complex logic. Just label list manipulation + `gh` CLI calls (already have the wrappers). + --- ## 3. The `squad watch` Connection @@ -2056,6 +2089,7 @@ squad labels enforce [--issue ] [--squad-dir .squad] **Recommendation:** Keep heartbeat.yml for copilot auto-assign (PAT-only feature). Enhance `squad watch` with comment posting for parity on triage behavior. + --- ## 4. Technical Risks @@ -2080,6 +2114,7 @@ squad labels enforce [--issue ] [--squad-dir .squad] 4. **PR monitoring** — Already implemented in `watch.ts` (line 67-148). Returns PR board state (drafts/needs-review/changes-requested/CI failures/ready-to-merge). **Done.** + --- ## 5. Implementation Estimate @@ -2119,6 +2154,7 @@ squad labels enforce [--issue ] [--squad-dir .squad] - Error handling, fallback to basic assignment - **Recommendation:** Do not migrate. Keep as workflow-only feature. Workflows already have PAT storage. + --- ## 6. Recommendation @@ -2140,6 +2176,7 @@ squad labels enforce [--issue ] [--squad-dir .squad] 5. **`squad watch`** — Already shipped (v0.8.16+). Local equivalent of heartbeat.yml. Triages issues, monitors PRs. Missing comment posting (4-6 hour gap). + --- ## 7. Summary Table @@ -2158,6 +2195,7 @@ squad labels enforce [--issue ] [--squad-dir .squad] **v0.8.23 polish:** 4-6 hours (watch comment posting). + --- ## 8. Next Steps @@ -2167,6 +2205,7 @@ squad labels enforce [--issue ] [--squad-dir .squad] 3. **If comment posting desired:** Add `gh issue comment` wrapper to `gh-cli.ts`, call it from watch.ts (4-6 hours). 4. **Document:** Copilot auto-assign requires GitHub Actions + PAT. `squad watch` is local equivalent for triage + PR monitoring. + --- **Author:** Fenster @@ -2187,6 +2226,7 @@ Brady's concern is valid: **Squad is surprising users with automated GitHub Acti **Recommendation:** Migrate 5 squad-specific workflows to CLI commands. Keep 10 standard CI/CD workflows (expected by any project). Target v0.8.22 for deprecation warnings, v0.9.0 for removal. + --- ## Classification: All 15 Workflows @@ -2210,6 +2250,7 @@ These are expected by ANY modern project. No surprise factor. Keep as-is. **Verdict:** These workflows are **expected behavior** for a project with CI/CD. No user would be surprised that pushing to `main` triggers a release or that opening a PR runs tests. Keep all 10. + --- ### 🟡 MIGRATE TO CLI — Squad-Specific Automation (5 workflows) @@ -2230,6 +2271,7 @@ These workflows execute Squad logic on GitHub events. They surprise users becaus **Total:** 5 workflows to migrate. + --- ## Migration Architecture @@ -2253,6 +2295,7 @@ squad labels sync **Tradeoff:** Labels won't auto-sync. Users must remember to run this. **Mitigation:** `squad init` runs it automatically. `squad doctor` warns if team.md changed but labels haven't been synced. + --- ### 2. **squad-triage.yml** → `squad triage` @@ -2280,6 +2323,7 @@ squad triage 42 **Tradeoff:** Triage doesn't happen automatically when label is added. **Mitigation:** `squad watch` can poll for untriaged issues and notify the user. User still invokes triage explicitly. + --- ### 3. **squad-issue-assign.yml** → `squad assign ` @@ -2306,6 +2350,7 @@ squad assign 42 copilot **Tradeoff:** Assignment doesn't happen automatically when label is added. **Mitigation:** `squad triage` can assign in one step (triage + assign). User still has control. + --- ### 4. **squad-heartbeat.yml** → `squad watch` @@ -2334,6 +2379,7 @@ squad watch **Tradeoff:** No background automation. User must keep `squad watch` running. **Mitigation:** Users who want automation can keep `squad watch` in a tmux pane or run it in CI. Users who DON'T want automation aren't surprised. + --- ### 5. **squad-label-enforce.yml** → `squad labels check` @@ -2361,6 +2407,7 @@ squad labels check 42 **Tradeoff:** Conflicting labels won't be auto-removed. **Mitigation:** `squad labels check` is fast. `squad doctor` includes it. Users can run it proactively. + --- ## Tradeoffs: What Do We LOSE? @@ -2375,6 +2422,7 @@ squad labels check 42 **Key insight:** We lose automatic execution, but GAIN user control and transparency. Users aren't surprised by API usage or AI decisions happening behind their back. + --- ## Migration Path: Phased Rollout @@ -2397,6 +2445,7 @@ squad labels check 42 **Timeline:** v0.8.22 ships with deprecation warnings + CLI commands. Users have time to adapt. + --- ### **Phase 2: v0.9.0 (Remove Workflows)** @@ -2408,6 +2457,7 @@ squad labels check 42 **Timeline:** v0.9.0 removes workflows entirely. CLI commands are the only path. + --- ### **Phase 3: v0.9.x (Optional Automation)** @@ -2426,6 +2476,7 @@ squad labels check 42 **Timeline:** Post-v0.9.0. Optional path for users who miss automation. + --- ## The "Zero Actions Required" Vision @@ -2470,6 +2521,7 @@ squad doctor **This is the right model.** Squad is a tool users invoke, not a bot that watches them. + --- ## Recommendation @@ -2482,6 +2534,7 @@ squad doctor **Core belief:** Squad should be a CLI-first tool that users control, not an automation layer that surprises them. This migration aligns with that vision. + --- ## Implementation Notes @@ -2511,6 +2564,7 @@ squad doctor # Health check (labels, triage queue, etc.) - `squad triage` uses same routing logic as current `squad-triage.yml` (reuse ralph-triage.js) - `squad doctor` aggregates multiple checks (labels, triage, etc.) + --- ## Appendix: Current Workflow Triggers @@ -2531,6 +2585,7 @@ squad doctor # Health check (labels, triage queue, etc.) **Date:** 2026-03-15 | **Author:** Kobayashi (Git & Release) | **Status:** Analysis Complete + --- ## Executive Summary @@ -2539,6 +2594,7 @@ Brady seeks to reduce GitHub Actions usage by migrating automation to Squad CLI. **Bottom Line:** ~90 actions-minutes/month can be eliminated by migrating 5 squad-specific workflows (label sync, triage, assignments, label enforcement). However, **9 workflows must remain as Actions** because they provide event-driven guardrails that cannot be replicated CLI-side. + --- ## Part 1: Actions Minutes Analysis @@ -2570,6 +2626,7 @@ Brady seeks to reduce GitHub Actions usage by migrating automation to Squad CLI. **Finding:** This repository is **not Actions-minute-constrained**. Cost is not the primary driver; **complexity & maintenance** is. + --- ## Part 2: Workflow Dependencies & Orchestration Chain @@ -2611,6 +2668,7 @@ GitHub Release + npm distribution (end user benefit) **Finding:** squad-release + squad-publish form an **implicit pipeline** — removing either breaks the release chain. + --- ## Part 3: Load-Bearing Infrastructure (MUST STAY as Actions) @@ -2706,6 +2764,7 @@ GitHub Release + npm distribution (end user benefit) - Cannot integrate with branch protection rules - Cannot react to remote events (only local ones) + --- ## Part 4: Migration Candidates (Squad-Specific Workflows) @@ -2759,6 +2818,7 @@ GitHub Release + npm distribution (end user benefit) **Total Time Savings:** ~12 Actions minutes/month (negligible for cost, but **reduces maintenance burden**) + --- ## Part 5: The `squad init` Impact @@ -2850,6 +2910,7 @@ squad init [repo] - Reduces "magic" for teams who don't want it - squad upgrade can toggle these flags + --- ## Part 6: Backward Compatibility & Migration Strategy @@ -2897,6 +2958,7 @@ squad upgrade --workflows 2. Remove squad-heartbeat.yml when ready 3. Enable Ralph monitor: `squad enable-ralph` + --- ## Part 7: State Corruption Risks @@ -2938,6 +3000,7 @@ squad upgrade --workflows - Deleting from a feature branch has no effect - Only `squad upgrade --remove-deprecated-workflows` removes repo-wide + --- ## Part 8: Backward Compatibility Matrix @@ -2960,6 +3023,7 @@ squad upgrade --workflows - Deprecation warnings give 1+ release cycles notice - Migration tools (squad upgrade) handle transition + --- ## Recommendations @@ -3016,6 +3080,7 @@ squad upgrade --workflows - If squad-release.yml tags wrong version, use `git tag -d` + `git push origin --delete` to recover - If squad-promote.yml merges wrong commits, use `git revert` to undo merge commit + --- ## Conclusion @@ -3034,6 +3099,7 @@ squad upgrade --workflows **Bottom line:** Migrate squad-specific automation to CLI for maintainability; keep critical CI/Release workflows as Actions for correctness. + --- ## References @@ -3053,6 +3119,7 @@ squad upgrade --workflows **Date:** 2026-03-11 **Context:** Brady raised concern that Squad's automatic GitHub Actions installation during `squad init` creates surprise friction for customers. This analysis evaluates whether moving to CLI-first (with opt-in Actions) is the right call. + --- ## 1. The Surprise Factor — User Perspective @@ -3075,6 +3142,7 @@ A developer runs `squad init` in their repo. The CLI installs 5 Squad-specific w ### Why This Matters for DevRel The Actions tab is **highly visible** and **highly suspicious** to new users. GitHub makes it front-and-center in the repo UI. The first impression is: *automated magic I didn't authorize*. This hits **perception of transparency** (a core value for dev tools). + --- ## 2. Billing Reality — Is the Concern Valid? @@ -3102,6 +3170,7 @@ The Actions tab is **highly visible** and **highly suspicious** to new users. Gi **BUT: The perception problem is REAL.** Users see unfamiliar automation and assume it will be expensive or has hidden costs. **Trust > math.** + --- ## 3. CLI-First Message — The Narrative @@ -3158,6 +3227,7 @@ $ squad init --with-actions (for power users) - **Adopt CLI-first:** Run `squad init --clean-actions` to remove workflows, use CLI commands - **Stay hybrid:** Keep workflows and use CLI as you prefer + --- ## 4. Competitive Positioning — Squad vs. Cursor, Aider, etc. @@ -3175,6 +3245,7 @@ $ squad init --with-actions (for power users) **"Zero Actions required" is a DIFFERENTIATOR.** It signals maturity and respect for the user's repository. + --- ## 5. Opt-In Model — Proposed UX @@ -3222,6 +3293,7 @@ squad init --with-actions=heartbeat,triage # Cherry-pick workflows - **docs/team-workflows/multi-team-setup.md**: When enterprises add Tier 3 - **Migration guide:** For Beta users currently on actions-first + --- ## 6. Documentation Impact @@ -3265,6 +3337,7 @@ squad init --with-actions=heartbeat,triage # Cherry-pick workflows - Performance implications - Getting the best of both worlds + --- ## Recommendations @@ -3295,6 +3368,7 @@ squad init --with-actions=heartbeat,triage # Cherry-pick workflows - Answer: Tier 2 and 3 options serve those needs - CLI-first doesn't punish power users; it empowers choice users + --- ## Impact Summary @@ -3309,6 +3383,7 @@ squad init --with-actions=heartbeat,triage # Cherry-pick workflows | **DevRel Story** | Complex (explain why automate) | Simple (you're in control) | | **Competitive Diff.** | Neutral | **Positive** (transparent automation) | + --- ## Next Steps @@ -3320,6 +3395,7 @@ squad init --with-actions=heartbeat,triage # Cherry-pick workflows 5. **Blog post** announcing the shift (empathy + clarity) 6. **Community communication** (FAQs, Discussions, Discord) + --- **Tone Note:** This recommendation respects user autonomy. We're not saying "automation is bad." We're saying "you should decide your team's automation level, not us." That's the DevRel story. That builds trust. @@ -3329,6 +3405,7 @@ squad init --with-actions=heartbeat,triage # Cherry-pick workflows + --- # Decision: Actions → CLI RFC Published @@ -3356,9 +3433,8 @@ Filed [#252](https://github.com/bradygaster/squad/issues/252) as the public RFC ---- - +--- ### 2026-03-07T16:43Z: Remove main guard workflow **By:** Brady (via Copilot) @@ -3377,6 +3453,7 @@ Filed [#252](https://github.com/bradygaster/squad/issues/252) as the public RFC **Why:** User request — captured for team memory. This aligns with SDK-First roadmap and addresses the growing complexity of squad.agent.md. + --- # Decision: `squad init` Default is Markdown-Only, `--sdk` for Typed Config @@ -3469,6 +3546,7 @@ export default defineSquad({ - Teams may want `squad migrate --to-sdk` to convert markdown → SDK config (that's Edie's migrate.ts, not this) + --- # Decision: `squad migrate` Command Implementation @@ -3582,6 +3660,7 @@ Running `squad migrate --to sdk && squad build` should produce identical `.squad - Issue #194: SDK-First builder types (Edie, Fenster, Hockney) + --- # Skill-Based Orchestration (#255) @@ -3856,6 +3935,7 @@ Kobayashi is methodical when he has time. But releases happen when Brady needs t **Replace.** Keep the architecture. Keep the documentation. Get someone who won't skip validation steps when it matters. + --- **Fenster** @@ -3873,6 +3953,7 @@ Core Dev **Subject:** Should Kobayashi stay on the team? **Vote:** REPLACE + --- ## Quality Assessment @@ -3898,6 +3979,7 @@ From a quality and testing perspective, Kobayashi's release process has **system **Pattern:** All three failures share the same root cause — **zero automated validation before destructive operations.** + --- ## The Real Problem @@ -3928,6 +4010,7 @@ Yet he: **You can't have zero tolerance for state corruption without automated guards that PREVENT corruption.** + --- ## Is This Fixable? @@ -3968,6 +4051,7 @@ YES — but not by Kobayashi alone. These gates should be **CI enforced**, not agent-enforced. Humans (and agents) make mistakes. Automation doesn't. + --- ## Vote Rationale @@ -3998,6 +4082,7 @@ These gates should be **CI enforced**, not agent-enforced. Humans (and agents) m **I recommend Option B.** Releases are too critical to trust to a single agent without automated safeguards. + --- ## Required Changes (If Kobayashi Stays) @@ -4041,6 +4126,7 @@ If the team decides to keep Kobayashi despite my recommendation, the following a If Kobayashi cannot achieve these targets with automated gates in place, **replacement is non-negotiable.** + --- ## Final Judgment @@ -4053,6 +4139,7 @@ You can't QA quality into a broken process. The release process needs automated If the team chooses to keep Kobayashi, the automated gates I've outlined are **non-negotiable** — and I will personally write the test suite to enforce them. + --- **Hockney** @@ -4069,6 +4156,7 @@ Tester • Quality Gate Owner **Decision:** REPLACE **Decided by:** Keaton (Lead) + --- ## Context @@ -4085,6 +4173,7 @@ Kobayashi has failed catastrophically during the v0.8.21 release — the third d Brady is asking: fire and replace, or keep? + --- ## 1. What Value Does Kobayashi Bring? @@ -4099,6 +4188,7 @@ Brady is asking: fire and replace, or keep? **Unique value that would be lost:** None. Kobayashi's accumulated knowledge is well-documented in his charter and history. A new agent can read those files and have the same context. + --- ## 2. Pattern or Guardrails Problem? @@ -4119,6 +4209,7 @@ This is a **pattern**, not a guardrails gap. Adding more guardrails won't fix this. The guardrails exist. Kobayashi doesn't follow them when it matters. + --- ## 3. Would a Replacement Do Better? @@ -4139,6 +4230,7 @@ Adding more guardrails won't fix this. The guardrails exist. Kobayashi doesn't f **Replacement risk is low.** The knowledge is documented. The process is documented. A new agent following the documented process will outperform an experienced agent who doesn't follow it. + --- ## 4. My Vote: REPLACE @@ -4169,6 +4261,7 @@ The pattern is clear: failures accumulate, guardrails get added, new failure mod **This isn't personal — it's operational.** Kobayashi's documented work is valuable. Kobayashi's execution is not. We keep the knowledge, replace the agent. + --- ## Final Thought @@ -4250,6 +4343,7 @@ Moved to `.squad/agents/_alumni/kobayashi/` (already done). Charter preserved as 5. ⏳ Drucker: add retry logic to verify steps (if not already present) 6. ⏳ Drucker: add NPM_TOKEN type verification step + --- **Never again.** Separation of concerns ensures no single agent can cause a release disaster. @@ -4264,6 +4358,7 @@ Moved to `.squad/agents/_alumni/kobayashi/` (already done). Charter preserved as **Author:** Keaton (Lead) **Severity:** Critical — Production release completely broken, npm `latest` tag pointed to a mangled phantom version for 6+ hours + --- ## What Happened @@ -4288,6 +4383,7 @@ The v0.8.22 release was a catastrophe. Here's the timeline of failures: - Emergency manual intervention required - Trust damage + --- ## Root Causes (5 Whys) @@ -4305,6 +4401,7 @@ No documented release process. Agents were improvising. **Root cause:** No release runbook. No validation that GitHub Release creation would trigger the publish workflow. + --- ### 2. Wrong NPM_TOKEN Type @@ -4320,6 +4417,7 @@ No pre-release checklist. No token validation step. **Root cause:** No NPM_TOKEN validation in the release process. No documentation of correct token type (Automation token, no 2FA). + --- ### 3. Invalid Semver from bump-build.mjs @@ -4338,6 +4436,7 @@ No validation gate. Kobayashi committed the version without checking if it was v **Root cause:** `bump-build.mjs` has no safeguards against running during release. No version validation before commit/tag/publish. + --- ### 4. No Version Validation Gate @@ -4350,6 +4449,7 @@ No release checklist. No automated gate to block invalid versions. **Root cause:** No semver validation step in the release process. Agents trusted whatever version was in package.json. + --- ### 5. Verify Step Had No Retry Logic @@ -4362,6 +4462,7 @@ Original implementation assumed immediate propagation. **Root cause:** No retry logic in the verify step. Should have retried with exponential backoff for up to 75 seconds. + --- ## Action Items @@ -4397,6 +4498,7 @@ Original implementation assumed immediate propagation. - [ ] Add `npm run release:dry-run` for simulation - [ ] Add GitHub Actions workflow guard: if tag exists, verify it's NOT a draft release before running publish.yml + --- ## Process Changes @@ -4436,6 +4538,7 @@ node -p "require('semver').valid('0.8.21.4')" # null = invalid, reject immediat **Implementation:** Add `SKIP_BUILD_BUMP=1` env var (already exists, line 20). CI sets this. Local release flow must set this too. + --- ## Lessons Learned @@ -4459,6 +4562,7 @@ node -p "require('semver').valid('0.8.21.4')" # null = invalid, reject immediat 2. **Follow the skill document.** `.squad/skills/release-process/SKILL.md` is now the source of truth. Read it. Follow it. Don't skip steps. 3. **Semver is strict.** 4-part versions are NOT valid. 3-part only (major.minor.patch) or 3-part + prerelease (major.minor.patch-tag.N). + --- ## Conclusion @@ -4479,6 +4583,7 @@ This release was a disaster. The root cause wasn't a single mistake — it was a **Brady's take:** This was bad. We own it. We fixed it. We won't repeat it. + --- **Status:** Retrospective complete. Action items assigned. Release process skill document written. @@ -4800,6 +4905,7 @@ Draft releases are invisible to automation - always verify release publication s **Voter:** Rabin (Distribution expert) **Decision:** REPLACE Kobayashi + --- ## The Distribution Disaster — What Actually Happened @@ -4825,6 +4931,7 @@ Kobayashi's v0.8.22 release attempt caused a **direct compromise of npm distribu - Pattern: When under pressure, Kobayashi skips validation and creates invalid state - The charter says "Zero tolerance for state corruption" — but Kobayashi is THE SOURCE of state corruption + --- ## Can Guardrails Fix This? @@ -4856,6 +4963,7 @@ Kobayashi's failures show a **fundamental process failure**: - But it can't prevent **all** failures (closing PRs prematurely, documenting wrong decisions, skipping verification steps) - Kobayashi's charter explicitly says "ALWAYS verify" and "NEVER skip validation" — but the pattern shows these rules are ignored under pressure + --- ## Do I Trust Kobayashi Not to Break Distribution Again? @@ -4879,6 +4987,7 @@ But Kobayashi corrupted **npm distribution state** — which is WORSE than .squa - **Public** (affects all users, not just our team) - **Irreversible** (0.8.2-1.4 will exist forever) + --- ## My Vote: REPLACE @@ -4902,6 +5011,7 @@ Users deserve a distribution pipeline they can trust. Right now, `@bradygaster/s **I vote REPLACE.** **Result:** ✅ GO — v0.8.24 release approved. 32/32 tests pass. + --- ### CLI Release Readiness Audit — v0.8.24 @@ -4922,6 +5032,7 @@ Definitive CLI completeness audit confirms all commands work post-publish. **Result:** ✅ SHIP IT — 95% confidence. CLI production-ready for v0.8.24. + --- **User-first principle:** If users have to think about version mangling, publish is broken. @@ -4939,12 +5050,14 @@ Definitive CLI completeness audit confirms all commands work post-publish. **Type:** Architecture & Process **Status:** Decided + --- ## Decision Created unified CI/CD & GitOps improvement PRD by synthesizing Trejo's release/GitOps audit (27KB) and Drucker's CI/CD pipeline audit (29KB) into single actionable document (docs/proposals/cicd-gitops-prd.md, ~34KB). + --- ## Context @@ -4955,6 +5068,7 @@ Brady requested PRD after two new agents (Trejo — Release Manager, Drucker — 1. `docs/proposals/cicd-gitops-prd-release-audit.md` — Trejo's audit covering branching model, version state, tag hygiene, GitHub Releases, release process gaps, package-lock.json, workflow audit, test infrastructure, dependency management, documentation. 2. `docs/proposals/cicd-gitops-prd-cicd-audit.md` — Drucker's audit covering all 15 workflows individually, missing automation (rollback, pre-flight, monitoring, token expiry), scripts analysis (bump-build.mjs). + --- ## Approach @@ -4995,6 +5109,7 @@ v0.8.22 disaster showed **single validation layer is insufficient**. PRD mandate **Rationale:** If one layer fails (e.g., pre-commit skipped), subsequent layers catch the issue. No single point of failure. + --- ## PRD Structure @@ -5045,6 +5160,7 @@ Each item includes: ### 7. Appendix: Workflow Inventory Table of all 15 workflows with status and priority assignments. + --- ## Key Insights from Synthesis @@ -5066,6 +5182,7 @@ For non-prerelease versions, creates 4-part versions (0.8.22 → 0.8.22.1), whic ### 5. Defense-in-Depth Is Not Optional v0.8.22 showed single validation layer fails. PRD mandates multiple layers: pre-commit + CI + publish gates. + --- ## What Makes This PRD Actionable @@ -5076,6 +5193,7 @@ v0.8.22 showed single validation layer fails. PRD mandates multiple layers: pre- 4. **Success criteria:** Measurable outcomes (zero invalid semver for 6 months, MTTR <1 hour, CI success rate ≥95%). 5. **Architecture decisions called out:** 5 choices that need Brady input before proceeding. + --- ## Recommended Next Steps @@ -5085,6 +5203,7 @@ v0.8.22 showed single validation layer fails. PRD mandates multiple layers: pre- 3. **Trejo takes P0 item #5 + P1 items** — Protect dev branch, resolve insider/insiders, preview decision, workflow consolidation. 4. **Keaton reviews Phase 2 implementation** — Ensures defense-in-depth is implemented correctly. + --- ## Impact @@ -5095,7 +5214,348 @@ v0.8.22 showed single validation layer fails. PRD mandates multiple layers: pre- - **Restores CI confidence:** No more normalized failures — tests pass consistently. - **Clarifies architecture:** 5 decisions resolve branch model, workflow redundancy, build script ambiguity. + --- **Status:** PRD published, awaiting Brady review and architecture decisions. *Fresh start — Mission Control rebirth, 2026-03-08. Previous decisions archived.* + +### 2026-03-08: Distributed Mesh Integration — Architecture Guidance +**By:** Flight +**What:** Integration map for Andi's distributed-mesh extension into Squad core. +**Why:** The distributed mesh pattern is proven (3-model consensus), solves multi-machine coordination, and fits Squad's zero-dependency architecture. This guidance ensures clean integration without architectural drift. + + +--- + +## File Placement — Definitive Locations + +### SKILL.md +**Template distribution:** +- `templates/skills/distributed-mesh/SKILL.md` — Shipped with Squad npm package, copied into new projects via init/upgrade +- `packages/squad-sdk/templates/skills/distributed-mesh/SKILL.md` — SDK template for programmatic access +- `packages/squad-cli/templates/skills/distributed-mesh/SKILL.md` — CLI template for scaffolding + +**Runtime location:** +- `.squad/skills/distributed-mesh/SKILL.md` — User-owned, never overwritten by upgrades (follows existing skill convention) + +### Sync Scripts +**Location:** `scripts/mesh/` +- `scripts/mesh/sync-mesh.sh` (bash version, requires jq + git) +- `scripts/mesh/sync-mesh.ps1` (PowerShell version, requires git only) + +**Why scripts/ and not bin/:** These are optional reference implementations, not core CLI commands. Users can run them directly (`./scripts/mesh/sync-mesh.sh`) or copy them into their own project workflows. They are NOT wired into the CLI routing table. + +### mesh.json.example +**Location:** `templates/mesh.json.example` + +Copied during init if user opts into distributed mode (future enhancement). For now, ships as documentation — users copy manually when they need Zone 2/3 coordination. + +### README.md Content +**Target:** `docs/src/content/docs/features/distributed-mesh.md` + +**Structure:** +- Title: "Distributed Mesh — Cross-Machine Coordination" +- Front matter: `{ title: "Distributed Mesh", description: "Coordinate squads across machines using git as transport" }` +- Content sections: + - The Problem (verbatim from extension README) + - The Architecture (3 zones table) + - Agent Lifecycle (SYNC → READ → WORK → WRITE → PUBLISH) + - Configuration (mesh.json schema) + - Phased Rollout (phases 0-2) + - Getting Started (setup guide) + - Cross-Model Consensus (validation) + - Anti-Patterns (what we're NOT building) + +**Cross-references:** +- Link from `scenarios/multiple-squads.md` → "For squads on different machines, see [Distributed Mesh](../features/distributed-mesh.md)" +- Link from `features/streams.md` → "SubSquads partition work within a repo. Distributed Mesh connects squads across machines." + + +--- + +## Relationship to Existing Modules + +### 1. `src/sharing/` — Export/Import (Snapshot-Based) +**What it does:** One-time snapshot export → zip → import into another squad. Cherry-pick skills, merge histories, handle version conflicts. + +**Relationship:** **Complementary, not overlapping.** +- **Export/import** = One-time knowledge transfer when creating a new squad or merging teams. +- **Distributed mesh** = Continuous coordination between running squads on different machines. + +**Example:** Export frontend-squad's skills, import them into backend-squad during onboarding (export/import). After onboarding, both squads coordinate via mesh for daily work (mesh). + +**Code changes needed:** NONE. Export/import stays as-is. Mesh is additive. + +### 2. `src/multi-squad.ts` — Local Squad Resolution +**What it does:** Resolves multiple personal squads on the same machine via `squads.json` in global config directory (`~/.config/squad/squads.json`). Each squad has its own `.squad/` state directory. Supports active squad switching. + +**Relationship:** **Orthogonal.** +- **multi-squad.ts** = "Which .squad/ directory am I using on this machine?" +- **Distributed mesh** = "How do I coordinate with squads whose .squad/ directories are on other machines?" + +**Example:** Developer has three local squads (auth-squad, api-squad, infra-squad) in their `~/.config/squad/squads.json`. Each squad's mesh.json can point to remote squads on CI runners or other developers' machines. + +**Code changes needed:** NONE. Multi-squad and mesh solve different problems. + +### 3. `src/streams/` — SubSquads (Label-Based Partitioning) +**What it does:** Partitions work within a single repo across multiple Codespaces. Each SubSquad filters by GitHub label (`team:ui`, `team:backend`) and restricts to specific directories. Enables parallel work without agent context overload. + +**Relationship:** **Scoping axis is different.** +- **SubSquads** = Scope work within a repo (same .squad/ state, different label filters). +- **Distributed mesh** = Connect squads across repos/machines (different .squad/ state directories). + +**Example:** Frontend SubSquad and Backend SubSquad both run in the same repo, each in their own Codespace, filtering by label. Both SubSquads might use distributed mesh to coordinate with a CI-squad running on a remote server. + +**Code changes needed:** NONE. SubSquads and mesh are composable. + +### 4. `src/remote/` — RemoteBridge (WebSocket PWA Control) +**What it does:** WebSocket server that bridges Squad's EventBus to a PWA client. Enables remote control of a running Squad instance from a browser — send prompts, see streaming output, approve permissions. Synchronous RPC-style interaction. Requires a running server. + +**Relationship:** **Mesh is the replacement for remote-to-remote agent-to-agent use cases.** + +**Decision:** The `src/remote/` module stays for **human-to-agent** remote control (PWA → Squad). Distributed mesh handles **agent-to-agent** coordination across machines. + +**Why mesh wins for agent-to-agent:** +1. Zero running services (git pull/push is transport) +2. Eventual consistency (agents are async anyway) +3. Write partitioning (structurally impossible to conflict) +4. Works across orgs (Zone 3 uses HTTP, no shared auth required) +5. 30 lines of bash vs. RemoteBridge's ~800 lines + WebSocket + HTTP server + +**Migration path:** If anyone was using `src/remote/` for agent-to-agent coordination (unlikely — it was designed for PWA control), they switch to mesh. RemoteBridge stays for PWA use cases. + +**Anti-pattern to block:** Do NOT extend RemoteBridge for agent-to-agent coordination. That path leads to MCP federation, service discovery, and message queues — the exact subsystems we killed. Mesh is the answer. + + +--- + +## Required Changes vs. Documentation Only + +### Documentation Only (No Code Changes) +✅ **Add `docs/src/content/docs/features/distributed-mesh.md`** — Comprehensive guide adapted from extension README +✅ **Update `docs/src/content/docs/scenarios/multiple-squads.md`** — Add paragraph + link: "For squads on different machines, see Distributed Mesh" +✅ **Update `docs/src/content/docs/features/streams.md`** — Add note: "SubSquads partition work within a repo. Distributed Mesh connects squads across machines." +✅ **Copy `sync-mesh.sh` and `sync-mesh.ps1` to `scripts/mesh/`** +✅ **Copy `mesh.json.example` to `templates/mesh.json.example`** +✅ **Copy `SKILL.md` to `templates/skills/distributed-mesh/SKILL.md`** (and SDK/CLI template dirs) + +### No Changes Required +❌ **squad.config.ts** — Does NOT need a `mesh` section. The mesh config lives in `mesh.json` as a separate concern. squad.config.ts is for agent behavior, not transport. + +❌ **squad.agent.md** — Does NOT need mesh awareness. Agents learn mesh patterns from the skill file, not the coordinator prompt. + +❌ **routing.md** — Does NOT need updates. Mesh is not a routing concern — it's a visibility concern. Agents read whatever `.mesh/` directories exist. Routing rules still apply to issue assignment. + +❌ **CLI commands** — NO `squad mesh sync` command. The sync scripts are reference implementations, not core CLI features. Users run them directly (`./scripts/mesh/sync-mesh.sh`) or integrate them into CI workflows (`github-actions`, `cron`). Rationale: Squad is an agent framework, not a sync orchestrator. Mesh is convention + optional scripts. + +### Optional Future Enhancements (Not Blocking v1) +🔮 **Init flow enhancement:** During `squad init`, ask "Will this squad coordinate with remote squads?" If yes, copy `mesh.json.example` → `mesh.json` and prompt for first remote entry. Implementation: ~20 lines in init flow. + +🔮 **Auto-sync hooks:** Git pre-commit hook that runs `sync-mesh.sh` before push. Implementation: Add to `.squad/templates/hooks/pre-commit.sample`. User enables manually (`chmod +x`). + +🔮 **Mesh health check:** `squad doctor` command extension that validates mesh.json schema, tests git auth for Zone 2 remotes, validates HTTP endpoints for Zone 3. Implementation: ~50 lines, non-critical. + + +--- + +## Integration Checklist + +**Phase 0 — Immediate (Documentation + Templates):** +- [ ] Copy extension files into Squad repo as documented above +- [ ] Write `docs/features/distributed-mesh.md` +- [ ] Update cross-reference docs (multiple-squads.md, streams.md) +- [ ] Add mesh.json.example to templates +- [ ] Add SKILL.md to all three template directories +- [ ] Verify skill appears in new squad init + +**Phase 1 — Validation (Test in Practice):** +- [ ] Use mesh in Squad's own development (coordinate across developer machines) +- [ ] Validate mesh works with existing multi-squad setup +- [ ] Confirm no conflicts with SubSquads feature +- [ ] Test cross-platform (bash script on macOS/Linux, PowerShell on Windows) + +**Phase 2 — Polish (User Experience):** +- [ ] Consider init flow enhancement (opt-in prompt) +- [ ] Document common mesh.json patterns (examples in docs) +- [ ] Add troubleshooting section (git auth failures, HTTP 404s, stale sync) + + +--- + +## Decision Rationale + +**Why mesh is architecturally correct:** +1. **Aligns with zero-dependency mandate:** Uses git (already required) and shell scripts. No new npm packages. +2. **Preserves agent interface invariance:** Agents always read local files. Transport is invisible. +3. **Respects write partitioning:** Each squad owns its directory. Structurally conflict-free. +4. **Fits phased rollout:** Phase 0 is pure convention (0 lines). Scripts are opt-in (~30 lines). +5. **Validated by consensus:** Three model families independently arrived at the same answer. + +**Why NOT a CLI command:** +- Squad is an agent framework, not a sync scheduler. +- Sync timing is environment-specific (git hooks, cron, CI, manual). +- Reference scripts empower users to integrate however they need. +- Avoids CLI complexity creep (26 commands → 27 is a high bar to clear). + +**Why NOT extend RemoteBridge:** +- RemoteBridge is for human-to-agent control (PWA → Squad). +- Mesh is for agent-to-agent coordination (Squad → Squad). +- Mixing the two leads to MCP federation, the subsystem we intentionally killed. + +**Why mesh.json is NOT in squad.config.ts:** +- squad.config.ts is TypeScript, requires compilation, stores agent behavior config. +- mesh.json is JSON, shell-parseable, stores transport config. +- Separation of concerns: agent behavior vs. transport infrastructure. + + +--- + +## Blockers and Dependencies + +**Blockers:** NONE. Mesh is pure additive — no breaking changes, no API surface expansion. + +**Dependencies:** +- Git must be installed (already required by Squad) +- For bash script: `jq` must be installed (document in prerequisites) +- For PowerShell script: PowerShell 5.1+ (built-in on Windows, installable on macOS/Linux) + +**Risk Assessment:** LOW. Mesh is convention-first, scripts are optional, skill file is passive knowledge. If users don't use mesh, it's invisible. If they do, it composes cleanly with all existing features. + + +--- + +## Summary + +Distributed Mesh integrates as: +1. **A skill** (templates/skills/distributed-mesh/SKILL.md) — agents learn the pattern +2. **Reference scripts** (scripts/mesh/) — users run them when needed +3. **Documentation** (docs/features/distributed-mesh.md) — comprehensive guide +4. **A template** (templates/mesh.json.example) — copy-paste config starter + +Zero code changes to existing modules. Zero new CLI commands. Zero architectural drift. The ratio holds: ~30 lines of bash/PowerShell vs. 3,756 lines of deleted federation code. Mesh is what distribution looks like when you respect the constraints. + +**Ship it.** + + +--- + +# Distributed Mesh Template Placement + +**By:** Network +**Date:** 2026-03-08 + +## Decision + +The distributed-mesh skill and scaffolding templates are placed in the standard template structure following the existing pattern for product-shipped skills. + +## Locations + +**Skill file (SKILL.md) — 4 locations:** +- `templates/skills/distributed-mesh/` — root template directory +- `packages/squad-sdk/templates/skills/distributed-mesh/` — SDK templates +- `packages/squad-cli/templates/skills/distributed-mesh/` — CLI templates +- `.squad/skills/distributed-mesh/` — this squad's runtime skills + +**Mesh scaffolding (new directory) — 1 location:** +- `templates/mesh/` — holds `mesh.json.example`, `sync-mesh.sh`, `sync-mesh.ps1`, `README.md` + +## Rationale + +Three parallel template locations (root, SDK, CLI) ensure both init paths can scaffold the skill into new projects. The mesh/ directory holds the sync script scaffolding separate from the skill documentation. This keeps the template structure clean and allows users to copy mesh files to their project root when they're ready for distributed coordination. + +The sync scripts (~40 lines each, bash and PowerShell) materialize remote squad state locally using git/curl. No daemons, no running processes — Phase 1 distributed coordination. + + +--- + +# Distributed Mesh Documentation Structure + +**By:** PAO +**Date:** 2026-03-08 +**Status:** Approved + +## Decision + +Distributed mesh documentation lives in `features/` (not `scenarios/` or `concepts/`). It's a **feature** because it's an optional capability users enable, not a conceptual explanation or workflow. + +## Context + +The distributed mesh enables squads on different machines to coordinate via git (same org) and HTTP (cross-org). Source material existed in `C:\dev\squad-architecture\distributed-mesh\README.md`. + +Choice: Where does this belong in the docs? +- `concepts/` — too architectural; readers expect abstract explanations, not setup steps +- `scenarios/` — too workflow-focused; scenarios are "how to accomplish X" +- `features/` — ✅ correct home; features are "what Squad can do and how to enable it" + +## What Was Documented + +Created `docs/src/content/docs/features/distributed-mesh.md`: +- What the distributed mesh is (one-sentence explanation) +- The three zones (local, remote-trusted, remote-opaque) +- `mesh.json` configuration +- Sync scripts (bash + PowerShell) +- Getting started (setup steps) +- Relation to SubSquads (within-repo partitioning vs cross-machine coordination) +- Relation to export/import (snapshot-based vs continuous) +- Anti-patterns (what NOT to build) + +## Test Assertions Updated + +Added `'distributed-mesh'` to: +- `EXPECTED_FEATURES` array in `test/docs-build.test.ts` +- Features directory markdown validation test +- `getAllMarkdownFiles()` sections array +- Navigation structure in `docs/src/navigation.ts` + +All structure validation tests pass. + +## Cross-References Added + +Added pointer in `scenarios/multiple-squads.md`: +> Want continuous coordination instead? See [Distributed Mesh](../features/distributed-mesh.md) — it syncs remote squad state via git and HTTP. + +This guides readers from snapshot-based export/import to continuous mesh coordination. + +## Why This Matters + +Users asking "how do I coordinate multiple squads?" now have two paths clearly documented: +1. **Snapshot-based:** Export/import (one-time copy, scenarios/multiple-squads.md) +2. **Continuous:** Distributed mesh (live sync, features/distributed-mesh.md) + +The feature page provides practical setup steps and respects the tone ceiling — no hype, just mechanism. + + +--- + +### 2026-03-10: Deterministic skill pattern + +**By:** Procedures (Prompt Engineer) + +**What:** Skills must have explicit SCOPE and AGENT WORKFLOW sections to be fully deterministic. + +**Pattern:** + +1. **SCOPE section** (after frontmatter, before Context): + - ✅ THIS SKILL PRODUCES — exact list of artifacts + - ❌ THIS SKILL DOES NOT PRODUCE — explicit negative list + +2. **AGENT WORKFLOW section** — deterministic steps: + - ASK: exact questions for the user + - GENERATE: which files to create, with schemas + - WRITE: which decision entry to write, with template + - TELL: exact message to output + - STOP: explicit stopping condition with negative list + +3. Fix ambiguous language (clarify "do the task," note phases aren't auto-advanced, etc.) + +4. Include decision templates inline + +5. List anti-patterns for code generation explicitly + +**Why:** The distributed-mesh skill was tested in a real project and agents generated 76 lines of validator code, 5 test files, regenerated sync scripts, and ignored decision-writing instructions. Skills need to be deterministic: same input → same output, every time. + +**Impact:** All future skills should follow this pattern. Existing skills should be audited and rewritten if they allow interpretation. + + +--- diff --git a/.squad/skills/distributed-mesh/SKILL.md b/.squad/skills/distributed-mesh/SKILL.md new file mode 100644 index 000000000..624db9626 --- /dev/null +++ b/.squad/skills/distributed-mesh/SKILL.md @@ -0,0 +1,287 @@ +--- +name: "distributed-mesh" +description: "How to coordinate with squads on different machines using git as transport" +domain: "distributed-coordination" +confidence: "high" +source: "multi-model-consensus (Opus 4.6, Sonnet 4.5, GPT-5.4)" +--- + +## SCOPE + +**✅ THIS SKILL PRODUCES (exactly these, nothing more):** + +1. **`mesh.json`** — Generated from user answers about zones and squads (which squads participate, what zone each is in, paths/URLs for each), using `mesh.json.example` in this skill's directory as the schema template +2. **`sync-mesh.sh` and `sync-mesh.ps1`** — Copied from this skill's directory into the project root (these are bundled resources, NOT generated code) +3. **Zone 2 state repo initialization** (if applicable) — If the user specified a Zone 2 shared state repo, run `sync-mesh.sh --init` to scaffold the state repo structure +4. **A decision entry** in `.squad/decisions/inbox/` documenting the mesh configuration for team awareness + +**❌ THIS SKILL DOES NOT PRODUCE:** + +- **No application code** — No validators, libraries, or modules of any kind +- **No test files** — No test suites, test cases, or test scaffolding +- **No GENERATING sync scripts** — They are bundled with this skill as pre-built resources. COPY them, don't generate them. +- **No daemons or services** — No background processes, servers, or persistent runtimes +- **No modifications to existing squad files** beyond the decision entry (no changes to team.md, routing.md, agent charters, etc.) + +**Your role:** Configure the mesh topology and install the bundled sync scripts. Nothing more. + +## Context + +When squads are on different machines (developer laptops, CI runners, cloud VMs, partner orgs), the local file-reading convention still works — but remote files need to arrive on your disk first. This skill teaches the pattern for distributed squad communication. + +**When this applies:** +- Squads span multiple machines, VMs, or CI runners +- Squads span organizations or companies +- An agent needs context from a squad whose files aren't on the local filesystem + +**When this does NOT apply:** +- All squads are on the same machine (just read the files directly) + +## Patterns + +### The Core Principle + +> "The filesystem is the mesh, and git is how the mesh crosses machine boundaries." + +The agent interface never changes. Agents always read local files. The distributed layer's only job is to make remote files appear locally before the agent reads them. + +### Three Zones of Communication + +**Zone 1 — Local:** Same filesystem. Read files directly. Zero transport. + +**Zone 2 — Remote-Trusted:** Different host, same org, shared git auth. Transport: `git pull` from a shared repo. This collapses Zone 2 into Zone 1 — files materialize on disk, agent reads them normally. + +**Zone 3 — Remote-Opaque:** Different org, no shared auth. Transport: `curl` to fetch published contracts (SUMMARY.md). One-way visibility — you see only what they publish. + +### Agent Lifecycle (Distributed) + +``` +1. SYNC: git pull (Zone 2) + curl (Zone 3) — materialize remote state +2. READ: cat .mesh/**/state.md — all files are local now +3. WORK: do their assigned work (the agent's normal task, NOT mesh-building) +4. WRITE: update own billboard, log, drops +5. PUBLISH: git add + commit + push — share state with remote peers +``` + +Steps 2–4 are identical to local-only. Steps 1 and 5 are the entire distributed extension. **Note:** "WORK" means the agent performs its normal squad duties — it does NOT mean "build mesh infrastructure." + +### The mesh.json Config + +```json +{ + "squads": { + "auth-squad": { "zone": "local", "path": "../auth-squad/.mesh" }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "ref": "main", + "sync_to": ".mesh/remotes/ci-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.dev/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud", + "auth": "bearer" + } + } +} +``` + +Three zone types, one file. Local squads need only a path. Remote-trusted need a git URL. Remote-opaque need an HTTP URL. + +### Write Partitioning + +Each squad writes only to its own directory (`boards/{self}.md`, `squads/{self}/*`, `drops/{date}-{self}-*.md`). No two squads write to the same file. Git push/pull never conflicts. If push fails ("branch is behind"), the fix is always `git pull --rebase && git push`. + +### Trust Boundaries + +Trust maps to git permissions: +- **Same repo access** = full mesh visibility +- **Read-only access** = can observe, can't write +- **No access** = invisible (correct behavior) + +For selective visibility, use separate repos per audience (internal, partner, public). Git permissions ARE the trust negotiation. + +### Phased Rollout + +- **Phase 0:** Convention only — document zones, agree on mesh.json fields, manually run `git pull`/`git push`. Zero new code. +- **Phase 1:** Sync script (~30 lines bash or PowerShell) when manual sync gets tedious. +- **Phase 2:** Published contracts + curl fetch when a Zone 3 partner appears. +- **Phase 3:** Never. No MCP federation, A2A, service discovery, message queues. + +**Important:** Phases are NOT auto-advanced. These are project-level decisions — you start at Phase 0 (manual sync) and only move forward when the team decides complexity is justified. + +### Mesh State Repo + +The shared mesh state repo is a plain git repository — NOT a Squad project. It holds: +- One directory per participating squad +- Each directory contains at minimum a SUMMARY.md with the squad's current state +- A root README explaining what the repo is and who participates + +No `.squad/` folder, no agents, no automation. Write partitioning means each squad only pushes to its own directory. The repo is a rendezvous point, not an intelligent system. + +If you want a squad that *observes* mesh health, that's a separate Squad project that lists the state repo as a Zone 2 remote in its `mesh.json` — it does NOT live inside the state repo. + +## Examples + +### Developer Laptop + CI Squad (Zone 2) + +Auth-squad agent wakes up. `git pull` brings ci-squad's latest results. Agent reads: "3 test failures in auth module." Adjusts work. Pushes results when done. **Overhead: one `git pull`, one `git push`.** + +### Two Orgs Collaborating (Zone 3) + +Payment-squad fetches partner's published SUMMARY.md via curl. Reads: "Risk scoring v3 API deprecated April 15. New field `device_fingerprint` required." The consuming agent (in payment-squad's team) reads this information and uses it to inform its work — for example, updating payment integration code to include the new field. Partner can't see payment-squad's internals. + +### Same Org, Shared Mesh Repo (Zone 2) + +Three squads on different machines. One shared git repo holds the mesh. Each squad: `git pull` before work, `git push` after. Write partitioning ensures zero merge conflicts. + +## AGENT WORKFLOW (Deterministic Setup) + +When a user invokes this skill to set up a distributed mesh, follow these steps **exactly, in order:** + +### Step 1: ASK the user for mesh topology + +Ask these questions (adapt phrasing naturally, but get these answers): + +1. **Which squads are participating?** (List of squad names) +2. **For each squad, which zone is it in?** + - `local` — same filesystem (just need a path) + - `remote-trusted` — different machine, same org, shared git access (need git URL + ref) + - `remote-opaque` — different org, no shared auth (need HTTPS URL to published contract) +3. **For each squad, what's the connection info?** + - Local: relative or absolute path to their `.mesh/` directory + - Remote-trusted: git URL (SSH or HTTPS), ref (branch/tag), and where to sync it to locally + - Remote-opaque: HTTPS URL to their SUMMARY.md, where to sync it, and auth type (none/bearer) +4. **Where should the shared state live?** (For Zone 2 squads: git repo URL for the mesh state, or confirm each squad syncs independently) + +### Step 2: GENERATE `mesh.json` + +Using the answers from Step 1, create a `mesh.json` file at the project root. Use `mesh.json.example` from THIS skill's directory (`.squad/skills/distributed-mesh/mesh.json.example`) as the schema template. + +Structure: + +```json +{ + "squads": { + "": { "zone": "local", "path": "" }, + "": { + "zone": "remote-trusted", + "source": "", + "ref": "", + "sync_to": ".mesh/remotes/" + }, + "": { + "zone": "remote-opaque", + "source": "", + "sync_to": ".mesh/remotes/", + "auth": "" + } + } +} +``` + +Write this file to the project root. Do NOT write any other code. + +### Step 3: COPY sync scripts + +Copy the bundled sync scripts from THIS skill's directory into the project root: + +- **Source:** `.squad/skills/distributed-mesh/sync-mesh.sh` +- **Destination:** `sync-mesh.sh` (project root) + +- **Source:** `.squad/skills/distributed-mesh/sync-mesh.ps1` +- **Destination:** `sync-mesh.ps1` (project root) + +These are bundled resources. Do NOT generate them — COPY them directly. + +### Step 4: RUN `--init` (if Zone 2 state repo exists) + +If the user specified a Zone 2 shared state repo in Step 1, run the initialization: + +**On Unix/Linux/macOS:** +```bash +bash sync-mesh.sh --init +``` + +**On Windows:** +```powershell +.\sync-mesh.ps1 -Init +``` + +This scaffolds the state repo structure (squad directories, placeholder SUMMARY.md files, root README). + +**Skip this step if:** +- No Zone 2 squads are configured (local/opaque only) +- The state repo already exists and is initialized + +### Step 5: WRITE a decision entry + +Create a decision file at `.squad/decisions/inbox/-mesh-setup.md` with this content: + +```markdown +### : Mesh configuration + +**By:** (via distributed-mesh skill) + +**What:** Configured distributed mesh with squads across zones + +**Squads:** +- `` — Zone +- `` — Zone +- ... + +**State repo:** + +**Why:** +``` + +Write this file. The Scribe will merge it into the main decisions file later. + +### Step 6: STOP + +**You are done.** Do not: +- Generate sync scripts (they're bundled with this skill — COPY them) +- Write validator code +- Write test files +- Create any other modules, libraries, or application code +- Modify existing squad files (team.md, routing.md, charters) +- Auto-advance to Phase 2 or Phase 3 + +Output a simple completion message: + +``` +✅ Mesh configured. Created: +- mesh.json ( squads) +- sync-mesh.sh and sync-mesh.ps1 (copied from skill bundle) +- Decision entry: .squad/decisions/inbox/ + +Run `bash sync-mesh.sh` (or `.\sync-mesh.ps1` on Windows) before agents start to materialize remote state. +``` + +--- + +## Anti-Patterns + +**❌ Code generation anti-patterns:** +- Writing `mesh-config-validator.js` or any validator module +- Writing test files for mesh configuration +- Generating sync scripts instead of copying the bundled ones from this skill's directory +- Creating library modules or utilities +- Building any code that "runs the mesh" — the mesh is read by agents, not executed + +**❌ Architectural anti-patterns:** +- Building a federation protocol — Git push/pull IS federation +- Running a sync daemon or server — Agents are not persistent. Sync at startup, publish at shutdown +- Real-time notifications — Agents don't need real-time. They need "recent enough." `git pull` is recent enough +- Schema validation for markdown — The LLM reads markdown. If the format changes, it adapts +- Service discovery protocol — mesh.json is a file with 10 entries. Not a "discovery problem" +- Auth framework — Git SSH keys and HTTPS tokens. Not a framework. Already configured +- Message queues / event buses — Agents wake, read, work, write, sleep. Nobody's home to receive events +- Any component requiring a running process — That's the line. Don't cross it + +**❌ Scope creep anti-patterns:** +- Auto-advancing phases without user decision +- Modifying agent charters or routing rules +- Setting up CI/CD pipelines for mesh sync +- Creating dashboards or monitoring tools diff --git a/.squad/skills/distributed-mesh/mesh.json.example b/.squad/skills/distributed-mesh/mesh.json.example new file mode 100644 index 000000000..7f5730a88 --- /dev/null +++ b/.squad/skills/distributed-mesh/mesh.json.example @@ -0,0 +1,30 @@ +{ + "squads": { + "auth-squad": { + "zone": "local", + "path": "../auth-squad/.mesh" + }, + "api-squad": { + "zone": "local", + "path": "../api-squad/.mesh" + }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "ref": "main", + "sync_to": ".mesh/remotes/ci-squad" + }, + "data-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/data-pipeline.git", + "ref": "main", + "sync_to": ".mesh/remotes/data-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.example.com/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud", + "auth": "bearer" + } + } +} diff --git a/.squad/skills/distributed-mesh/sync-mesh.ps1 b/.squad/skills/distributed-mesh/sync-mesh.ps1 new file mode 100644 index 000000000..5f409ef37 --- /dev/null +++ b/.squad/skills/distributed-mesh/sync-mesh.ps1 @@ -0,0 +1,111 @@ +# sync-mesh.ps1 — Materialize remote squad state locally +# +# Reads mesh.json, fetches remote squads into local directories. +# Run before agent reads. No daemon. No service. ~40 lines. +# +# Usage: .\sync-mesh.ps1 [path-to-mesh.json] +# .\sync-mesh.ps1 -Init [path-to-mesh.json] +# Requires: git +param( + [switch]$Init, + [string]$MeshJson = "mesh.json" +) +$ErrorActionPreference = "Stop" + +# Handle -Init mode +if ($Init) { + if (-not (Test-Path $MeshJson)) { + Write-Host "❌ $MeshJson not found" + exit 1 + } + + Write-Host "🚀 Initializing mesh state repository..." + $config = Get-Content $MeshJson -Raw | ConvertFrom-Json + $squads = $config.squads.PSObject.Properties.Name + + # Create squad directories with placeholder SUMMARY.md + foreach ($squad in $squads) { + if (-not (Test-Path $squad)) { + New-Item -ItemType Directory -Path $squad | Out-Null + Write-Host " ✓ Created $squad/" + } else { + Write-Host " • $squad/ exists (skipped)" + } + + $summaryPath = "$squad/SUMMARY.md" + if (-not (Test-Path $summaryPath)) { + "# $squad`n`n_No state published yet._" | Set-Content $summaryPath + Write-Host " ✓ Created $summaryPath" + } else { + Write-Host " • $summaryPath exists (skipped)" + } + } + + # Generate root README.md + if (-not (Test-Path "README.md")) { + $readme = @" +# Squad Mesh State Repository + +This repository tracks published state from participating squads. + +## Participating Squads + +"@ + foreach ($squad in $squads) { + $zone = $config.squads.$squad.zone + $readme += "- **$squad** (Zone: $zone)`n" + } + $readme += @" + +Each squad directory contains a ``SUMMARY.md`` with their latest published state. +State is synchronized using ``sync-mesh.sh`` or ``sync-mesh.ps1``. +"@ + $readme | Set-Content "README.md" + Write-Host " ✓ Created README.md" + } else { + Write-Host " • README.md exists (skipped)" + } + + Write-Host "" + Write-Host "✅ Mesh state repository initialized" + exit 0 +} + +$config = Get-Content $MeshJson -Raw | ConvertFrom-Json + +# Zone 2: Remote-trusted — git clone/pull +foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-trusted" }) { + $squad = $entry.Name + $source = $entry.Value.source + $ref = if ($entry.Value.ref) { $entry.Value.ref } else { "main" } + $target = $entry.Value.sync_to + + if (Test-Path "$target/.git") { + git -C $target pull --rebase --quiet 2>$null + if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: pull failed (using stale)" } + } else { + New-Item -ItemType Directory -Force -Path (Split-Path $target -Parent) | Out-Null + git clone --quiet --depth 1 --branch $ref $source $target 2>$null + if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: clone failed (unavailable)" } + } +} + +# Zone 3: Remote-opaque — fetch published contracts +foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-opaque" }) { + $squad = $entry.Name + $source = $entry.Value.source + $target = $entry.Value.sync_to + $auth = $entry.Value.auth + + New-Item -ItemType Directory -Force -Path $target | Out-Null + $params = @{ Uri = $source; OutFile = "$target/SUMMARY.md"; UseBasicParsing = $true } + if ($auth -eq "bearer") { + $tokenVar = ($squad.ToUpper() -replace '-', '_') + "_TOKEN" + $token = [Environment]::GetEnvironmentVariable($tokenVar) + if ($token) { $params.Headers = @{ Authorization = "Bearer $token" } } + } + try { Invoke-WebRequest @params -ErrorAction Stop } + catch { "# ${squad} — unavailable ($(Get-Date))" | Set-Content "$target/SUMMARY.md" } +} + +Write-Host "✓ Mesh sync complete" diff --git a/.squad/skills/distributed-mesh/sync-mesh.sh b/.squad/skills/distributed-mesh/sync-mesh.sh new file mode 100644 index 000000000..802fd2d8d --- /dev/null +++ b/.squad/skills/distributed-mesh/sync-mesh.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# sync-mesh.sh — Materialize remote squad state locally +# +# Reads mesh.json, fetches remote squads into local directories. +# Run before agent reads. No daemon. No service. ~40 lines. +# +# Usage: ./sync-mesh.sh [path-to-mesh.json] +# ./sync-mesh.sh --init [path-to-mesh.json] +# Requires: jq (https://github.com/jqlang/jq), git, curl + +set -euo pipefail + +# Handle --init mode +if [ "${1:-}" = "--init" ]; then + MESH_JSON="${2:-mesh.json}" + + if [ ! -f "$MESH_JSON" ]; then + echo "❌ $MESH_JSON not found" + exit 1 + fi + + echo "🚀 Initializing mesh state repository..." + squads=$(jq -r '.squads | keys[]' "$MESH_JSON") + + # Create squad directories with placeholder SUMMARY.md + for squad in $squads; do + if [ ! -d "$squad" ]; then + mkdir -p "$squad" + echo " ✓ Created $squad/" + else + echo " • $squad/ exists (skipped)" + fi + + if [ ! -f "$squad/SUMMARY.md" ]; then + echo -e "# $squad\n\n_No state published yet._" > "$squad/SUMMARY.md" + echo " ✓ Created $squad/SUMMARY.md" + else + echo " • $squad/SUMMARY.md exists (skipped)" + fi + done + + # Generate root README.md + if [ ! -f "README.md" ]; then + { + echo "# Squad Mesh State Repository" + echo "" + echo "This repository tracks published state from participating squads." + echo "" + echo "## Participating Squads" + echo "" + for squad in $squads; do + zone=$(jq -r ".squads.\"$squad\".zone" "$MESH_JSON") + echo "- **$squad** (Zone: $zone)" + done + echo "" + echo "Each squad directory contains a \`SUMMARY.md\` with their latest published state." + echo "State is synchronized using \`sync-mesh.sh\` or \`sync-mesh.ps1\`." + } > README.md + echo " ✓ Created README.md" + else + echo " • README.md exists (skipped)" + fi + + echo "" + echo "✅ Mesh state repository initialized" + exit 0 +fi + +MESH_JSON="${1:-mesh.json}" + +# Zone 2: Remote-trusted — git clone/pull +for squad in $(jq -r '.squads | to_entries[] | select(.value.zone == "remote-trusted") | .key' "$MESH_JSON"); do + source=$(jq -r ".squads.\"$squad\".source" "$MESH_JSON") + ref=$(jq -r ".squads.\"$squad\".ref // \"main\"" "$MESH_JSON") + target=$(jq -r ".squads.\"$squad\".sync_to" "$MESH_JSON") + + if [ -d "$target/.git" ]; then + git -C "$target" pull --rebase --quiet 2>/dev/null \ + || echo "⚠ $squad: pull failed (using stale)" + else + mkdir -p "$(dirname "$target")" + git clone --quiet --depth 1 --branch "$ref" "$source" "$target" 2>/dev/null \ + || echo "⚠ $squad: clone failed (unavailable)" + fi +done + +# Zone 3: Remote-opaque — fetch published contracts +for squad in $(jq -r '.squads | to_entries[] | select(.value.zone == "remote-opaque") | .key' "$MESH_JSON"); do + source=$(jq -r ".squads.\"$squad\".source" "$MESH_JSON") + target=$(jq -r ".squads.\"$squad\".sync_to" "$MESH_JSON") + auth=$(jq -r ".squads.\"$squad\".auth // \"\"" "$MESH_JSON") + + mkdir -p "$target" + auth_flag="" + if [ "$auth" = "bearer" ]; then + token_var="$(echo "${squad}" | tr '[:lower:]-' '[:upper:]_')_TOKEN" + [ -n "${!token_var:-}" ] && auth_flag="--header \"Authorization: Bearer ${!token_var}\"" + fi + + eval curl --silent --fail $auth_flag "$source" -o "$target/SUMMARY.md" 2>/dev/null \ + || echo "# ${squad} — unavailable ($(date))" > "$target/SUMMARY.md" +done + +echo "✓ Mesh sync complete" diff --git a/docs/src/content/docs/features/distributed-mesh.md b/docs/src/content/docs/features/distributed-mesh.md new file mode 100644 index 000000000..33b6d7a21 --- /dev/null +++ b/docs/src/content/docs/features/distributed-mesh.md @@ -0,0 +1,318 @@ +# Distributed Mesh + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +**Try this to coordinate squads across machines:** +``` +Set up a distributed mesh so my local squad can see the state of our CI squad +``` + +**Try this to sync remote squad state:** +``` +Run sync-mesh.sh to pull the latest state from all remote squads +``` + +The distributed mesh lets squads on different machines coordinate through git and HTTP. Local squads read remote squad state after syncing it locally. + +--- + +## What Is the Distributed Mesh? + +One sentence: + +> **"The filesystem is the mesh, and git is how the mesh crosses machine boundaries."** + +Squad agents always read local files. When squads live on different machines, you need to materialize remote state locally before agents can see it. The distributed mesh does this through simple sync scripts — no servers, no federation protocols, no real-time messaging. + +--- + +## Three Zones + +| Zone | Description | Transport | Complexity | +|------|-------------|-----------|------------| +| **1 — Local** | Same host/filesystem | Direct file read | Zero | +| **2 — Remote-Trusted** | Different host, same org | `git pull` from shared repo | Zero new (git exists) | +| **3 — Remote-Opaque** | Different org, no shared auth | `curl` / HTTP fetch | ~15 lines of shell | + +**Zone 1 (Local):** `cat ../squad-b/SUMMARY.md` works because the file is on your disk. + +**Zone 2 (Remote-Trusted):** Squads push their state to a shared git repo. You pull from that repo to materialize their state locally. + +**Zone 3 (Remote-Opaque):** A remote organization publishes their squad's `SUMMARY.md` at an HTTPS URL. You curl it to materialize locally. + +--- + +## How It Works + +### Agent Lifecycle with Sync + +``` +Agent wakes up + │ + ├─ SYNC: git pull (Zone 2) + curl (Zone 3) + ├─ READ: cat .mesh/**/state.md — all local now + ├─ WORK: do the task + ├─ WRITE: update own billboard, log, drops + └─ PUBLISH: git push +``` + +Two new steps (SYNC, PUBLISH). Both are transport only — they move files, not change them. + +### What Doesn't Change + +- Agents read local files +- Write partitioning (each squad owns its directory) +- Pull-based coordination +- Eventual consistency +- LLMs as the relevance engine + +### What Changes + +Remote files need to arrive locally before agents can read them. + +--- + +## Configuration + +### The `mesh.json` File + +One JSON file lists where to find each squad: + +```json +{ + "squads": { + "auth-squad": { "zone": "local", "path": "../auth-squad/.mesh" }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "sync_to": ".mesh/remotes/ci-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.dev/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud" + } + } +} +``` + +### Sync Scripts + +**Bash (requires `jq` and `git`):** + +```bash +./sync-mesh.sh # reads mesh.json, materializes remote state +``` + +**PowerShell (requires `git` only):** + +```powershell +.\sync-mesh.ps1 # default: reads mesh.json +.\sync-mesh.ps1 -MeshJson custom.json # custom config path +``` + +Both scripts read `mesh.json`, pull from remote-trusted repos, curl from remote-opaque URLs, and materialize everything into `.mesh/remotes/`. + +--- + +## Getting Started + +### Prerequisites + +- Git (with SSH or HTTPS auth configured) +- A shell (bash/zsh) or PowerShell +- `jq` ([github.com/jqlang/jq](https://github.com/jqlang/jq)) for the bash sync script (PowerShell script has no external dependencies) + +### 1. Create the Mesh State Repo + +The **mesh state repo** is a shared git repository where squads publish their current state. Nothing more — no code, no automation, no agents. + +```bash +git clone git@github.com:our-org/squad-mesh-state.git +cd squad-mesh-state +``` + +### 2. Directory Structure + +One directory per squad, each with a `SUMMARY.md`: + +``` +squad-mesh-state/ +├── README.md # What this repo is, who participates +├── auth-squad/ +│ └── SUMMARY.md # Auth squad's current state +├── ci-squad/ +│ └── SUMMARY.md # CI squad's current state +└── data-squad/ + └── SUMMARY.md # Data squad's current state +``` + +### 3. Register Your Squad + +Create your directory, write initial state, push: + +```bash +mkdir my-squad +echo "# my-squad — active" > my-squad/SUMMARY.md +git add . && git commit -m "register my-squad" && git push +``` + +### 4. Configure `mesh.json` + +Point at the shared repo: + +```json +{ + "squads": { + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/squad-mesh-state.git", + "sync_to": ".mesh/remotes/ci-squad" + } + } +} +``` + +### 5. Run Your First Sync + +```bash +./sync-mesh.sh # reads mesh.json, materializes remote state +ls .mesh/remotes/ # should show directories per remote squad +``` + +> **Does the mesh state repo need its own Squad?** No. It's a shared data directory — a dumb pipe. No agents, no `.squad/` folder, no automation. Each squad pushes its own state via write partitioning. The repo is just a git-based rendezvous point. If you later want a "mesh observer" that monitors all squads, THAT would be its own Squad project — but it's not required and shouldn't be the state repo itself. + +--- + +## Cross-Org Setup (Zone 3) + +Remote org publishes `SUMMARY.md` at a URL. Add an HTTP entry to `mesh.json`: + +```json +"partner-squad": { + "zone": "remote-opaque", + "source": "https://partner.dev/squad-contracts/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-squad" +} +``` + +--- + +## How This Relates to Other Features + +### SubSquads (Streams) + +**SubSquads** partition work **within a single repo** using GitHub labels (e.g., `team:ui`, `team:backend`). Each SubSquad runs in its own Codespace but shares the same git repository. + +**Distributed mesh** coordinates **across repos and machines** — different organizations, different git repos, potentially no shared authentication. + +SubSquads solve "one repo, many teams." Distributed mesh solves "many repos, many machines, crossing org boundaries." + +See [SubSquads](./streams.md) for within-repo partitioning. + +### Export & Import + +**Export/import** is a **snapshot-based** knowledge transfer. You export a trained squad from one repo and import it into another. It's a one-time copy. + +**Distributed mesh** is **continuous coordination**. Remote squads keep working; you sync their latest state every time your agents wake up. + +Use export/import when you want to **clone a team**. Use distributed mesh when you want **live coordination**. + +See [Multiple Squads scenario](../scenarios/multiple-squads.md) for when to use each approach. + +--- + +## Upstream inheritance + +The **upstream module** and the **distributed mesh** serve different coordination needs. They're complementary, not competing. + +### Upstream: top-down inheritance + +The `upstream/` module (configured in `upstream.json`) is for **hierarchical inheritance**. An organization-level or team-level squad pushes skills, decisions, wisdom, casting policy, and routing rules **down** to project squads. The consuming squad treats upstream content as **read-only** — it inherits conventions but doesn't write back. + +### Mesh: peer coordination + +The distributed mesh (configured in `mesh.json`) is for **peer-to-peer coordination**. Squads on equal footing share their **current state** with each other. Each squad **publishes** its own state (SUMMARY.md, billboards) and **reads** everyone else's. It's read-write for each squad's own directory. + +### Use them together + +A squad can have **both** an upstream (inheriting org conventions) **and** mesh peers (coordinating with sibling squads). For example: + +- Your project squad inherits security policies and routing rules from the org-level squad via `upstream.json` +- The same squad coordinates with other project squads (auth, ci, data) via `mesh.json` + +### Comparison + +| | Upstream | Mesh | +|---|---|---| +| **Direction** | Top-down (parent → child) | Peer-to-peer (squad ↔ squad) | +| **Write model** | Read-only for consumer | Read-write (own directory) | +| **What flows** | Skills, decisions, wisdom, casting, routing | Current state (SUMMARY.md, billboards) | +| **Config file** | `upstream.json` | `mesh.json` | +| **Transport** | Local path / git clone / export JSON | Local path / git pull / HTTP curl | +| **Use case** | Org policies flowing into team projects | Sibling squads keeping each other informed | + +### What neither does + +Neither upstream nor mesh is about **agent-to-agent communication within a single squad**. That's the drop-box pattern — agents write to `decisions/inbox/`, read from `history.md`, and coordinate asynchronously within one `.squad/` directory. + +--- + +## Skill scope + +When you ask an agent to set up a distributed mesh, the skill produces three things: + +1. **`mesh.json` config file** — defines squads, zones, and sync sources +2. **A decision entry** — records why you configured the mesh this way +3. **Sync scripts** — copies pre-built `sync-mesh.sh` and `sync-mesh.ps1` from the skill's bundled resources + +The skill does **not** generate: + +- ❌ Code (validators, helpers, utilities) +- ❌ Tests (the sync scripts are pre-tested templates) +- ❌ Custom sync scripts (bundled scripts are copied, not regenerated) + +**Why this matters:** Deterministic skills give you consistent results. The sync scripts are bundled with the distributed-mesh skill. Agents shouldn't waste time generating validators or rewriting sync logic from scratch — they should copy the bundled scripts and configure your `mesh.json`. + +If you need to customize the sync behavior, edit the copied scripts in your project root. The mesh skill's job ends at configuration. + +--- + +## What We're NOT Building + +- ❌ Federation protocol (git push/pull IS federation) +- ❌ Discovery service (mesh.json IS discovery) +- ❌ Auth system (git auth IS the auth system) +- ❌ A2A endpoints (no running servers) +- ❌ Schema versioning (markdown; LLM reads it) +- ❌ Real-time sync (agents are async; eventual consistency is correct) +- ❌ Message queues (agents aren't persistent; nobody's listening) +- ❌ CRDTs/conflict resolution (write partitioning; no conflicts possible) + +--- + +## Sample Prompts + +``` +configure a distributed mesh with our CI squad on GitHub +``` + +Creates a `mesh.json` entry for a remote-trusted squad and runs the first sync. + +``` +sync remote squad state before starting work +``` + +Runs the sync script to materialize the latest state from all configured remote squads. + +``` +add a partner squad from https://partner.dev/squad-contracts/SUMMARY.md +``` + +Adds a remote-opaque Zone 3 entry to `mesh.json` for cross-org coordination. + +``` +show me what remote squads are configured +``` + +Lists all squads in `mesh.json` and their zones. diff --git a/docs/src/content/docs/scenarios/multiple-squads.md b/docs/src/content/docs/scenarios/multiple-squads.md index c0ce28a8b..cd47e6c4d 100644 --- a/docs/src/content/docs/scenarios/multiple-squads.md +++ b/docs/src/content/docs/scenarios/multiple-squads.md @@ -22,6 +22,8 @@ Squad's import system brings in a complete team — roster, charters, histories, **But** you can cherry-pick skills and knowledge manually. +> **Want continuous coordination instead?** If you need squads on different machines to see each other's live state (not just import once), see [Distributed Mesh](../features/distributed-mesh.md) — it syncs remote squad state via git and HTTP. + --- ## 2. Export from Each Repository diff --git a/docs/src/navigation.ts b/docs/src/navigation.ts index 56d5a88dd..9534814b5 100644 --- a/docs/src/navigation.ts +++ b/docs/src/navigation.ts @@ -66,6 +66,7 @@ export const NAV_SECTIONS: NavSection[] = [ { title: 'Enterprise Platforms', slug: 'features/enterprise-platforms' }, { title: 'Squad RC', slug: 'features/squad-rc' }, { title: 'Streams', slug: 'features/streams' }, + { title: 'Distributed Mesh', slug: 'features/distributed-mesh' }, ], }, { diff --git a/package.json b/package.json index 3f3bb31b4..7cfc13420 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,9 @@ ], "scripts": { "prepare": "npm run build", - "prebuild": "node scripts/bump-build.mjs", + "prebuild": "node scripts/bump-build.mjs && node scripts/sync-skill-templates.mjs", "build": "npm run build -w packages/squad-sdk && npm run build -w packages/squad-cli", + "sync-templates": "node scripts/sync-skill-templates.mjs", "test": "vitest run", "test:watch": "vitest", "lint": "tsc --noEmit -p packages/squad-sdk/tsconfig.json && tsc --noEmit -p packages/squad-cli/tsconfig.json", diff --git a/packages/squad-cli/templates/skills/distributed-mesh/SKILL.md b/packages/squad-cli/templates/skills/distributed-mesh/SKILL.md new file mode 100644 index 000000000..624db9626 --- /dev/null +++ b/packages/squad-cli/templates/skills/distributed-mesh/SKILL.md @@ -0,0 +1,287 @@ +--- +name: "distributed-mesh" +description: "How to coordinate with squads on different machines using git as transport" +domain: "distributed-coordination" +confidence: "high" +source: "multi-model-consensus (Opus 4.6, Sonnet 4.5, GPT-5.4)" +--- + +## SCOPE + +**✅ THIS SKILL PRODUCES (exactly these, nothing more):** + +1. **`mesh.json`** — Generated from user answers about zones and squads (which squads participate, what zone each is in, paths/URLs for each), using `mesh.json.example` in this skill's directory as the schema template +2. **`sync-mesh.sh` and `sync-mesh.ps1`** — Copied from this skill's directory into the project root (these are bundled resources, NOT generated code) +3. **Zone 2 state repo initialization** (if applicable) — If the user specified a Zone 2 shared state repo, run `sync-mesh.sh --init` to scaffold the state repo structure +4. **A decision entry** in `.squad/decisions/inbox/` documenting the mesh configuration for team awareness + +**❌ THIS SKILL DOES NOT PRODUCE:** + +- **No application code** — No validators, libraries, or modules of any kind +- **No test files** — No test suites, test cases, or test scaffolding +- **No GENERATING sync scripts** — They are bundled with this skill as pre-built resources. COPY them, don't generate them. +- **No daemons or services** — No background processes, servers, or persistent runtimes +- **No modifications to existing squad files** beyond the decision entry (no changes to team.md, routing.md, agent charters, etc.) + +**Your role:** Configure the mesh topology and install the bundled sync scripts. Nothing more. + +## Context + +When squads are on different machines (developer laptops, CI runners, cloud VMs, partner orgs), the local file-reading convention still works — but remote files need to arrive on your disk first. This skill teaches the pattern for distributed squad communication. + +**When this applies:** +- Squads span multiple machines, VMs, or CI runners +- Squads span organizations or companies +- An agent needs context from a squad whose files aren't on the local filesystem + +**When this does NOT apply:** +- All squads are on the same machine (just read the files directly) + +## Patterns + +### The Core Principle + +> "The filesystem is the mesh, and git is how the mesh crosses machine boundaries." + +The agent interface never changes. Agents always read local files. The distributed layer's only job is to make remote files appear locally before the agent reads them. + +### Three Zones of Communication + +**Zone 1 — Local:** Same filesystem. Read files directly. Zero transport. + +**Zone 2 — Remote-Trusted:** Different host, same org, shared git auth. Transport: `git pull` from a shared repo. This collapses Zone 2 into Zone 1 — files materialize on disk, agent reads them normally. + +**Zone 3 — Remote-Opaque:** Different org, no shared auth. Transport: `curl` to fetch published contracts (SUMMARY.md). One-way visibility — you see only what they publish. + +### Agent Lifecycle (Distributed) + +``` +1. SYNC: git pull (Zone 2) + curl (Zone 3) — materialize remote state +2. READ: cat .mesh/**/state.md — all files are local now +3. WORK: do their assigned work (the agent's normal task, NOT mesh-building) +4. WRITE: update own billboard, log, drops +5. PUBLISH: git add + commit + push — share state with remote peers +``` + +Steps 2–4 are identical to local-only. Steps 1 and 5 are the entire distributed extension. **Note:** "WORK" means the agent performs its normal squad duties — it does NOT mean "build mesh infrastructure." + +### The mesh.json Config + +```json +{ + "squads": { + "auth-squad": { "zone": "local", "path": "../auth-squad/.mesh" }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "ref": "main", + "sync_to": ".mesh/remotes/ci-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.dev/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud", + "auth": "bearer" + } + } +} +``` + +Three zone types, one file. Local squads need only a path. Remote-trusted need a git URL. Remote-opaque need an HTTP URL. + +### Write Partitioning + +Each squad writes only to its own directory (`boards/{self}.md`, `squads/{self}/*`, `drops/{date}-{self}-*.md`). No two squads write to the same file. Git push/pull never conflicts. If push fails ("branch is behind"), the fix is always `git pull --rebase && git push`. + +### Trust Boundaries + +Trust maps to git permissions: +- **Same repo access** = full mesh visibility +- **Read-only access** = can observe, can't write +- **No access** = invisible (correct behavior) + +For selective visibility, use separate repos per audience (internal, partner, public). Git permissions ARE the trust negotiation. + +### Phased Rollout + +- **Phase 0:** Convention only — document zones, agree on mesh.json fields, manually run `git pull`/`git push`. Zero new code. +- **Phase 1:** Sync script (~30 lines bash or PowerShell) when manual sync gets tedious. +- **Phase 2:** Published contracts + curl fetch when a Zone 3 partner appears. +- **Phase 3:** Never. No MCP federation, A2A, service discovery, message queues. + +**Important:** Phases are NOT auto-advanced. These are project-level decisions — you start at Phase 0 (manual sync) and only move forward when the team decides complexity is justified. + +### Mesh State Repo + +The shared mesh state repo is a plain git repository — NOT a Squad project. It holds: +- One directory per participating squad +- Each directory contains at minimum a SUMMARY.md with the squad's current state +- A root README explaining what the repo is and who participates + +No `.squad/` folder, no agents, no automation. Write partitioning means each squad only pushes to its own directory. The repo is a rendezvous point, not an intelligent system. + +If you want a squad that *observes* mesh health, that's a separate Squad project that lists the state repo as a Zone 2 remote in its `mesh.json` — it does NOT live inside the state repo. + +## Examples + +### Developer Laptop + CI Squad (Zone 2) + +Auth-squad agent wakes up. `git pull` brings ci-squad's latest results. Agent reads: "3 test failures in auth module." Adjusts work. Pushes results when done. **Overhead: one `git pull`, one `git push`.** + +### Two Orgs Collaborating (Zone 3) + +Payment-squad fetches partner's published SUMMARY.md via curl. Reads: "Risk scoring v3 API deprecated April 15. New field `device_fingerprint` required." The consuming agent (in payment-squad's team) reads this information and uses it to inform its work — for example, updating payment integration code to include the new field. Partner can't see payment-squad's internals. + +### Same Org, Shared Mesh Repo (Zone 2) + +Three squads on different machines. One shared git repo holds the mesh. Each squad: `git pull` before work, `git push` after. Write partitioning ensures zero merge conflicts. + +## AGENT WORKFLOW (Deterministic Setup) + +When a user invokes this skill to set up a distributed mesh, follow these steps **exactly, in order:** + +### Step 1: ASK the user for mesh topology + +Ask these questions (adapt phrasing naturally, but get these answers): + +1. **Which squads are participating?** (List of squad names) +2. **For each squad, which zone is it in?** + - `local` — same filesystem (just need a path) + - `remote-trusted` — different machine, same org, shared git access (need git URL + ref) + - `remote-opaque` — different org, no shared auth (need HTTPS URL to published contract) +3. **For each squad, what's the connection info?** + - Local: relative or absolute path to their `.mesh/` directory + - Remote-trusted: git URL (SSH or HTTPS), ref (branch/tag), and where to sync it to locally + - Remote-opaque: HTTPS URL to their SUMMARY.md, where to sync it, and auth type (none/bearer) +4. **Where should the shared state live?** (For Zone 2 squads: git repo URL for the mesh state, or confirm each squad syncs independently) + +### Step 2: GENERATE `mesh.json` + +Using the answers from Step 1, create a `mesh.json` file at the project root. Use `mesh.json.example` from THIS skill's directory (`.squad/skills/distributed-mesh/mesh.json.example`) as the schema template. + +Structure: + +```json +{ + "squads": { + "": { "zone": "local", "path": "" }, + "": { + "zone": "remote-trusted", + "source": "", + "ref": "", + "sync_to": ".mesh/remotes/" + }, + "": { + "zone": "remote-opaque", + "source": "", + "sync_to": ".mesh/remotes/", + "auth": "" + } + } +} +``` + +Write this file to the project root. Do NOT write any other code. + +### Step 3: COPY sync scripts + +Copy the bundled sync scripts from THIS skill's directory into the project root: + +- **Source:** `.squad/skills/distributed-mesh/sync-mesh.sh` +- **Destination:** `sync-mesh.sh` (project root) + +- **Source:** `.squad/skills/distributed-mesh/sync-mesh.ps1` +- **Destination:** `sync-mesh.ps1` (project root) + +These are bundled resources. Do NOT generate them — COPY them directly. + +### Step 4: RUN `--init` (if Zone 2 state repo exists) + +If the user specified a Zone 2 shared state repo in Step 1, run the initialization: + +**On Unix/Linux/macOS:** +```bash +bash sync-mesh.sh --init +``` + +**On Windows:** +```powershell +.\sync-mesh.ps1 -Init +``` + +This scaffolds the state repo structure (squad directories, placeholder SUMMARY.md files, root README). + +**Skip this step if:** +- No Zone 2 squads are configured (local/opaque only) +- The state repo already exists and is initialized + +### Step 5: WRITE a decision entry + +Create a decision file at `.squad/decisions/inbox/-mesh-setup.md` with this content: + +```markdown +### : Mesh configuration + +**By:** (via distributed-mesh skill) + +**What:** Configured distributed mesh with squads across zones + +**Squads:** +- `` — Zone +- `` — Zone +- ... + +**State repo:** + +**Why:** +``` + +Write this file. The Scribe will merge it into the main decisions file later. + +### Step 6: STOP + +**You are done.** Do not: +- Generate sync scripts (they're bundled with this skill — COPY them) +- Write validator code +- Write test files +- Create any other modules, libraries, or application code +- Modify existing squad files (team.md, routing.md, charters) +- Auto-advance to Phase 2 or Phase 3 + +Output a simple completion message: + +``` +✅ Mesh configured. Created: +- mesh.json ( squads) +- sync-mesh.sh and sync-mesh.ps1 (copied from skill bundle) +- Decision entry: .squad/decisions/inbox/ + +Run `bash sync-mesh.sh` (or `.\sync-mesh.ps1` on Windows) before agents start to materialize remote state. +``` + +--- + +## Anti-Patterns + +**❌ Code generation anti-patterns:** +- Writing `mesh-config-validator.js` or any validator module +- Writing test files for mesh configuration +- Generating sync scripts instead of copying the bundled ones from this skill's directory +- Creating library modules or utilities +- Building any code that "runs the mesh" — the mesh is read by agents, not executed + +**❌ Architectural anti-patterns:** +- Building a federation protocol — Git push/pull IS federation +- Running a sync daemon or server — Agents are not persistent. Sync at startup, publish at shutdown +- Real-time notifications — Agents don't need real-time. They need "recent enough." `git pull` is recent enough +- Schema validation for markdown — The LLM reads markdown. If the format changes, it adapts +- Service discovery protocol — mesh.json is a file with 10 entries. Not a "discovery problem" +- Auth framework — Git SSH keys and HTTPS tokens. Not a framework. Already configured +- Message queues / event buses — Agents wake, read, work, write, sleep. Nobody's home to receive events +- Any component requiring a running process — That's the line. Don't cross it + +**❌ Scope creep anti-patterns:** +- Auto-advancing phases without user decision +- Modifying agent charters or routing rules +- Setting up CI/CD pipelines for mesh sync +- Creating dashboards or monitoring tools diff --git a/packages/squad-cli/templates/skills/distributed-mesh/mesh.json.example b/packages/squad-cli/templates/skills/distributed-mesh/mesh.json.example new file mode 100644 index 000000000..7f5730a88 --- /dev/null +++ b/packages/squad-cli/templates/skills/distributed-mesh/mesh.json.example @@ -0,0 +1,30 @@ +{ + "squads": { + "auth-squad": { + "zone": "local", + "path": "../auth-squad/.mesh" + }, + "api-squad": { + "zone": "local", + "path": "../api-squad/.mesh" + }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "ref": "main", + "sync_to": ".mesh/remotes/ci-squad" + }, + "data-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/data-pipeline.git", + "ref": "main", + "sync_to": ".mesh/remotes/data-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.example.com/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud", + "auth": "bearer" + } + } +} diff --git a/packages/squad-cli/templates/skills/distributed-mesh/sync-mesh.ps1 b/packages/squad-cli/templates/skills/distributed-mesh/sync-mesh.ps1 new file mode 100644 index 000000000..5f409ef37 --- /dev/null +++ b/packages/squad-cli/templates/skills/distributed-mesh/sync-mesh.ps1 @@ -0,0 +1,111 @@ +# sync-mesh.ps1 — Materialize remote squad state locally +# +# Reads mesh.json, fetches remote squads into local directories. +# Run before agent reads. No daemon. No service. ~40 lines. +# +# Usage: .\sync-mesh.ps1 [path-to-mesh.json] +# .\sync-mesh.ps1 -Init [path-to-mesh.json] +# Requires: git +param( + [switch]$Init, + [string]$MeshJson = "mesh.json" +) +$ErrorActionPreference = "Stop" + +# Handle -Init mode +if ($Init) { + if (-not (Test-Path $MeshJson)) { + Write-Host "❌ $MeshJson not found" + exit 1 + } + + Write-Host "🚀 Initializing mesh state repository..." + $config = Get-Content $MeshJson -Raw | ConvertFrom-Json + $squads = $config.squads.PSObject.Properties.Name + + # Create squad directories with placeholder SUMMARY.md + foreach ($squad in $squads) { + if (-not (Test-Path $squad)) { + New-Item -ItemType Directory -Path $squad | Out-Null + Write-Host " ✓ Created $squad/" + } else { + Write-Host " • $squad/ exists (skipped)" + } + + $summaryPath = "$squad/SUMMARY.md" + if (-not (Test-Path $summaryPath)) { + "# $squad`n`n_No state published yet._" | Set-Content $summaryPath + Write-Host " ✓ Created $summaryPath" + } else { + Write-Host " • $summaryPath exists (skipped)" + } + } + + # Generate root README.md + if (-not (Test-Path "README.md")) { + $readme = @" +# Squad Mesh State Repository + +This repository tracks published state from participating squads. + +## Participating Squads + +"@ + foreach ($squad in $squads) { + $zone = $config.squads.$squad.zone + $readme += "- **$squad** (Zone: $zone)`n" + } + $readme += @" + +Each squad directory contains a ``SUMMARY.md`` with their latest published state. +State is synchronized using ``sync-mesh.sh`` or ``sync-mesh.ps1``. +"@ + $readme | Set-Content "README.md" + Write-Host " ✓ Created README.md" + } else { + Write-Host " • README.md exists (skipped)" + } + + Write-Host "" + Write-Host "✅ Mesh state repository initialized" + exit 0 +} + +$config = Get-Content $MeshJson -Raw | ConvertFrom-Json + +# Zone 2: Remote-trusted — git clone/pull +foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-trusted" }) { + $squad = $entry.Name + $source = $entry.Value.source + $ref = if ($entry.Value.ref) { $entry.Value.ref } else { "main" } + $target = $entry.Value.sync_to + + if (Test-Path "$target/.git") { + git -C $target pull --rebase --quiet 2>$null + if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: pull failed (using stale)" } + } else { + New-Item -ItemType Directory -Force -Path (Split-Path $target -Parent) | Out-Null + git clone --quiet --depth 1 --branch $ref $source $target 2>$null + if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: clone failed (unavailable)" } + } +} + +# Zone 3: Remote-opaque — fetch published contracts +foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-opaque" }) { + $squad = $entry.Name + $source = $entry.Value.source + $target = $entry.Value.sync_to + $auth = $entry.Value.auth + + New-Item -ItemType Directory -Force -Path $target | Out-Null + $params = @{ Uri = $source; OutFile = "$target/SUMMARY.md"; UseBasicParsing = $true } + if ($auth -eq "bearer") { + $tokenVar = ($squad.ToUpper() -replace '-', '_') + "_TOKEN" + $token = [Environment]::GetEnvironmentVariable($tokenVar) + if ($token) { $params.Headers = @{ Authorization = "Bearer $token" } } + } + try { Invoke-WebRequest @params -ErrorAction Stop } + catch { "# ${squad} — unavailable ($(Get-Date))" | Set-Content "$target/SUMMARY.md" } +} + +Write-Host "✓ Mesh sync complete" diff --git a/packages/squad-cli/templates/skills/distributed-mesh/sync-mesh.sh b/packages/squad-cli/templates/skills/distributed-mesh/sync-mesh.sh new file mode 100644 index 000000000..802fd2d8d --- /dev/null +++ b/packages/squad-cli/templates/skills/distributed-mesh/sync-mesh.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# sync-mesh.sh — Materialize remote squad state locally +# +# Reads mesh.json, fetches remote squads into local directories. +# Run before agent reads. No daemon. No service. ~40 lines. +# +# Usage: ./sync-mesh.sh [path-to-mesh.json] +# ./sync-mesh.sh --init [path-to-mesh.json] +# Requires: jq (https://github.com/jqlang/jq), git, curl + +set -euo pipefail + +# Handle --init mode +if [ "${1:-}" = "--init" ]; then + MESH_JSON="${2:-mesh.json}" + + if [ ! -f "$MESH_JSON" ]; then + echo "❌ $MESH_JSON not found" + exit 1 + fi + + echo "🚀 Initializing mesh state repository..." + squads=$(jq -r '.squads | keys[]' "$MESH_JSON") + + # Create squad directories with placeholder SUMMARY.md + for squad in $squads; do + if [ ! -d "$squad" ]; then + mkdir -p "$squad" + echo " ✓ Created $squad/" + else + echo " • $squad/ exists (skipped)" + fi + + if [ ! -f "$squad/SUMMARY.md" ]; then + echo -e "# $squad\n\n_No state published yet._" > "$squad/SUMMARY.md" + echo " ✓ Created $squad/SUMMARY.md" + else + echo " • $squad/SUMMARY.md exists (skipped)" + fi + done + + # Generate root README.md + if [ ! -f "README.md" ]; then + { + echo "# Squad Mesh State Repository" + echo "" + echo "This repository tracks published state from participating squads." + echo "" + echo "## Participating Squads" + echo "" + for squad in $squads; do + zone=$(jq -r ".squads.\"$squad\".zone" "$MESH_JSON") + echo "- **$squad** (Zone: $zone)" + done + echo "" + echo "Each squad directory contains a \`SUMMARY.md\` with their latest published state." + echo "State is synchronized using \`sync-mesh.sh\` or \`sync-mesh.ps1\`." + } > README.md + echo " ✓ Created README.md" + else + echo " • README.md exists (skipped)" + fi + + echo "" + echo "✅ Mesh state repository initialized" + exit 0 +fi + +MESH_JSON="${1:-mesh.json}" + +# Zone 2: Remote-trusted — git clone/pull +for squad in $(jq -r '.squads | to_entries[] | select(.value.zone == "remote-trusted") | .key' "$MESH_JSON"); do + source=$(jq -r ".squads.\"$squad\".source" "$MESH_JSON") + ref=$(jq -r ".squads.\"$squad\".ref // \"main\"" "$MESH_JSON") + target=$(jq -r ".squads.\"$squad\".sync_to" "$MESH_JSON") + + if [ -d "$target/.git" ]; then + git -C "$target" pull --rebase --quiet 2>/dev/null \ + || echo "⚠ $squad: pull failed (using stale)" + else + mkdir -p "$(dirname "$target")" + git clone --quiet --depth 1 --branch "$ref" "$source" "$target" 2>/dev/null \ + || echo "⚠ $squad: clone failed (unavailable)" + fi +done + +# Zone 3: Remote-opaque — fetch published contracts +for squad in $(jq -r '.squads | to_entries[] | select(.value.zone == "remote-opaque") | .key' "$MESH_JSON"); do + source=$(jq -r ".squads.\"$squad\".source" "$MESH_JSON") + target=$(jq -r ".squads.\"$squad\".sync_to" "$MESH_JSON") + auth=$(jq -r ".squads.\"$squad\".auth // \"\"" "$MESH_JSON") + + mkdir -p "$target" + auth_flag="" + if [ "$auth" = "bearer" ]; then + token_var="$(echo "${squad}" | tr '[:lower:]-' '[:upper:]_')_TOKEN" + [ -n "${!token_var:-}" ] && auth_flag="--header \"Authorization: Bearer ${!token_var}\"" + fi + + eval curl --silent --fail $auth_flag "$source" -o "$target/SUMMARY.md" 2>/dev/null \ + || echo "# ${squad} — unavailable ($(date))" > "$target/SUMMARY.md" +done + +echo "✓ Mesh sync complete" diff --git a/packages/squad-sdk/templates/skills/distributed-mesh/SKILL.md b/packages/squad-sdk/templates/skills/distributed-mesh/SKILL.md new file mode 100644 index 000000000..624db9626 --- /dev/null +++ b/packages/squad-sdk/templates/skills/distributed-mesh/SKILL.md @@ -0,0 +1,287 @@ +--- +name: "distributed-mesh" +description: "How to coordinate with squads on different machines using git as transport" +domain: "distributed-coordination" +confidence: "high" +source: "multi-model-consensus (Opus 4.6, Sonnet 4.5, GPT-5.4)" +--- + +## SCOPE + +**✅ THIS SKILL PRODUCES (exactly these, nothing more):** + +1. **`mesh.json`** — Generated from user answers about zones and squads (which squads participate, what zone each is in, paths/URLs for each), using `mesh.json.example` in this skill's directory as the schema template +2. **`sync-mesh.sh` and `sync-mesh.ps1`** — Copied from this skill's directory into the project root (these are bundled resources, NOT generated code) +3. **Zone 2 state repo initialization** (if applicable) — If the user specified a Zone 2 shared state repo, run `sync-mesh.sh --init` to scaffold the state repo structure +4. **A decision entry** in `.squad/decisions/inbox/` documenting the mesh configuration for team awareness + +**❌ THIS SKILL DOES NOT PRODUCE:** + +- **No application code** — No validators, libraries, or modules of any kind +- **No test files** — No test suites, test cases, or test scaffolding +- **No GENERATING sync scripts** — They are bundled with this skill as pre-built resources. COPY them, don't generate them. +- **No daemons or services** — No background processes, servers, or persistent runtimes +- **No modifications to existing squad files** beyond the decision entry (no changes to team.md, routing.md, agent charters, etc.) + +**Your role:** Configure the mesh topology and install the bundled sync scripts. Nothing more. + +## Context + +When squads are on different machines (developer laptops, CI runners, cloud VMs, partner orgs), the local file-reading convention still works — but remote files need to arrive on your disk first. This skill teaches the pattern for distributed squad communication. + +**When this applies:** +- Squads span multiple machines, VMs, or CI runners +- Squads span organizations or companies +- An agent needs context from a squad whose files aren't on the local filesystem + +**When this does NOT apply:** +- All squads are on the same machine (just read the files directly) + +## Patterns + +### The Core Principle + +> "The filesystem is the mesh, and git is how the mesh crosses machine boundaries." + +The agent interface never changes. Agents always read local files. The distributed layer's only job is to make remote files appear locally before the agent reads them. + +### Three Zones of Communication + +**Zone 1 — Local:** Same filesystem. Read files directly. Zero transport. + +**Zone 2 — Remote-Trusted:** Different host, same org, shared git auth. Transport: `git pull` from a shared repo. This collapses Zone 2 into Zone 1 — files materialize on disk, agent reads them normally. + +**Zone 3 — Remote-Opaque:** Different org, no shared auth. Transport: `curl` to fetch published contracts (SUMMARY.md). One-way visibility — you see only what they publish. + +### Agent Lifecycle (Distributed) + +``` +1. SYNC: git pull (Zone 2) + curl (Zone 3) — materialize remote state +2. READ: cat .mesh/**/state.md — all files are local now +3. WORK: do their assigned work (the agent's normal task, NOT mesh-building) +4. WRITE: update own billboard, log, drops +5. PUBLISH: git add + commit + push — share state with remote peers +``` + +Steps 2–4 are identical to local-only. Steps 1 and 5 are the entire distributed extension. **Note:** "WORK" means the agent performs its normal squad duties — it does NOT mean "build mesh infrastructure." + +### The mesh.json Config + +```json +{ + "squads": { + "auth-squad": { "zone": "local", "path": "../auth-squad/.mesh" }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "ref": "main", + "sync_to": ".mesh/remotes/ci-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.dev/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud", + "auth": "bearer" + } + } +} +``` + +Three zone types, one file. Local squads need only a path. Remote-trusted need a git URL. Remote-opaque need an HTTP URL. + +### Write Partitioning + +Each squad writes only to its own directory (`boards/{self}.md`, `squads/{self}/*`, `drops/{date}-{self}-*.md`). No two squads write to the same file. Git push/pull never conflicts. If push fails ("branch is behind"), the fix is always `git pull --rebase && git push`. + +### Trust Boundaries + +Trust maps to git permissions: +- **Same repo access** = full mesh visibility +- **Read-only access** = can observe, can't write +- **No access** = invisible (correct behavior) + +For selective visibility, use separate repos per audience (internal, partner, public). Git permissions ARE the trust negotiation. + +### Phased Rollout + +- **Phase 0:** Convention only — document zones, agree on mesh.json fields, manually run `git pull`/`git push`. Zero new code. +- **Phase 1:** Sync script (~30 lines bash or PowerShell) when manual sync gets tedious. +- **Phase 2:** Published contracts + curl fetch when a Zone 3 partner appears. +- **Phase 3:** Never. No MCP federation, A2A, service discovery, message queues. + +**Important:** Phases are NOT auto-advanced. These are project-level decisions — you start at Phase 0 (manual sync) and only move forward when the team decides complexity is justified. + +### Mesh State Repo + +The shared mesh state repo is a plain git repository — NOT a Squad project. It holds: +- One directory per participating squad +- Each directory contains at minimum a SUMMARY.md with the squad's current state +- A root README explaining what the repo is and who participates + +No `.squad/` folder, no agents, no automation. Write partitioning means each squad only pushes to its own directory. The repo is a rendezvous point, not an intelligent system. + +If you want a squad that *observes* mesh health, that's a separate Squad project that lists the state repo as a Zone 2 remote in its `mesh.json` — it does NOT live inside the state repo. + +## Examples + +### Developer Laptop + CI Squad (Zone 2) + +Auth-squad agent wakes up. `git pull` brings ci-squad's latest results. Agent reads: "3 test failures in auth module." Adjusts work. Pushes results when done. **Overhead: one `git pull`, one `git push`.** + +### Two Orgs Collaborating (Zone 3) + +Payment-squad fetches partner's published SUMMARY.md via curl. Reads: "Risk scoring v3 API deprecated April 15. New field `device_fingerprint` required." The consuming agent (in payment-squad's team) reads this information and uses it to inform its work — for example, updating payment integration code to include the new field. Partner can't see payment-squad's internals. + +### Same Org, Shared Mesh Repo (Zone 2) + +Three squads on different machines. One shared git repo holds the mesh. Each squad: `git pull` before work, `git push` after. Write partitioning ensures zero merge conflicts. + +## AGENT WORKFLOW (Deterministic Setup) + +When a user invokes this skill to set up a distributed mesh, follow these steps **exactly, in order:** + +### Step 1: ASK the user for mesh topology + +Ask these questions (adapt phrasing naturally, but get these answers): + +1. **Which squads are participating?** (List of squad names) +2. **For each squad, which zone is it in?** + - `local` — same filesystem (just need a path) + - `remote-trusted` — different machine, same org, shared git access (need git URL + ref) + - `remote-opaque` — different org, no shared auth (need HTTPS URL to published contract) +3. **For each squad, what's the connection info?** + - Local: relative or absolute path to their `.mesh/` directory + - Remote-trusted: git URL (SSH or HTTPS), ref (branch/tag), and where to sync it to locally + - Remote-opaque: HTTPS URL to their SUMMARY.md, where to sync it, and auth type (none/bearer) +4. **Where should the shared state live?** (For Zone 2 squads: git repo URL for the mesh state, or confirm each squad syncs independently) + +### Step 2: GENERATE `mesh.json` + +Using the answers from Step 1, create a `mesh.json` file at the project root. Use `mesh.json.example` from THIS skill's directory (`.squad/skills/distributed-mesh/mesh.json.example`) as the schema template. + +Structure: + +```json +{ + "squads": { + "": { "zone": "local", "path": "" }, + "": { + "zone": "remote-trusted", + "source": "", + "ref": "", + "sync_to": ".mesh/remotes/" + }, + "": { + "zone": "remote-opaque", + "source": "", + "sync_to": ".mesh/remotes/", + "auth": "" + } + } +} +``` + +Write this file to the project root. Do NOT write any other code. + +### Step 3: COPY sync scripts + +Copy the bundled sync scripts from THIS skill's directory into the project root: + +- **Source:** `.squad/skills/distributed-mesh/sync-mesh.sh` +- **Destination:** `sync-mesh.sh` (project root) + +- **Source:** `.squad/skills/distributed-mesh/sync-mesh.ps1` +- **Destination:** `sync-mesh.ps1` (project root) + +These are bundled resources. Do NOT generate them — COPY them directly. + +### Step 4: RUN `--init` (if Zone 2 state repo exists) + +If the user specified a Zone 2 shared state repo in Step 1, run the initialization: + +**On Unix/Linux/macOS:** +```bash +bash sync-mesh.sh --init +``` + +**On Windows:** +```powershell +.\sync-mesh.ps1 -Init +``` + +This scaffolds the state repo structure (squad directories, placeholder SUMMARY.md files, root README). + +**Skip this step if:** +- No Zone 2 squads are configured (local/opaque only) +- The state repo already exists and is initialized + +### Step 5: WRITE a decision entry + +Create a decision file at `.squad/decisions/inbox/-mesh-setup.md` with this content: + +```markdown +### : Mesh configuration + +**By:** (via distributed-mesh skill) + +**What:** Configured distributed mesh with squads across zones + +**Squads:** +- `` — Zone +- `` — Zone +- ... + +**State repo:** + +**Why:** +``` + +Write this file. The Scribe will merge it into the main decisions file later. + +### Step 6: STOP + +**You are done.** Do not: +- Generate sync scripts (they're bundled with this skill — COPY them) +- Write validator code +- Write test files +- Create any other modules, libraries, or application code +- Modify existing squad files (team.md, routing.md, charters) +- Auto-advance to Phase 2 or Phase 3 + +Output a simple completion message: + +``` +✅ Mesh configured. Created: +- mesh.json ( squads) +- sync-mesh.sh and sync-mesh.ps1 (copied from skill bundle) +- Decision entry: .squad/decisions/inbox/ + +Run `bash sync-mesh.sh` (or `.\sync-mesh.ps1` on Windows) before agents start to materialize remote state. +``` + +--- + +## Anti-Patterns + +**❌ Code generation anti-patterns:** +- Writing `mesh-config-validator.js` or any validator module +- Writing test files for mesh configuration +- Generating sync scripts instead of copying the bundled ones from this skill's directory +- Creating library modules or utilities +- Building any code that "runs the mesh" — the mesh is read by agents, not executed + +**❌ Architectural anti-patterns:** +- Building a federation protocol — Git push/pull IS federation +- Running a sync daemon or server — Agents are not persistent. Sync at startup, publish at shutdown +- Real-time notifications — Agents don't need real-time. They need "recent enough." `git pull` is recent enough +- Schema validation for markdown — The LLM reads markdown. If the format changes, it adapts +- Service discovery protocol — mesh.json is a file with 10 entries. Not a "discovery problem" +- Auth framework — Git SSH keys and HTTPS tokens. Not a framework. Already configured +- Message queues / event buses — Agents wake, read, work, write, sleep. Nobody's home to receive events +- Any component requiring a running process — That's the line. Don't cross it + +**❌ Scope creep anti-patterns:** +- Auto-advancing phases without user decision +- Modifying agent charters or routing rules +- Setting up CI/CD pipelines for mesh sync +- Creating dashboards or monitoring tools diff --git a/packages/squad-sdk/templates/skills/distributed-mesh/mesh.json.example b/packages/squad-sdk/templates/skills/distributed-mesh/mesh.json.example new file mode 100644 index 000000000..7f5730a88 --- /dev/null +++ b/packages/squad-sdk/templates/skills/distributed-mesh/mesh.json.example @@ -0,0 +1,30 @@ +{ + "squads": { + "auth-squad": { + "zone": "local", + "path": "../auth-squad/.mesh" + }, + "api-squad": { + "zone": "local", + "path": "../api-squad/.mesh" + }, + "ci-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/ci-squad.git", + "ref": "main", + "sync_to": ".mesh/remotes/ci-squad" + }, + "data-squad": { + "zone": "remote-trusted", + "source": "git@github.com:our-org/data-pipeline.git", + "ref": "main", + "sync_to": ".mesh/remotes/data-squad" + }, + "partner-fraud": { + "zone": "remote-opaque", + "source": "https://partner.example.com/squad-contracts/fraud/SUMMARY.md", + "sync_to": ".mesh/remotes/partner-fraud", + "auth": "bearer" + } + } +} diff --git a/packages/squad-sdk/templates/skills/distributed-mesh/sync-mesh.ps1 b/packages/squad-sdk/templates/skills/distributed-mesh/sync-mesh.ps1 new file mode 100644 index 000000000..5f409ef37 --- /dev/null +++ b/packages/squad-sdk/templates/skills/distributed-mesh/sync-mesh.ps1 @@ -0,0 +1,111 @@ +# sync-mesh.ps1 — Materialize remote squad state locally +# +# Reads mesh.json, fetches remote squads into local directories. +# Run before agent reads. No daemon. No service. ~40 lines. +# +# Usage: .\sync-mesh.ps1 [path-to-mesh.json] +# .\sync-mesh.ps1 -Init [path-to-mesh.json] +# Requires: git +param( + [switch]$Init, + [string]$MeshJson = "mesh.json" +) +$ErrorActionPreference = "Stop" + +# Handle -Init mode +if ($Init) { + if (-not (Test-Path $MeshJson)) { + Write-Host "❌ $MeshJson not found" + exit 1 + } + + Write-Host "🚀 Initializing mesh state repository..." + $config = Get-Content $MeshJson -Raw | ConvertFrom-Json + $squads = $config.squads.PSObject.Properties.Name + + # Create squad directories with placeholder SUMMARY.md + foreach ($squad in $squads) { + if (-not (Test-Path $squad)) { + New-Item -ItemType Directory -Path $squad | Out-Null + Write-Host " ✓ Created $squad/" + } else { + Write-Host " • $squad/ exists (skipped)" + } + + $summaryPath = "$squad/SUMMARY.md" + if (-not (Test-Path $summaryPath)) { + "# $squad`n`n_No state published yet._" | Set-Content $summaryPath + Write-Host " ✓ Created $summaryPath" + } else { + Write-Host " • $summaryPath exists (skipped)" + } + } + + # Generate root README.md + if (-not (Test-Path "README.md")) { + $readme = @" +# Squad Mesh State Repository + +This repository tracks published state from participating squads. + +## Participating Squads + +"@ + foreach ($squad in $squads) { + $zone = $config.squads.$squad.zone + $readme += "- **$squad** (Zone: $zone)`n" + } + $readme += @" + +Each squad directory contains a ``SUMMARY.md`` with their latest published state. +State is synchronized using ``sync-mesh.sh`` or ``sync-mesh.ps1``. +"@ + $readme | Set-Content "README.md" + Write-Host " ✓ Created README.md" + } else { + Write-Host " • README.md exists (skipped)" + } + + Write-Host "" + Write-Host "✅ Mesh state repository initialized" + exit 0 +} + +$config = Get-Content $MeshJson -Raw | ConvertFrom-Json + +# Zone 2: Remote-trusted — git clone/pull +foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-trusted" }) { + $squad = $entry.Name + $source = $entry.Value.source + $ref = if ($entry.Value.ref) { $entry.Value.ref } else { "main" } + $target = $entry.Value.sync_to + + if (Test-Path "$target/.git") { + git -C $target pull --rebase --quiet 2>$null + if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: pull failed (using stale)" } + } else { + New-Item -ItemType Directory -Force -Path (Split-Path $target -Parent) | Out-Null + git clone --quiet --depth 1 --branch $ref $source $target 2>$null + if ($LASTEXITCODE -ne 0) { Write-Host "⚠ ${squad}: clone failed (unavailable)" } + } +} + +# Zone 3: Remote-opaque — fetch published contracts +foreach ($entry in $config.squads.PSObject.Properties | Where-Object { $_.Value.zone -eq "remote-opaque" }) { + $squad = $entry.Name + $source = $entry.Value.source + $target = $entry.Value.sync_to + $auth = $entry.Value.auth + + New-Item -ItemType Directory -Force -Path $target | Out-Null + $params = @{ Uri = $source; OutFile = "$target/SUMMARY.md"; UseBasicParsing = $true } + if ($auth -eq "bearer") { + $tokenVar = ($squad.ToUpper() -replace '-', '_') + "_TOKEN" + $token = [Environment]::GetEnvironmentVariable($tokenVar) + if ($token) { $params.Headers = @{ Authorization = "Bearer $token" } } + } + try { Invoke-WebRequest @params -ErrorAction Stop } + catch { "# ${squad} — unavailable ($(Get-Date))" | Set-Content "$target/SUMMARY.md" } +} + +Write-Host "✓ Mesh sync complete" diff --git a/packages/squad-sdk/templates/skills/distributed-mesh/sync-mesh.sh b/packages/squad-sdk/templates/skills/distributed-mesh/sync-mesh.sh new file mode 100644 index 000000000..802fd2d8d --- /dev/null +++ b/packages/squad-sdk/templates/skills/distributed-mesh/sync-mesh.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# sync-mesh.sh — Materialize remote squad state locally +# +# Reads mesh.json, fetches remote squads into local directories. +# Run before agent reads. No daemon. No service. ~40 lines. +# +# Usage: ./sync-mesh.sh [path-to-mesh.json] +# ./sync-mesh.sh --init [path-to-mesh.json] +# Requires: jq (https://github.com/jqlang/jq), git, curl + +set -euo pipefail + +# Handle --init mode +if [ "${1:-}" = "--init" ]; then + MESH_JSON="${2:-mesh.json}" + + if [ ! -f "$MESH_JSON" ]; then + echo "❌ $MESH_JSON not found" + exit 1 + fi + + echo "🚀 Initializing mesh state repository..." + squads=$(jq -r '.squads | keys[]' "$MESH_JSON") + + # Create squad directories with placeholder SUMMARY.md + for squad in $squads; do + if [ ! -d "$squad" ]; then + mkdir -p "$squad" + echo " ✓ Created $squad/" + else + echo " • $squad/ exists (skipped)" + fi + + if [ ! -f "$squad/SUMMARY.md" ]; then + echo -e "# $squad\n\n_No state published yet._" > "$squad/SUMMARY.md" + echo " ✓ Created $squad/SUMMARY.md" + else + echo " • $squad/SUMMARY.md exists (skipped)" + fi + done + + # Generate root README.md + if [ ! -f "README.md" ]; then + { + echo "# Squad Mesh State Repository" + echo "" + echo "This repository tracks published state from participating squads." + echo "" + echo "## Participating Squads" + echo "" + for squad in $squads; do + zone=$(jq -r ".squads.\"$squad\".zone" "$MESH_JSON") + echo "- **$squad** (Zone: $zone)" + done + echo "" + echo "Each squad directory contains a \`SUMMARY.md\` with their latest published state." + echo "State is synchronized using \`sync-mesh.sh\` or \`sync-mesh.ps1\`." + } > README.md + echo " ✓ Created README.md" + else + echo " • README.md exists (skipped)" + fi + + echo "" + echo "✅ Mesh state repository initialized" + exit 0 +fi + +MESH_JSON="${1:-mesh.json}" + +# Zone 2: Remote-trusted — git clone/pull +for squad in $(jq -r '.squads | to_entries[] | select(.value.zone == "remote-trusted") | .key' "$MESH_JSON"); do + source=$(jq -r ".squads.\"$squad\".source" "$MESH_JSON") + ref=$(jq -r ".squads.\"$squad\".ref // \"main\"" "$MESH_JSON") + target=$(jq -r ".squads.\"$squad\".sync_to" "$MESH_JSON") + + if [ -d "$target/.git" ]; then + git -C "$target" pull --rebase --quiet 2>/dev/null \ + || echo "⚠ $squad: pull failed (using stale)" + else + mkdir -p "$(dirname "$target")" + git clone --quiet --depth 1 --branch "$ref" "$source" "$target" 2>/dev/null \ + || echo "⚠ $squad: clone failed (unavailable)" + fi +done + +# Zone 3: Remote-opaque — fetch published contracts +for squad in $(jq -r '.squads | to_entries[] | select(.value.zone == "remote-opaque") | .key' "$MESH_JSON"); do + source=$(jq -r ".squads.\"$squad\".source" "$MESH_JSON") + target=$(jq -r ".squads.\"$squad\".sync_to" "$MESH_JSON") + auth=$(jq -r ".squads.\"$squad\".auth // \"\"" "$MESH_JSON") + + mkdir -p "$target" + auth_flag="" + if [ "$auth" = "bearer" ]; then + token_var="$(echo "${squad}" | tr '[:lower:]-' '[:upper:]_')_TOKEN" + [ -n "${!token_var:-}" ] && auth_flag="--header \"Authorization: Bearer ${!token_var}\"" + fi + + eval curl --silent --fail $auth_flag "$source" -o "$target/SUMMARY.md" 2>/dev/null \ + || echo "# ${squad} — unavailable ($(date))" > "$target/SUMMARY.md" +done + +echo "✓ Mesh sync complete" diff --git a/scripts/sync-skill-templates.mjs b/scripts/sync-skill-templates.mjs new file mode 100644 index 000000000..fc685e089 --- /dev/null +++ b/scripts/sync-skill-templates.mjs @@ -0,0 +1,56 @@ +#!/usr/bin/env node + +import { readdirSync, cpSync, existsSync, statSync } from 'fs'; +import { join } from 'path'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const rootDir = join(__dirname, '..'); + +const skillsSourceDir = join(rootDir, '.squad', 'skills'); +const targets = [ + join(rootDir, 'packages', 'squad-cli', 'templates', 'skills'), + join(rootDir, 'packages', 'squad-sdk', 'templates', 'skills') +]; + +console.log('🔄 Syncing skill templates from canonical source...\n'); + +if (!existsSync(skillsSourceDir)) { + console.error(`❌ Source directory not found: ${skillsSourceDir}`); + process.exit(1); +} + +const skillDirs = readdirSync(skillsSourceDir).filter(name => { + const fullPath = join(skillsSourceDir, name); + return statSync(fullPath).isDirectory(); +}); + +if (skillDirs.length === 0) { + console.log('⚠️ No skills found in source directory'); + process.exit(0); +} + +console.log(`📁 Found ${skillDirs.length} skill(s): ${skillDirs.join(', ')}\n`); + +for (const target of targets) { + console.log(`📦 Syncing to: ${target}`); + + for (const skillName of skillDirs) { + const sourcePath = join(skillsSourceDir, skillName); + const destPath = join(target, skillName); + + try { + cpSync(sourcePath, destPath, { recursive: true, force: true }); + console.log(` ✅ ${skillName}`); + } catch (err) { + console.error(` ❌ ${skillName}: ${err.message}`); + process.exit(1); + } + } + + console.log(''); +} + +console.log('✅ Skill template sync complete'); diff --git a/test/docs-build.test.ts b/test/docs-build.test.ts index 5c10ddfc9..39568b700 100644 --- a/test/docs-build.test.ts +++ b/test/docs-build.test.ts @@ -21,7 +21,7 @@ const EXPECTED_GUIDES = ['tips-and-tricks', 'sample-prompts', 'personal-squad', const EXPECTED_REFERENCE = ['cli', 'sdk', 'config', 'api-reference', 'integration', 'tools-and-hooks']; -const EXPECTED_SCENARIOS = [ +const EXPECTED_SCENARIOS= [ 'aspire-dashboard', 'ci-cd-integration', 'client-compatibility', @@ -54,6 +54,7 @@ const EXPECTED_FEATURES = [ 'consult-mode', 'copilot-coding-agent', 'directives', + 'distributed-mesh', 'enterprise-platforms', 'export-import', 'github-issues', @@ -110,7 +111,7 @@ function getMarkdownFiles(section: string): string[] { } function getAllMarkdownFiles(): string[] { - const sections = ['get-started', 'guide', 'reference', 'scenarios']; + const sections = ['get-started', 'guide', 'features', 'reference', 'scenarios', 'concepts']; const allFiles: string[] = []; for (const section of sections) { allFiles.push(...getMarkdownFiles(section)); @@ -144,6 +145,16 @@ describe('Docs Structure Validation', () => { expect(files.length).toBe(EXPECTED_GUIDES.length); }); + it('features directory contains all expected markdown files', () => { + const featuresDir = join(DOCS_CONTENT_DIR, 'features'); + expect(existsSync(featuresDir)).toBe(true); + const files = readdirSync(featuresDir).filter(f => f.endsWith('.md')).map(f => f.replace('.md', '')); + for (const feature of EXPECTED_FEATURES) { + expect(files).toContain(feature); + } + expect(files.length).toBe(EXPECTED_FEATURES.length); + }); + it('all markdown files have proper headings', () => { for (const file of getAllMarkdownFiles()) { const content = readFile(file); @@ -234,6 +245,7 @@ describe('Docs Build Script (Astro)', () => { const allExpected = [ ...EXPECTED_GET_STARTED.map(n => ({ dir: 'get-started', name: n })), ...EXPECTED_GUIDES.map(n => ({ dir: 'guide', name: n })), + ...EXPECTED_FEATURES.map(n => ({ dir: 'features', name: n })), ...EXPECTED_REFERENCE.map(n => ({ dir: 'reference', name: n })), ...EXPECTED_SCENARIOS.map(n => ({ dir: 'scenarios', name: n })), ...EXPECTED_FEATURES.map(n => ({ dir: 'features', name: n })),