Skip to content

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: .gitattributes marks them export-ignore, and kit:update delivers just the top-level documents of wikis/. In your project the wikis/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 any php 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.md and CLAUDE.md are generated by Boost — editing them by hand is lost work on the next boost:update. Durable rules go in .ai/rules (the record-rule tool) or in wikis/.

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 neither boost:add-skill nor boost:update copies them there. tests/Kit/AgentesDaEsteiraTest.php turns red when the copy fell behind.

To update the skills in your project:

Janela do terminal
php artisan boost:add-skill gsferro/laravel-ai-skills --all --force # the five skills, boost:update included
cp .ai/skills/*/agents/*.md .claude/agents/ # the agents, which Boost does not copy

Then 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/rules answer 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 by pest --arch, PHPStan or Rector, the rule points to the test instead of asking for goodwill.

For a typo, .env tweak, 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):

  1. AI_AGENT, if it has content. Empty or whitespace-only does not count — the detector runs trim() and reports “no agent”.
  2. 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.
  3. 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

Janela do terminal
PAO_DISABLE=1 php artisan test # human output, even under an agent
PAO_FORCE=1 php artisan test # agent output, even without an agent

Both are real environment variables, and they do not belong in .env. pao reads them from $_SERVER before Laravel exists — a line in the project’s .env has no effect.

Use PAO_DISABLE=1 when you are debugging alongside the agent and want the full output.

Two gotchas that save time

  • --compact is superseded under an agent. The plugin injects --no-output --no-progress, so php artisan test --compact and php artisan test give the same result when an agent runs them.
  • pint --format agent is 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.

Janela do terminal
brew tap laravel/moat https://github.com/laravel/moat
brew install laravel/moat/moat
moat your-org # an organisation or user
moat owner/repo # a repository

It 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.