🔧 Add shared Claude Code agent tooling - #212
Merged
Merged
Conversation
Adds a committed .claude/ so the conventions in AGENTS.md are enforced rather than merely remembered. Everything shells into the php container, since the toolchain exists nowhere else, and no-ops when it is down. Hooks: - fix-style.sh runs PHP CS Fixer / Twig CS Fixer on each edited file - guard-protected-files.sh blocks edits to applied migrations and .env*.local, while still allowing new migration files Skills: /ci-check mirrors ci.yaml with the container-up and cache-warm preflight CI gets for free; /new-module scaffolds a DDD module. Subagents: ddd-boundary-reviewer and i18n-parity-reviewer, both scoped to the diff. The former carries an allow-list of accepted deviations so it does not flag the Doctrine and elao/enum idioms already in Domain/. MCP: postgres-dev resolves the randomly-assigned host port and the credentials from the running container, keeping secrets out of the repo.
Four documented claims did not match the code: - components live in templates/component/, not templates/components/ - the base template is templates/app/base.html.twig - only PageView uses constructor promotion; Experience, Settings and User declare plain public properties - only Analytics has a Domain repository interface, the other modules inject the concrete repository The last two were stated as established patterns, so following them produced code that did not match its neighbours. Both now describe what the code does, and note when the Domain interface is worth adding. Also documents the template inheritance chain, including the chrome-less pages that extend app/base.html.twig directly, and adds a section covering the committed .claude/ tooling.
Two French strings used a curly apostrophe, against the straight-quotes convention in AGENTS.md. Both sat inside single-quoted strings, so the quoting had to change with them: the PHP one is now escaped, the YAML one switched to double quotes to match its neighbours in the catalogue. The surrounding copy already uses straight apostrophes throughout (n'a, d'expériences, j'ai, aujourd'hui), so these were outliers rather than deliberate French typography.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a committed
.claude/so the conventions inAGENTS.mdare enforced rather than merely remembered, corrects four documented claims that did not match the code, and fixes two stray typographic quotes..claude/settings.jsonand.mcp.jsonare checked in, so the two hooks below start running on every contributor's machine as soon as this merges. That is the intent, but it is worth knowing before approving rather than discovering it mid-edit. Both shell into thephpcontainer and no-op silently when the stack is down.Tooling
Hooks
hooks/fix-style.shEdit/Writevendor/,var/, generated assets,migrations/.hooks/guard-protected-files.shEdit/Write.env*.local. Creating a new migration file is still allowed.Skills —
/ci-checkmirrorsci.yamlin order, adding the container-up andmake ccpreflight CI gets for free (PHPStan reads the compiled container XML, so a stalevar/cache/dev/produces false positives)./new-modulescaffolds a DDD module across the eight places it touches, with templates taken from the realExperience/Resumecode.Subagents —
ddd-boundary-reviewerandi18n-parity-reviewer, both scoped to the diff rather than the whole tree. The DDD one carries an explicit allow-list of accepted deviations (DoctrinerepositoryClass,elao/enum,Clock, Security interfaces inDomain/); without it, it would fire on every existing entity.MCP —
postgres-devgives read-only access to the dev database.compose.override.yamlpublishes Postgres asports: - "5432", so Docker assigns a random host port on everyup— a hardcoded connection string would break on first restart. The wrapper resolves the port viadocker compose portand reads credentials from the running container, so no password is stored in the repo.Doc corrections
Four claims in
AGENTS.md/CLAUDE.mddid not match the code:templates/components/templates/component/, singular`base.html.twig`(4 spots)templates/app/base.html.twigPageViewpromotes;Experience,Settings,Useruse plain public propertiesAnalyticshas one; the other four modules inject the concrete repositoryThe last two mattered most — both were stated as established patterns, so following them produced code that did not match its neighbours. Both now describe what the code actually does, plus when the Domain interface is worth adding.
Also documents the template inheritance chain, including the chrome-less pages (CV, login, error) that extend
app/base.html.twigdirectly instead of the intermediate bases.Typographic quotes
Two French strings used a curly apostrophe, against the straight-quotes rule in
AGENTS.md. Both sat inside single-quoted strings, so the quoting changed with them — the PHP one is escaped, the YAML one switched to double quotes to match its neighbours. The surrounding copy already uses straight apostrophes throughout (n'a,d'expériences,j'ai,aujourd'hui), so these were outliers, not deliberate French typography.Verification
guard-protected-files.shpasses 7/7 cases: blocks applied migrations, allows new ones, blocks.env.local, allows plain.envdeclare(strict_types=1), Yoda, trailing comma and blank-line-before-returnphp -lpasses; PHP CS Fixer reports 0 fixable issues on the changed controller; both message catalogues parse through Symfony's YAML component100755Not verified: no project images exist locally, so
make upmeans a full FrankenPHP build and I did not run one. The fixer was therefore exercised on the host rather than in-container; what is untested is only the/app/$relpath prefix, which follows from./:/appandWORKDIR /app. Same for the MCP wrapper. Both fail safe — they no-op rather than corrupt anything. Worth onemake upplus a PHP edit before merging.