| name | laravel-tackle |
| description | Configure, extend, and build on Laravel Tackle — an AI agent harness for Laravel (similar to Claude Code or Codex, but installed into the app via Composer). Use this skill when installing Tackle, writing custom tools or agents, configuring the self-healer, or opting jobs out of healing. |
Laravel Tackle
Laravel Tackle is an AI agent harness for Laravel. It provides the runtime layer — tool infrastructure, safety boundaries (PathGuard, BudgetTracker, shell modes), and a CodingAgent contract — that agents run inside. The harness ships with three built-in agents and can be extended with custom tools and agents without forking the package.
When to use this skill
Use this skill when:
- Installing or configuring Laravel Tackle
- Writing a custom tool (
tackle:tool) or agent (tackle:agent)
- Extending or swapping the coding agent
- Configuring the self-healing queue worker (modes, thresholds, GitHub tokens)
- Opting a job or scheduled task out of self-healing
- Running
ai:review for code review
- Querying the healing audit log
Installation
composer require jordandalton/laravel-tackle
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
php artisan vendor:publish --tag="tackle-config"
Add your API key to .env:
ANTHROPIC_API_KEY=sk-ant-...
Available tools (DefaultCodingAgent)
| Tool | What it does |
|---|
ReadFile | Read any file in the workspace |
Glob | List files by pattern |
SearchCode | Grep-style search — file, line, snippet |
EditFile | str_replace edit — unique match required |
WriteFile | Create a new file |
RunArtisan | Run an artisan command (allowlist-gated) |
RunTests | Run Pest / PHPUnit |
RunPint | Format files with Laravel Pint |
RunShell | General shell (governed by shell mode) |
QueryDatabase | Read-only SELECT query → JSON (100 row cap) |
ReadLog | Tail storage/logs/laravel.log with optional filter |
ListRoutes | Registered routes — method, URI, name, action |
GitDiff | Git diff — supports staged, commit, against, path, stat |
ReadTelescopeEntry | Telescope exception entries — by job UUID or recent list |
ReadSentryIssue | Fetch a Sentry issue by ID (exception, stacktrace, breadcrumbs, request). Omit ID to list recent unresolved issues. No-ops if SENTRY_AUTH_TOKEN/SENTRY_ORG unset. |
ReadGitHubIssue | Fetch a GitHub issue by number (title, body, labels, all comments). Omit number to list recent open issues. No-ops if GITHUB_TOKEN/GITHUB_REPO unset. |
AskUser | Present the user with a select() or multiselect() to choose between options |
ConfirmAction | Ask the user to confirm() before a destructive or irreversible operation |
Generating tools and agents
Use the built-in generators to scaffold new classes:
php artisan tackle:tool MyTool
php artisan tackle:agent MyAgent
php artisan tackle:agent MyAgent --full
Stubs can be published and customised:
php artisan vendor:publish --tag="tackle-stubs"
Writing a custom tool
Extend Tackle\Tools\AbstractTool and implement description(), schema(), and handle().
namespace App\Ai\Tools;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Tools\Request;
use Tackle\Tools\AbstractTool;
class ReadDatabase extends AbstractTool
{
public function description(): string
{
return 'Run a read-only SQL SELECT query and return results as JSON.';
}
public function schema(JsonSchema $schema): array
{
return [
'query' => $schema->string()->description('The SELECT query to run.')->required(),
];
}
public function handle(Request $request): string
{
$sql = $request->string('query', '');
if (! str_starts_with(strtolower(ltrim($sql)), 'select')) {
return 'Only SELECT queries are allowed.';
}
return json_encode(\DB::select($sql), JSON_PRETTY_PRINT);
}
}
Rules:
- Return a string from
handle() — the agent reads it as tool output.
- To refuse an action, return a descriptive string rather than throwing.
- File access tools should accept a
Tackle\Support\PathGuard via constructor injection.
Adding a tool to the agent
Extend DefaultCodingAgent and merge your tool into tools(), then rebind the contract.
namespace App\Ai;
use App\Ai\Tools\ReadDatabase;
use Tackle\Agents\DefaultCodingAgent;
class MyCodingAgent extends DefaultCodingAgent
{
public function __construct(
private ReadDatabase $readDatabase,
mixed ...$args,
) {
parent::__construct(...$args);
}
public function tools(): iterable
{
return [...parent::tools(), $this->readDatabase];
}
}
use App\Ai\MyCodingAgent;
use Tackle\Contracts\CodingAgent;
public function register(): void
{
$this->app->bind(CodingAgent::class, MyCodingAgent::class);
}
Swapping the agent entirely
Implement Tackle\Contracts\CodingAgent directly (it extends laravel/ai's Agent, HasTools, and Conversational) and use the Promptable trait.
use Laravel\Ai\Promptable;
use Tackle\Contracts\CodingAgent;
class MyAgent implements CodingAgent
{
use Promptable;
public function instructions(): string { return 'You are a billing specialist.'; }
public function messages(): iterable { return []; }
public function tools(): iterable { return []; }
}
$this->app->bind(\Tackle\Contracts\CodingAgent::class, MyAgent::class);
Self-healing queue workers
Setup
php artisan vendor:publish --tag="tackle-migrations"
php artisan migrate
AI_CODE_HEALING_ENABLED=true
AI_CODE_HEALING_MODE=pr # pr | patch
AI_CODE_HEALING_THRESHOLD=1 # failures before healing triggers
AI_CODE_HEALING_QUEUE=healer
GITHUB_TOKEN=ghp_... # required for pr mode
Start the healer on its own worker process:
php artisan queue:work --queue=healer
Modes
| Mode | Behaviour |
|---|
pr (default) | Pushes a fix branch and opens a GitHub pull request |
patch | Merges the fix directly if tests pass; falls back to pr if they fail |
GitHub token resolution order
GITHUB_TOKEN in .env
- GitHub CLI — Tackle runs
gh auth token automatically if gh is installed
tackle.healing.github_token in config/tackle.php
Opting a job out of healing
use Tackle\Attributes\Healable;
#[Healable(false)]
class ChargeSubscription implements ShouldQueue
{
public function handle(): void { }
}
Jobs without the attribute, or with #[Healable(true)], are healed normally.
Scheduled task healing
Tackle listens to ScheduledTaskFailed automatically when AI_CODE_HEALING_ENABLED=true. No extra configuration needed. Patched scheduled tasks are not re-dispatched — the fix takes effect on the next scheduled run.
Code review
php artisan ai:review
php artisan ai:review --staged
php artisan ai:review --against=main
php artisan ai:review --commit=abc1234
php artisan ai:review --focus=security,performance
The ReviewAgent is read-only — it has ReadFile, Glob, and SearchCode but no editing tools. It reads full files for context before commenting on any changed function.
Explain code
php artisan ai:explain app/Services/BillingService.php
php artisan ai:explain app/Services/BillingService.php --method=charge
The ExplainAgent is read-only. It reads the full file and any related classes before explaining.
Generate tests
php artisan ai:test app/Services/BillingService.php
php artisan ai:test app/Services/BillingService.php --method=charge
php artisan ai:test app/Http/Controllers/UserController.php --feature
php artisan ai:test app/Services/BillingService.php --unit
The TestWriterAgent reads the class, checks existing test conventions, writes a Pest test file, then runs the tests to confirm they pass. Test type is inferred from the path when no flag is given.
Health check
php artisan tackle:health
Checks: config published, API key set, git repo with commits, .env.testing present, and (if healing enabled) migration run and GitHub token available.
Replay a healing attempt
php artisan tackle:replay
php artisan tackle:replay --class="App\Jobs\ProcessPayment"
php artisan tackle:replay --id=42
Healing audit log
php artisan tackle:healing-log
php artisan tackle:healing-log --type=job
php artisan tackle:healing-log --type=scheduled_task
php artisan tackle:healing-log --outcome=pr_opened
php artisan tackle:healing-log --outcome=patched
php artisan tackle:healing-log --outcome=failed
php artisan tackle:healing-log --limit=50
Contextual attributes
Tackle provides three Laravel contextual attributes for constructor injection:
use Tackle\Attributes\AiProvider;
use Tackle\Attributes\AiModel;
use Tackle\Attributes\Workspace;
public function __construct(
#[AiProvider] string $provider, // config('tackle.provider')
#[AiModel] string $model, // config('tackle.model')
#[Workspace] PathGuard $guard, // PathGuard for the app workspace
) {}
Common pitfalls
git worktree add failed — the project must have at least one commit: git add -A && git commit -m "initial".
- Healer branch pushed but no PR — GitHub token not found. Run
gh auth status or set GITHUB_TOKEN in .env.
- Tests always fail in sandbox — ensure
.env and .env.testing exist and are committed or that the project has them; the worktree symlinks them automatically.
- Config not updated after publishing — run
php artisan config:clear after editing config/tackle.php.
- Healer skipping a job — check for
#[Healable(false)] on the job class or a threshold setting higher than the current failure count.