Skip to content

One canonical agent instruction file, and a parallel verification gate - #4

Merged
anilcancakir merged 3 commits into
mainfrom
feature/shared-agent-instructions-and-gate
Aug 4, 2026
Merged

One canonical agent instruction file, and a parallel verification gate#4
anilcancakir merged 3 commits into
mainfrom
feature/shared-agent-instructions-and-gate

Conversation

@anilcancakir

Copy link
Copy Markdown
Contributor

What changed

Mirrors the structural work done in uptizm (which forks this boilerplate), adapted rather than copied where the two repos genuinely differ.

  • AGENTS.md becomes the single canonical instruction file; CLAUDE.md is a symlink to it. Codex, opencode, and Copilot's agent surface read AGENTS.md natively; Claude Code reads CLAUDE.md and has no AGENTS.md discovery, so one lookup key means no double-load.
  • bin/sync-instructions generates the Copilot mirrors under .github/, rewriting the path-scoped rule's paths: list into Copilot's applyTo: string. --check fails CI on drift.
  • bin/check is one gate that fans the suites out across cores.
  • docs/verification-loop.md carries the three verification layers, including the dusk end-to-end walk at desktop and mobile width.
  • CI gates every PR.

Why

Several agents can work this repo at once, four different tools each looked for a different instruction file, and nothing measured a change before merge. Since production apps fork this project, the boilerplate is where the convention belongs.

Evidence

bin/check on this branch, exit 0:

check: flutter backend | 8 cores, 4 per suite
check: resolving dart dependencies

  ok    flutter-analyze
  ok    backend-pint
  ok    flutter-test
  ok    backend-test

check: all green

Two failures found by running it rather than by reading it, both now fixed and both worth knowing about:

  • flutter analyze and flutter test each resolve dependencies on their own and collide on .dart_tool and ios/Flutter/ephemeral. Serializing a pub get first was not enough; --no-pub on both is what removes the race.
  • A Blade view calling @vite throws without a manifest, which lives in the gitignored public/build. A fresh worktree or runner has none, so a page test fails on Vite rather than on its subject.

config/magic-starter.php picks up a pre-existing Pint fix so the new gate is green on arrival.

  • bin/check green

