jordandalton/laravel-tackle 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jordandalton/laravel-tackle

Composer 安装命令:

composer require jordandalton/laravel-tackle

包简介

An interactive, terminal-based AI coding assistant for Laravel — a Claude Code native to your Laravel app.

README 文档

README

An interactive, terminal-based AI coding assistant for Laravel.

Think Claude Code, but installed directly into your Laravel app via Composer. Run php artisan ai:code, describe a task, and the agent reads your codebase, edits files, runs tests, and formats code — all within your project.

Built on top of laravel/ai.

Contents

Before you start

Run through this checklist once before your first session:

  • Commit or stash any in-progress work — the agent will modify files, and a clean git state is your undo button.
  • Set ANTHROPIC_API_KEY in .env (or the key for your chosen provider).
  • Publish the laravel/ai config: php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
  • Publish the Tackle config: php artisan vendor:publish --tag="laravel-tackle-config"
  • Run php artisan ai:code and type a small test task to confirm everything connects.

Requirements

Installation

composer require jordandalton/laravel-tackle
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
php artisan vendor:publish --tag="laravel-tackle-config"

The service provider and ai:code command register automatically via Laravel package auto-discovery.

API key setup

Tackle uses Anthropic (Claude) by default. Add your key to .env:

ANTHROPIC_API_KEY=sk-ant-...

The config/ai.php published above already includes the anthropic provider block — just add the env var and you're ready.

Environment variables

All config options can be set via .env. Nothing requires editing a PHP file.

Variable Default Description
ANTHROPIC_API_KEY Your Anthropic API key (required for the default provider)
AI_CODE_PROVIDER anthropic Provider name — must match a key in config/ai.php
AI_CODE_MODEL claude-sonnet-4-6 Model to use
AI_CODE_MAX_STEPS 40 Max tool-call cycles per agent turn
AI_CODE_BUDGET 1.00 Hard spend limit in USD per session
AI_CODE_SHELL approve Shell mode: off | allowlist | approve | yolo
AI_CODE_MEMORY file Session persistence: none | file | database

Usage

php artisan ai:code

Type a task at the prompt. The agent maintains full conversation history within a session, so you can follow up, ask questions, and give corrections naturally.

Type exit or quit to end the session.

Shell mode flag

Pass --shell to override the configured shell mode for a single session without touching your config or .env:

# Safe read-only exploration — no commands will run at all
php artisan ai:code --shell=off
php artisan ai:code --off          # shorthand

# Require your approval before every shell command (config default)
php artisan ai:code --shell=approve
php artisan ai:code --approve      # shorthand

# Only allow commands from shell_allowlist, no prompt
php artisan ai:code --shell=allowlist
php artisan ai:code --allowlist    # shorthand

# No restrictions, no prompts — CI or fully-trusted environments only
php artisan ai:code --shell=yolo
php artisan ai:code --yolo         # shorthand

The flag is session-scoped and does not persist to config.

Example session

┌ What should I work on? ──────────────────────────────────────┐
│ Add a slug field to the Post model                           │
└──────────────────────────────────────────────────────────────┘

→ searching for Post model
→ reading app/Models/Post.php
→ creating database/migrations/2024_01_01_add_slug_to_posts.php
→ editing app/Models/Post.php
→ running tests

All done. Migration created, $fillable updated, and tests pass.

┌ What should I work on? ──────────────────────────────────────┐
│ Make the slug auto-generate from the title on creation       │
└──────────────────────────────────────────────────────────────┘

Tips for better results

Be specific about what you want. Vague tasks produce vague results. The more context you give upfront, the less back-and-forth is needed.

Instead of… Try…
"Add a feature" "Add a published_at timestamp to Post with a scope for published posts and a migration"
"Fix the bug" "The UserController@store is returning a 500 when email is null — find out why and fix it"
"Refactor this" "The OrderService class is doing too much — extract the payment logic into a PaymentService"

Use --off for questions and exploration. If you just want to understand the codebase without making changes, --off mode prevents the agent from running any commands, so you can ask freely.

php artisan ai:code --off
# "How is authentication handled in this app?"
# "What does the Job queue setup look like?"

Point it at the right place. If you know which file or module is relevant, say so. "Look at app/Services/BillingService.php" is faster than letting it search from scratch.

Correct it mid-session. If the agent does something wrong, just say so in the next prompt. It reads your correction in context and adjusts. You don't need to restart the session.

Keep tasks focused. One clear task per session works better than a long list. Once a task is done, review the diff, commit it, then start a new session for the next task.

Review before you move on. After each task the agent shows a git diff --stat. Look at it before typing your next task. If something looks wrong, say so or discard with git checkout -- ..

Session memory

The memory config controls what happens to conversation history when you exit.

Mode Behaviour
none History is lost when the session ends. Every php artisan ai:code starts fresh.
file (Default) The session transcript is saved to storage/ai-code/. Re-running ai:code picks up where you left off.
database Uses laravel/ai's RemembersConversations. Requires publishing and running the laravel/ai migrations first.

