Context is paid for on every turn
A short AGENTS.md for a Symfony and Vue project
# Billing API: Symfony + Vue 3 front end
## Commands
- PHP tests: `vendor/bin/phpunit`
- Static analysis: `vendor/bin/phpstan analyse`
- Front end: `npm run lint` then `npm run test:unit`
- A task is only done when `make ci` passes
## Layout
- src/Domain: no dependency on Doctrine or Symfony
- src/Infrastructure: Doctrine adapters and HTTP clients
- assets/: Vue 3, Composition API, strict TypeScript
- Versions: see composer.json and package.json
## Rules
- `declare(strict_types=1);` in every new PHP file
- No EntityManagerInterface in a controller: go through a handler
- Never edit a Doctrine migration that is already merged
## Before creating an endpoint
- Read docs/agents/api.md (naming, HTTP codes, error format)
Two choices are deliberate. The PHP and Symfony versions aren't copied in: they live in composer.json, which doesn't lie. And the last section points to a file instead of importing it. An @docs/agents/api.md import would load at launch, in every session: the Claude Code docs state that imports organize a long file without reducing its cost. A plain mention lets the agent read the file only when it needs it.
What only applies to part of the code
---
paths:
- "assets/**/*.{ts,vue}"
---
# Vue front end
- <script setup lang="ts"> and Composition API only
- HTTP calls go through the composables in assets/api/, never fetch inside a component
- A component over 200 lines gets split
Without Claude-specific files, a nested assets/AGENTS.md plays a similar role: Claude Code loads it when it opens a file in that folder, as long as that folder has no CLAUDE.md.
Skills: progressive disclosure
.claude/skills/symfony-endpoint/
├── SKILL.md
└── references/
└── conventions.md
---
name: symfony-endpoint
description: Creates a Symfony REST endpoint (DTO, handler, controller, functional test) following the project conventions. Use it for any new API route.
---
# New endpoint
1. Read references/conventions.md before writing any code.
2. Input DTO with Validator component constraints.
3. Handler in src/Application, with no HttpFoundation dependency.
4. Functional test with WebTestCase.
5. Run vendor/bin/phpunit --filter on the new test, then vendor/bin/phpstan analyse.
The description is the line that matters most: it decides whether the agent loads the skill. The spec also requires name to be lowercase with hyphens, and identical to the folder name.
On YoanDev, Yoan Bernabeu describes a training where the team built a skill together to bootstrap a Symfony project to its standards, then tested results with and without it across several cases. It will be distributed through the team's skill marketplace, versioned and reviewed like code. For skills shared across a whole organization, he released Skillcrew, a CLI that syncs a Git repository of skills to the various agents. The tool is at v0.1.0, and Yoan Bernabeu himself notes that project-specific skills stay in the project's repository.
The CI that enforces the budget
Bash
#!/usr/bin/env bash
set -euo pipefail
max_agents=150
max_skill=500
status=0
if [[ -f AGENTS.md ]]; then
lines=$(wc -l < AGENTS.md)
if (( lines > max_agents )); then
echo "AGENTS.md: $lines lines (max $max_agents)"
status=1
fi
fi
while IFS= read -r -d '' skill; do
dir=$(basename "$(dirname "$skill")")
lines=$(wc -l < "$skill")
name=$(sed -n 's/^name: *//p' "$skill" | head -n 1)
if (( lines > max_skill )); then
echo "$skill: $lines lines (max $max_skill)"
status=1
fi
if [[ "$name" != "$dir" ]]; then
echo "$skill: name '$name' does not match folder '$dir'"
status=1
fi
if ! grep -q '^description: .' "$skill"; then
echo "$skill: missing description"
status=1
fi
done < <(find .agents/skills .claude/skills -name SKILL.md -print0 2>/dev/null)
exit "$status"
Yaml
name: agent-files
on:
pull_request:
paths:
- "AGENTS.md"
- "CLAUDE.md"
- ".claude/**"
- ".agents/**"
- "bin/check-agent-files.sh"
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: bash bin/check-agent-files.sh
The traps
- Believing a written rule is applied. The Claude Code docs say it: these files are context, not enforced configuration. Anything that must be blocked goes through PHPStan, the CI or a PreToolUse hook (a command Claude Code runs before each tool call, which can block it), not one more sentence.
- Copying numbers by hand. Claude Camus found that file sizes noted by hand were off by 9 to 36% the very next day. Versions, counters, sizes: point to the source or generate them with a script.
- Piling up without ever removing. Each dev adds an instruction after an incident, nobody deletes one. Claude Camus's diagnostic found 34 skills never invoked: schedule the cleanup instead of waiting for it.
Sources
- Mes agents lisaient trop : ce que dix semaines de chasse aux tokens m'ont appris — OCTO Talks, Claude Camus, October 23, 2026
- Former une équipe aux agents IA : l'outil, c'est la partie facile — YoanDev, Yoan Bernabeu, October 8, 2026
- Skillcrew : les skills de votre équipe, dans tous les agents, toujours à jour — YoanDev, Yoan Bernabeu, October 11, 2026
- How Claude remembers your project — Claude Code documentation (file size, imports, AGENTS.md, path-scoped rules)
- Agent Skills Specification — SKILL.md format specification