Deliberate differences from the fork

  • No worker scope and no paratest: this backend has a handful of tests, and paratest would spend more time booting workers than it saves. The parallelism that pays here is across the halves.
  • No sibling checkouts in CI. This repo resolves from pub.dev, and CI resolving the published versions is exactly what catches a dependency on unreleased sibling code.
  • PHP 8.4 rather than 8.5: that is the floor the committed lock actually demands (symfony 8.1 needs >=8.4.1, so composer.json's ^8.3 is stale), and a boilerplate is worth testing at its floor.

Mirrors the structural work done in uptizm, which forks this boilerplate, adapted
rather than copied where the two repos genuinely differ.

Four tools now work these repos and each looked for a different instruction file,
so a rule written for one was invisible to the others. AGENTS.md becomes the
single hand-edited source; CLAUDE.md is a symlink, because Claude Code reads
CLAUDE.md and has no native AGENTS.md discovery, so there is one lookup key and no
double-load. The Copilot mirrors under .github/ are generated copies rather than
symlinks: GitHub does not document symlink following for its instruction files and
there is an open bug against the VS Code extension for that setup. The path-scoped
rule could not be symlinked regardless, since .claude/rules/*.md spells its globs
as a YAML list under paths: and Copilot wants one comma-separated string under
applyTo:, so bin/sync-instructions rewrites the frontmatter and --check fails CI
on drift.

bin/check is the gate. Two things in it are load-bearing and were both learned by
watching it fail: flutter analyze and flutter test each resolve dependencies on
their own and collide on .dart_tool and ios/Flutter/ephemeral, so one prepare step
owns resolution and both commands take --no-pub; and a Blade view calling @Vite
throws without a manifest that lives in gitignored public/build, so the manifest
is ensured before any test renders a page. The backend suite runs sequentially
here on purpose: with a handful of tests, paratest would spend more time booting
workers than it saves.

Where this repo differs from the fork, the adaptation is deliberate: no worker
scope, no paratest, no sibling checkouts in CI (this repo resolves from pub.dev,
and CI resolving the PUBLISHED versions is what catches a dependency on
unreleased sibling code), and PHP 8.4 rather than 8.5 because that is the floor
the lock actually demands and a boilerplate is worth testing at its floor.

config/magic-starter.php picks up a pre-existing Pint fix, so the new gate is
green on arrival rather than red for a reason nobody introduced.
Copilot AI lite review requested due to automatic review settings August 4, 2026 18:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Establishes a single canonical agent-instruction source (AGENTS.md), adds generation + CI drift checking for Copilot instruction mirrors, and introduces a unified parallel verification gate (bin/check) backed by CI and a documented verification loop.

Changes:

  • Added AGENTS.md as the canonical instructions source and generated Copilot mirrors under .github/ via bin/sync-instructions (with --check for CI drift detection).
  • Introduced bin/check as a parallel, buffered-output verification gate for Flutter + backend suites, plus CI jobs to run equivalent checks per half.
  • Added verification documentation (docs/verification-loop.md) and a PR template emphasizing evidence-based verification.

Reviewed changes

Copilot reviewed 9 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
docs/verification-loop.md Documents the 3-layer verification loop (static, visual, dusk E2E) and evidence expectations.
bin/sync-instructions Generates .github/ Copilot instruction mirrors from canonical + path-scoped Claude rules; supports CI drift checking.
bin/check Adds a parallelized local verification gate to run Flutter/backend suites with buffered logs and worktree bootstrapping.
backend/config/magic-starter.php Refactors feature references to use an imported Features symbol for readability/consistency.
AGENTS.md Consolidates canonical agent instructions into a single source intended for all tools.
.github/workflows/ci.yml Adds CI workflow gating PRs with instruction mirror checks plus Flutter/backend suites.
.github/pull_request_template.md Adds an evidence-forward PR template aligned to the verification loop.
.github/instructions/design.instructions.md Adds generated Copilot path-scoped design rules for lib/**.
.github/copilot-instructions.md Adds generated Copilot repo-wide instruction mirror sourced from AGENTS.md.
.claude/rules/design.md Extends design rules with an explicit anti-pattern table and blockers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Adding CI proved this repo could not be installed anywhere but this machine, which
matters more here than in a product repo: apps fork this one as their starting
point.

composer.json still carried a path repository pointing at ../../magic-starter-laravel
and required it as @dev, so composer.lock held a "type": "path" entry that no
other checkout can resolve; CI failed with "Source path is not found". The package
has been on Packagist through 0.0.5 for a while, so this moves to ^0.0.5 and drops
the repository. Develop both together by adding the path repo locally and
reverting it before committing.

Guzzle was pinned at 7.12.3 by a stale lock, with six advisories against it
including a high-severity host-check bypass. Updating it alone changed nothing
because 7.15.2 also needs newer promises and psr7, so this updates the three
together. composer audit is now clean.

package-lock.json was missing, so  exited non-zero and the asset build
could not run at all. It is committed now, and bin/check falls back to
 rather than reporting an asset failure that is really a missing
lockfile.
design.md told every agent that a className setting a color must carry its dark:
counterpart, and then said the alias system already handles it. The second half is
the true one: an alias expands to both modes, so dark:bg-surface is nonsense.

sync-instructions skipped a rule it could not parse while --check reported "up to
date", because it compares generated output against generated output: a whole
path-scoped rule could be invisible to Copilot with CI green. Unparseable
frontmatter, a malformed glob list and an empty body are now fatal.

bin/check demands backend/vendor rather than failing pint with rc 127, runs
config:clear before the suite (a cached config outranks phpunit.xml's sqlite pin
and would migrate:fresh a real database), kills its jobs on the way out so a
tool-call timeout does not orphan them, and names the scope in the summary because
"all green" read identically after --fast, which runs no tests.

The workflow no longer cancels a main run and every job has a timeout.
@anilcancakir
anilcancakir merged commit e6571d5 into main Aug 4, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants