agentleFS
dayvisonassisdayvisonassis/sdd-skills/skills/gate-builder/SKILL.md

gate-builder

Skill3 starsChanged 32 days agoMITView on GitHub

Builds the deterministic quality-gate infrastructure for a project (typecheck, lint with zero-warnings, dependency/architecture checks, tests, dead-code, and a single runGate entry point) from the Deep Analysis Report (+ Architecture Analysis Report). Auto-detects greenfield vs. brownfield, proposes a gate plan for confirmation, then writes the configs/scripts and verifies each gate runs. The gates it builds are later declared in each feature's contract.md by spec-writer.

  • Reads credentials

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

16 rules. About 0 are common, 8 are distinctive, and 8 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈8

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If neither report is found, the skill can still operate in a reduced mode by reading the codebase directly (see Edge Cases), but the …

    line 25
  2. Distinctive:

    No application/business code is modified — only gate configuration, scripts, and docs.

    line 33
  3. Distinctive:

    Do not enable it in the default gate list until it has been proven green once.

    line 117
  4. Very specific:

    Create or extend the gate's config (e.g.

    line 196
  5. Distinctive:

    Add/declare any required dev dependencies (respecting the package manager from the Architecture Report).

    line 197
  6. Very specific:

    Add a per-gate script entry to the manifest (package.json scripts or equivalent), each runnable standalone (gate:lint, gate:arch, ...).

    line 200
  7. Very specific:

    Create a single entry point (scripts/runGate.mjs or the stack's idiom) that runs the gates in order, cheapest first (typecheck → lint → …

    line 209
  8. Very specific:

    Add a top-level gate script that invokes it.

    line 210
  9. Very specific:

    Run runGate (and each gate individually if the orchestrator stops early).

    line 216
  10. Distinctive:

    Greenfield: every gate should pass on the skeleton (or honestly report what's missing — e.g.

    line 217
  11. Distinctive:

    Keep this section next to the gate list, not in an appendix, and keep it honest: it is the contract for what still needs a human or a …

    line 231
  12. Very specific:

    Prefer the Deep Analysis Report as the primary source and the Architecture Report for stack/tooling.

    line 255
  13. Distinctive:

    Verify each gate actually runs before claiming success.

    line 262
  14. Very specific:

    Only write gate configs/scripts/docs — never modify application/business code.

    line 263
  15. Distinctive:

    No reports found: prefer to request the Deep/Architecture reports.

    line 279
  16. Very specific:

    Existing runGate/gate scripts already present: treat as brownfield; extend the existing orchestrator and scripts rather than replacing …

    line 285

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Gate Builder

Construct the deterministic quality gates of a project — the automated, pass/fail checks that guard structural and behavioral integrity (see https://github.com/dayvisonassis/sdd-skills/blob/main/docs/Como_criar_gates.md). The skill reads the analysis reports, decides which gates the project needs, proposes a plan, and — after confirmation — writes the gate configs/scripts and a single orchestration entry point (runGate), verifying each gate actually runs.

Where this fits the SDD flow: gate-builder builds the gate infrastructure that must exist before features are spec'd. Later, spec-writer declares these gates (by id) in each feature's contract.md, and implement-feature / evaluator execute them. See https://github.com/dayvisonassis/sdd-skills/blob/main/docs/ARQUITETURA_DAS_SKILLS.md and https://github.com/dayvisonassis/sdd-skills/blob/main/docs/Como_criar_gates.md.

INPUT

Free-form. The skill needs:

  • Deep Analysis Report (primary source) — produced by the deep-analyzer agent. Provides cross-cutting patterns, anti-patterns, test gaps, config-access patterns (e.g. scattered process.env), and complexity.
  • Architecture Analysis Report (secondary source) — produced by the architecture-analyzer agent. Provides the stack/runtime/framework, dependency inventory, and the test infrastructure/tooling.
  • Auto-discovery: if paths are not passed, look in docs/architecture/ for the most recent deep-analysis-*.md (primary) and architecture-analysis-*.md (secondary).
  • Optional free-form overrides — e.g. "lint only", "no dead-code gate", "strict zero-warnings now", "don't touch package.json".

If neither report is found, the skill can still operate in a reduced mode by reading the codebase directly (see Edge Cases), but the reports are strongly preferred — request them if the codebase is large/ambiguous.

OUTPUT

  • Phase 1 — a Gate Plan (chat + saved doc): which gates, which commands/configs, greenfield vs. brownfield strategy, and the runGate order. Each gate gets a stable id (typecheck, lint, build, tests, arch, deadcode, ...) — the same id spec-writer will use in contract.md.
  • Phase 2 — after confirmation — the gate infrastructure: config files, scripts, package.json (or equivalent) entries, and the runGate orchestrator, plus a short GATES.md documenting how to run them.
  • A verification report: each gate executed once, with pass/fail and notes (especially the brownfield baseline of pre-existing warnings/failures).

No application/business code is modified — only gate configuration, scripts, and docs.


EXECUTION STEPS

Step 1: Resolve Input & Load Reports

  • Locate the Deep Analysis Report and the Architecture Analysis Report (passed paths, or newest in docs/architecture/).
  • From the Architecture Report, extract: runtime/language, framework, package manager, dependency inventory, and the test infrastructure (test runner, config files) — Section 2 and Section 11.
  • From the Deep Analysis Report, extract: cross-cutting patterns (error handling, validation, configuration access pattern — §2.5), anti-patterns (circular deps, God objects, N+1, hardcoded config), test gaps, and complexity hot-spots.
  • Parse overrides (gate inclusions/exclusions, strictness, "don't touch X").

Step 2: Detect Project State (greenfield vs. brownfield)

Decide the build strategy:

  • Greenfield = no real gate tooling exists yet (no lint/typecheck/test config beyond scaffolding defaults; reports show minimal/zero tests). → Build the full gate stack from the stack's conventions.
  • Brownfield = the project already has some tooling and a body of code. → Adapt to the existing commands and configs; integrate gates without breaking the build; introduce zero-warnings incrementally (see Step 4).

Detection signals: presence of lint/typecheck/test config files and scripts (Architecture §2/§11), amount of existing code, and the test-coverage estimate. State which mode was detected and why.

Step 3: Select the Gate Set

From Como_criar_gates.md, choose the gates the project needs, mapped to the detected stack. Each gate gets a stable id:

Gate idPurposeTypical command (stack-adapted)Derived from
typecheckType contracttsc --noEmit (or stack equivalent)Architecture stack
lintConsistency, zero warningseslint . --max-warnings=0 (or equivalent)Architecture tooling
buildCompiles/buildsproject build commandArchitecture stack
testsBehaviorunit/integration test commandArchitecture §11
archBoundariesdependency-cruiser rules + custom check-architecture scriptDeep §2/§9 anti-patterns
deadcodeHygieneknip (or equivalent)Deep test gaps / unused code
design-systemUI conformancestylelint (CSS) + custom template lint rules (HTML/JSX) + filename checksa design-system doc of the project (see below) + the dominant UI patterns in the code
visual-contractRendered valuesa browser runner (Playwright/equivalent) asserting computed valuesdefects that static rules structurally cannot see (see below)
e2eUser flowsa browser runner driving real flows through the UI and API of the running appthe project's UI runtime surfaces + the test infrastructure (see below)

What a test gate builds — and what it never does. For tests and e2e, this skill builds the runner and the harness: config, scripts, the orchestrator entry, and in greenfield the runner's installation. It writes no feature tests and no test rules. Where tests live, their patterns, their data policy and which accounts they use are architecture decisions of the team. This skill records them in GATES.md — it does not make them: the generic test-writers and validators read the project from there, and they are dispatched per feature by implement-feature and evaluator through contract.md — never by this skill. In greenfield with no decided test strategy, record in GATES.md that it is undecided (test patterns, data policy, which accounts feature tests use) instead of inventing one. The harness still needs a directory and an account for its seed: pick them, and mark both provisional in GATES.md for the team to confirm.

The test profile — what GATES.md must state for the tests gates. One section, read by unit-test-writer, integration-test-writer, their validators, implement-feature, evaluator and spec-writer. It states the project profile of each rule file (../unit-test-writer/references/unit-rules.md and ../integration-test-writer/references/integration-rules.md, first section of each):

  • a suites table — one row per suite: its id, its kind (unit or integration), the sources it covers, where its tests live and how they are named, and the gate that runs it. This table is what selects a test-writer; a suite it does not list has none;
  • per suite, the runner, the language of a test file and its import or module form, and the command for one selection (a file, a package or a name filter, whichever the runner selects by) and for the whole suite, with the environment each needs;
  • the tracked path of the project's own test rules, when the team has them — the order doubles are installed in, banned testing APIs, shared helpers. Point at them; never write them here, and say so when there are none;
  • for an integration suite: the entry point, the environment and the helpers that open and close it, the authentication helper, and the data policy — the records never touched, how a test creates its own, the removal order per entity, or the isolation mechanism that replaces manual cleanup;
  • the query counter, when the project has a query-growth (N+1) check: the helper, what it observes, and where the check applies. Without one, say that the project has no such check.

In brownfield, derive each item from the suites that already exist (Architecture §11) and mark what was inferred. Never state a convention the code does not show.

The visual-contract gate — why a static rule is not enough. A linter reads one file; it cannot see a colour composed over a translucent parent, a transform, or a value a global !important overrode. Component tests usually run in a DOM emulator (jsdom and friends) with no layout at all — no real getBoundingClientRect, no resolved transform, no global cascade — so a suite can be entirely green while a label sits on top of the text it labels. Real cases this catches, all of which survived a green run: a status badge at 2.19:1 contrast in one theme only; a floating label overlapping the typed value; that same label at 12px next to siblings rendering at 9px; overlay select options at the framework default because the panel lives outside the component's style encapsulation; and one user action firing two identical requests.

Start it from defects you actually hit, not from a wish list, and keep it small — it grows one assertion per bug. Points worth encoding: element heights and densities, contrast ratios of text over tinted backgrounds in every theme, effective font size (font-size × scale, since comparing font-size between a scaled and an unscaled element proves nothing), overlay-rendered widgets, hover states that a global stylesheet may hijack, and one-action-one-request.

Mind the two properties that make it different from every other gate, and design for them explicitly:

  • It needs the app running. Scope it changed-files-style so a backend-only change is a no-op pass; when UI files did change and the app is unreachable, fail with instructions rather than skipping. A gate that skips quietly is the "green means verified" illusion in its purest form. Provide one deliberate escape hatch (an env flag) that prints a loud banner naming what went unverified.
  • It runs headless. That is correct for a gate and is not the same thing as the headed run a human follows during a smoke test — say so wherever both are mentioned, or someone will watch an empty screen waiting for a window that never opens.

Do not enable it in the default gate list until it has been proven green once. An unproven browser gate turns every run red for harness reasons (login walls, CAPTCHA, timing) rather than code reasons, which is worse than not having it.

The e2e gate — the harness is the gate's, the tests are not. Where visual-contract reads rendered values, e2e drives a user flow and asserts what observably follows (a search narrows, a submit is refused, a record appears). It shares the two properties above — it needs the app running, and it runs headless — and adds three of its own:

  • Separate from visual-contract. Its own runner config and test directory. A browser runner collects every test under its configured directory, so a shared config makes each gate silently run the other's suite.
  • Sessions are bootstrapped once and reused — across runs, not only within one. Authenticate in the runner's global setup, store the session, and let every test reuse it; on the next run, reuse the stored session while it is still valid instead of logging in again, and share the visual gate's stored sessions when both exist. Auth endpoints are usually rate-limited, and every caller of this gate (the implementer, the evaluator, the correctors) runs it repeatedly — a harness that logs in per run spends the budget in a few evaluations, and one that logs in per test fails its second run on the sign-in screen, which reads as product defects. Never forge a session or bypass an anti-bot check; use only the application's documented non-production anti-bot setting (not to be confused with the gate's own skip flag above), and name it in GATES.md. One runner project per session (e.g. admin and agent), so the folder a test lives in decides its session.
  • A seed test proves the harness, not the product. An e2e gate with zero tests passes having verified nothing. Build one seed test per session that lands on the app — authenticated, when the app has authentication — it is infrastructure, like the deliberate violation of Step 7 — and prove the gate fail→pass by breaking a seed's expectation. Feature tests come later, from the project's e2e test-writer.

Scope it like visual-contract but wider: a flow crosses the stack, so it runs when UI or API sources change, or the suite itself; no-op otherwise. Like visual-contract, keep it out of the default gate list until it has been proven green once — and record in GATES.md when it was, because the SDD skills treat the project as having an e2e suite only once GATES.md lists an e2e gate proven green.

Tests create and remove their own data through the product, often as a different session from the one the flow runs in (an agent flow whose cleanup needs an administrator). Give them a sanctioned way to do it: one API fixture per session — a request context on the backend base URL (often a different origin from the UI) carrying that session's token — and put every session's account in one tenant, since deletes are usually tenant-scoped; the seed of one session can assert it. Document in GATES.md the fixtures, the API base URL, where to read the dev server's last build, and that the suite writes through the product into whatever database the app uses — the test-writer's data policy is what keeps that database clean, the gate cannot. The generic e2e-test-writer and e2e-test-validator read the project from that e2e section, so it must state their project profile (../e2e-test-writer/references/e2e-rules.md, first section): a profiles table (profile, product role, folder, API fixture, tenant), the test language and import form, and the project's data policy — the records other suites read by id, the configuration tests only reference, and for each entity the create and remove routes, the profile allowed to use them, and whether the delete is soft. Without a data policy, the writer protects every record a test did not create.

Tailor arch to the anti-patterns and rules surfaced in the reports: e.g. forbid domain → infrastructure imports (circular deps in Deep §9), restrict process.env to a single env module (Deep §2.5 scattered config), forbid try-catch in handlers, flag God objects. Only include gates that make sense for the stack — do not invent a build gate for a pure library with no build, etc.

The design-system gate (conditional — only when a design-system doc exists)

Propose this gate only if the project has a design-system / UI-standards document. Find it with the resolution order of the design-system skill (../design-system/SKILL.md, Step 1 — the one definition): the path GATES.md already names, then a tracked doc at a conventional path (docs/design-system.md, DESIGN.md, docs/**/design*.md, docs/**/ui*.md, a .cursor/rules/*.mdc describing UI standards, a Storybook/tokens doc).

If none exists, do not build this gate (there is nothing to enforce against), and say that the design-system skill can write the doc in its author mode. Never invent design rules — and never build this gate from that skill's bundled baseline (Material 3 or any other): a baseline guides UI that is being written, it is not a decision this project made.

Shared source must be tracked. The gate config, runGate, and GATES.md must reference the design-system doc at a git-tracked path (so the team/CI has it). Beware: skill folders like .claude/skills/ are frequently gitignored — a doc living only there is local and would vanish from the shared repo. If the only doc is untracked, have it moved to a tracked location (e.g. docs/) before building the gate. Record the doc's path in the design-system section of GATES.md: that entry is what the other SDD skills resolve first.

A doc written from the design-system skill's template already keeps the two kinds of rule apart, in its "Machine-checkable rules" and "Judgement rules" sections; for any other doc, make that split yourself, as follows.

Deterministic-only policy (critical). A design-system doc mixes two kinds of rule:

  • Machine-checkable (deterministic): banned component APIs/attributes, required a11y attributes, forbidden file types, hardcoded values vs. design tokens, !important on tokens, banned widgets. → these become the gate.
  • Subjective/visual: information density, hierarchy, spacing "feel", aesthetics, empty/loading placement semantics. → these never enter the gate; they stay as guidance + a visual-verification step (e.g. browser-MCP). Do not attempt to gate aesthetics.

Derive rules from the REAL dominant pattern, not only the doc. For each candidate rule, measure the codebase: count conforming vs. non-conforming occurrences and adopt the majority as the enforced standard, reconciling with the doc. If the doc and the code disagree, surface the divergence for the user to decide before encoding the rule. If there is no clear majority (~50/50), make the rule advisory (warning) or leave it out this phase. This keeps the gate from fighting the app's current standard.

Tooling & scoping. CSS → stylelint with a minimal config (only the project's rules; avoid a heavy preset that fights the formatter) plus a small local stylelint plugin for project-specific rules (e.g. token-only colors that still allow var(--token, #hex) fallbacks; no !important on --* tokens). HTML/JSX templates → custom lint rules on the framework's template AST (e.g. a local ESLint plugin / --rulesdir for Angular templates) — most design-system rules have no built-in equivalent, so expect to author them. Filename bans (e.g. no .component.scss) → a name check in runGate. Always changed-files-scoped in brownfield (the codebase will have thousands of legacy violations); enforce zero-warnings on new/changed files only. Start noisy/high-legacy rules (e.g. hardcoded colors) as advisory and ratchet to blocking after remediation.

Cross-file structural checks — how to gate rules that look subjective. A linter sees one file at a time, so rules like "dialogs must use the compact density" or "listing pages must use the filter sidebar" get filed as subjective and left ungated. Often they are not: implement them as a small check in runGate that reads a changed template and then follows the component's own references to verify the rule. Two proven examples:

  • Density: a template that is a dialog (contains the dialog-content/actions markers) and has form fields → parse styleUrls from the sibling component file, resolve each path, and require that the union of those CSS files declares the density token (e.g. --mat-form-field-container-height). This catches a whole family of screens silently rendering the framework default instead of the specified height — a gap no single-file lint and no grep can see.
  • Required composition: a template with the page-shell + table + pagination markers must also contain the filter-sidebar component.
  • Declared-but-untested controls: when a screen declares its filters as data (a filterConfig-style array of field descriptors), each declared field key must appear somewhere in the sibling spec. This catches the field nobody ever wrote a test for. Be clear-eyed about its limit: a spec that merely mentions the key satisfies it, so this gate proves coverage exists, never that the control was driven end-to-end — that stays a headed-run obligation and belongs in the "What these gates do NOT check" section of GATES.md.

Guidelines: derive the "is this file of kind X?" test from markers already in the template (no config to maintain); emit a message that names the file and the fix; keep it changed-files-scoped like the rest; and validate fail→fix→pass by deliberately breaking one file, confirming a non-zero exit, then restoring. Measure the blast radius on the existing codebase first — if most legacy files violate the rule, either narrow the "kind X" test (e.g. only pages, excluding tables embedded in dialogs/dashboards) or make it advisory.

Step 4: Produce the Gate Plan (Phase 1 output)

Present a plan and await explicit confirmation before writing anything. Template:

Gate Plan for <project> — mode: greenfield | brownfield

Gates to build:
- [typecheck] tsc --noEmit                         (new config: tsconfig strict)
- [lint]      eslint . --max-warnings=0            (brownfield: warnings baselined, see below)
- [build]     npm run build
- [tests]     vitest run
- [arch]      dependency-cruiser + scripts/check-architecture.ts
              rules: domain↛infrastructure; process.env only in src/env.ts
- [deadcode]  knip

Orchestration: scripts/runGate.mjs runs them in order (cheap→expensive):
  typecheck → lint → build → arch → tests → deadcode  (stops at first failure, exit 1)

Files to create/modify:
- create: .dependency-cruiser.cjs, scripts/runGate.mjs, scripts/check-architecture.ts, GATES.md
- modify: package.json (scripts: "gate", "gate:lint", ...), eslintrc (max-warnings)

Brownfield strategy (if applicable):
- Establish a baseline: record current warnings/failures so the gate fails only on NEW issues
- Enable --max-warnings=0 only after the baseline is clean, OR scope strictness to changed files first

OK to build? (yes/no)

For brownfield, the plan MUST state how zero-warnings is introduced incrementally (baseline file, or per-directory ratchet, or changed-files-only first) so the gate does not immediately fail on a sea of pre-existing warnings. For greenfield, strict gates apply from the start.

Proceed only on explicit "yes". On "no"/ambiguous, save the plan doc and stop without writing gate files. Honor "don't touch X" overrides by excluding those files from the plan.

Step 5: Build the Gates (Phase 2 — after confirmation)

For each selected gate, in runGate order:

5.1 — Write the config/tooling

  • Create or extend the gate's config (e.g. tsconfig strictness, eslint config with --max-warnings=0, .dependency-cruiser.cjs with the rules from Step 3, a check-architecture script encoding project-specific rules, knip config).
  • Add/declare any required dev dependencies (respecting the package manager from the Architecture Report). If installation is out of scope or disallowed by an override, declare them in the manifest and note "needs install" in the verification report.

5.2 — Wire the script

  • Add a per-gate script entry to the manifest (package.json scripts or equivalent), each runnable standalone (gate:lint, gate:arch, ...).

5.3 — Brownfield baseline (when applicable)

  • For gates that would fail on pre-existing issues (lint zero-warnings, deadcode, arch), capture a baseline and configure the gate to fail only on new violations, per the strategy confirmed in Step 4. Document the baseline so it can be tightened later.

Never modify application/business code to "make a gate pass" — that is the job of feature work / fix-runner, not gate-builder. Gate-builder only writes gate configs, scripts, and docs.

Step 6: Build the Orchestrator (runGate)

  • Create a single entry point (scripts/runGate.mjs or the stack's idiom) that runs the gates in order, cheapest first (typecheck → lint → build → arch → tests → deadcode, then the gates that need the running app, visual-contract → e2e), stops at the first failure, and exits non-zero on any failure.
  • Add a top-level gate script that invokes it. The orchestrator is what local dev, CI, and the SDD agents (implement-feature, evaluator) will call.

Registry shape (reconcile with the actual code). The Phase-1 plan describes each gate conceptually as id + command + scope + description, but the emitted orchestrator registers gates as a concrete array of objects with exactly three fields: { id, label, run }, where run: () => boolean (true = pass) wraps the command and the scoping inside a closure (there is no separate command/scope field). Changed-files scoping is computed once (git diff vs the base ref) and applied inside each run via a shared helper (e.g. lintGate/stylesGate that filters the changed set to the app + extensions and no-ops to true when empty). To add a gate: push one { id, label, run } object into the array (in cheap→expensive order), add a matching gate:<id> script, and document it in GATES.md. Note the runner does not read contract.md — the SDD agents do, invoking npm run gate:<id> per the ids a feature declares.

Step 7: Verify Each Gate Runs

  • Run runGate (and each gate individually if the orchestrator stops early). Capture pass/fail per gate.
  • Greenfield: every gate should pass on the skeleton (or honestly report what's missing — e.g. no tests yet).
  • Brownfield: confirm gates pass against the baseline (i.e. they don't fail on pre-existing issues) and DO fail on a deliberately introduced violation (a quick sanity check), then revert that probe.
  • Record results; do not claim success for a gate that did not actually execute.

Step 8: Document & Report

  • Write GATES.md: the gate list with ids, the command for each, the runGate order, the brownfield baseline note (if any), and the sections the other SDD skills read — the test profile for the tests gates, the project profile for the e2e gate, and the path of the design-system doc for the design-system gate (Step 3). This is the human- and agent-readable contract of what gates exist — spec-writer reads the same tooling when it declares gates in contract.md.
  • GATES.md MUST also carry a "What these gates do NOT check" section. Gates are deterministic commands; a green run is routinely mistaken for "verified", and the gaps are invisible precisely because nothing reports them. This section is the only tracked place where those obligations live — skill folders like .claude/skills/ are usually gitignored (see the shared-source warning in Phase 1) and an assistant's local memory does not reach the team at all. State at minimum:

    • Interactive behaviour — unless the project has the e2e gate, and then only on the flows it covers. Without it, no gate drives a filter, a select, a toggle or pagination. A listing screen whose gates are green may still ship a filter that is wired to nothing. Whoever validates must exercise each control individually, and an empty result never validates a filter — filtering by a value that matches nothing returns zero rows whether the filter works or is ignored, so it must be exercised with a value present in the data. Where e2e exists, list here the screens and controls it does not drive yet.
    • Measured visual conformance — unless the project has the visual-contract gate. Colour, contrast, spacing and density rules that the linters express as advisories, or cannot express at all, are only proven by reading computed values in a browser, never by the presence of a class; a global !important can silently defeat a component rule, so the documented value and the rendered value may differ. Where visual-contract exists, list here only what it does not yet assert — and keep that list honest as the suite grows, or this section quietly becomes fiction in the opposite direction.
    • Anything a rule marks as a warning rather than an error. Name them, because "the gate passed" hides them. Flag the trap explicitly: silencing an advisory by swapping a value (e.g. a colour for a token) can regress the very property the advisory was pointing at, so any such swap must be re-measured.
    • Whatever the stack's gates provably cannot reach (real credentials, external services, telephony/hardware, cross-browser).

    Keep this section next to the gate list, not in an appendix, and keep it honest: it is the contract for what still needs a human or a headed run.

  • Output a final report:
Gate infrastructure built — mode: greenfield | brownfield

Gates:
✓ [typecheck] runs · passing
✓ [lint] runs · passing (baseline: N pre-existing warnings recorded)
✓ [build] runs · passing
✗ [tests] runs · 0 tests yet (greenfield) — gate present, will enforce once tests exist
✓ [arch] runs · passing (rules: domain↛infra, env-only process.env)
✓ [deadcode] runs · passing

Entry point: `npm run gate` → scripts/runGate.mjs (stops at first failure)
Docs: GATES.md
Next: spec-writer will declare these gate ids in each feature's contract.md

RULES

Always:

  • Prefer the Deep Analysis Report as the primary source and the Architecture Report for stack/tooling; auto-discover the newest in docs/architecture/ if not passed.
  • Auto-detect greenfield vs. brownfield and state the detection and strategy.
  • Give every gate a stable id (the same id spec-writer cites in contract.md).
  • Tailor the arch gate to the anti-patterns/rules actually surfaced in the reports.
  • Present a Gate Plan and await explicit confirmation before writing gate files.
  • In brownfield, introduce zero-warnings incrementally with a recorded baseline — never break the existing build.
  • Build a single runGate orchestrator (cheap→expensive, stop at first failure, non-zero exit).
  • Verify each gate actually runs before claiming success; record the brownfield baseline.
  • Only write gate configs/scripts/docs — never modify application/business code.
  • For tests/e2e, build the runner and harness (and the e2e seed test) and record the project's profile in GATES.md, but never write feature tests or test rules.

Never:

  • Modify application/business code to make a gate pass (that's feature work / fix-runner).
  • Invent gates the stack cannot run, or a build gate where there is nothing to build.
  • Enable --max-warnings=0 on a brownfield repo with pre-existing warnings without a baseline/ratchet.
  • Skip the confirmation gate (Phase 1 → Phase 2) unless an override explicitly authorizes auto-build.
  • Claim a gate "passes" without executing it.
  • Overwrite an existing gate config wholesale — extend/merge and preserve project intent.
  • Touch files excluded by a "don't touch X" override.

Edge Cases

No reports found: prefer to request the Deep/Architecture reports. If the user insists, operate in reduced mode by reading manifests + config directly to detect stack and tooling, and clearly flag that the gate selection is inferred without the analysis depth.

Reports reference a stack with no native typecheck (e.g. plain JS): skip typecheck or substitute a // @ts-check + jsconfig approach if the project wants it; document the choice. Do not force TypeScript on a non-TS project.

Brownfield with many pre-existing lint warnings: baseline them (record count/list) and configure the gate to fail only on new warnings, or apply zero-warnings to changed files first; tighten over time. State this in the plan and GATES.md.

Existing runGate/gate scripts already present: treat as brownfield; extend the existing orchestrator and scripts rather than replacing them. Reconcile gate ids with what already exists.

Monorepo / multiple packages: detect per-package tooling from the reports; either build per-package gates with a root orchestrator that fans out, or scope to the package the user named. State the structure in the plan.

Dev dependencies cannot be installed in this environment: declare them in the manifest, wire the scripts, and mark each affected gate "needs install" in the verification report instead of falsely reporting it passing.

Pure library (no build/runtime surface): include typecheck, lint, tests, arch, deadcode; omit build if there is genuinely nothing to build. Do not fabricate runtime gates.

User asks the gate-builder to also write tests (or test conventions): decline that part. Build the runner, the harness and the seed; point to the test-writers for tests — they read the profile this skill records in GATES.md, and where no suite covers a file implement-feature writes the test itself — and record undecided test conventions in GATES.md for the team.

User override "lint only" / excludes a gate: build only the requested gates; the runGate order adapts. Note the omitted gates so they can be added later.

Gate plan declined (Phase 1 "no"): save the plan doc to docs/architecture/ (or alongside the reports) and stop — no gate files written.

Project-specific rule from the report can't be expressed in a generic tool: encode it in the custom check-architecture script (e.g. "process.env only in env module", "no try-catch in handlers", "composition root only in main") rather than forcing it into dependency-cruiser.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.