File memory

With the default file mode, transcripts are stored as JSON in storage/ai-code/. The directory is created automatically. You can delete files there to clear history, or add storage/ai-code/ to .gitignore to keep session history out of your repository.

Database memory

To use database mode, publish and run the laravel/ai migrations:

php artisan vendor:publish --tag="laravel-ai-migrations"
php artisan migrate

Then set AI_CODE_MEMORY=database in .env.

Configuration

After publishing the config, edit config/ai-code.php. All values can be set via environment variables — see the Environment variables table above.

return [
    // laravel/ai provider name — must match a key in config/ai.php
    'provider' => env('AI_CODE_PROVIDER', 'anthropic'),

    // Model to use
    'model' => env('AI_CODE_MODEL', 'claude-sonnet-4-6'),

    // Maximum agent steps per turn (tool calls + reasoning cycles)
    'max_steps' => env('AI_CODE_MAX_STEPS', 40),

    // Hard spend limit for the session in USD — aborts when exceeded
    'budget_usd' => env('AI_CODE_BUDGET', 1.00),

    // Shell execution policy: off | allowlist | approve | yolo
    'shell'           => env('AI_CODE_SHELL', 'approve'),
    'shell_allowlist' => ['composer', 'npm', 'php artisan'],

    // Artisan commands the agent may run without a confirmation prompt
    'artisan_allowlist' => ['make:*', 'route:list', 'migrate', 'db:seed', 'test'],

    // Glob patterns (relative to workspace) the agent can never read or write
    'protected_paths' => ['.env', '.env.*', 'storage/*', 'vendor/*', '.git/*'],

    // Root directory for the agent — null defaults to base_path()
    'workspace' => null,

    // Session memory: none | file (default) | database
    'memory' => env('AI_CODE_MEMORY', 'file'),
];

Shell modes

Mode Behaviour
off RunShell refuses everything. Use RunArtisan / RunTests instead.
allowlist Only commands whose first token matches shell_allowlist run unattended.
approve Default. Every command shows a confirmation prompt before running.
yolo Runs anything, no prompt. Dangerous — CI or fully-trusted environments only.

Artisan allowlist

The artisan_allowlist supports glob patterns, so make:* covers make:model, make:controller, etc. Commands not matching any pattern are refused.

Protected paths

The protected_paths globs prevent the agent from reading or writing sensitive files regardless of what it is asked to do. This is enforced in PHP, not via prompting. Add your own patterns here if your project has additional secrets.

Built-in tools

These tools are available to the agent in every session.

Tool What it does
ReadFile Reads a file's contents. Always runs through PathGuard first.
Glob Lists files matching a pattern. Protected paths are excluded from results.
SearchCode Grep-style search returning file + line + snippet. Capped at 50 results.
EditFile str_replace edit — old_str must appear exactly once or the edit is refused.
WriteFile Creates a new file. Refuses if the path already exists.
RunArtisan Runs php artisan <command> in a subprocess. Allowlist-gated.
RunTests Runs Pest or php artisan test in a subprocess. Returns full output.
RunPint Runs Laravel Pint to format files. Called before finishing a task.
RunShell General shell — governed by the shell config mode.

All file reads happen in-process. Everything that executes code runs as a subprocess, so a broken generated file cannot crash the agent session.

Limitations

Things Tackle cannot do in v1:

  • No internet access. The agent cannot fetch URLs, read documentation, or call external APIs. It works only with files in your workspace.
  • No binary files. ReadFile reads text. Images, compiled assets, and other binaries are not readable by the agent.
  • No auto-commit or push. All edits are left unstaged. The agent will never run git commit or git push.
  • History resets on exit (unless memory=file or memory=database). With the default file mode, history persists between sessions automatically.
  • Budget is estimated, not exact. The spend limit is calculated from token counts using approximate per-model pricing. Actual charges from your provider may differ slightly.
  • Tests need a working environment. RunTests runs your actual test suite. If tests require a database or other services, those must be running and configured before starting a session.

Customization

Adding your own tools

Create a class that extends Tackle\Tools\AbstractTool, then extend DefaultCodingAgent to merge it into the tool list, and rebind the contract.

Step 1 — Write the tool:

// app/Ai/Tools/ReadDatabase.php
namespace App\Ai\Tools;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Illuminate\Support\Facades\DB;
use Laravel\Ai\Tools\Request;
use Tackle\Tools\AbstractTool;

class ReadDatabase extends AbstractTool
{
    public function description(): string
    {
        return 'Run a read-only SQL query and return results as JSON. SELECT only.';
    }

    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);
    }
}

Step 2 — Extend the agent:

// app/Ai/MyCodingAgent.php
namespace App\Ai;

use App\Ai\Tools\ReadDatabase;
use Tackle\Agents\DefaultCodingAgent;

class MyCodingAgent extends DefaultCodingAgent
{
    public function __construct(
        private ReadDatabase $readDatabase,
        ...$args,
    ) {
        parent::__construct(...$args);
    }

