Skip to content

About

This is the Claude Managed Agents package.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Claude Managed Agents for Laravel

Run your Claude Code skills from a Laravel application.

The skills in your app's .claude/skills/ folder are the ones Claude Code runs when you type /name arguments. This package runs those same skills from PHP, in Anthropic-hosted Managed Agents sandboxes, with queued jobs, live progress, spend caps, and the agent's output files downloaded to your disk.

use function ClaudeManagedAgents\skill;

$run = skill('/one-page-site Kestrel Coffee, a coffee bar in Portland')
    ->budget(5)
    ->dispatch();

How it works

  1. Your skill is uploaded to the Skills API the first time it runs, and again only when one of its files changes.
  2. An environment and an agent are created once and reused: the sandbox recipe, and an agent with your skill attached and a system prompt that tells it to behave as if you had typed the command in Claude Code, unattended.
  3. A session starts with your command as its first message, capped at your budget.
  4. A queued job follows it, storing each event (agent messages, tool calls, status changes) and the running cost, then queues itself again a few seconds later. No worker is held for the length of a run.
  5. When the session goes idle, everything the agent wrote to /mnt/session/outputs/ is downloaded to your disk and the run is marked completed.

Laravel events fire along the way, so your app can react without polling.

Requirements

  • PHP 8.3+, Laravel 12 or 13
  • An Anthropic Console API key in a workspace with Managed Agents enabled. A claude.ai subscription login cannot be used to power an application.
  • A real queue (database, Redis, SQS) and a running worker for dispatch(). run() works without one.

Installation

composer require maxai/claude-managed-agents
php artisan migrate
ANTHROPIC_API_KEY=sk-ant-...
QUEUE_CONNECTION=database

Publish the config if you want to change the defaults:

php artisan vendor:publish --tag=claude-agents-config

Try it without an API key first: CLAUDE_AGENTS_DRIVER=fake simulates runs end to end, free.

Running a skill

use ClaudeManagedAgents\Facades\ClaudeAgents;
use function ClaudeManagedAgents\skill;

// Queue it and return straight away.
$run = skill('/release-notes '.$mergedChanges)->dispatch();

// Or run it here and wait, printing progress (Artisan commands, scripts).
$run = skill('/smoke-test hello')->run(function ($event, $run) {
    echo $event->summary.PHP_EOL;
});

// The facade does the same.
$run = ClaudeAgents::skill('/one-page-site ...')->dispatch();

Options, all optional:

skill('/one-page-site ...')
    ->budget(10)                       // hard cap in USD; null for none
    ->model('claude-opus-5-5')         // default from config
    ->effort('high')                   // low, medium, high, xhigh (default), max
    ->environment('open-web')          // a named environment from config
    ->until($rubric, maxIterations: 3) // grade against a rubric, revise until it passes
    ->for($user)                       // attach the run to any model
    ->withMetadata(['ticket' => 42])
    ->instructions('Use British English.')
    ->withRepository('https://github.com/acme/app', $token, 'main')
    ->dispatch();

Following a run

An AgentRun is an Eloquent model.

$run->status;          // RunStatus enum: Pending, Starting, Running, Paused, Collecting, Completed, Failed, Cancelled
$run->cost();          // dollars spent so far, at list price
$run->last_message;    // the agent's latest message
$run->messages();      // every agent message, oldest first
$run->events;          // every stored event, with ->type, ->summary and ->payload
$run->files;           // downloaded outputs
$run->output('index.html');
$run->result;          // the agent's final message
$run->traceUrl();      // the session in the Anthropic Console

$run->raiseBudget(25); // a run paused at its budget resumes
$run->cancel();        // stop; outputs written so far are still collected
$run->sync();          // pull the latest events now, outside the queue

Events, for listeners:

Event When
AgentRunStarted The session was created
AgentRunProgressed A new session event arrived ($event->event->type, ->summary)
AgentRunPaused The run reached its budget, or is waiting on an action
AgentRunCompleted The session finished and its outputs are downloaded
AgentRunFailed The run could not start, or its session ended in an error

Artisan

php artisan claude-agents:skills                          # what can run, and whether each is uploaded
php artisan claude-agents:run /smoke-test hello           # run and follow it here
php artisan claude-agents:run /one-page-site "..." --queue --budget=5
php artisan claude-agents:status [run-id] [--sync]
php artisan claude-agents:budget {run-id} {dollars}
php artisan claude-agents:cancel {run-id}
php artisan claude-agents:publish [skill] [--force]       # upload ahead of the first run

Writing skills for both Claude Code and your app

Any Claude Code skill works, with three things to keep in mind:

  • Outputs. Only files in /mnt/session/outputs/ come back. A skill that should work in both places can say: write to /mnt/session/outputs/ when it exists, otherwise ./outputs/.
  • Nobody answers questions. The agent is told to choose and say what it chose; a skill that depends on a conversation will not work unattended.
  • The sandbox is not your laptop. It is Ubuntu with Python, Node, PHP 8.3, Playwright and Chromium preinstalled. A skill that calls your app's own code needs the repository mounted (->withRepository() or CLAUDE_AGENTS_REPOSITORY) and its dependencies installed by the skill. Skill names may not contain "claude" or "anthropic".

Networking

The default environment is limited: package registries only. A skill that fetches arbitrary websites needs ->environment('open-web') (unrestricted egress) or a host allowlist in config/claude-agents.php.

Testing your app

use ClaudeManagedAgents\Facades\ClaudeAgents;

$fake = ClaudeAgents::fake()->outputs(['index.html' => '<h1>Hi</h1>']);

$run = skill('/one-page-site test')->dispatch()->refresh();

expect($run->output('index.html'))->toBe('<h1>Hi</h1>');
$fake->assertSkillUploaded('one-page-site');
$fake->assertSessionCreated(fn ($parameters) => $parameters['budget'] !== null);

->pauseAtBudget(), ->eventsPerPoll(2), ->script([...]) and ->cost(1.5) shape the simulated session.

Costs

A run is billed to your API key at Anthropic's token prices plus the sandbox's running time. Most of a long run's cost is the conversation being re-read on every model request (cache reads), so it grows with how long the agent works. Always set a budget. The package records the session's list-price cost on the run; your invoice may differ if your organization has negotiated rates.

Security

  • Output files are written by a model that may have read untrusted web pages. Treat HTML outputs as untrusted: serve them with a Content-Security-Policy: sandbox header, never inline on your own origin.
  • Repository tokens passed to withRepository() are stored encrypted and sent only to Anthropic's git proxy; they never enter the sandbox.

License

MIT.

About

This is the Claude Managed Agents package.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages