Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Agents Laravel Package

packstub/filament-agents

A Filament plugin that adds AI agent management to your Laravel admin panel. Create and configure agents, define prompts, attach tools, run conversations, and monitor activity through native Filament resources and a clean, familiar interface built for Laravel.

View on GitHub
Deep Wiki
Context7

Getting Started

Hard floors first. PHP 8.4+, Filament v5. If either is false, stop — there is no fallback path. Confirm your panel provider already boots v5 and that your test suite runs against the database you actually deploy on (Postgres is now exercised in CI, but verify on your schema, not on a fresh one).

Install as a pinned pair. The plugin is a thin Filament adapter over packstub/agents, and the two move together. Install both with explicit constraints, not ^ floating:

composer require packstub/filament-agents:^1.16 packstub/agents:^1.9

Then publish and migrate the engine's tables (conversations, turns, proposals, budgets — that's engine-owned, not plugin-owned):

php artisan vendor:publish --tag=agents-config
php artisan vendor:publish --tag=agents-migrations
php artisan migrate

Register the plugin on the panel. This is the seam where the assistant inherits the panel's guard, tenancy, and policies — FilamentContext binds panel + guard + tenant, and TenantSet keeps firing. Register it on the panel(s) you actually want the assistant in, not globally, and check that a tenant-scoped login still resolves correctly before writing any tools.

Where to look first, in this order:

  1. AgentResource — your domain boundary. Record shapes, prompt domain blocks, and the agent slots live here. Everything you own lives here; everything you don't lives upstream.
  2. The agent's tool list — this is the single list feeding both the in-panel chat (laravel/ai) and the MCP server (laravel/mcp). Read it before writing anything; it's the whole surface area.
  3. The AI turns page — your debugging console. Transcripts, proposals, and the Decided by column.
  4. The operator limits page — budgets. Look at it before you let anyone near a write tool.

First use case: read-only, one resource, real data. Resist the temptation to start with writes. Pick the resource operators already ask humans about (orders, invoices, tickets). Write one tool that queries it through the panel's existing scopes and filters and returns a structured table answer. Concretely:

  • The tool delegates to a query object or a Filament table query — do not reimplement filtering in the tool. If the tool's answer doesn't match what the list page shows, the assistant loses trust in week one.
  • Return the panel's own table/chart payload rather than markdown tables, so filters, pagination, and column formatting come for free. Answer quality then tracks how good your resource already is, which is a useful forcing function.
  • Ask three questions you already know the answers to. Then check the transcript and confirm Decided by is empty — it should be, since nothing was approved.

Only after that reads correctly do you add one approvable write tool (a status update, a note append), exercise the approval flow, and check the turns page shows the decision and its provenance.

Implementation Patterns

Keep tools thin and shared. The single-tool-list design means every tool runs in two contexts: inside a panel (with FilamentContext, a user, a tenant) and over MCP (with whatever an external client presents). Write tools that assume neither. Pattern:

// domain logic in app/, tool is a thin adapter
final class SearchOrdersTool extends Tool
{
    public function handle(array $arguments): ToolResult
    {
        $orders = app(SearchOrders::class)->forPanelUser(
            FilamentContext::user(),
            $arguments,
        );

        return ToolResult::table(OrderResource::class, $orders);
    }
}

The SearchOrders class is yours, testable without an LLM, and reusable from a controller or command. The tool class is 5 lines and disposable. That ratio is the pattern.

Authorization: inherit, don't reinvent. Panel authorization is the source of truth by design, and it's the most defensible thing in the package. Practical rules:

  • Never withoutGlobalScopes() in a tool to "make it work." If a tool returns nothing for a tenant, that's the tenancy working.
  • Call policies explicitly for anything sensitive ($user->can('viewAny', Order::class)), even though scopes already filter — belt and braces, and it documents intent in review.
  • Do not build a parallel permission model for the assistant. The whole point is that a reviewer reasons about AI access using rules they already know.

Split read tools from approvable write tools, deliberately. Reads answer immediately. Writes go through the approvable-tool path: the turn loop pauses, a proposal lands in the chat, and a human approves. The default is no.

  • Model mutation as a proposal, never as a silent side effect — including "just" adding a note.
  • Make the proposal body legible: a human is reading it under time pressure, in a locale you may not have tested.
  • Budget UX time for the ambiguous case. v1.16 reads a typed reply through your app's rule, per-locale word lists, and an opt-in classifier. "Ok?" and "Yes, but only Alpha." do not approve. Design the "not approved, here's why" response in the chat, because your operators will type these.

Own the approval vocabulary in your app. The word lists ship with the engine but are extendable and replaceable in-app. For every locale you serve:

  • Write the word lists for that locale's actual consent idioms, not translations of English.
  • Test the negatives: polite hedges, conditionals, questions-as-consent. These are the ones that fail.
  • Enable the classifier only after the rule and word lists are baselined — then it's an added signal, not a substitute.
  • Version the files. A change to yes vocabulary is a behavior change to your consent policy, not a copy tweak.

