Working with AI agents
The kit ships ready for you to develop with a coding agent (Claude Code, Codex, Cursor, Junie, OpenCode) — and, more importantly, with the documentation the agent needs to read so it doesn’t reinvent or break what’s already there.
📚 wikis/ — the kit’s documentation
wikis/README.md is the entry point. It’s where everything an agent (or a new teammate) needs before the first line of code lives:
| Document | What it answers |
|---|---|
wikis/arquitetura.md |
the three panels, the kit’s “glue”, a request’s lifecycle, the three authorization levels |
wikis/convencoes.md |
the non-negotiable rules and the traps already handled — the document that prevents the “fix” that breaks things |
wikis/ia.md |
the agent as data, fail-closed guardrails, execution ledger |
wikis/receitas.md |
step by step: Resource, page, widget, health check, command, AI agent |
wikis/agentes-e-skills.md |
Boost, MCP, the installed skills and the execution trio |
wikis/pacotes.md |
which package owns which screen — so you don’t reimplement vendor code |
It’s also the folder where you write your project’s own docs: wikis/specs/{branch}/{feature}/ gets one folder per feature, created by the skill below.
The wiki is written in pt-BR, like the kit’s UI and code comments.
The kit’s own
wikis/specs/— the ADRs of the features that built the kit itself, cited throughout this README — stay in the kit’s repository only:.gitattributesmarks themexport-ignore, andkit:updatedelivers just the top-level documents ofwikis/. In your project thewikis/specs/folder is born empty, for your own features. To read a decision cited here, see the repository: https://github.com/gsferro/filament-starter-kit-easy.
The installed skills
Laravel Boost is configured (boost.json) for five agents, with an MCP server (php artisan boost:mcp) and the skills listed in boost.json itself, synchronized to all of them — among them laravel-best-practices, pest-testing, ai-sdk-development, filament-development, tailwindcss-development, pulse-development, laravel-backup and blaze-optimize.
The one that changes the workflow is feature-wiki (4.0.0): invoked before implementing any feature, it creates wikis/specs/{branch}/{feature}/ with the requirement, the action plan (PRD), the architecture decisions (ADR) and progress tracking — and it sets the project’s logging standard. It carries the feature all the way to the PR together with the other four skills of the same collection, all versioned in the kit:
| Skill | Role in the cycle |
|---|---|
feature-wiki |
requirement, plan, ADR and progress; diff review and reconciliation |
feature-test-design |
derives the test cases (04/05) from the requirement, never from the plan |
feature-quality-gate |
independent QA before the PR → 06-relatorio-qa.md |
requirement-to-rule |
turns a durable decision into an .ai/rules rule |
feature-tickets |
slices the wiki into tickets when the plan doesn’t fit one session — only via /feature-tickets |
💡 New feature? Call
/feature-wiki. It’s the first step, before anyphp artisan make:*. The skill researches the code, writes the plan, and only then does implementation start. For a typo, a config tweak, a pure refactor or a dependency bump, skip it — the skill itself tells you when it isn’t worth it.
In Claude Code it works alongside two plugins already enabled in .claude/settings.json, each covering a different layer:
| Layer | Tool | Role |
|---|---|---|
| Communication | Caveman | terse replies — does not apply to the wiki, code, commits or security warnings |
| Planning | feature-wiki | PRD + ADR + test cases + tracking |
| Execution | Ponytail | the minimum code that works — without cutting validation, security or error handling |
AGENTS.mdandCLAUDE.mdare generated by Boost — editing them by hand is lost work on the nextboost:update. Durable rules go in.ai/rules(therecord-ruletool) or inwikis/.
The pipeline’s sub-agents (Claude Code)
In Claude Code, feature-wiki dispatches the work that needs independence to sub-agents born
without the session’s context: whoever reviews the diff did not implement it, whoever judges the test
cases did not derive them, whoever approves the delivery did not write the wiki. There are five, in
.claude/agents/:
| Agent | What it does | What the hook denies |
|---|---|---|
fw-revisor-diff |
diff review, as soon as the tests pass | reading the plan (01) and the progress (03); changing the tree |
fw-executor-ct |
writes and runs the backend tests from 04 |
reading 01 and 02; editing app/, migrations and the wiki |
fw-executor-ctb |
writes and runs the browser tests from 05 |
editing app/, migrations and the wiki |
fw-adversario-ct |
tries to prove the test cases let a defect through | reading anything beyond 00, 04/05 and the skills |
fw-qa-gate |
runs the quality gate and returns 06 as text |
changing the tree |
Since 4.0.0, each one declares a PreToolUse hook that runs
.ai/skills/feature-wiki/scripts/guarda-subagente.sh before every tool. For file reads, searches and
edits the denial is by construction — the tool never runs; in Bash, it is by command pattern. Two
consequences:
- On Windows, the hook needs Git for Windows (Git Bash). Without
it Claude Code runs the hook in PowerShell, the hook denies every tool, and the session falls back
to
general-purpose, with no tool restriction. - Claude Code only reads agents from
.claude/agents/, and neitherboost:add-skillnorboost:updatecopies them there.tests/Kit/AgentesDaEsteiraTest.phpturns red when the copy fell behind.
To update the skills in your project:
php artisan boost:add-skill gsferro/laravel-ai-skills --all --force # the five skills, boost:update includedcp .ai/skills/*/agents/*.md .claude/agents/ # the agents, which Boost does not copyThen reopen the Claude Code session: the sub-agent list is read when the session opens. Updating
the kit with php artisan kit:update brings the skills and agents along — .ai/skills, .claude,
.agents and .junie are among the paths it delivers.
Caveman and Ponytail outside of Claude Code
The trio above is only a real trio if all three layers exist. In Claude Code, Caveman and
Ponytail come as plugin (.claude/settings.json) — with automatic activation by hook and
commands in the /ponytail:… and /caveman:… namespace. In other agents there is no plugin
system, and feature-wiki would invoke a /ponytail-review that does not exist.
That’s why the kit versions a copy of the three skills that feature-wiki cites by name, in
.ai/skills/ and in each agent’s mirror:
| Skill | What feature-wiki uses it for |
|---|---|
ponytail |
the simplicity ladder during implementation |
ponytail-review |
plan audit against over-engineering (step 6, mandatory) and diff audit at the end |
caveman |
terse agent ↔ you communication; does not apply to wiki, code, commit or security warning |
The invocation name changes: in Claude Code, the plugin answers to /ponytail:ponytail-review; in
the other agents, the local copy answers to /ponytail-review, with no namespace.
All three are listed in boost.json, so boost:update keeps them synchronized in every mirror —
.claude/skills/ included, where the copy lives alongside the plugin. They are MIT copies, with the
original LICENSE attached — updating is re-copying from upstream
(Caveman,
Ponytail).
The feature cycle with an agent
The kit does not ask you to trust the agent: it asks the agent to leave a trail. Each step produces a file that the next step checks.
The numbering is that of the feature-wiki 4.0.0 steps.
| Step | You do | The agent produces | Why it exists |
|---|---|---|---|
| 0–4 | /feature-wiki with the request in plain text; answer the questions |
00-requisito.md — immutable copy of what you asked —, 01-plano-acao.md (PRD), 02-decisoes-arquiteturais.md (ADR) and 03-progresso.md |
The requirement is never rewritten to fit what was implemented. It is what judges the delivery |
| 5–6 | read, adjust and approve | deep review of the plan against the code, and audit by ponytail-review |
Reviewing a plan is cheap; reviewing 900 lines of diff is not. Ponytail cuts unnecessary steps before they become code |
| 7 | — | 04-casos-de-teste.md, and 05-casos-de-teste-browser.md when there is a screen, by feature-test-design |
The test derives from the requirement, after Ponytail’s cut — testing the plan would only confirm the plan |
| 8 | only if the plan doesn’t fit one session: /feature-tickets |
one ticket per vertical slice, one per session | A large feature doesn’t become a session that loses context halfway |
| — | — | implementation following the plan, with 03-progresso.md updated and the tests running |
A session that drops resumes from where it stopped, without rebuilding context. Green is a precondition for the next step, not the delivery |
| 9 | — | diff review by someone who did not implement it (/code-review and fw-revisor-diff) |
It is the gate that reads the code: the others read the plan, the requirement or the screen |
| 10 | — | reconciliation: wiki, code and tests tell the same story | What changed during implementation goes back into the plan, marked |
| 11 | — | /feature-quality-gate → 06-relatorio-qa.md |
Confronts requirement × plan × running app. The traceability matrix exposes the clause that never became a step, test or code — the omission a green suite does not denounce |
| 12 | approve | /requirement-to-rule → rule in .ai/rules |
A decision that matters beyond this feature starts to matter for every future session, of any agent |
What this changes in practice:
- The agent reads before writing.
wikis/and.ai/rulesanswer what already exists, and the feature roadmap below lists the 68 ready features. A feature reimplemented from scratch because the agent didn’t know it existed is the most expensive and most invisible cost. - Context becomes a file, not chat history. Switching agent, machine or person does not lose the why of the decision — it is in the ADR, versioned in the same commit as the code.
- Simple by default, without cutting what matters. Ponytail never simplifies validation at a trust boundary, error handling that prevents data loss, security or accessibility.
- Less token per reply. Caveman cuts the prose from the conversation; wiki, code and commit continue in normal Portuguese.
- Every fix sticks. A resolved trap becomes
.ai/rules— and the next gate already checks it. When it can be proven bypest --arch, PHPStan or Rector, the rule points to the test instead of asking for goodwill.
For a typo,
.envtweak, dependency bump or pure refactor, skip the cycle. The skill itself tells you when it isn’t worth it — ceremony in a one-line change is the over-engineering Ponytail exists to cut.
Agent output — laravel/pao
The kit already ships laravel/pao in require-dev,
and you have probably never noticed: it only acts when an AI agent is running the command. For a
person at the terminal, nothing changes.
Under an agent, the whole suite answers with one line:
{"tool":"pest","result":"passed","tests":2614,"passed":2614,"assertions":10164,"duration_ms":283774}And when it fails, that line carries file, line and message for each case — already extracted,
so the agent does not have to scan hundreds of lines of coloured output.
| Tool | What changes under an agent |
|---|---|
| Pest, PHPUnit, Paratest | one JSON line; failures in failures[] with file and line |
| PHPStan | JSON grouped by file, truncated at 30 errors (use -v for all) |
| Rector | JSON; under --dry-run, a changed file counts as a failure |
| Artisan | no ANSI and no decoration — Kit version .. 0.39.1 instead of the dotted line |
| Pint | not pao — Pint has its own detection and already emits JSON by itself |
How it knows it is an agent
In three layers, in this order (vendor/laravel/agent-detector/src/AgentDetector.php):
AI_AGENT, if it has content. Empty or whitespace-only does not count — the detector runstrim()and reports “no agent”.- The presence of any of 19 known variables:
CLAUDECODE,CURSOR_AGENT,GEMINI_CLI,CODEX_SANDBOX,CODEX_CI,CODEX_THREAD_ID,COPILOT_CLI, and more. Only the name matters here, not the value. There is no wildcard:CODEX_HOME, for instance, triggers nothing. - The file system:
file_exists('/opt/.devin')identifies Devin with no environment variable at all.
The kit’s CI defines none of the 19, so output there is unchanged.
A useful side effect of layers 1 and 2: anything that scrubs the environment — env -u, sudo
without -E, docker run without -e — silently turns pao off. Not on Devin: there the
detection is by file and survives a scrubbed environment.
How to turn it off
PAO_DISABLE=1 php artisan test # human output, even under an agentPAO_FORCE=1 php artisan test # agent output, even without an agentBoth are real environment variables, and they do not belong in
.env.paoreads them from$_SERVERbefore Laravel exists — a line in the project’s.envhas no effect.
Use PAO_DISABLE=1 when you are debugging alongside the agent and want the full output.
Two gotchas that save time
--compactis superseded under an agent. The plugin injects--no-output --no-progress, sophp artisan test --compactandphp artisan testgive the same result when an agent runs them.pint --format agentis redundant under an agent. Pint detects it on its own. The flag is still useful to force JSON outside an agent session.
GitHub security auditing — laravel/moat (optional)
moat is not a PHP package and is not a kit dependency. It
is a CLI written in Rust that performs a read-only review of the security configuration of a
GitHub organisation or repository: 2FA enforcement, branch protection, secret scanning, workflow
permissions — over 25 checks.
It changes nothing; it only reports.
brew tap laravel/moat https://github.com/laravel/moatbrew install laravel/moat/moat
moat your-org # an organisation or usermoat owner/repo # a repositoryIt needs GitHub authentication (GITHUB_TOKEN, GH_TOKEN, or the gh CLI already signed in), and
supports terminal, JSON or Markdown output.
It is a tool for whoever maintains the repository, not for whoever uses the kit. It audits configuration on GitHub, not your code. And installation goes through Homebrew, which is not standard on Windows — there the path is WSL or downloading the release binary.