How to review PRs for architectural quality — module boundaries, dependency direction, export surface, pattern consistency
When reviewing a PR that touches core architecture, the reviewer must verify that structural invariants are preserved. This skill covers reviewing existing PRs for architectural quality — not writing proposals (see architectural-proposals/SKILL.md for that).
Use this skill when a PR includes any of:
package.json, import additions across package boundaries)index.ts barrel files)The Squad codebase has two core packages with a strict dependency direction:
squad-cli → depends on → squad-sdk
squad-sdk → NEVER depends on → squad-cli
Check every new import statement in the PR:
@bradygaster/squad-sdk)The CLI has protected bootstrap files that must use ONLY Node.js built-in modules (node:fs, node:path, node:child_process, node:util). These files run before the SDK is loaded.
Protected files (authoritative list from copilot-instructions.md):
| File | Purpose |
|---|---|
packages/squad-cli/src/cli/core/detect-squad-dir.ts | Finds .squad/ at startup |
packages/squad-cli/src/cli/core/errors.ts | Error classes (SquadError, fatal()) |
packages/squad-cli/src/cli/core/gh-cli.ts | GitHub CLI wrapper |
packages/squad-cli/src/cli/core/output.ts | Color/emoji console output |
packages/squad-cli/src/cli/core/history-split.ts | Portable knowledge separator |
Review checklist for bootstrap files:
import or require of anything outside node:*FSStorageProvider, StorageProvider, or SDK abstractions— zero dependencies markers in file headersChanges to barrel files (index.ts) have downstream impact. Barrel files define the public API of a package.
Review checklist:
FSStorageProvidr vs. FSStorageProvider).export * from './internal-module', verify that the internal module doesn't accidentally expose private types.When a PR applies a codebase-wide pattern change (e.g., "convert all fs calls to StorageProvider"), verify the 5-step checklist from project instructions:
— zero dependencies headers were skippedimport { X } from '@bradygaster/squad-sdk' references an export that actually exists in the SDK barrel fileTemplate files exist in four locations and must stay consistent:
templates/ # Source of truth
.squad-templates/ # Local project templates
packages/squad-cli/templates/ # CLI-bundled templates
.github/workflows/ # Workflow templates
If a PR modifies a template in one location, check:
TEMPLATE_MANIFEST in templates.ts still correctly map files to agents?.squad/ Leakage Check.squad/ files (team config, decisions, agent charters) must NOT leak into feature PRs that are about code changes.
Check:
.squad/team.md, .squad/decisions.md, .squad/routing.md, or agent charters — unless the issue specifically calls for it.squad/decisions/inbox/ files are acceptable if the PR documents a decision made during implementation.squad-templates/ changes are acceptable only if the PR is about template functionalityNew code should follow established patterns in the codebase. Look for:
kebab-case file names, PascalCase classes)SquadError and fatal() from errors.ts, or does it invent its own error patterns?StorageProvider for file I/O (except in protected bootstrap files)?core/The packages/squad-cli/src/cli/core/ directory contains a mix of:
When reviewing changes to core/ files:
core/ — determine if they are bootstrap or post-SDK and document accordinglyExample 1: Reject — SDK import in bootstrap file
PR adds to detect-squad-dir.ts:
import { FSStorageProvider } from '@bradygaster/squad-sdk';
Finding: REJECT — detect-squad-dir.ts is a protected bootstrap file.
It runs before the SDK is loaded. This import will crash the CLI at startup.
Recommendation: Use node:fs directly. See Protected Files table.
Example 2: Reject — Reverse dependency
PR adds to packages/squad-sdk/src/storage.ts:
import { detectSquadDir } from '@bradygaster/squad-cli';
Finding: REJECT — SDK must never depend on CLI. Dependency direction is
CLI → SDK, not reverse. Move the shared logic to SDK or extract to a
shared utility within the SDK package.
Example 3: Approve with note — Template change in one location
PR modifies templates/squad.agent.md but not .squad-templates/squad.agent.md
Finding: APPROVE with note — Template was updated in templates/ but the
same file in .squad-templates/ was not synced. Verify whether .squad-templates/
should match or if it intentionally diverges.
Example 4: Reject — Sweeping refactor hits protected file
PR titled "Convert all fs calls to StorageProvider" modifies 15 files,
including packages/squad-cli/src/cli/core/output.ts
Finding: REJECT — output.ts is a protected zero-dependency bootstrap file.
The PR must skip this file. See Sweeping Refactor Rules step 1.
Example 5: Flag — Mass file deletion
PR deletes 25 files as part of "cleanup unused modules"
Finding: FLAG — More than 20 files deleted. This exceeds the red flag
threshold. Verify each deletion is intentional and no downstream imports
are broken. Recommend splitting into smaller PRs.
Structure your architectural review as:
## Architectural Review
**Verdict:** APPROVE | APPROVE WITH NOTES | REQUEST CHANGES | REJECT
### Findings
1. [severity: critical|high|medium|low] — description
- File(s): path/to/file.ts
- Recommendation: what to fix
2. [severity: ...] — ...
### Summary
Brief explanation of architectural impact and any required follow-ups.
.squad/ config changes in feature PRs without justificationcore/ files slip in without classifying them as bootstrap vs. post-SDK