    public function tools(): iterable
    {
        return [...parent::tools(), $this->readDatabase];
    }
}

Step 3 — Rebind in your service provider:

// app/Providers/AppServiceProvider.php
use App\Ai\MyCodingAgent;
use Tackle\Contracts\CodingAgent;

public function register(): void
{
    $this->app->bind(CodingAgent::class, MyCodingAgent::class);
}

The Laravel container resolves all constructor dependencies automatically, so your tool class can type-hint anything it needs (DB connections, services, etc.).

Tool contract

Every tool receives a Laravel\Ai\Tools\Request object in handle(). It behaves like a read-only request bag:

$request->string('key', 'default');   // string value
$request->boolean('key', false);      // boolean value
$request->integer('key', 0);          // integer value
$request->get('key', 'default');      // raw value
$request->all();                      // all arguments as array

When a tool should refuse an action, return a string explaining why rather than throwing an exception. The agent reads the refusal message and reroutes itself accordingly.

Swapping the agent entirely

If you need deeper control — different instructions, a different conversation strategy, or a completely different set of tools — implement the CodingAgent contract directly and rebind it:

// app/Ai/MyAgent.php
namespace App\Ai;

use Laravel\Ai\Promptable;
use Tackle\Contracts\CodingAgent;

class MyAgent implements CodingAgent
{
    use Promptable;

    public function instructions(): string
    {
        return 'You are a specialist in this project. Only touch the billing module.';
    }

    public function messages(): iterable
    {
        return [];
    }

    public function tools(): iterable
    {
        return [
            // your tools here
        ];
    }
}
$this->app->bind(\Tackle\Contracts\CodingAgent::class, MyAgent::class);

The CodingAgent contract extends Laravel\Ai\Contracts\Agent, HasTools, and Conversational, so laravel/ai's full streaming and tool-calling machinery works automatically as long as you use the Promptable trait.

Changing the model or provider

The quickest way is via .env:

AI_CODE_PROVIDER=openai
AI_CODE_MODEL=gpt-4o

The provider name must match a key in config/ai.php. Any provider supported by laravel/ai (Anthropic, OpenAI, Gemini, Groq, Ollama, etc.) works as long as it supports tool calling.

Safety

  • Protected paths — the agent cannot read or write .env, storage/, vendor/, or .git/ by default. Enforced in PathGuard, not via prompting. The model cannot talk its way around this.
  • Unstaged edits — all file changes are left unstaged. Review with git diff; discard with git checkout -- ..
  • Budget cap — the session aborts once estimated spend exceeds budget_usd.
  • Subprocess isolationRunArtisan, RunTests, RunPint, and RunShell all run as child processes. A broken generated file cannot crash the session.
  • Shell is gated — the default approve mode requires your confirmation before any shell command runs. Use --off for read-only exploration.

Troubleshooting

HTTP request returned status code 401

Your API key is missing or incorrect. Check that ANTHROPIC_API_KEY (or the key for your chosen provider) is set in .env and that config/ai.php has been published and contains the matching provider block.

Agent error: ... and the session continues

The agent caught an exception during a turn. The error is shown but the session stays alive — type your next task to continue. If the same error repeats, check the message for clues (auth issues, missing binaries, filesystem permissions).

Session aborted: estimated cost exceeds the budget limit

You've hit the budget_usd cap. Increase it in .env:

AI_CODE_BUDGET=5.00

Or pass a higher limit for a single session by editing the config temporarily. The default $1.00 limit is intentionally conservative.

ai:code requires an interactive TTY

The command must be run in a real terminal — not piped, not in a CI job, not through a non-interactive shell. This is required because the approval prompts need user input.

Path '...' is outside the workspace root

The agent tried to access a file outside the configured workspace (defaults to base_path()). If you're working in a monorepo or non-standard layout, set workspace in config/ai-code.php to the correct root path.

Path '...' matches protected pattern

The agent tried to read or write a protected file (.env, vendor/, etc.). This is intentional — protected paths are blocked in code, not via prompting. If you need to unblock a path (e.g. you're working on a package inside vendor/), remove or narrow the relevant pattern in protected_paths.

old_str not found / old_str appears N times

The agent is trying to edit a file but the string it wants to replace either doesn't exist or appears more than once. This usually means the agent needs to re-read the file to get the current content. Tell it: "read the file again before editing."

Pint is not installed

Install Pint as a dev dependency in the host app:

composer require laravel/pint --dev

Tests fail during a session

This is expected behaviour. When RunTests returns failures, the agent reads the output and attempts to fix the code. If it gets stuck, tell it what the failure means or paste the relevant stack trace as your next message.

Known Risks

laravel/ai is new and fast-moving. The version is pinned to ^0.1. Breaking changes upstream are likely. Check the changelog before upgrading.

This tool modifies your codebase and runs commands. Always run it inside a committed git working tree so you have a clear undo path (git checkout -- .).

Development

composer install
./vendor/bin/pest        # run tests
./vendor/bin/pint        # format code

License

MIT

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 4
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-13

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固