diff --git a/docs/src/content/docs/concepts/architecture.md b/docs/src/content/docs/concepts/architecture.md index b0ea9739d..54eaa1298 100644 --- a/docs/src/content/docs/concepts/architecture.md +++ b/docs/src/content/docs/concepts/architecture.md @@ -1,71 +1,49 @@ -# Architecture - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - -How Squad works — one page, no handwaving. - ---- - -## System diagram - -``` -User request - ↓ -Coordinator (routing engine) - ↓ -Spawns agents in parallel - ↓ -Agents read memory (.squad/) → work → write results - ↓ -Scribe merges decisions, Ralph tracks issues - ↓ -Results returned to user -``` - ---- - -## Components - -### Coordinator - -The coordinator is Squad's routing engine. It reads your request, checks routing rules in `.squad/routing.md`, and decides which agents to spawn. If you say "team," it decomposes the work and launches multiple agents in parallel. If you name an agent, it routes directly to them. - -### Agents - -Each agent is a specialist with a charter, role, and persistent memory. Agents are spawned as independent subprocesses with their own context windows and tools. They read `.squad/decisions.md` and their own history before working, then write results back. Agents never see each other's conversations — the coordinator orchestrates coordination. - -### Memory (.squad/) - -All team state lives in `.squad/`. This includes the roster (`team.md`), routing rules (`routing.md`), decisions (`decisions.md`), agent charters and histories (`agents/`), and ceremony schedules (`ceremonies.md`). Agents read this before every spawn. You own these files — edit them anytime. - -### Routing - -Routing rules in `.squad/routing.md` define which agent handles which work. The coordinator reads these rules before spawning. You can override routing by naming an agent directly in your request. - -### Scribe - -The Scribe is a silent agent that tracks decisions and logs sessions. Every team has a Scribe. You never talk to them directly — they work in the background, merging decisions from all agents into `.squad/decisions.md`. - -### Ralph - -Ralph is the work monitor. He watches your GitHub or GitLab issues, tracks work in progress, and alerts the team when something is ready. Every team has a Ralph. He's silent unless you ask him for status. - ---- - -## What happens when you say "Team, build X"? - -1. **Coordinator reads the request** and checks `.squad/routing.md` for decomposition rules. -2. **Coordinator spawns multiple agents in parallel** — one for frontend, one for backend, one for tests, etc. -3. **Each agent reads `.squad/decisions.md`** and their own history (`agents/{name}/history.md`), then works independently. -4. **Agents write results** to their history files and propose decisions. -5. **Scribe merges all decisions** into `.squad/decisions.md`. -6. **Coordinator returns labeled results** to you, tagged with each agent's name. - ---- - -## Learn more - -- [**Your Team**](./your-team.md) — How agents form, specialize, and work together -- [**Work routing**](../features/routing.md) — How the coordinator decides which agents to spawn -- [**Memory and knowledge**](memory-and-knowledge.md) — How decisions, skills, and history persist -- [**Parallel work**](parallel-work.md) — How agents work simultaneously without conflicts +# Architecture +How Squad works — one page, no handwaving. + +--- +## System diagram +``` +User request + ↓ +Coordinator (routing engine) + ↓ +Spawns agents in parallel + ↓ +Agents read memory (.squad/) → work → write results + ↓ +Scribe merges decisions, Ralph tracks issues + ↓ +Results returned to user +``` + +--- +## Components +### Coordinator +The coordinator is Squad's routing engine. It reads your request, checks routing rules in `.squad/routing.md`, and decides which agents to spawn. If you say "team," it decomposes the work and launches multiple agents in parallel. If you name an agent, it routes directly to them. +### Agents +Each agent is a specialist with a charter, role, and persistent memory. Agents are spawned as independent subprocesses with their own context windows and tools. They read `.squad/decisions.md` and their own history before working, then write results back. Agents never see each other's conversations — the coordinator orchestrates coordination. +### Memory (.squad/) +All team state lives in `.squad/`. This includes the roster (`team.md`), routing rules (`routing.md`), decisions (`decisions.md`), agent charters and histories (`agents/`), and ceremony schedules (`ceremonies.md`). Agents read this before every spawn. You own these files — edit them anytime. +### Routing +Routing rules in `.squad/routing.md` define which agent handles which work. The coordinator reads these rules before spawning. You can override routing by naming an agent directly in your request. +### Scribe +The Scribe is a silent agent that tracks decisions and logs sessions. Every team has a Scribe. You never talk to them directly — they work in the background, merging decisions from all agents into `.squad/decisions.md`. +### Ralph +Ralph is the work monitor. He watches your GitHub or GitLab issues, tracks work in progress, and alerts the team when something is ready. Every team has a Ralph. He's silent unless you ask him for status. + +--- +## What happens when you say "Team, build X"? +1. **Coordinator reads the request** and checks `.squad/routing.md` for decomposition rules. +2. **Coordinator spawns multiple agents in parallel** — one for frontend, one for backend, one for tests, etc. +3. **Each agent reads `.squad/decisions.md`** and their own history (`agents/{name}/history.md`), then works independently. +4. **Agents write results** to their history files and propose decisions. +5. **Scribe merges all decisions** into `.squad/decisions.md`. +6. **Coordinator returns labeled results** to you, tagged with each agent's name. + +--- +## Learn more +- [**Your Team**](./your-team.md) — How agents form, specialize, and work together +- [**Work routing**](../features/routing.md) — How the coordinator decides which agents to spawn +- [**Memory and knowledge**](memory-and-knowledge.md) — How decisions, skills, and history persist +- [**Parallel work**](parallel-work.md) — How agents work simultaneously without conflicts diff --git a/docs/src/content/docs/concepts/github-workflow.md b/docs/src/content/docs/concepts/github-workflow.md index 5bbd4826e..2a5c9b269 100644 --- a/docs/src/content/docs/concepts/github-workflow.md +++ b/docs/src/content/docs/concepts/github-workflow.md @@ -1,32 +1,21 @@ # GitHub Integration - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - Squad plugs directly into your GitHub workflow — issues become branches, branches become PRs, PRs become merged code. No context-switching, no copy-paste, no ticket juggling. Just tell your squad what to build and watch the commits roll in. --- - ## Try This - ``` Connect to myorg/myrepo and show me the backlog ``` - ``` Work on issue #42 ``` - ``` Ralph, go — process the backlog until it's clear ``` --- - ## How It Works - The lifecycle is simple: **connect → backlog → work → PR → merge**. - ``` Connect repo → Show backlog → Assign issues → Agent branches + implements ↓ @@ -46,13 +35,9 @@ Connect repo → Show backlog → Assign issues → Agent branches + imple **Prerequisite:** Install and authenticate the `gh` CLI (`gh auth login`). Squad uses it for all GitHub operations. --- - ## Working with your team - Squad is built for mixed teams — humans set direction, AI agents execute and report back. The Lead agent bridges between them, routing work and surfacing decisions when a human needs to act. - ### Humans in the lifecycle - The following is **one example** of how a mixed team might divide responsibilities. Your team decides its own process — use [ceremonies](../features/ceremonies.md) and [directives](../features/human-team-members.md) to shape the workflow that fits. | Stage | Who acts | What happens | @@ -64,17 +49,12 @@ The following is **one example** of how a mixed team might divide responsibiliti | **Merge** | Human or Ralph | Squash-merge, branch cleanup, issue closed | This is a starting point. Define your own checkpoints by configuring [ceremonies](../features/ceremonies.md) and capturing [directives](../features/human-team-members.md). - For details on how work routes to humans, see [Human team members](../features/human-team-members.md). - For ceremony details, see [Ceremonies](../features/ceremonies.md). - For agent anatomy and how each team member (AI, human, @copilot) is structured, see [your-team.md](your-team.md). --- - ## Label Taxonomy - Labels aren't just tags — they're Squad's **state machine**. Five namespaces drive workflow automation, routing, and lifecycle tracking. | Namespace | Purpose | Example Values | Mutual Exclusivity | @@ -88,16 +68,12 @@ Labels aren't just tags — they're Squad's **state machine**. Five namespaces d Within `go:`, `release:`, `type:`, and `priority:`, applying a second label **auto-removes** the first. The `squad:{member}` namespace allows multiple labels for collaborative work. ### How Labels Drive Automation - Labels power four automation layers: - 1. **Enforcement** — `label-enforcement.yml` watches for changes and removes duplicates within a namespace. 2. **Sync** — Cross-namespace cascading: `go:no` → auto-adds `release:backlog`; `priority:p0` → ensures `go:yes`. 3. **Triage** — Ralph uses labels to route work: `squad:fenster` → Fenster picks it up; no `squad:*` + `type:bug` → routes based on `routing.md`. 4. **Heartbeat** — `squad-heartbeat.yml` runs every 30 minutes, auto-triaging unassigned issues and escalating stale research. - ### State Machine Flow - ```mermaid graph TD A["New issue"] --> B["squad label"] @@ -112,19 +88,14 @@ graph TD I -->|No| H J --> K["Issue closed"] ``` - Labels are created automatically during `init` or `upgrade`. Add custom labels with: - ```bash gh label create "squad:designer" --color "0366d6" --description "Work assigned to Designer" ``` --- - ## Ralph — Work Monitor - Ralph is a built-in squad member who tracks the work queue, monitors CI status, and keeps the team moving. He's always on the roster — no casting required. - ### Talking to Ralph | You say | What happens | @@ -153,34 +124,26 @@ Ralph **never stops on his own while work remains** — he keeps cycling until t |-------|------|-----| | **In-session** | You're at the keyboard | `"Ralph, go"` — active loop | | **Local watchdog** | You're AFK but machine is on | `squad watch --interval 10` | -| **Cloud heartbeat** | Fully unattended | `squad-heartbeat.yml` GitHub Actions events | +| **Cloud heartbeat** | Event-driven | `squad-heartbeat.yml` GitHub Actions events | The heartbeat workflow (`squad-heartbeat.yml`) is installed during `init` or `upgrade`. It runs on issue close, PR merge, and manual dispatch. Edit the workflow in `.github/workflows/squad-heartbeat.yml` to customize triggers. For periodic polling without events, use `squad watch` locally. - **PAT requirement:** Ralph needs `gh` CLI authenticated with a Classic PAT (scopes: `repo` and `project`). The default `GITHUB_TOKEN` doesn't have sufficient scopes. --- - ## PRD Mode - Got a product spec? Hand it to Squad and the Lead decomposes it into prioritized, dependency-tracked work items. - ``` Read the PRD at docs/product-spec.md and break it into work items ``` - The Lead agent: 1. Decomposes the spec into discrete work items (WI-1, WI-2, etc.) 2. Assigns priorities: P0 (must-have), P1 (important), P2 (nice-to-have) 3. Routes items to agents based on domain expertise 4. Tracks dependencies — won't start WI-4 if it depends on WI-2 - Independent items run in parallel. When requirements change, give Squad the updated PRD — the Lead diffs against existing items and adjusts the backlog without undoing completed work. --- - ## Project Boards - Squad integrates with GitHub Projects V2 for visual workflow tracking. **Labels are the source of truth** — boards are one-way projections that visualize the state machine. | Board Column | Label State | @@ -192,21 +155,15 @@ Squad integrates with GitHub Projects V2 for visual workflow tracking. **Labels | **Done** | Issue closed | Board sync runs on label changes, issue close, PR merge, and a 30-minute schedule. Dragging an issue on the board triggers a webhook that applies the corresponding label. - **Status:** Label-based state machine is fully implemented. Automated board sync workflows are in development for v0.4.0. You can use `gh project` commands now — full automation is coming. --- - ## Notifications - Your squad pings you when they need input, hit an error, or finish work. Squad uses MCP-based notification servers — you bring your own delivery channel. - See the [Notifications Guide](../features/notifications.md) for [platform setup](../features/notifications.md#quick-start-teams-simplest-path) (Teams, Discord, iMessage, webhooks), [trigger configuration](../features/notifications.md#what-triggers-a-notification), and [sample MCP configs](../features/notifications.md#sample-mcp-configs). --- - ## Tips - - You don't need to assign issues to agents — Squad routes based on domain expertise defined in charters and `routing.md`. - If `gh` isn't authenticated, Squad will tell you. Run `gh auth login` first. - Use `priority:p0` to fast-track critical items — it auto-sets `go:yes`. @@ -214,61 +171,42 @@ See the [Notifications Guide](../features/notifications.md) for [platform setup] - Ralph's in-session loop is session-scoped — state resets between sessions. Use `squad watch` or the heartbeat for persistent monitoring. --- - ## Sample Prompts - ``` connect to bradygaster/squad and show me the backlog ``` - Links Squad to a GitHub repo and displays all open issues. - ``` work on all issues labeled "bug" ``` - Processes multiple bug issues in parallel — each gets its own branch and PR. - ``` mark issue #42 as approved for v0.4.0 ``` - Applies `go:yes` and `release:v0.4.0` labels, removing any conflicting labels. - ``` Ralph, go — start monitoring and process the backlog until it's clear ``` - Activates Ralph's self-chaining loop to continuously triage, assign, and process work. - ``` read the PRD at docs/product-spec.md and break it into work items ``` - Ingests a product spec and creates a prioritized, dependency-tracked backlog. - ``` there's review feedback on PR #24 ``` - The author agent reads review comments and pushes fixes to the existing branch. - ``` list all p0 features approved for the next release ``` - Queries issues with `priority:p0 + type:feature + go:yes + release:{current milestone}`. - ``` squad watch --interval 5 ``` - Starts persistent local polling — checks GitHub every 5 minutes for new work and triages automatically. --- - ## See Also - - [Your Team](./your-team.md) — How work routes to the right agent - [Work Routing](../features/routing.md) — Domain routing and agent assignment - [Parallel Work](./parallel-work.md) — Multi-agent parallel execution on batched issues diff --git a/docs/src/content/docs/concepts/memory-and-knowledge.md b/docs/src/content/docs/concepts/memory-and-knowledge.md index f5fda72c6..877f7880e 100644 --- a/docs/src/content/docs/concepts/memory-and-knowledge.md +++ b/docs/src/content/docs/concepts/memory-and-knowledge.md @@ -1,32 +1,21 @@ # Memory & Knowledge - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - Squad remembers everything — coding conventions, architecture decisions, deployment patterns, your personal preferences. Memory grows with every session, compounding across three layers so agents stop making the same mistakes and start anticipating your needs. --- - ## Try This - ``` Always use single quotes in TypeScript ``` - ``` What decisions has the team made about testing strategy? ``` - ``` Show me what skills this team has learned ``` --- - ## How It Works - Memory lives in three layers, each serving a different purpose: - ```mermaid graph TD A["Skills Layer
.copilot/skills/{name}/SKILL.md
Reusable patterns • Portable
How to set up CI with GitHub Actions"] @@ -36,7 +25,6 @@ graph TD A --> B B --> C ``` - ### How Memory Compounds | Stage | What Agents Know | @@ -48,37 +36,23 @@ graph TD The first session is always the least capable. Give the team a few sessions to build up context — they'll stop asking questions they've already answered. --- - ## Personal Memory: `history.md` - Each agent has its own history file at `.squad/agents/{name}/history.md`. After every session, agents append what they learned — architecture decisions, conventions, file paths, user preferences. - **Only that agent reads its own history.** This means each team member builds specialized knowledge about their domain. Kane learns the auth system inside and out. Dallas masters the component library. Lambert memorizes the test infrastructure. - ### Progressive Summarization - When an agent's `history.md` exceeds ~12KB, older entries get archived into a summary section. Recent entries stay detailed; older entries condense. This keeps files within a useful context budget without losing accumulated knowledge. --- - ## Shared Decisions: `decisions.md` - Team-wide decisions live in `.squad/decisions.md`. **Every agent reads this before working.** This is the team's shared brain. - Decisions get captured three ways: - 1. **From agent work** — agents write to `.squad/decisions/inbox/{agent-name}-{slug}.md` 2. **From your directives** — when you say "always…" or "never…" (see below) 3. **From Scribe merges** — the Scribe agent periodically consolidates inbox files into the canonical `decisions.md`, deduplicating overlapping entries - ### Decision Archiving - As your project grows, `decisions.md` accumulates hundreds of blocks. Stale sprint artifacts and one-time planning fragments consume context without adding value. When this happens, old decisions archive to `.squad/decisions-archive.md` — preserved for reference but no longer loaded into agent context. - Active decisions (ongoing policies, user preferences, current architecture) stay in `decisions.md`. Agents always read the lean, current shared brain. - ### Memory Architecture - ``` .squad/ ├── decisions.md # Shared — all agents read @@ -99,13 +73,9 @@ Active decisions (ongoing policies, user preferences, current architecture) stay ``` --- - ## Directives - Directives are team rules that persist across sessions. Say "always" or "never" and Squad captures it permanently. Every agent reads directives before working. - ### Signal Word Detection - The coordinator listens for these phrases and captures them as directives: | Phrase | Example | @@ -118,7 +88,6 @@ The coordinator listens for these phrases and captures them as directives: | `"make sure to"` | "Make sure to document all public APIs" | ### Capture Flow - ```mermaid sequenceDiagram participant You @@ -134,49 +103,33 @@ sequenceDiagram Scribe->>Agents: decisions.md updated Agents->>Agents: All agents read before next task ``` - ### Directive Scope - Directives can shape: - - **Coding style** — formatting, naming conventions, language features - **Tool preferences** — linters, formatters, test runners - **Workflow rules** — branch naming, commit messages, PR templates - **Scope constraints** — "Don't touch legacy/ directory" - **Review requirements** — "Always have Lead review security changes" - ### Directive Conflicts - When a new directive contradicts an existing one, the Scribe detects the overlap and asks you: "Replace, merge, or skip?" You decide, and `decisions.md` updates accordingly. - ### Viewing and Removing Directives - ``` Show me the team directives ``` - ``` What's our rule on testing? ``` - ``` Remove the no-Friday-deploy rule ``` - You can also edit `.squad/decisions.md` directly — it's plain Markdown. - ### Compliance - Directives are context-aware guidelines, not hard constraints. If an agent violates one, the [reviewer protocol](your-team.md#reviewer-protocol) catches it during review, or you flag it directly. --- - ## Skills - Skills are reusable knowledge files that live at `.copilot/skills/{skill-name}/SKILL.md`. Unlike decisions (project policies like "use PostgreSQL"), skills are transferable techniques ("how to set up CI with GitHub Actions"). - **All agents can read any skill.** Skills are team-wide knowledge, not per-agent. - ### Starter vs. Earned | Type | Source | Example | @@ -187,7 +140,6 @@ Skills are reusable knowledge files that live at `.copilot/skills/{skill-name}/S Starter skills are overwritten on upgrade. Earned skills are never touched. ### Confidence Lifecycle - Earned skills have a confidence level reflecting how battle-tested they are: | Level | Meaning | @@ -199,19 +151,14 @@ Earned skills have a confidence level reflecting how battle-tested they are: Confidence only goes up, never down. A skill that reaches `high` stays there. ### How Skills Get Used - 1. **Before working** — agents read skill files relevant to the task 2. **During routing** — the coordinator checks skills when deciding who to spawn (an agent with a relevant earned skill may be preferred) 3. **After working** — agents may write new skills or update existing ones based on what they learned - ### Portability - Skills export and import with your team. Move a trained team to a new repo, and all their earned knowledge comes along. This makes skills the most portable form of [team](your-team.md) intelligence. --- - ## Knowledge persistence - Not all knowledge in `.squad/` lasts forever. When files grow large, Squad compacts them to keep performance fast. Here's what persists and what gets summarized: | What | File | Compacted? | Where old content goes | Who reads it | @@ -230,9 +177,7 @@ Knowledge that needs to survive compaction belongs in **skills**. Reusable patte > 💡 **Where to store permanent knowledge:** Put reusable patterns and techniques in `.copilot/skills/`. Put team rules and preferences in directives (they persist in `decisions.md`). For org-wide knowledge that multiple teams need, use [upstream inheritance](/features/upstream-inheritance) to share a skills library. --- - ## Tips - - **Commit `.squad/`** — anyone who clones the repo gets the team with all their accumulated knowledge. - Directives ("always…", "never…") are the fastest way to shape team behavior. Use them liberally. - If an agent keeps making the same mistake, check `decisions.md` — the relevant convention might be missing. @@ -240,61 +185,42 @@ Knowledge that needs to survive compaction belongs in **skills**. Reusable patte - Manually seed skills by pasting your existing conventions into a `SKILL.md` — instant team knowledge. --- - ## Sample Prompts - ``` Always use Prettier with single quotes and no semicolons ``` - Creates a coding style directive all agents will follow. - ``` From now on, all commit messages must follow Conventional Commits format ``` - Sets a workflow directive — agents format commits as `feat:`, `fix:`, `docs:`, etc. - ``` What does Kane remember about the authentication system? ``` - Queries Kane's personal `history.md` for relevant context. - ``` Show me the team decisions about API design ``` - Searches `decisions.md` for a particular topic. - ``` Create a skill for our deployment process ``` - Manually creates a new skill file and guides you through documenting the pattern. - ``` Which skills have low confidence? ``` - Finds recently-created skills that haven't been validated across multiple contexts yet. - ``` Never use `any` type in TypeScript — always define explicit types ``` - Establishes a type safety directive. Agents will avoid `any` and use proper types. - ``` Search past decisions for database choices ``` - Finds historical decisions related to a specific topic or keyword. --- - ## See Also - - [Your Team](./your-team.md) — How agents use shared memory to coordinate - [Architecture](./architecture.md) — How the coordinator and agents share state - [Parallel Work](./parallel-work.md) — How agents maintain consistency while working in parallel diff --git a/docs/src/content/docs/concepts/parallel-work.md b/docs/src/content/docs/concepts/parallel-work.md index 999a3fba7..966126d40 100644 --- a/docs/src/content/docs/concepts/parallel-work.md +++ b/docs/src/content/docs/concepts/parallel-work.md @@ -1,32 +1,21 @@ # Parallel Work & Models - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - Squad launches independent work in parallel by default — multiple agents working simultaneously, no waiting. It also picks the right AI model for each agent based on what they're doing, so you get quality where it counts and speed everywhere else. --- - ## Try This - ``` Have three agents work on this in parallel: UI mockups, API spec, and database schema ``` - ``` Use Sonnet for code, Haiku for everything else ``` - ``` Work on issues #12, #15, and #18 at the same time ``` --- - ## How Parallel Execution Works - When the coordinator receives a multi-part task, it follows a fan-out pattern: - ```mermaid graph TD A["Coordinator
receives work"] @@ -50,26 +39,20 @@ graph TD G --> I H --> I ``` - 1. **Dependency Analysis** — Check if tasks have data dependencies (A needs output from B). 2. **Fan-Out** — Launch all independent agents in parallel using background mode. 3. **Wait** — Coordinator polls agent status until all complete. 4. **Collect** — Aggregate results, check for errors, route to next step. - ### Example - > "Implement user authentication: API endpoints, frontend form, tests, and documentation" - Coordinator spawns **4 agents in parallel**: - Backend → API endpoints - Frontend → Login/signup form - Tester → Integration tests - DevRel → Auth documentation - All work simultaneously. No agent waits unless there's a code dependency. --- - ## Background vs. Sync | Mode | When Used | Behavior | @@ -79,7 +62,6 @@ All work simultaneously. No agent waits unless there's a code dependency. | **Sync** | Reviewer gate (Lead must approve first) | Agent runs, coordinator waits for [review](your-team.md#reviewer-protocol) decision | ### Background (Fan-Out) - ```mermaid graph LR A["Coordinator"] --> B["Agent 1
background"] @@ -92,11 +74,8 @@ graph LR F --> H G --> H ``` - Agents don't see each other's output until the coordinator collects and synthesizes. - ### Sync (Dependencies & Gates) - ```mermaid graph TD A["Coordinator"] --> B["Agent 1
sync"] @@ -107,40 +86,26 @@ graph TD F --> G["Coordinator"] G --> H["Reviewer
sync gates"] ``` - Each step blocks until the previous completes. - ### Eager Execution - Squad's default is **eager parallelism** — launch everything that can run, let the coordinator handle synchronization. - - **Faster throughput** — no artificial sequencing - **Better utilization** — multiple agents saturate available compute - **Resilient** — if one agent stalls, others keep working - Trade-off: increased API cost. If cost is a concern: - ``` Work sequentially to save costs ``` - ### Deadlock Avoidance - When agents have circular dependencies (A needs B, B needs A), the coordinator detects the cycle and asks you to pick a resolution: run A first, run B first, or redesign. - ### Concurrency Limits - - **Default:** 5 agents in parallel - **Adjustable:** `"Run at most 2 agents at once"` → Coordinator batches work accordingly --- - ## Model Selection - Squad routes each agent to the right AI model based on what they're doing — not a one-size-fits-all default. - ### Selection Layers - First match wins: | Layer | How It Works | @@ -173,17 +138,12 @@ First match wins: | Designer / Visual | `claude-opus-4.5` | Vision capability required | ### Model Catalog (16 models) - Squad supports models across three tiers: - - **Premium:** claude-opus-4.6, claude-opus-4.6-fast, claude-opus-4.5 - **Standard:** claude-sonnet-4.5, gpt-5.2-codex, claude-sonnet-4, gpt-5.2, gpt-5.1-codex, gpt-5.1, gpt-5, gemini-3-pro-preview - **Fast/Cheap:** claude-haiku-4.5, gpt-5.1-codex-mini, gpt-4.1, gpt-5-mini, gpt-5.1-codex-mini - ### Fallback Chains - If a model is unavailable (plan restriction, rate limit, deprecation), Squad silently retries with the next in chain. Never falls back **up** in tier — a fast task won't land on a premium model. - ``` Premium: claude-opus-4.6 → claude-opus-4.6-fast → claude-opus-4.5 → claude-sonnet-4.5 Standard: claude-sonnet-4.5 → gpt-5.2-codex → claude-sonnet-4 → gpt-5.2 @@ -191,34 +151,23 @@ Fast: claude-haiku-4.5 → gpt-5.1-codex-mini → gpt-4.1 → gpt-5-mini ``` --- - ## Copilot Coding Agent (@copilot) - -Add the GitHub Copilot coding agent to your Squad as an autonomous team member. It picks up issues, creates branches, and opens PRs — all without a chat session. - +Add the GitHub Copilot coding agent to your Squad as an async team member. It picks up approved issues, creates branches, and opens PRs in the background. ### Prerequisites - 1. **Copilot coding agent enabled** on the repo (Settings → Copilot → Coding agent) 2. **`copilot-setup-steps.yml`** exists in `.github/` 3. **GitHub Actions** enabled on the repo - ### Quick Start - ```bash # Add @copilot with auto-assign squad copilot --auto-assign - # Create a classic PAT (repo scope) and add as secret gh secret set COPILOT_ASSIGN_TOKEN - # Commit and push git add .github/ .squad/ && git commit -m "feat: add copilot to squad" && git push - # Test — label any issue with squad:copilot ``` - Or in conversation: `"Add copilot to the squad with auto-assign enabled"` - ### How @copilot Differs | | AI Agent | Human Member | @copilot | @@ -226,10 +175,9 @@ Or in conversation: `"Add copilot to the squad with auto-assign enabled"` | Badge | ✅ Active | 👤 Human | 🤖 Coding Agent | | Charter | ✅ | ❌ | ❌ (uses `copilot-instructions.md`) | | Works in session | ✅ | ❌ | ❌ (async via issue assignment) | -| Creates PRs | Via session | Outside Squad | Autonomously | +| Creates PRs | Via session | Outside Squad | In the background | ### Capability Profile - The profile in `team.md` controls what @copilot handles: | Tier | Meaning | Examples | @@ -239,54 +187,37 @@ The profile in `team.md` controls what @copilot handles: | 🔴 **Not suitable** | Route to a squad member | Architecture, multi-system design, security-critical, ambiguous requirements | ### Auto-Assign Flow - When the `squad:copilot` label is added to an issue: 1. Workflow posts a routing comment 2. Workflow assigns `copilot-swe-agent[bot]` to the issue 3. Coding agent creates a `copilot/*` branch and opens a draft PR - Auto-assign requires a classic PAT stored as `COPILOT_ASSIGN_TOKEN` (fine-grained PATs return 403 for this endpoint). --- - ## Git Worktrees - Squad supports git worktrees with two strategies for teams working across multiple branches simultaneously. - ### Worktree-Local (Independent State) - Each worktree gets its own `.squad/` directory. Agents in one worktree don't see state from another. - ``` project/ ├── .squad/ # Main worktree team - project-feature-a/ ├── .squad/ # Feature A team (independent) - project-feature-b/ ├── .squad/ # Feature B team (independent) ``` - **Best for:** multiple features with different teams, experimental branches, different compositions per worktree. - ### Main-Checkout (Shared State) - All worktrees share `.squad/` from the main checkout via symlink. - ``` project/ ├── .squad/ # Shared by all worktrees - project-feature-a/ ├── .squad -> ../project/.squad/ # Symlink - project-feature-b/ ├── .squad -> ../project/.squad/ # Symlink ``` - **Best for:** same team on multiple branches, coordinated parallel development, solo dev with multiple branches. - ### Which Strategy? | Scenario | Strategy | @@ -297,75 +228,53 @@ project-feature-b/ | Multiple teams in same repo | Worktree-local | Setup is one command: `"Use the main worktree's team"` (creates symlink) or `"Initialize Squad in this worktree"` (creates independent `.squad/`). - Squad uses `merge=union` for append-only log files to avoid conflicts across worktrees. --- - ## Tips - - Eager parallelism is the default. Only switch to sequential if cost is a real concern. - Start conservative with @copilot's capability profile and expand as you see what it handles well. -- Use `squad:copilot` labels with [issue-driven development](../scenarios/issue-driven-dev.md) for fully autonomous processing. +- Use `squad:copilot` labels with [issue-driven development](../scenarios/issue-driven-dev.md) for background processing with review gates. - Fallback chains are silent — you won't notice model switches unless you ask `"what model did Kane use?"`. - For worktrees, main-checkout is usually the right choice unless you need truly isolated teams. --- - ## Sample Prompts - ``` Build the new dashboard feature — everyone work in parallel ``` - Coordinator spawns all relevant agents (Frontend, Backend, Tester, DevRel) simultaneously. - ``` Work on issues #12, #15, and #18 at the same time ``` - Spawns 3 agents in parallel, one per issue. - ``` Implement the API first, then write tests — do it sequentially ``` - Forces sync mode: Backend completes, then Tester starts. - ``` Run at most 2 agents at once to save costs ``` - Sets concurrency limit. Coordinator batches work in groups. - ``` Use opus for this architecture work ``` - One-off override to premium model for a high-stakes task. - ``` Always use haiku to save costs ``` - Session-wide preference for the cheapest model tier. - ``` Add copilot to the squad with auto-assign enabled ``` - Adds @copilot to the roster and configures automatic issue assignment. - ``` Use the main worktree's Squad team ``` - Creates a symlink so this worktree shares the main checkout's `.squad/` state. --- - ## See Also - - [Your Team](./your-team.md) — How agents form and specialize for different roles - [Architecture](./architecture.md) — How the coordinator orchestrates parallel execution - [Memory & Knowledge](./memory-and-knowledge.md) — How agents share context across parallel work diff --git a/docs/src/content/docs/concepts/portability.md b/docs/src/content/docs/concepts/portability.md index c03ce760f..dbde4a064 100644 --- a/docs/src/content/docs/concepts/portability.md +++ b/docs/src/content/docs/concepts/portability.md @@ -1,30 +1,20 @@ # Portability & Extensions - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - Your squad isn't locked to one repo, one editor, or one set of tools. Export a trained team and import it somewhere else. Install plugins for instant expertise. Inherit org-wide practices from upstream repos. Wire up MCP servers so agents can talk to anything. --- - ## Try This - ``` Export my team to a file — I want to use them on another project ``` - ``` Install the AWS deployment plugin ``` - ``` Add the platform team's repo as an upstream source ``` --- - ## How It Works - Squad is designed to be **portable by default**. Four systems make this possible: | System | What It Does | @@ -45,18 +35,13 @@ MCP Servers (GitHub, Teams, Trello, Aspire, etc.) ``` --- - ## Export & Import - Squad teams are portable. Export your trained agents, casting state, skills, and decisions to a single JSON file. - ### Export - ```bash squad export # creates squad-export.json squad export --out ./backups/team.json # custom path ``` - ### What's Included | Data | Included | @@ -70,41 +55,28 @@ squad export --out ./backups/team.json # custom path Skills are fully portable — they export and import with perfect fidelity. ### Import - ```bash squad import squad-export.json ``` - If `.squad/` already exists, Squad warns you and stops. Use `--force` to archive the existing team and replace it: - ```bash squad import squad-export.json --force ``` - Nothing is deleted — the current team moves to an archive. - ### History Splitting - During import, agent histories are split into: - - **Portable knowledge** — general patterns and conventions that transfer across projects - **Project-specific learnings** — context-tagged entries tied to the original repo - Imported agents bring their skills and general knowledge without assuming your project works the same way. --- - ## Plugins - Plugins are community-curated bundles of agent templates, skills, and best practices. Install one and your agents get instant expertise. - ### What's in a Plugin - - **Agent templates** — specialized role charters (e.g., "AWS DevOps", "Python Data Science") - **Skills** — reusable `.copilot/skills/SKILL.md` files - **Instructions** — `decisions.md` snippets for conventions and routing - **Sample prompts** — ready-to-use prompts that activate plugin capabilities - ### Available Marketplaces | Marketplace | What's Inside | @@ -115,33 +87,23 @@ Plugins are community-curated bundles of agent templates, skills, and best pract | **security-hardening** | OWASP, input validation, secrets management | ### Installing a Plugin - ``` Install the react-component-library plugin from awesome-copilot ``` - Or use the command: - ``` /plugin install awesome-copilot/react-component-library ``` - Squad downloads the bundle, merges agent templates into `.squad/agents/`, adds skills to `.copilot/skills/`, updates `decisions.md`, and seeds agents with the new knowledge. - ### Managing Marketplaces - ``` /plugin marketplace add github/awesome-copilot # register /plugin marketplace browse awesome-copilot # browse /plugin marketplace remove awesome-copilot # unregister ``` - Installed plugins remain even after removing a marketplace — you just can't install new ones from it. - ### Creating Your Own Marketplace - A plugin marketplace is just a GitHub repo with a specific structure: - ``` my-team-plugins/ ├── awesome-patterns/ @@ -156,15 +118,11 @@ my-team-plugins/ │ └── fault-tolerance.md └── README.md ``` - Register it with `squad` and your team can install from it. --- - ## Upstream Inheritance - Declare external Squad sources and automatically inherit their context at session start. Knowledge flows down from org → team → repo without duplicating configuration. - ### Three Source Types | Type | Example | Use Case | @@ -174,15 +132,12 @@ Declare external Squad sources and automatically inherit their context at sessio | **export** | `./exports/snapshot.json` | Offline use or version pinning | ### What Gets Inherited - - **Skills** — all `.copilot/skills/*/SKILL.md` files - **Decisions** — `.squad/decisions.md` - **Wisdom** — `.squad/identity/wisdom.md` - **Casting Policy** — `.squad/casting/policy.json` - **Routing** — `.squad/routing.md` - ### Closest-Wins Resolution - ``` Org-level upstream ↓ @@ -192,36 +147,25 @@ Repo config (local .squad/) ↓ Agent instance ``` - Upstreams are read in order from `upstream.json` — **later entries override earlier ones** for the same content type. Your local `.squad/` always wins. - ### Quick Start - ```bash # Local upstream squad upstream add ../org-practices/.squad --name org - # Git upstream squad upstream add https://github.com/acme/platform-squad.git --name platform --ref main - # Export snapshot squad upstream add ./exports/snapshot.json --name snapshot - # List configured upstreams squad upstream list - # Sync git upstreams squad upstream sync ``` - Git upstreams clone to `.squad/_upstream_repos/{name}` (auto-added to `.gitignore`). Local and export upstreams are read live at session start — no sync needed. --- - ## MCP Setup - MCP (Model Context Protocol) servers extend Squad with external services. Agents discover and use MCP tools automatically — no per-agent configuration required. - ### Configuration | Platform | Config File | @@ -230,7 +174,6 @@ MCP (Model Context Protocol) servers extend Squad with external services. Agents | **VS Code** | `.vscode/settings.json` (under `copilot.mcp.servers`) | ### Example: GitHub MCP - ```json { "mcpServers": { @@ -244,13 +187,10 @@ MCP (Model Context Protocol) servers extend Squad with external services. Agents } } ``` - Use environment variables instead of hardcoding tokens: - ```bash export GITHUB_TOKEN=$(gh auth token) ``` - ### Other Integrations | Service | What Agents Can Do | @@ -263,11 +203,8 @@ export GITHUB_TOKEN=$(gh auth token) Agents discover tools at spawn time and use them naturally during work. See [GitHub Integration](github-workflow.md) for how notifications connect to your workflow. --- - ## VS Code Integration - Squad runs identically in VS Code — same `.squad/` state, same agents, same decisions. Initialize with CLI, open in VS Code, and everything just works. - ### Key Differences from CLI | Feature | CLI | VS Code | @@ -278,23 +215,18 @@ Squad runs identically in VS Code — same `.squad/` state, same agents, same de | File writes | Automatic | May prompt for approval (once) | ### What's the Same - - Same `.squad/` directory and state - Same team roster, skills, and decisions - Parallel execution works (multiple agents per turn) - MCP tools are inherited from workspace config - ### Tips - - Use single-root workspaces (multi-root has path resolution bugs) - Accept file modification approval once — subsequent writes are automatic - For heavy parallel work (5+ agents), SQL workflows, or per-spawn model selection → use CLI - Check the model picker if agents seem slow — switch to Haiku for cost savings --- - ## Tips - - Export before running `upgrade` — it's your rollback point. - The export JSON is human-readable — inspect it to see exactly what your team knows. - Imported agents keep their names and universe casting. @@ -302,53 +234,36 @@ Squad runs identically in VS Code — same `.squad/` state, same agents, same de - Order matters in `upstream.json` — later entries override earlier ones. Use `remove` + `add` to reorder. --- - ## Sample Prompts - ``` export the current team ``` - Creates a `squad-export.json` snapshot of the entire team. - ``` import squad-export.json into this repo ``` - Imports a team snapshot into the current project's `.squad/` directory. - ``` install the azure-infrastructure plugin for the DevOps agent ``` - Downloads the Azure plugin and seeds the DevOps agent with cloud expertise. - ``` show me available plugins for React development ``` - Searches all configured marketplaces for React-related plugins. - ``` add the platform team's repo as an upstream source ``` - Inherits skills, decisions, and routing from a shared org repo. - ``` show me all configured MCP servers and which ones are working ``` - Tests each MCP server and reports status. - ``` squad upstream sync ``` - Updates all git upstream clones and validates local/export paths. - ``` package our current React conventions into a plugin called react-best-practices ``` - Exports your relevant skills and decisions into a reusable plugin bundle for sharing. diff --git a/docs/src/content/docs/concepts/your-team.md b/docs/src/content/docs/concepts/your-team.md index e144b2485..b81b5cd0b 100644 --- a/docs/src/content/docs/concepts/your-team.md +++ b/docs/src/content/docs/concepts/your-team.md @@ -1,32 +1,21 @@ # Your Team - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - Squad builds you a team of AI specialists that live in your repo. Tell it what you're working on, and it proposes a roster — backend devs, testers, writers, a lead — each with their own personality, expertise, and memory. Your team grows smarter every session. --- - ## Try This - ``` Set up a team for a React + Node.js API with PostgreSQL ``` - ``` Fenster, fix the login validation bug ``` - ``` Add a security specialist to the team ``` --- - ## How It Works - When you first run Squad in a repository, it walks through a four-step init flow: - ```mermaid graph LR A["Discovery
scan repo
detect stack"] @@ -38,14 +27,11 @@ graph LR B --> C C --> D ``` - 1. **Discovery** — Squad scans your repo: languages, file structure, test frameworks, dependencies, existing workflows. 2. **Proposal** — It suggests a roster with 3–7 members tailored to what it found. 3. **Confirmation** — You review and customize: accept as-is, add roles, remove roles, rename members. 4. **Creation** — Squad writes the `.squad/` directory, creates charters, and sets up the coordinator. - ### What Gets Created - ``` .squad/ ├── team.md # Team roster @@ -62,7 +48,6 @@ graph LR ├── orchestration-log/ # Coordinator state └── casting/ # Universe assignments ``` - ### Default Team Composition | Role | When Included | @@ -76,15 +61,11 @@ graph LR | **Scribe** | Always — silent decision logger | --- - ## Human Team Members - Not every team member needs to be AI. Add real people for decisions that need a human — design sign-off, security review, product approval. - ``` Add Sarah as design reviewer ``` - Sarah appears on the roster with a 👤 Human badge. | | AI Agent | Human Member | @@ -96,13 +77,10 @@ Sarah appears on the roster with a 👤 Human badge. | Can review work | ✅ | ✅ | When work routes to a human, Squad **pauses** and tells you someone needs to act. You relay the task outside of Squad, then report back what happened. Stale reminders keep things moving. - Not sure whether someone should be a roster member or just a normal GitHub collaborator? See [When to add a human member](../features/human-team-members.md#when-to-add-a-human-member) for a decision framework. --- - ## Work Routing - The coordinator routes work automatically using three strategies. First match wins: | Strategy | How It Works | Example | @@ -114,7 +92,6 @@ The coordinator routes work automatically using three strategies. First match wi **Routing priority:** Named > Domain > Skill-aware. If nothing matches, the Lead triages. ### Sample Routing Table - ```markdown | Pattern | Owner | Reason | |---------|-------|--------| @@ -122,26 +99,19 @@ The coordinator routes work automatically using three strategies. First match wi | `src/components/**/*.tsx` | Frontend | React components | | `*.test.ts` | Tester | Test files | | `docs/**` | DevRel | Documentation | -``` +``` GitHub issues with `squad:{member}` labels route directly — `squad:fenster` goes to Fenster, no triage needed. - ### Multi-Agent Work - Some tasks need multiple agents: - ``` Fenster, implement the API. Hockney, write the tests. ``` - The coordinator spawns both in parallel. They work independently and coordinate through shared `.squad/` state. See [Parallel Work & Models](parallel-work.md) for details. --- - ## Reviewer Protocol - When a reviewer (Lead, Tester) rejects work, the original agent gets **locked out** — no self-revision allowed. This prevents endless fix-retry loops. - ``` Agent A writes code → Lead rejects → Agent A locked out → Coordinator reassigns to Agent B or escalates to you @@ -153,11 +123,9 @@ Agent A writes code → Lead rejects → Agent A locked out | **Request changes** | Author locked out, work reassigned or escalated | ### Lockout Details - - **Task-specific** — locked out of that PR/issue, not all work - **Session-persistent** — survives restarts (stored in `.squad/orchestration-log/`) - **Clearable** — `"Unlock Fenster for issue #42"` - ### Reviewer Authority | Reviewer | Scope | @@ -167,13 +135,10 @@ Agent A writes code → Lead rejects → Agent A locked out | **You** | Final arbiter — can override any decision | ### Deadlock Handling - If all capable agents are locked out, the coordinator escalates to you with options: manual fix, unlock with guidance, or close as won't-fix. --- - ## Ceremonies - Structured team meetings that trigger at key moments — automatically or on demand. | Ceremony | Auto-Triggers When | What Happens | @@ -186,13 +151,10 @@ Run either manually anytime: ``` Run a design review before we start the authentication rebuild ``` - You can also create custom ceremonies, disable auto-triggers, or skip a ceremony for a single task. Config lives in `.squad/ceremonies.md`. --- - ## Response Modes - Squad auto-selects the right level of effort for each request: | Mode | Time | What Happens | Triggered By | @@ -205,7 +167,6 @@ Squad auto-selects the right level of effort for each request: **Pro tip:** `"Team, ..."` prompts trigger Full mode. Named agent prompts (`"Kane, ..."`) trigger Standard. Quick questions get Direct automatically. --- - ## Customizing After Init | What You Say | What Happens | @@ -219,28 +180,22 @@ Squad auto-selects the right level of effort for each request: Running `init` on an existing Squad repo automatically offers upgrade mode. --- - ## Planning your team - Before running `squad init`, think through these decisions. Squad will scan your repo and propose a team — having answers ready makes setup faster. - - **What does your project do?** Have a 1–2 sentence description of the language, stack, and purpose ready — Squad uses this to pick roles - **What roles do you need?** The [default composition](#default-team-composition) covers common cases, or let Squad propose custom roles based on your repo - **How many agents?** Typical teams are 3–7 agents. Scribe (memory) is always included - **Will humans join the team?** [Human members](#human-team-members) can serve as reviewers or domain experts alongside AI agents -- **Will @copilot participate?** The GitHub Copilot coding agent can pick up issues autonomously — see [Agent anatomy](#agent-anatomy) +- **Will @copilot participate?** The GitHub Copilot coding agent can pick up approved issues in the background — see [Agent anatomy](#agent-anatomy) - **How will you track work?** GitHub Issues with `squad:{member}` labels, or conversational tasking via named prompts - **Do you want review gates?** [Reviewers](#reviewer-protocol) can approve or reject work before it proceeds - **What ceremonies matter?** [Design reviews and retrospectives](#ceremonies) can auto-trigger or run on demand - **What model preferences?** Default is automatic selection, or specify preferred models per agent — see [Parallel Work & Models](parallel-work.md) -- **How many squads, and where do they live?** One squad per repo is the default — your `.squad/` directory lives alongside your code. For multi-repo projects, you can run one squad per repo (each with its own team) or share a single squad across repos using a personal squad or linked team repo. Start with one squad in one repo and expand as needed. +- **How many squads, and where do they live?** One squad per repo is the default — your `.squad/` directory lives alongside your code. For multi-repo projects, start with one squad per repo, then use linked team roots, exports, or upstream inheritance when you need shared context. --- - ## Agent anatomy - An agent is a directory at `.squad/agents/{name}/`. The contents depend on the member type. - For how humans differ from AI agents, see [Human team members](#human-team-members) above. | | @copilot (🤖) | @@ -251,43 +206,31 @@ For how humans differ from AI agents, see [Human team members](#human-team-membe | Spawnable | ❌ Works via issue assignment | **AI agents** have a `charter.md` (identity, expertise, voice — compiled into the system prompt at spawn time) and an optional `history.md` (append-only cross-session learnings). - **@copilot** (🤖) appears on the roster and works via GitHub issue assignment. It reads `.github/copilot-instructions.md` instead of a charter. - **Retired agents** move to `.squad/agents/_alumni/{name}/` — charter preserved as a read-only archive, not spawnable. --- - ## Cross-agent context - Agents don't share memory directly. Context flows through explicit shared files: - - **`team.md`** — who's on the team and what they do - **`routing.md`** — work assignment rules the coordinator reads on every request - **`decisions.md`** — canonical team memory: directives, patterns, learnings - **`.squad/decisions/inbox/`** — agents drop decision files here; the Scribe merges them into `decisions.md` - Each agent's `history.md` is personal — only that agent reads it at spawn time. For the full picture on knowledge flow, see [Memory and knowledge](../features/memory.md). --- - ## Hiring an agent - To add a new AI agent to your team: - - [ ] Create `.squad/agents/{name}/` directory - [ ] Write `charter.md` — start from `.squad/templates/charter.md` - [ ] Add to `team.md` roster with status `✅ Active` - [ ] Add to `routing.md` with work type assignments - [ ] (Optional) Create `history.md` for persistent memory - [ ] (Optional) Allocate a name via the casting system - To add a **human member**, skip the directory — just add them to `team.md`. See [Human team members](#human-team-members) for badge and routing details. --- - ## Tips - - **Commit `.squad/`** to version control — anyone who clones the repo gets the full team with all accumulated knowledge. - Use human members for approval gates: design review, compliance, final sign-off. - Design reviews prevent agents from building conflicting implementations — let them run on multi-agent tasks. @@ -295,61 +238,42 @@ To add a **human member**, skip the directory — just add them to `team.md`. Se - You're the relay for human members. Squad can't message them directly — it tells you, and you coordinate. --- - ## Sample Prompts - ``` Start a new Squad team for this project ``` - Triggers init mode — Squad analyzes the repo and proposes a team. - ``` Fenster, implement the new search API. Hockney, write integration tests for it. ``` - Named routing to two agents. Both spawn in [parallel](parallel-work.md). - ``` Add Jordan as security reviewer ``` - Adds a human team member with a specific review responsibility. - ``` Route all database migrations to Backend ``` - Adds a domain routing rule to `.squad/routing.md`. - ``` Lead, review PR #15 ``` - Triggers review — Lead evaluates and either approves (merge) or rejects (lockout author). - ``` Unlock Fenster for issue #42 — I've given better guidance ``` - Clears lockout so Fenster can revise the PR with your additional context. - ``` Run a retro on why those tests failed ``` - Starts a retrospective ceremony to analyze failures and capture learnings. - ``` Who handles authentication work? ``` - Coordinator checks routing and skills, reports the responsible agent(s). --- - ## See Also - - [Architecture](./architecture.md) — How the coordinator, agents, and shared memory work together - [Work Routing](../features/routing.md) — How work gets assigned to the right agent - [Parallel Work & Models](./parallel-work.md) — Agents working simultaneously without conflicts diff --git a/docs/src/content/docs/features/remote-control.md b/docs/src/content/docs/features/remote-control.md deleted file mode 100644 index 47ff15d6f..000000000 --- a/docs/src/content/docs/features/remote-control.md +++ /dev/null @@ -1,326 +0,0 @@ -# Squad Remote Control - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - - -Control Copilot CLI from your phone via a secure WebSocket tunnel. Perfect for demos, pairing on mobile, or monitoring runs from anywhere. - -```bash -squad start --tunnel -# Shows QR code → scan with phone → terminal appears in browser -``` - ---- - -## What It Does - -`squad start` spawns Copilot CLI in a pseudo-terminal (PTY) and mirrors output to your phone in real-time via: - -1. **PTY** — Copilot runs in a full interactive terminal -2. **WebSocket server** — Terminal I/O streams live via WebSocket -3. **devtunnel** — Secure public URL with authentication (optional) -4. **Phone browser** — xterm.js terminal renders on your phone - -Architecture diagram: - -``` -[Copilot CLI in PTY] - ↓ (terminal output/input) -[WebSocket Server] - ↓ (bidirectional) -[devtunnel] (optional, provides public URL) - ↓ (HTTPS + private auth) -[Phone Browser (xterm.js)] - ↓ (mobile keyboard shortcuts, replay buffer) -[Your Phone] -``` - ---- - -## Prerequisites - -### Required - -- **devtunnel CLI** (for `--tunnel` mode) - ```bash - # Windows (winget) - winget install Microsoft.devtunnel - - # macOS (Homebrew) - brew install devtunnel - - # Or via GitHub releases - # https://github.com/microsoft/devtunnel/releases - ``` - -- **devtunnel authentication** (required before first use) - ```bash - devtunnel user login - # Browser opens → authenticate → success - ``` - -### Optional - -- **Node.js 18+** (for CLI) -- **Modern browser** on phone (iOS Safari, Chrome, Firefox) - ---- - -## Usage Examples - -### Basic: Local PTY Terminal - -No tunnel, no phone access — just run Copilot in a PTY: - -```bash -squad start -# Output: Started PTY terminal (PID: 12345) -# Copilot running locally -``` - -### With Phone Access (devtunnel + QR) - -Create a tunnel, show QR code, let your phone scan and connect: - -```bash -squad start --tunnel -# Output: Started devtunnel session -# Session ID: abc123xyz -# QR Code: [████████████████] -# URL: https://abc123xyz-dev.devtunnels.ms -# -# Tap or scan QR on your phone → terminal appears -``` - -Scan the QR code with your phone camera. Opens browser → terminal renders with xterm.js. - -### Custom Port - -Specify the WebSocket server port: - -```bash -squad start --port 3456 -# Output: WebSocket listening on localhost:3456 -# Access via: ws://localhost:3456 -``` - -### Custom Command - -Run a different shell or program instead of copilot: - -```bash -squad start --tunnel --command powershell -squad start --tunnel --command "python" -squad start --tunnel --command "bash -i" -``` - -### Pass Copilot Flags Through - -All flags after `--tunnel` pass to copilot: - -```bash -squad start --tunnel --yolo -squad start --tunnel --model gpt-4 -squad start --tunnel --no-config -``` - ---- - -## Security Model - -Remote access has **7 layers** of security: - -### 1. **devtunnel Private Auth** -- URL requires `Authorization` header (devtunnel access token) -- Tunnel is private by default — no public discovery - -### 2. **Session Token (UUID, 4-hour TTL)** -- Each session gets a unique token, valid for 4 hours -- Token embedded in QR code or shown as connection string -- Expires automatically - -### 3. **Ticket-Based WebSocket Auth** -- First request exchanges session token for single-use ticket -- Ticket valid 60 seconds, single use only -- Prevents token replay attacks - -### 4. **HTTP Rate Limiting** -- 30 requests per minute per IP address -- Blocks brute-force connection attempts -- Rate limit resets hourly - -### 5. **Environment Variable Blocklist** -- 27 common secret patterns redacted from output -- Blocks: `PASSWORD`, `TOKEN`, `SECRET`, `KEY`, `AWS_`, `GITHUB_`, `API_KEY`, etc. -- ANSI escape sequences cannot bypass redaction - -### 6. **Secret Redaction (27 Patterns + ANSI Bypass Prevention)** -- Secrets matching patterns replaced with `[REDACTED]` -- ANSI codes cannot hide redaction logic -- Example: `Password=mysecret123` → `Password=[REDACTED]` - -### 7. **Connection Limits** -- **Global:** Max 5 concurrent phone connections per session -- **Per IP:** Max 2 concurrent connections per IP address -- Excess connections rejected with 429 (Too Many Requests) - ---- - -## Mobile Keyboard - -When your phone connects, a key bar appears below the terminal: - -| Key | Action | -|-----|--------| -| **↑** / **↓** | Scroll history / scroll terminal output | -| **←** / **→** | Move cursor left / right | -| **Tab** | Insert tab character (or autocomplete if supported) | -| **Enter** | Send command / newline | -| **Esc** | Send Escape key (menu mode, cancel) | -| **Ctrl+C** | Send interrupt signal (SIGINT) — kills running command | -| **Space** | Insert space | -| **⌫** | Backspace / delete | - ---- - -## Replay Buffer - -When a new phone joins the session: - -1. **Terminal history is replayed** — joins don't see a blank screen -2. **Replay window** — last 1000 lines of terminal output -3. **Scrollback included** — can scroll to see previous commands - -This means late-joiners see context, not blank canvas. - ---- - -## Session Dashboard - -List and manage active devtunnel sessions: - -```bash -squad start --list-sessions -# Output: -# Session 1: abc123xyz (2 phones connected, 1h 23m running) -# Session 2: def456uvw (0 phones, 2m running) -# Session 3: ghi789rst (1 phone, idle) -``` - -Kill a session: - -```bash -squad start --kill-session abc123xyz -# Output: Session closed. Remaining: 2 -``` - ---- - -## Architecture Notes - -### PTY-Only Mode - -Remote Control runs in **PTY-only mode** — no Copilot ACP (Agent Control Protocol) messages flow through the WebSocket. The terminal is a **mirror**, not a command channel: - -- Terminal I/O (text, control codes) ↔ WebSocket -- ACP protocol stays local to the Copilot process -- No agent instructions flow through the tunnel - -This design keeps the tunnel stateless and reduces surface area. - ---- - -## Audit Logging - -All connections, authentication, and security events are logged: - -```bash -~/.cli-tunnel/audit/squad-audit-2025-01-15.jsonl -``` - -Each line is a JSON object: - -```json -{ - "timestamp": "2025-01-15T10:23:45.123Z", - "event": "connection", - "session_id": "abc123xyz", - "phone_ip": "203.0.113.42", - "status": "authenticated" -} -``` - -Events logged: -- `connection` — Phone connected -- `disconnection` — Phone disconnected -- `auth_failure` — Token/ticket validation failed -- `rate_limit` — Rate limit exceeded -- `redaction` — Secret pattern matched and redacted -- `command` — Command executed (summary, no args) - -Rotate daily, keep 30 days by default. - ---- - -## Troubleshooting - -### "devtunnel not found" - -Install devtunnel: - -```bash -winget install Microsoft.devtunnel -``` - -Or check `PATH`: - -```bash -where devtunnel -# Should show path to executable -``` - -### "Not authenticated to devtunnel" - -Log in: - -```bash -devtunnel user login -``` - -### Phone doesn't connect (QR code error) - -1. Check QR code isn't expired (valid for 5 minutes) -2. Verify phone is on same network or has internet -3. Try manual URL instead of QR: - ```bash - # Copy URL from terminal and paste in phone browser - https://abc123xyz-dev.devtunnels.ms - ``` - -### Terminal freezes - -This is typically Copilot waiting for input. Type a command or press Enter: - -``` -squad > [CURSOR BLINKING] -``` - -Press Enter to see the prompt. - -### Audit logs missing - -Ensure `~/.cli-tunnel/` directory exists: - -```bash -mkdir -p ~/.cli-tunnel/audit -``` - -Logs are created on first event. - ---- - -## See Also - -- [CLI Reference](../reference/cli.md) — All commands -- [Getting Started](../get-started/installation.md) — Squad setup -- [VS Code Integration](./vscode.md) — Remote Control in VS Code diff --git a/docs/src/content/docs/guide/personal-squad.md b/docs/src/content/docs/guide/personal-squad.md deleted file mode 100644 index 08479686b..000000000 --- a/docs/src/content/docs/guide/personal-squad.md +++ /dev/null @@ -1,352 +0,0 @@ -# Your Personal Squad - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - -:::tip[Git helps protect your project state] -We strongly recommend using git to version-control your project `.squad/` directory. Every session writes to it — decisions, logs, orchestration history. Agent charters, skills, and casting histories live in your personal squad directory (not committed to projects). Without version control, context window resets, crashes, or accidental deletions could be unrecoverable. If git isn't an option, regular manual backups to external storage or cloud sync can help protect your work. -::: - -**Try this:** -```bash -squad init --global -``` - -Your agents follow you everywhere now. Same team, every project, persistent memory. - -This tutorial walks you through setup, explains what's happening behind the scenes, and shows a few ways personal squads make your work better. - ---- - -## 1. What Is a Personal Squad? - -Normally, Squad lives inside a single project — `.squad/` in your repo root. Your agents know that project. They don't know your other ones. - -A personal squad flips that. Your team identity — agents, charters, skills, casting history — moves to your personal squad directory. Every project you work in can point to it. - -**Personal squad location by platform:** - -| Platform | Path | -|----------|------| -| Linux | `~/.config/squad/` | -| macOS | `~/Library/Application Support/squad/` | -| Windows | `%APPDATA%\squad\` | - -What that means in practice: - -- Your agents remember your conventions across all your repos -- Skills learned in one project carry over to every other one -- Your Lead reviews code the same way everywhere -- You don't repeat yourself when starting a new project - -You're still one person. But your team travels with you. - ---- - -## 2. Set It Up - -### Install the CLI globally - -```bash -npm install -g @bradygaster/squad-cli -``` - -Now `squad` works from any directory. Not tied to a specific project. - -### Initialize your personal squad - -```bash -squad init --global -``` - -You'll see: - -``` -✅ Personal squad initialized. - {personal squad directory} — your global team root - Agents, skills, and casting will be shared across projects. -``` - -That's it. You have a personal team root. - -### Verify it's working - -```bash -squad status -``` - -``` -Squad Status - Global squad: {personal squad directory} - Agents: 0 (none cast yet — start a session to form your team) - Skills: 0 -``` - -No agents yet. They form when you start your first session. The global directory is just the container — your team comes to life when you give them work. - -### Connect a project - -Navigate to any project and run: - -```bash -cd ~/projects/my-api -squad init -``` - -Squad detects your global team root and writes a pointer: - -``` -✅ Squad initialized. - .squad/config.json → teamRoot: {personal squad directory} - Team identity inherited from personal squad. - Project-local state (decisions, logs) stays here. -``` - -Your project now has its own `.squad/` directory for local state, but your agents, skills, and casting come from the global root. - -Repeat for any project you want connected. - ---- - -## 3. What Just Happened? (Behind the Scenes) - -Two things were created. Understanding the split is the key to personal squads. - -### The global directory: your personal squad - -This is your **team identity**. It contains: - -``` -{personal squad directory}/ - agents/ — your agent charters and histories - casting/ — who's been cast, role assignments - skills/ — accumulated knowledge ("always use Zod", "prefer Tailwind") -``` - -This is the stuff that makes your agents *yours*. It persists across sessions. It grows as you work. It follows you from project to project. - -### The global `squad.agent.md` — a reference, not a live file - -You'll also see `.github/agents/squad.agent.md` inside your global config directory. This file is **not** discoverable by GitHub Copilot — Copilot only reads agent files inside a git repository's `.github/agents/` folder. - -So why is it there? It serves as a **local reference** of the Squad agent instructions that were applied to your projects. The actual source for `squad init` is the packaged template bundled with the CLI (`squad.agent.md.template`), so the global copy is not used as input for future inits. It exists so you can see what Squad generated without opening a project. - -If you want Copilot to use Squad's agent instructions in a project, run `squad init` in that project's root — that creates the "real" `.github/agents/squad.agent.md` inside the git repo where Copilot can discover it. - -### The project pointer: `.squad/config.json` - -Inside each connected project, `.squad/config.json` looks like this: - -```json -{ - "version": 1, - "teamRoot": "{personal squad directory}", - "projectKey": null -} -``` - -That `teamRoot` field is the magic. When Squad's resolution system sees it, the project enters **remote mode**. Here's how the two modes compare: - -| | **Local mode** (default) | **Remote mode** (personal squad) | -|---|---|---| -| Team identity | `.squad/` in project | Personal squad directory (global) | -| Decisions & logs | `.squad/` in project | `.squad/` in project | -| Agents shared? | No — project only | Yes — across all connected projects | -| Skills shared? | No | Yes | - -In remote mode: - -- **Team identity** (agents, charters, skills, casting) → loaded from your personal squad directory -- **Project-local state** (decisions, logs, orchestration-log) → stays in this project's `.squad/` - -The resolution system walks up directories looking for `.squad/`. When it finds one with a `teamRoot` in `config.json`, it switches to remote mode — pulling team identity from the external path while keeping project state local. - -### Why the split matters - -Your agents know you across projects. They remember your conventions. But each project has its own decisions and logs. - -The API project doesn't get cluttered with the frontend project's session history. The Discord bot's architectural decisions stay in the Discord bot. Clean separation — shared brain, local memory. - ---- - -## 4. Use Case: Your Side Projects Get a Team - -You have three side projects. A CLI tool, a web app, a Discord bot. All different stacks. All just you. - -```bash -# Already done once -squad init --global - -# Connect each project -cd ~/projects/cli-tool && squad init -cd ~/projects/web-app && squad init -cd ~/projects/discord-bot && squad init -``` - -Now when you open any of them: - -``` -> Fredo, set up the database layer. -``` - -Fredo already knows you prefer PostgreSQL. He knows you use Zod for validation. He picked that up from working on your CLI tool last week. You didn't tell him again — he remembered. - -Your Lead reviews code the same way in every repo. Your Tester follows the same patterns. Three projects, one consistent team. - -Without a personal squad, you'd re-explain your conventions every time you start a new project. With one, the onboarding is already done. - ---- - -## 5. Use Case: Code Review Across Repos - -Your Lead agent reviews every pull request in every project. But more than that — they remember architectural decisions from *other* repos. - -``` -> Michael, review this new endpoint. -``` - -``` -🏗️ Michael — reviewing /api/users endpoint - -Looks good. Two notes: - - In your CLI tool, you standardized on cursor-based pagination. - This endpoint uses offset pagination. Intentional? - - Missing rate limiting. We added this as a skill after the - auth module in your web app. -``` - -Michael isn't just reviewing code in isolation. He's cross-referencing decisions and skills from your other projects. That's the personal squad at work — knowledge that spans repos. - -The more projects you connect, the richer these reviews become. Your Lead builds a mental model of how *you* build software, not just how one project works. - ---- - -## 6. Use Case: Learning a New Codebase - -You join an open-source project. New repo, unfamiliar code. But your agents already know *you*. - -For projects you don't own — OSS contributions, client work, temporary collaborations — use **consult mode**. Your team consults invisibly, and the project never knows Squad was there: - -```bash -cd ~/projects/new-oss-contribution -squad consult -``` - -Your personal squad is copied into the project's `.squad/` directory, hidden via `.git/info/exclude`. The agents don't know the codebase yet — they'll learn it. But they already know your preferences: - -- How you like code structured -- What testing patterns you follow -- Your communication style (direct? exploratory? detail-oriented?) - -``` -> Team, help me understand this codebase. Where's the entry point -> and how does routing work? -``` - -Your agents explore the repo with your familiar voice. They ask the questions you'd ask. The codebase is new — but your relationship with your team isn't. - -When you're done, extract the generic learnings back to your personal squad and clean up: - -```bash -squad extract --clean -``` - -It's not a cold start. It's your team meeting a new project. - -> 📖 **Full guide:** [Consult Mode](../features/consult-mode.md) — invisible consulting, learning extraction, license handling. - ---- - -## 7. Use Case: Automating Your Personal Workflow - -Your personal squad isn't just for writing code. It's a workflow tool. - -Set a directive once: - -``` -> Always run linting before marking a task done. -``` - -``` -📌 Captured. Linting required before task completion. -``` - -That directive is now in your personal squad directory — every project, every session. Your agents enforce it everywhere. You set the standard once and it sticks. - -Over time, your personal squad becomes an opinionated workflow engine. Not because you configured it that way — because you worked with it and it learned. - ---- - -## 8. Use Case: Skills That Grow Everywhere - -Skills accumulate in your personal squad directory under `skills/`. Every project contributes. - -After a few weeks: - -``` -{personal squad directory}/skills/ - always-use-zod.md - prefer-tailwind.md - cursor-pagination.md - rate-limit-auth-endpoints.md - structured-logging.md - error-boundaries-in-react.md -``` - -These came from different projects. The Zod skill was learned in your API. The Tailwind preference was captured in your web app. The rate-limiting skill came from a code review rejection. - -Now every new project starts with all of that knowledge baked in. Your agents don't make the same mistakes twice — in any repo. - -This is the long game. Early sessions feel similar to project-local squads. But after a few weeks of cross-project work, the difference is real. Your skills directory becomes a personal engineering handbook that your agents actually read. - ---- - -## 9. Where It's Headed - -Honest moment: this is new. Personal squads work, but they're early. - -What works well today: -- Shared team identity across projects -- Skills that accumulate and carry over -- Consistent agent behavior everywhere you work -- **Consult mode** — bring your team to projects you don't own, invisibly ([docs](../features/consult-mode.md)) - -What's still rough: -- No sync mechanism between machines yet — your personal squad directory is local to your machine -- Project keys aren't used for anything yet (that `null` in config.json) -- No UI for browsing your global skills or agent histories (it's files for now) - -We're building in the open. If something feels off, [open an issue](https://github.com/bradygaster/squad/issues). If something feels right, we want to hear about that too. - ---- - -## Tips - -- **Git-first workflow is strongly recommended.** Commit your project `.squad/` directory to git after any session. Without version control: - - Session state could be lost on crashes, context resets, or machine reboots - - Project-local decisions and logs are at risk - - Accidental deletions may be unrecoverable - - Cross-project context could vanish - - Think of git as your insurance policy for your project's local state. It's a good habit: after a session ends, run `git add .squad/ && git commit -m "squad: project state"`. (Agent histories, skills, and team identity are stored in your personal squad directory — not in project repos.) - -- **Commit project `.squad/` but not personal squad directory.** The project-local state (decisions, logs) belongs in version control. Your global identity (agents, skills, casting) is personal — keep it out of repos. - ```bash - # DO THIS - git add .squad/ - git commit -m "squad: project state" - - # DON'T commit your personal squad directory (~/.config/squad/ or similar) — it's machine-specific - ``` - -- **Check status anytime.** `squad status` shows your global squad directory and which projects are connected. -- **Skills are the payoff.** The more projects you work across, the more skills accumulate. After a month, your agents have a real knowledge base tailored to how *you* build software. -- **It's just files.** Your personal squad directory is a folder on your machine. You can browse it, edit it, back it up, copy it to another machine manually. No magic, no cloud, no lock-in. But **always back up or version-control your `.squad/` state**. -- **Global install matters.** `npm install -g @bradygaster/squad-cli` gives you the `squad` command everywhere. Without it, you'd need `npx` in each project. Global CLI + global squad = full portability. - ---- - -## What to Try Next - -- [**Your First Session**](../get-started/first-session.md) — The full walkthrough from zero to fan-out -- [**Solo Dev Scenario**](../scenarios/solo-dev.md) — Squad for one-person teams -- [**Tips & Tricks**](tips-and-tricks.md) — Patterns that work diff --git a/docs/src/content/docs/guide/shell.md b/docs/src/content/docs/guide/shell.md deleted file mode 100644 index 8ff557b7c..000000000 --- a/docs/src/content/docs/guide/shell.md +++ /dev/null @@ -1,343 +0,0 @@ -# Interactive Shell Guide - -> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. - -> 💡 **Recommended: Use GitHub Copilot CLI** — The best way to interact with Squad today is through the [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli). Run `copilot --agent squad` to start a session with your team. The Copilot CLI provides the richest agent experience, including tool use, parallel execution, and full MCP integration. - -The Squad interactive shell gives you a persistent connection to your team.Instead of spawning short-lived CLI invocations, the shell maintains a real-time session where you can talk to agents, issue commands, and watch work happen. - ---- - -## Getting Started - -### Enter the Shell - -```bash -squad -``` - -With no arguments, `squad` enters the interactive shell. You'll see a prompt: - -``` -squad > -``` - -### Exit the Shell - -``` -squad > /quit -``` - -Or press **Ctrl+C**. - ---- - -## Shell Commands - -All shell commands start with a forward slash `/`. - -### `/status` — Check team status - -Display the current state of your squad: active agents, sessions, and recent work. - -``` -squad > /status -``` - -Output: - -``` -Team Status -──────────────────── -Active Agents: 4/5 - Keaton (lead): idle - McManus (devrel): working (10s) - Verbal (backend): working (25s) - Fenster (tester): idle - Kobayashi (scribe): logging - -Sessions: 5 -Latest decision: "Use React Query for data fetching" (2m ago) -``` - -### `/history` — View recent work - -Display the session log and recent decisions. - -``` -squad > /history -``` - -Shows: -- Last 10 completed tasks -- Decisions made in this session -- Agents that have worked -- Full session transcript (searchable) - -### `/agents` — List team members - -Show all agents on the team with their roles, expertise, and knowledge. - -``` -squad > /agents -``` - -### `/sessions` — List saved sessions - -View past shell sessions. Shows the 10 most recent sessions with their ID prefix, timestamp, and message count. - -``` -squad > /sessions -``` - -Output: - -``` -Saved Sessions (3 total) - 1. a1b2c3d4 6/15/2026, 2:30:00 PM (12 messages) - 2. e5f6a7b8 6/14/2026, 10:15:00 AM (8 messages) - 3. c9d0e1f2 6/13/2026, 4:45:00 PM (23 messages) - -Use /resume to restore a session. -``` - -### `/resume ` — Restore a past session - -Resume a previous session by providing the first few characters of its ID. The session's full message history is restored into the current shell. - -``` -squad > /resume a1b2 -✔ Restored session a1b2c3d4 (12 messages) -``` - -Typical workflow — pick up where you left off: - -``` -squad > /sessions -squad > /resume a1b2 -squad > @Keaton, where were we on the auth work? -``` - -### `/clear` — Clear the screen - -Clears terminal output. - -### `/help` — Show all commands - -### `/quit` — Exit the shell - -Close the shell and return to your terminal. - ---- - -## Addressing Agents - -You can talk to specific agents by name: - -### Using `@AgentName` - -``` -squad > @Keaton, analyze the architecture of this project -``` - -### Using natural language - -``` -squad > Keaton, set up the database schema for user authentication -``` - -Or without naming an agent — the coordinator routes to whoever is best suited: - -``` -squad > Write a blog post about our new casting system -``` - ---- - -## Message Routing - -### How Messages Get to Agents - -1. **You type a message** → Shell receives it -2. **Coordinator reads it** → Determines which agent(s) can usefully start -3. **Agents launch in parallel** → All applicable agents work simultaneously -4. **Agents write results** → To `.squad/` (decisions, history, skills, etc.) -5. **Shell streams updates** → You see progress in real-time - -### Parallel Execution - -When you give a task that multiple agents can handle: - -``` -squad > Build the login page -``` - -The coordinator might spawn: -- McManus (frontend) → building the UI -- Verbal (backend) → setting up auth endpoints -- Fenster (tester) → writing test cases -- Kobayashi (scribe) → logging everything - -All at once. All in parallel. - ---- - -## Session Management - -### What Is a Session? - -Each agent gets a **persistent session** — a long-lived context where it remembers: -- The task you gave it -- What it's already written to disk -- Previous decisions and learnings -- Its own knowledge base (charter, history) - -Sessions survive crashes. If an agent dies mid-work, it resumes from the exact checkpoint. - -### Viewing Session History - -``` -squad > /history -``` - -Shows full session log with start time, end time, duration, what the agent did, files written, decisions made, and any errors. - -### Resuming Work - -If an agent crashes or times out: - -``` -squad > @Keaton, check on Verbal and resume if needed -``` - ---- - -## Keyboard Shortcuts - -| Shortcut | Action | -|----------|--------| -| `↑` / `↓` | Scroll command history | -| `Ctrl+A` | Jump to start of line | -| `Ctrl+E` | Jump to end of line | -| `Ctrl+U` | Clear to start of line | -| `Ctrl+K` | Clear to end of line | -| `Ctrl+W` | Delete previous word | -| `Ctrl+C` | Exit shell | - ---- - -## Tips and Tricks - -### Check `/status` before big asks - -Before sending a complex task, check team status. If agents are already working, you might want to wait. - -### Reference decisions, not details - -Instead of explaining the whole architecture: - -``` -# Don't: -squad > Build the auth system. Use JWT. Refresh tokens every 1 hour... - -# Do: -squad > Build the auth system. See the auth decision in decisions.md. -``` - -Agents read your decisions — they're shortcuts for complex context. - -### Batch work through the coordinator - -``` -squad > @Keaton, here's what needs doing: -1. Set up database schema -2. Build API endpoints -3. Write tests - -Prioritize and route, please. -``` - -The coordinator will decompose, prioritize, and launch agents efficiently. - -### Check `/history` after long waits - -If you step away, run `/history` to see what happened. Every decision is logged, every task is recorded. - -### Name agents explicitly for urgent work - -``` -squad > @Keaton, this is critical: we need the deployment script fixed -``` - -The explicit mention ensures the lead coordinator sees it first. - ---- - -## Advanced Usage - -### Working with Multiple Tasks - -The coordinator queues tasks and parallelizes where possible: - -``` -squad > Write the API spec -squad > Build the React components -squad > Set up the database - -/status # See all three being worked on -``` - -### Asking Agents About Their Work - -``` -squad > @Verbal, what's left on the auth endpoints? -squad > @McManus, show me what you've written so far -squad > @Fenster, are the tests passing? -``` - -Agents respond with status, file paths, and blockers. - -### Custom Agent Chaining - -Instead of asking the coordinator to chain work, set up explicit hand-offs: - -``` -squad > @Keaton, when Verbal finishes the auth API, have him route testing to Fenster -``` - ---- - -## Using the Shell with VS Code - -1. Open an integrated terminal in VS Code -2. Run `squad` to enter the shell -3. Keep it open in a side panel -4. As you edit code, ask agents to review: `@Fenster, test this component` - ---- - -## Troubleshooting - -### Shell Hangs or No Response - -The coordinator might be evaluating a complex task, or an agent might be streaming large output. Press `Ctrl+C` to interrupt, then check `/status`. - -### Agent Not Responding - -Check `/status` and `/history` for blockers. Then ask the coordinator to route explicitly: - -``` -squad > @Keaton, route this task to @Verbal and report any blocks -``` - -### Shell Quit Unexpectedly - -Run `squad` again to restart. Check `.squad/log/` for error context. - ---- - -## See Also - -- [CLI Reference](../reference/cli.md) — All CLI commands -- [VS Code](../features/vscode.md) — Squad in VS Code -- [Parallel Execution](../features/parallel-execution.md) — How agents fan out diff --git a/docs/src/navigation.ts b/docs/src/navigation.ts index fc85d2b88..986799bc9 100644 --- a/docs/src/navigation.ts +++ b/docs/src/navigation.ts @@ -2,42 +2,35 @@ export interface NavItem { title: string; slug: string; } - export interface NavSection { title: string; dir: string; items: NavItem[]; } - export const NAV_SECTIONS: NavSection[] = [ { title: 'Get Started', dir: 'get-started', items: [ - { title: 'Quick start', slug: 'get-started/five-minute-start' }, + { title: 'Quick Start', slug: 'get-started/five-minute-start' }, { title: 'Installation', slug: 'get-started/installation' }, - { title: 'Choose your path', slug: 'get-started/choosing-your-path' }, { title: 'Your First Session', slug: 'get-started/first-session' }, - { title: 'Migration Guide', slug: 'get-started/migration' }, ], }, { - title: 'Guide', - dir: 'guide', + title: 'Concepts', + dir: 'concepts', items: [ - { title: 'Tips & Tricks', slug: 'guide/tips-and-tricks' }, - { title: 'Sample Prompts', slug: 'guide/sample-prompts' }, - { title: 'Personal Squad', slug: 'guide/personal-squad' }, - { title: 'Interactive Shell', slug: 'guide/shell' }, - { title: 'Extensibility', slug: 'guide/extensibility' }, - { title: 'Building Extensions', slug: 'guide/building-extensions' }, - { title: 'Building Resilient Agents', slug: 'guide/building-resilient-agents' }, - { title: 'Contributing', slug: 'guide/contributing' }, - { title: 'Contributors', slug: 'guide/contributors' }, + { title: 'Architecture', slug: 'concepts/architecture' }, + { title: 'Your Team', slug: 'concepts/your-team' }, + { title: 'Memory & Knowledge', slug: 'concepts/memory-and-knowledge' }, + { title: 'Parallel Work', slug: 'concepts/parallel-work' }, + { title: 'GitHub Workflow', slug: 'concepts/github-workflow' }, + { title: 'Portability', slug: 'concepts/portability' }, ], }, { - title: 'Features', + title: 'Core Features', dir: 'features', items: [ { title: 'Team Setup', slug: 'features/team-setup' }, @@ -48,47 +41,62 @@ export const NAV_SECTIONS: NavSection[] = [ { title: 'Memory', slug: 'features/memory' }, { title: 'Skills', slug: 'features/skills' }, { title: 'Directives', slug: 'features/directives' }, - { title: 'Ceremonies', slug: 'features/ceremonies' }, - { title: 'Reviewer Protocol', slug: 'features/reviewer-protocol' }, { title: 'GitHub Issues', slug: 'features/github-issues' }, { title: 'GitLab Issues', slug: 'features/gitlab-issues' }, - { title: 'Labels & Triage', slug: 'features/labels' }, - { title: 'PRD Mode', slug: 'features/prd-mode' }, - { title: 'Project Boards', slug: 'features/project-boards' }, { title: 'Ralph — Work Monitor', slug: 'features/ralph' }, { title: '@copilot Coding Agent', slug: 'features/copilot-coding-agent' }, + { title: 'VS Code', slug: 'features/vscode' }, + ], + }, + { + title: 'Advanced Features', + dir: 'features', + items: [ + { title: 'Ceremonies', slug: 'features/ceremonies' }, + { title: 'Reviewer Protocol', slug: 'features/reviewer-protocol' }, { title: 'Human Team Members', slug: 'features/human-team-members' }, { title: 'Consult Mode', slug: 'features/consult-mode' }, - { title: 'Remote Control', slug: 'features/remote-control' }, - { title: 'Storage Provider', slug: 'features/storage-provider' }, - { title: 'VS Code', slug: 'features/vscode' }, - { title: 'Git Worktrees', slug: 'features/worktrees' }, + { title: 'Labels & Triage', slug: 'features/labels' }, + { title: 'PRD Mode', slug: 'features/prd-mode' }, + { title: 'Project Boards', slug: 'features/project-boards' }, { title: 'Export & Import', slug: 'features/export-import' }, { title: 'Upstream Inheritance', slug: 'features/upstream-inheritance' }, { title: 'Marketplace', slug: 'features/marketplace' }, { title: 'Plugins', slug: 'features/plugins' }, { title: 'MCP', slug: 'features/mcp' }, { title: 'Notifications', slug: 'features/notifications' }, - { title: 'Enterprise Platforms', slug: 'features/enterprise-platforms' }, - { title: 'Squad RC', slug: 'features/squad-rc' }, { title: 'Streams', slug: 'features/streams' }, + { title: 'Git Worktrees', slug: 'features/worktrees' }, + { title: 'Squad RC', slug: 'features/squad-rc' }, + ], + }, + { + title: 'Infrastructure', + dir: 'features', + items: [ + { title: 'Enterprise Platforms', slug: 'features/enterprise-platforms' }, + { title: 'Storage Provider', slug: 'features/storage-provider' }, { title: 'Distributed Mesh', slug: 'features/distributed-mesh' }, { title: 'Capability Routing', slug: 'features/capability-routing' }, { title: 'Rate Limiting', slug: 'features/rate-limiting' }, { title: 'KEDA Autoscaling', slug: 'features/keda-scaling' }, + { title: 'State Backends', slug: 'features/state-backends' }, + { title: 'Dual-Mode Deployment', slug: 'features/dual-mode-deployment' }, ], }, { - title: 'Reference', - dir: 'reference', + title: 'Guides', + dir: 'guide', items: [ - { title: 'CLI', slug: 'reference/cli' }, - { title: 'SDK', slug: 'reference/sdk' }, - { title: 'SDK API Reference', slug: 'reference/api-reference' }, - { title: 'SDK Integration', slug: 'reference/integration' }, - { title: 'Tools & Hooks', slug: 'reference/tools-and-hooks' }, - { title: 'Config', slug: 'reference/config' }, - { title: 'Glossary', slug: 'reference/glossary' }, + { title: 'Tips & Tricks', slug: 'guide/tips-and-tricks' }, + { title: 'Sample Prompts', slug: 'guide/sample-prompts' }, + { title: 'Recipes', slug: 'cookbook/recipes' }, + { title: 'Building Extensions', slug: 'guide/building-extensions' }, + { title: 'Building Resilient Agents', slug: 'guide/building-resilient-agents' }, + { title: 'Extensibility', slug: 'guide/extensibility' }, + { title: 'GitHub Auth Setup', slug: 'guide/github-auth-setup' }, + { title: 'Contributing', slug: 'guide/contributing' }, + { title: 'Contributors', slug: 'guide/contributors' }, ], }, { @@ -98,56 +106,49 @@ export const NAV_SECTIONS: NavSection[] = [ { title: 'Existing Repo', slug: 'scenarios/existing-repo' }, { title: 'New Project', slug: 'scenarios/new-project' }, { title: 'Solo Developer', slug: 'scenarios/solo-dev' }, + { title: 'Mid-Project', slug: 'scenarios/mid-project' }, { title: 'Issue-Driven Dev', slug: 'scenarios/issue-driven-dev' }, - { title: 'Monorepo', slug: 'scenarios/monorepo' }, - { title: 'CI/CD Integration', slug: 'scenarios/ci-cd-integration' }, { title: 'Team of Humans', slug: 'scenarios/team-of-humans' }, + { title: 'Multiple Squads', slug: 'scenarios/multiple-squads' }, + { title: 'Monorepo', slug: 'scenarios/monorepo' }, { title: 'Large Codebase', slug: 'scenarios/large-codebase' }, + { title: 'Scaling Workstreams', slug: 'scenarios/scaling-workstreams' }, { title: 'Open Source', slug: 'scenarios/open-source' }, - { title: 'Multiple Squads', slug: 'scenarios/multiple-squads' }, - { title: 'Keep My Squad', slug: 'scenarios/keep-my-squad' }, - { title: 'Mid-Project', slug: 'scenarios/mid-project' }, + { title: 'CI/CD Integration', slug: 'scenarios/ci-cd-integration' }, + { title: 'Release Process', slug: 'scenarios/release-process' }, { title: 'Upgrading', slug: 'scenarios/upgrading' }, - { title: 'Multi-Codespace', slug: 'scenarios/multi-codespace' }, + { title: 'Migration Guide', slug: 'get-started/migration' }, { title: 'Private Repos', slug: 'scenarios/private-repos' }, { title: 'Cross-Org Auth', slug: 'scenarios/cross-org-auth' }, { title: 'Team Portability', slug: 'scenarios/team-portability' }, { title: 'Team State Storage', slug: 'scenarios/team-state-storage' }, + { title: 'Multi-Codespace', slug: 'scenarios/multi-codespace' }, { title: 'Switching Models', slug: 'scenarios/switching-models' }, - { title: 'Release Process', slug: 'scenarios/release-process' }, - { title: 'Scaling Workstreams', slug: 'scenarios/scaling-workstreams' }, - { title: 'Client Compatibility', slug: 'scenarios/client-compatibility' }, { title: 'Remote Q&A', slug: 'scenarios/remote-qa' }, { title: 'Disaster Recovery', slug: 'scenarios/disaster-recovery' }, - { title: 'Troubleshooting', slug: 'scenarios/troubleshooting' }, + { title: 'Client Compatibility', slug: 'scenarios/client-compatibility' }, { title: 'Aspire Dashboard', slug: 'scenarios/aspire-dashboard' }, + { title: 'Keep My Squad', slug: 'scenarios/keep-my-squad' }, + { title: 'Troubleshooting', slug: 'scenarios/troubleshooting' }, ], }, { - title: 'Concepts', - dir: 'concepts', - items: [ - { title: 'Architecture', slug: 'concepts/architecture' }, - { title: 'Your Team', slug: 'concepts/your-team' }, - { title: 'Memory & Knowledge', slug: 'concepts/memory-and-knowledge' }, - { title: 'Parallel Work', slug: 'concepts/parallel-work' }, - { title: 'GitHub Workflow', slug: 'concepts/github-workflow' }, - { title: 'Portability', slug: 'concepts/portability' }, - ], - }, - { - title: 'Cookbook', - dir: 'cookbook', + title: 'Reference', + dir: 'reference', items: [ - { title: 'Recipes', slug: 'cookbook/recipes' }, + { title: 'CLI', slug: 'reference/cli' }, + { title: 'SDK', slug: 'reference/sdk' }, + { title: 'SDK API Reference', slug: 'reference/api-reference' }, + { title: 'SDK Integration', slug: 'reference/integration' }, + { title: 'Tools & Hooks', slug: 'reference/tools-and-hooks' }, + { title: 'Config', slug: 'reference/config' }, + { title: 'Glossary', slug: 'reference/glossary' }, ], }, ]; - export const STANDALONE_PAGES = [ { title: "What's New", slug: 'whatsnew' }, { title: 'SDK-First Mode', slug: 'sdk-first-mode' }, { title: 'Community', slug: 'community' }, { title: 'Insider Program', slug: 'insider-program' }, ]; - diff --git a/docs/tests/build-output.test.mjs b/docs/tests/build-output.test.mjs index 029587ee4..b575750ce 100644 --- a/docs/tests/build-output.test.mjs +++ b/docs/tests/build-output.test.mjs @@ -1,231 +1,206 @@ -/** - * Build output tests for Phase 1 search improvements. - * Validates that pagefind attributes are correctly applied in the built HTML. - * Run with: node --test tests/build-output.test.mjs - */ -import { describe, it } from 'node:test'; -import assert from 'node:assert/strict'; -import fs from 'node:fs'; -import path from 'node:path'; - -const DOCS_ROOT = path.resolve(import.meta.dirname, '..'); -const DIST = path.join(DOCS_ROOT, 'dist'); - -// Collect HTML files from dist for reuse across tests -function findHtmlFiles(dir, files = []) { - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - const full = path.join(dir, entry.name); - if (entry.isDirectory() && entry.name !== '_astro' && entry.name !== 'pagefind') { - findHtmlFiles(full, files); - } else if (entry.isFile() && entry.name.endsWith('.html')) { - files.push(full); - } - } - return files; -} - -const allHtmlFiles = findHtmlFiles(DIST); - -// Exclude top-level pages (404, home, blog index) which use different layouts -const EXCLUDED_PAGES = ['404.html', `blog${path.sep}index.html`, 'index.html']; -function isContentPage(file) { - const rel = path.relative(DIST, file); - return !EXCLUDED_PAGES.some(exc => rel === exc || rel === exc.replace(/\//g, path.sep)); -} - -const docsHtmlFiles = allHtmlFiles.filter(f => - f.includes(`${path.sep}docs${path.sep}`) && isContentPage(f) -); -const blogHtmlFiles = allHtmlFiles.filter(f => - f.includes(`${path.sep}blog${path.sep}`) && isContentPage(f) -); - -// ── pagefind.yml ────────────────────────────────────────────────────────────── - -describe('pagefind.yml configuration', () => { - it('exists in the docs root', () => { - assert.ok( - fs.existsSync(path.join(DOCS_ROOT, 'pagefind.yml')), - 'pagefind.yml should exist at docs root' - ); - }); - - it('contains exclude_selectors for nav, footer, aside, pre, .astro-code', () => { - const content = fs.readFileSync(path.join(DOCS_ROOT, 'pagefind.yml'), 'utf-8'); - for (const selector of ['nav', 'footer', 'aside', 'pre', '.astro-code']) { - assert.ok( - content.includes(`"${selector}"`) || content.includes(`'${selector}'`) || content.includes(`- ${selector}`) || content.includes(`- "${selector}"`), - `pagefind.yml should exclude selector: ${selector}` - ); - } - }); -}); - -// ── Pagefind index output ───────────────────────────────────────────────────── - -describe('pagefind build output', () => { - it('pagefind directory exists in dist/', () => { - assert.ok( - fs.existsSync(path.join(DIST, 'pagefind')), - 'dist/pagefind/ directory should exist after build' - ); - }); - - it('pagefind.js is present in pagefind directory', () => { - assert.ok( - fs.existsSync(path.join(DIST, 'pagefind', 'pagefind.js')), - 'dist/pagefind/pagefind.js should exist' - ); - }); -}); - -// ── data-pagefind-body on article elements ──────────────────────────────────── - -describe('data-pagefind-body attribute', () => { - it('docs pages contain data-pagefind-body on article elements', () => { - assert.ok(docsHtmlFiles.length > 0, 'Should have docs HTML files to test'); - const missing = []; - for (const file of docsHtmlFiles) { - const html = fs.readFileSync(file, 'utf-8'); - if (!html.includes('data-pagefind-body')) { - missing.push(path.relative(DIST, file)); - } - } - assert.equal(missing.length, 0, `These docs pages lack data-pagefind-body: ${missing.join(', ')}`); - }); - - it('blog post pages contain data-pagefind-body on article elements', () => { - assert.ok(blogHtmlFiles.length > 0, 'Should have blog HTML files to test'); - for (const file of blogHtmlFiles) { - const html = fs.readFileSync(file, 'utf-8'); - assert.ok( - html.includes('data-pagefind-body'), - `Blog page missing data-pagefind-body: ${path.relative(DIST, file)}` - ); - } - }); -}); - -// ── data-pagefind-meta with section values ──────────────────────────────────── - -describe('data-pagefind-meta section attribute', () => { - it('docs pages have data-pagefind-meta with a section value', () => { - assert.ok(docsHtmlFiles.length > 0, 'Should have docs HTML files to test'); - const sectionPattern = /data-pagefind-meta="section:([^"]+)"/; - const missing = []; - for (const file of docsHtmlFiles) { - const html = fs.readFileSync(file, 'utf-8'); - if (!sectionPattern.test(html)) { - missing.push(path.relative(DIST, file)); - } - } - assert.equal( - missing.length, 0, - `These docs pages lack data-pagefind-meta section: ${missing.join(', ')}` - ); - }); - - it('section values match expected categories', () => { - const knownSections = new Set([ - 'Get Started', 'Guide', 'Features', 'Reference', - 'Scenarios', 'Concepts', 'Cookbook', 'Blog', 'Docs', 'Community' - ]); - const sectionPattern = /data-pagefind-meta="section:([^"]+)"/g; - const foundSections = new Set(); - for (const file of [...docsHtmlFiles, ...blogHtmlFiles]) { - const html = fs.readFileSync(file, 'utf-8'); - for (const match of html.matchAll(sectionPattern)) { - foundSections.add(match[1]); - } - } - assert.ok(foundSections.size > 0, 'Should find at least one section value'); - for (const section of foundSections) { - assert.ok( - knownSections.has(section), - `Unexpected section value "${section}" — expected one of: ${[...knownSections].join(', ')}` - ); - } - }); - - it('blog pages have section:Blog', () => { - assert.ok(blogHtmlFiles.length > 0, 'Should have blog HTML files to test'); - for (const file of blogHtmlFiles) { - const html = fs.readFileSync(file, 'utf-8'); - assert.ok( - html.includes('data-pagefind-meta="section:Blog"'), - `Blog page missing section:Blog — ${path.relative(DIST, file)}` - ); - } - }); -}); - -// ── data-pagefind-weight on headings ────────────────────────────────────────── - -describe('data-pagefind-weight on headings', () => { - it('docs pages have data-pagefind-weight="2" on h2 or h3 elements inside article', () => { - const weightPattern = /]*data-pagefind-weight="2"/; - // Only check pages that have h2/h3 inside a prose article (standard content pages) - const articleHeadingPattern = /data-pagefind-body[\s\S]*?]/; - const pagesWithArticleHeadings = docsHtmlFiles.filter(f => { - const html = fs.readFileSync(f, 'utf-8'); - return articleHeadingPattern.test(html); - }); - assert.ok(pagesWithArticleHeadings.length > 0, 'Should have docs pages with h2/h3 inside article'); - - const missing = []; - for (const file of pagesWithArticleHeadings) { - const html = fs.readFileSync(file, 'utf-8'); - if (!weightPattern.test(html)) { - missing.push(path.relative(DIST, file)); - } - } - assert.equal( - missing.length, 0, - `These pages with article headings lack data-pagefind-weight="2": ${missing.join(', ')}` - ); - }); -}); - -// ── data-pagefind-ignore on nav, footer, pre ────────────────────────────────── - -describe('data-pagefind-ignore attributes', () => { - // Use one representative docs page that has all elements - const sampleFile = docsHtmlFiles.find(f => f.includes('built-in-roles')); - const sampleHtml = sampleFile ? fs.readFileSync(sampleFile, 'utf-8') : ''; - - it('nav elements have data-pagefind-ignore', () => { - assert.ok(sampleFile, 'Sample file (built-in-roles) should exist'); - const navTags = [...sampleHtml.matchAll(/]*>/g)].map(m => m[0]); - assert.ok(navTags.length > 0, 'Page should contain nav elements'); - for (const tag of navTags) { - assert.ok( - tag.includes('data-pagefind-ignore'), - `nav element missing data-pagefind-ignore: ${tag.substring(0, 80)}` - ); - } - }); - - it('footer elements have data-pagefind-ignore', () => { - assert.ok(sampleFile, 'Sample file should exist'); - const footerTags = [...sampleHtml.matchAll(/]*>/g)].map(m => m[0]); - assert.ok(footerTags.length > 0, 'Page should contain footer elements'); - for (const tag of footerTags) { - assert.ok( - tag.includes('data-pagefind-ignore'), - `footer element missing data-pagefind-ignore: ${tag.substring(0, 80)}` - ); - } - }); - - it('pre (code block) elements have data-pagefind-ignore', () => { - assert.ok(sampleFile, 'Sample file should exist'); - const preTags = [...sampleHtml.matchAll(/]*>/g)].map(m => m[0]); - assert.ok(preTags.length > 0, 'Page should contain pre elements'); - for (const tag of preTags) { - assert.ok( - tag.includes('data-pagefind-ignore'), - `pre element missing data-pagefind-ignore: ${tag.substring(0, 80)}` - ); - } - }); -}); +/** + * Build output tests for Phase 1 search improvements. + * Validates that pagefind attributes are correctly applied in the built HTML. + * Run with: node --test tests/build-output.test.mjs + */ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import path from 'node:path'; +const DOCS_ROOT = path.resolve(import.meta.dirname, '..'); +const DIST = path.join(DOCS_ROOT, 'dist'); +// Collect HTML files from dist for reuse across tests +function findHtmlFiles(dir, files = []) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory() && entry.name !== '_astro' && entry.name !== 'pagefind') { + findHtmlFiles(full, files); + } else if (entry.isFile() && entry.name.endsWith('.html')) { + files.push(full); + } + } + return files; +} +const allHtmlFiles = findHtmlFiles(DIST); +// Exclude top-level pages (404, home, blog index) which use different layouts +const EXCLUDED_PAGES = ['404.html', `blog${path.sep}index.html`, 'index.html']; +function isContentPage(file) { + const rel = path.relative(DIST, file); + return !EXCLUDED_PAGES.some(exc => rel === exc || rel === exc.replace(/\//g, path.sep)); +} +const docsHtmlFiles = allHtmlFiles.filter(f => + f.includes(`${path.sep}docs${path.sep}`) && isContentPage(f) +); +const blogHtmlFiles = allHtmlFiles.filter(f => + f.includes(`${path.sep}blog${path.sep}`) && isContentPage(f) +); +// ── pagefind.yml ────────────────────────────────────────────────────────────── +describe('pagefind.yml configuration', () => { + it('exists in the docs root', () => { + assert.ok( + fs.existsSync(path.join(DOCS_ROOT, 'pagefind.yml')), + 'pagefind.yml should exist at docs root' + ); + }); + it('contains exclude_selectors for nav, footer, aside, pre, .astro-code', () => { + const content = fs.readFileSync(path.join(DOCS_ROOT, 'pagefind.yml'), 'utf-8'); + for (const selector of ['nav', 'footer', 'aside', 'pre', '.astro-code']) { + assert.ok( + content.includes(`"${selector}"`) || content.includes(`'${selector}'`) || content.includes(`- ${selector}`) || content.includes(`- "${selector}"`), + `pagefind.yml should exclude selector: ${selector}` + ); + } + }); +}); +// ── Pagefind index output ───────────────────────────────────────────────────── +describe('pagefind build output', () => { + it('pagefind directory exists in dist/', () => { + assert.ok( + fs.existsSync(path.join(DIST, 'pagefind')), + 'dist/pagefind/ directory should exist after build' + ); + }); + it('pagefind.js is present in pagefind directory', () => { + assert.ok( + fs.existsSync(path.join(DIST, 'pagefind', 'pagefind.js')), + 'dist/pagefind/pagefind.js should exist' + ); + }); +}); +// ── data-pagefind-body on article elements ──────────────────────────────────── +describe('data-pagefind-body attribute', () => { + it('docs pages contain data-pagefind-body on article elements', () => { + assert.ok(docsHtmlFiles.length > 0, 'Should have docs HTML files to test'); + const missing = []; + for (const file of docsHtmlFiles) { + const html = fs.readFileSync(file, 'utf-8'); + if (!html.includes('data-pagefind-body')) { + missing.push(path.relative(DIST, file)); + } + } + assert.equal(missing.length, 0, `These docs pages lack data-pagefind-body: ${missing.join(', ')}`); + }); + it('blog post pages contain data-pagefind-body on article elements', () => { + assert.ok(blogHtmlFiles.length > 0, 'Should have blog HTML files to test'); + for (const file of blogHtmlFiles) { + const html = fs.readFileSync(file, 'utf-8'); + assert.ok( + html.includes('data-pagefind-body'), + `Blog page missing data-pagefind-body: ${path.relative(DIST, file)}` + ); + } + }); +}); +// ── data-pagefind-meta with section values ──────────────────────────────────── +describe('data-pagefind-meta section attribute', () => { + it('docs pages have data-pagefind-meta with a section value', () => { + assert.ok(docsHtmlFiles.length > 0, 'Should have docs HTML files to test'); + const sectionPattern = /data-pagefind-meta="section:([^"]+)"/; + const missing = []; + for (const file of docsHtmlFiles) { + const html = fs.readFileSync(file, 'utf-8'); + if (!sectionPattern.test(html)) { + missing.push(path.relative(DIST, file)); + } + } + assert.equal( + missing.length, 0, + `These docs pages lack data-pagefind-meta section: ${missing.join(', ')}` + ); + }); + it('section values match expected categories', () => { + const knownSections = new Set([ + 'Get Started', 'Guides', 'Core Features', 'Advanced Features', + 'Infrastructure', 'Reference', 'Scenarios', 'Concepts', + 'Blog', 'Docs', 'Community' + ]); + const sectionPattern = /data-pagefind-meta="section:([^"]+)"/g; + const foundSections = new Set(); + for (const file of [...docsHtmlFiles, ...blogHtmlFiles]) { + const html = fs.readFileSync(file, 'utf-8'); + for (const match of html.matchAll(sectionPattern)) { + foundSections.add(match[1]); + } + } + assert.ok(foundSections.size > 0, 'Should find at least one section value'); + for (const section of foundSections) { + assert.ok( + knownSections.has(section), + `Unexpected section value "${section}" — expected one of: ${[...knownSections].join(', ')}` + ); + } + }); + it('blog pages have section:Blog', () => { + assert.ok(blogHtmlFiles.length > 0, 'Should have blog HTML files to test'); + for (const file of blogHtmlFiles) { + const html = fs.readFileSync(file, 'utf-8'); + assert.ok( + html.includes('data-pagefind-meta="section:Blog"'), + `Blog page missing section:Blog — ${path.relative(DIST, file)}` + ); + } + }); +}); +// ── data-pagefind-weight on headings ────────────────────────────────────────── +describe('data-pagefind-weight on headings', () => { + it('docs pages have data-pagefind-weight="2" on h2 or h3 elements inside article', () => { + const weightPattern = /]*data-pagefind-weight="2"/; + // Only check pages that have h2/h3 inside a prose article (standard content pages) + const articleHeadingPattern = /data-pagefind-body[\s\S]*?]/; + const pagesWithArticleHeadings = docsHtmlFiles.filter(f => { + const html = fs.readFileSync(f, 'utf-8'); + return articleHeadingPattern.test(html); + }); + assert.ok(pagesWithArticleHeadings.length > 0, 'Should have docs pages with h2/h3 inside article'); + const missing = []; + for (const file of pagesWithArticleHeadings) { + const html = fs.readFileSync(file, 'utf-8'); + if (!weightPattern.test(html)) { + missing.push(path.relative(DIST, file)); + } + } + assert.equal( + missing.length, 0, + `These pages with article headings lack data-pagefind-weight="2": ${missing.join(', ')}` + ); + }); +}); +// ── data-pagefind-ignore on nav, footer, pre ────────────────────────────────── +describe('data-pagefind-ignore attributes', () => { + // Use one representative docs page that has all elements + const sampleFile = docsHtmlFiles.find(f => f.includes('built-in-roles')); + const sampleHtml = sampleFile ? fs.readFileSync(sampleFile, 'utf-8') : ''; + it('nav elements have data-pagefind-ignore', () => { + assert.ok(sampleFile, 'Sample file (built-in-roles) should exist'); + const navTags = [...sampleHtml.matchAll(/]*>/g)].map(m => m[0]); + assert.ok(navTags.length > 0, 'Page should contain nav elements'); + for (const tag of navTags) { + assert.ok( + tag.includes('data-pagefind-ignore'), + `nav element missing data-pagefind-ignore: ${tag.substring(0, 80)}` + ); + } + }); + it('footer elements have data-pagefind-ignore', () => { + assert.ok(sampleFile, 'Sample file should exist'); + const footerTags = [...sampleHtml.matchAll(/]*>/g)].map(m => m[0]); + assert.ok(footerTags.length > 0, 'Page should contain footer elements'); + for (const tag of footerTags) { + assert.ok( + tag.includes('data-pagefind-ignore'), + `footer element missing data-pagefind-ignore: ${tag.substring(0, 80)}` + ); + } + }); + it('pre (code block) elements have data-pagefind-ignore', () => { + assert.ok(sampleFile, 'Sample file should exist'); + const preTags = [...sampleHtml.matchAll(/]*>/g)].map(m => m[0]); + assert.ok(preTags.length > 0, 'Page should contain pre elements'); + for (const tag of preTags) { + assert.ok( + tag.includes('data-pagefind-ignore'), + `pre element missing data-pagefind-ignore: ${tag.substring(0, 80)}` + ); + } + }); +});