Read audit from the column, not the transcript. Decided by carries app rule / word lists / classifier, with the classifier's reason on hover and (once the engine reaches 1.10) which classifier and its lowest confidence. Build your internal reporting off that column and its filter. Parsing transcripts for "did they say yes" is the trap; the column is the contract.

Budgets per workspace, wired to your tenancy. Per-workspace budgets plus the operator limits page are what gets a finance owner to sign off. Pattern:

  • Map "workspace" onto whatever your panel already treats as the tenant. Don't introduce a second notion of workspace.
  • Set a low default, and test the exhaustion path explicitly — mid-turn exhaustion is the interesting case, not "the button greys out."
  • Give exactly one or two named people the operator limits page and a documented reason to change a number.

MCP as a follow-on, with its own story. Exposing the same tool list over MCP is nearly free technically and not free organisationally. Before turning it on: decide which tools external clients may reach (probably not your write tools), how clients authenticate, and who supports an IDE plugin that now has access to tenant data. Ship it as a scoped second channel, not a footnote on the chat launch.

Testing cadence (Pest). Fake the model; assert on tools, not on prose:

  • Each tool: returns rows for the right tenant, returns nothing for the wrong one, respects the policy.
  • Approval parsing: a table-driven test per locale — yes, no, Ok?, Yes, but only Alpha., and three idioms you actually use.
  • Budgets: exhaustion mid-turn.
  • A smoke test that the MCP path can call a read tool without a panel request lifecycle.

Gotchas and Tips

Version lockstep is not optional. Plugin and engine upgrade as a pair; v1.16 requires engine ^1.9. Pin both, upgrade both in one commit, and read both changelogs. Anything that runs outside a panel — tool contracts, budget rules, migrations, config — is an engine change, and engine changes shape your upgrade path.

Approval semantics changed in v1.16, and that's a training problem. What counted as consent got stricter and fail-closed. If operators were trained on the old behavior, their muscle memory now produces non-approvals. Treat this as a UX and documentation release, not a dependency bump: brief the pilot cohort, and watch the turns page for replies that landed as questions rather than decisions.

A non-approval looks like a bug to the operator. "Ok?" doing nothing is correct and will be reported as broken. Put explanatory text in the chat response for unapproved proposals — ideally naming what would count as approval — before you widen the pilot.

Postgres parity is fixed, but verify on your data. Case-insensitive search now uses whereLike(..., caseSensitive: false) for the Chats search, snippets, and the @ record picker; unclassified chats sort null-first ascending and null-last descending; tenant lookup no longer pushes a slug at an integer key. All good — but if you have a custom collation, a citext column, or a tenant model where the "slug" is genuinely the key, re-run the sanity checks on staging. Don't assume a bug fix generalises to your schema.

Respect the namespace boundary. Both packages map Packstub\Agents\. A class name may exist in exactly one repo. Don't add app classes under that namespace, and don't "temporarily" patch a vendor file — you'll collide on the next release and lose the fix.

Domain logic stays in your app. Record shapes, filter vocabulary, prompt domain blocks, and approval vocabulary belong behind AgentResource and the agent's slots. If you find yourself wanting to change the turn loop, the tool contract, or the budget enforcement, that's an upstream conversation — and given the maturity profile, possibly a fork. Decide that policy before you're mid-feature.

Debugging order for "the assistant is wrong": (1) the tool in isolation, with a fake user, no LLM; (2) the resource's list page with the same filters — does the human UI agree?; (3) the turns transcript, to see what the model actually called with what arguments; (4) Decided by, if a write was involved. Almost every "the AI is broken" report is step 1 or 2.

Livewire specifics. The embedded AgentTable component and the turn-polling route both sit in the panel's Livewire lifecycle. If tables render in chat but not on a full page reload (or vice versa), suspect the component's hydration and the poll route's middleware/panel resolution before suspecting the model. Clear panel caches and check the poll route is reachable under your tenant middleware.

Maturity is the real risk, and it's a supply-chain one. 13 stars, zero dependents, single maintainer, MIT, active cadence. That's an early-adopter position, not a follower position. Concretely: pin versions, read every changelog before upgrading, code-review the dependency, and have a fork-or-vendor answer ready before production. Run the first deployment as a scoped pilot with a named owner and a rollback (disable the plugin on the panel — the tables can stay).

Extension points worth knowing before you need them: agent slots (per-agent prompt and tool composition), the per-locale approval word lists (extend or replace in-app), and the opt-in classifier. Those three cover most "we need to change the behaviour" requests without touching the engine — which is exactly where you want the line.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource