Repository navigation
feat(agent-context): richer squad.agent.md generation for AW coordinator awareness - #1880
bradygaster wants to merge 5 commits into
Conversation
…tor awareness (#1608) - Add SQUAD_TEAM_CONTEXT_BEGIN/END markers to squad.agent.md template - New agent-context.ts module: parseTeamMdMembers, parseRoutingMd, generateAWTeamContextBlock, injectTeamContext, refreshTeamContextInAgentFile - Sanitizes all untrusted metadata to prevent Markdown/HTML injection - Wire regeneration into cast.ts createTeam() and upgrade.ts writeAgentTemplate() - Focused tests: sanitization, parsing, generation, injection, prompt budget - Patch changeset for squad-cli Closes #1608 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🟠 Impact Analysis — PR #1880Risk tier: 🟠 HIGH 📊 Summary
🎯 Risk Factors
📦 Modules Affectedci-workflows (1 file)
root (2 files)
squad-cli (4 files)
squad-sdk (1 file)
templates (1 file)
tests (1 file)
This report is generated automatically for every PR. See #733 for details. |
🏗️ Architectural Review
Automated architectural review — informational only. |
🛫 PR Readiness Check
PR Scope: 📦🔧 Mixed (product + infrastructure)
|
| Status | Check | Details |
|---|---|---|
| ❌ | Single commit | 5 commits — consider squashing before review |
| ✅ | Not in draft | Ready for review |
| ❌ | Branch up to date | dev is 1 commit(s) ahead — rebase recommended |
| ❌ | Copilot review | No Copilot review yet — it may still be processing |
| ✅ | Changeset present | Changeset file found |
| ✅ | Scope clean | No .squad/ or docs/proposals/ files |
| ✅ | No merge conflicts | No merge conflicts |
| ✅ | Copilot threads resolved | 1 active Copilot thread(s) resolved (5 outdated skipped) |
| ✅ | CI passing | All checks passing |
Files Changed (10 files, +1519 −3)
| File | +/− |
|---|---|
.changeset/squad-agent-aw-context.md |
+5 −0 |
.github/agents/squad.agent.md |
+12 −1 |
.squad-templates/squad.agent.md |
+11 −0 |
packages/squad-cli/src/cli/core/agent-context.ts |
+561 −0 |
packages/squad-cli/src/cli/core/cast.ts |
+9 −0 |
packages/squad-cli/src/cli/core/upgrade.ts |
+11 −2 |
packages/squad-cli/templates/squad.agent.md.template |
+11 −0 |
packages/squad-sdk/templates/squad.agent.md.template |
+11 −0 |
templates/squad.agent.md.template |
+11 −0 |
test/squad-agent-aw-context.test.ts |
+877 −0 |
Total: +1519 −3
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
There was a problem hiding this comment.
🟡 Changes recommended
There are confirmed contract/behavior mismatches (ordering, dedupe, “no hardcoded team names”, status filtering) and a couple tests that can pass despite regressions due to conditional assertions.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds an auto-generated “Team Roster (AW Coordinator Reference)” block to squad.agent.md so outer Agentic Workflows coordinators can see Squad’s specialist roster, routing hints, and capability boundaries derived from .squad/team.md and .squad/routing.md. This is wired into squad cast and squad upgrade, with sanitization and byte-budget tests to prevent prompt injection and runaway size.
Changes:
- Introduces
agent-context.tsto parseteam.md/routing.md, sanitize fields, generate an AW context block, and inject it betweenSQUAD_TEAM_CONTEXT_BEGIN/ENDmarkers. - Updates
cast.tsandupgrade.tsto refresh the injected block at lifecycle points and to ignore the injected block when deciding whethersquad.agent.mdhas local customizations. - Updates all squad.agent template mirrors to include the new marker block + placeholder, and adds focused unit tests + a CLI changeset.
File summaries
| File | Description |
|---|---|
packages/squad-cli/src/cli/core/agent-context.ts |
New module for parsing/sanitizing/generating/injecting AW coordinator team context. |
packages/squad-cli/src/cli/core/cast.ts |
Refreshes AW team context in squad.agent.md after team creation. |
packages/squad-cli/src/cli/core/upgrade.ts |
Strips team-context block during upgrade comparisons; refreshes block post-template write. |
test/squad-agent-aw-context.test.ts |
Adds unit tests for parsing, sanitization, injection, and prompt-budget limits. |
.squad-templates/squad.agent.md |
Canonical template gains Team Roster section with begin/end markers and placeholder. |
templates/squad.agent.md.template |
Root template mirror updated with the same Team Roster marker block. |
packages/squad-cli/templates/squad.agent.md.template |
CLI template mirror updated with the same Team Roster marker block. |
packages/squad-sdk/templates/squad.agent.md.template |
SDK template mirror updated with the same Team Roster marker block. |
.github/agents/squad.agent.md |
Repo’s checked-in agent file updated to include marker block + a small wording tweak. |
.changeset/squad-agent-aw-context.md |
Patch changeset for @bradygaster/squad-cli documenting the feature. |
Review details
- Files reviewed: 10/10 changed files
- Comments generated: 6
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- sanitizeField/sanitizeBlock: strip Markdown link destinations ([label](url) -> label, [label][ref] -> label) and Unicode bidi control characters (U+200E/F, U+202A-E, U+2066-9) and other dangerous invisible structural controls - sanitizeTimestamp: new internal helper that truncates at first --> (prevents HTML comment breakout) and strips <!-- (prevents nested comment injection); applied in generateAWTeamContextBlock - refreshTeamContextInAgentFile no-op semantics: extract existing timestamp from current block, generate candidate with same timestamp so comparison is timestamp-independent; only writes when semantic team content actually changed. Exposes extractBlockTimestamp and _computeTeamContextRefresh for direct unit testing - buildRoutingHintsTable: remove false 'Deduplicates by agent' JSDoc claim; actual behavior (preserve source order, cap at 15) is correct and preserves distinct authoritative task types - generateAWTeamContextBlock: sort specialist table alphabetically by name for deterministic output regardless of team.md order; routing table preserves routing.md source order (intentionally ordered by priority) - buildAndInjectTeamContext: accept optional timestamp parameter and thread it through to generateAWTeamContextBlock - Tests: add bidi/link-stripping tests for sanitizeField/sanitizeBlock; add specialist-sort and routing-no-dedup tests; strengthen buildAndInjectTeamContext integration test to assert TEAM_CONTEXT_DEFAULT text; add direct tests for extractBlockTimestamp and _computeTeamContextRefresh (write/no-op/markers-absent paths); add refreshTeamContextInAgentFile file-absent no-op test; add timestamp injection prevention test; fix HTML-comment test to check the member table row specifically (block has legitimate HTML comment in timestamp line) Closes #1608 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…n refresh tests - Fix extractBlockTimestamp: replace [^.]+ with non-greedy (.+?) so ISO timestamps with fractional milliseconds (e.g. 2026-08-25T10:19:28.963Z) round-trip correctly. The old [^.]+ stopped at the first dot, causing the entire match to fail and extractBlockTimestamp to return undefined, which broke _computeTeamContextRefresh no-op semantics (the undefined existingTimestamp fell back to nowTimestamp, always producing a write). - Replace localeCompare with plain < / > string comparison in the generateAWTeamContextBlock sort so specialist table ordering is deterministic across all system locales. - Add extractBlockTimestamp round-trip tests (with and without fractional seconds) to guard against regex regressions. - Add filesystem round-trip tests for _computeTeamContextRefresh that write a real team.md, build content via buildAndInjectTeamContext, extract the embedded timestamp, and feed it back into refresh — proving the no-op path without pre-handing an already-known timestamp to a helper. - Add locale-independent sort stability test. Closes #1608 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ontext builders generateAWTeamContextBlock delegates to buildSpecialistTable and buildRoutingHintsTable, which embedded ActiveMember.name/role/status and RoutingRow.workType/agent verbatim. sanitizeField was only called in the parsers (parseTeamMdMembers, parseRoutingMd), so callers that construct ActiveMember/RoutingRow objects directly — including tests and any future programmatic callers — bypassed sanitization. Fix: call sanitizeField at the embedding point in each builder. sanitizeField is idempotent for already-sanitized data, so the parsers' pre-sanitization is unaffected. Closes #1608 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Thread PRRT_kwDORJ3-vM6cKFV5: remove hardcoded cast names (booster/capcom/control/eecom/flight/surgeon) from buildCapabilityBoundaries regexes; capability inference now uses only generic role keywords so any custom team gets correct output. - Thread PRRT_kwDORJ3-vM6cKFWZ: add blacklist-based status filtering to parseTeamMdMembers; rows with 'retired'/'disabled'/'inactive'/'alumni' status are excluded; all other statuses (including custom/unknown) are retained so non-standard teams are not silently dropped. Update JSDoc to reflect blacklist contract. Export isActiveStatus logic is documented. - Thread PRRT_kwDORJ3-vM6cKFWx: make parseTeamMdMembers sanitizer test unconditional — assert members.length===1 before asserting name content. - Thread PRRT_kwDORJ3-vM6cKFXM: make parseRoutingMd pipe-sanitizer test unconditional — assert rows.length===1 before asserting examples content. - Add parseTeamMdMembers status filtering describe block with it.each over all built-in status forms, known-inactive exclusions, custom/unknown retention, mixed-team counts, and determinism proof. - Add generateAWTeamContextBlock capability portability describe block proving generic role keywords (not cast names) drive derivation. Closes #1608 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
EECOM revision — addresses all CONTROL+FIDO blocking findings on #1608 PR.
Changes: no-op semantics for refreshTeamContextInAgentFile (timestamp-independent comparison via extractBlockTimestamp/_computeTeamContextRefresh); removed false dedup claim from buildRoutingHintsTable; implemented alphabetical sort for specialist table; strengthened integration test; bidi/link-stripping in sanitizeField/sanitizeBlock; sanitizeTimestamp truncates at first -->; buildAndInjectTeamContext accepts optional timestamp. Direct tests for all new paths.
Dependency blocker: @oxc-project/types@0.146.0 not in proxy — vitest could not run. TypeScript check: zero errors in changed files.
Closes #1608