mozex/anthropic-php
Community-maintained PHP SDK for the Anthropic API: send messages, stream responses, call tools, use extended thinking, web search, code execution, batches, and files. Works with any PSR-18 HTTP client, plus a Laravel wrapper. Full docs at mozex.dev.
Architecture fit. mozex/anthropic-php is a thin, transport-level SDK rather than a framework abstraction. It wraps the Anthropic REST API in typed request/response DTOs over any PSR-18 client, which means it slots in below our application's domain layer and does not impose opinions on how we model prompts, tools, or conversation state. That is the right shape for us: we can wrap it in our own LlmClient interface and keep provider switching as a future option. Two caveats matter for a TPM. First, the package is deliberately forward-compatible by passthrough — parameters are forwarded to the API as-is, so new Anthropic features work "the same day," but that also means the SDK gives us no compile-time or type-level validation of new parameters; correctness for bleeding-edge features rests on our own tests and the vendor's API contract. Second, response objects are readonly DTOs with typed properties ($response->usage->inputTokens), which is a genuine integration win over array-shaped clients — it makes our own downstream code cheaper to write and safer to refactor.
Integration feasibility. Low friction technically. composer require, PHP 8.2+, php-http/discovery auto-resolves a PSR-18 client so it will reuse whatever Guzzle/Symfony client the app already has rather than adding a second HTTP stack. Auth is a single API key handed to the factory or Anthropic::client(). Every surface we'd realistically need in a first phase is present and documented: messages, streaming, tool use, token counting, models list, batches, files, citations, error handling, and rate-limit metadata on every response including streams. The ClientFake test double is the standout feature from a delivery-planning standpoint — assertSent() against queued fake responses removes the need for HTTP mocking infrastructure and makes AI features testable in CI without network access or spend.
Technical risk. This is where the package rates poorly and where I'd anchor the decision.
mozex/anthropic-laravel for container binding, config, and a facade. That is a second low-adoption dependency in the same bus-factor position. My default recommendation is to skip it, register Anthropic\Client in a service provider ourselves, and keep the dependency graph shallower.Key questions.
ClientFake coverage satisfy our test-coverage gate, or do we also need contract tests against the live API to catch passthrough drift?Stack fit. Strong on the mechanics, neutral on the framework. PHP 8.2+ with readonly DTOs and backed enums (OverrideStrategy) aligns with a modern Laravel codebase; PSR-18 compliance means zero conflict with an existing Guzzle or Symfony HTTP client and no duplicate connection pooling or timeout configuration. It plays well with Laravel's queue workers, which matters because batches and long-running tool loops belong on queues, not in request cycles. The gap is that Laravel-native ergonomics (config publishing, config/anthropic.php, facade, container singleton) live in a sibling package, not here.
Migration path. No migration required if this is net-new capability — greenfield integration, not a replacement. If we already have hand-rolled curl/Guzzle calls to the Anthropic API, the migration is mechanical: each call site maps to messages()->create(), createStreamed(), countTokens(), or the batch endpoints, and the raw-JSON parsing we wrote disappears into typed responses. I would migrate one call site first — ideally the lowest-risk one, such as an async batch summarization job — and hold the rest until the pattern is proven. If we are currently on a different Anthropic PHP client, sequence the swap behind our own adapter interface so the change never reaches feature code.
Compatibility. MIT license, no copyleft exposure. PHP 8.2+ is the only hard constraint; confirm no service still runs 8.1. PSR-18 + php-http/discovery means no vendor lock-in at the transport layer — worth stating explicitly to any reviewer who sees "SDK" and assumes a bundled Guzzle fork. Response DTOs being readonly is compatible with our coding standards but does mean we cannot mutate responses in place; our mapping layer must construct our own domain objects rather than decorate SDK responses. Watch the package's own version pinning: pin to a minor (~1.3.0) rather than a caret on 1.x, and treat every bump as a reviewed change given the release cadence.
Sequencing.
Client singleton in a service provider, build a ClientFake-backed test suite, and run one real non-streaming message call. Success criteria: tests pass offline in CI, one real call returns typed data, rate-limit metadata is readable via $response->meta().LlmClient contract and implement it over the SDK. This is the single highest-value engineering decision in the whole integration and should not be deferred.ErrorException / RateLimitException (429-specific subclass is a helpful affordance), and logging that captures meta() for token-limit visibility and cost attribution.createStreamed() behind a feature flag; validate against our frontend transport. Add tool-use loops only once the non-streaming path is stable, since tool loops are where retry and failure semantics get genuinely hard.Do not adopt mozex/anthropic-laravel in Phase 1. Revisit only if we find ourselves reimplementing config and facade ergonomics that we actually need.
Maintenance. The operational burden splits into two very different halves. The SDK is low-maintenance: typed DTOs mean our code breaks loudly at the boundary, ClientFake means our tests don't touch the network, and passthrough parameters mean we are not blocked waiting for a release when Anthropic ships something new. The dependency is higher-maintenance than its size suggests: fast release cadence plus single maintainer plus zero dependents means we must own version discipline and read diffs, not changelogs. Budget a recurring line item — roughly a half-day per quarter — for upgrade review, plus a defined owner. I would also add a lightweight contract test hitting the live API on a schedule to catch the failure mode the passthrough design creates: a parameter silently forwarded that the API has changed or rejected.
Support. Community-supported only. Issues go to GitHub; security reports go to a maintainer email, not a CVE process with an SLA. There is no vendor to escalate to, no support contract, and no guarantee of a response window. For an internal tool or a non-blocking async feature, that is tolerable. For a customer-facing, revenue-path capability, it means we are the support tier — and someone on our team must be able to read and patch PHP SDK internals. The MIT license is the real safety net: worst case we fork and vendor it, but that is a named contingency requiring headcount, not a theoretical one.
Scaling. The SDK itself is not the bottleneck — it is stateless over PSR-18, so scaling is whatever our HTTP client and PHP-FPM/queue workers already do. Real scaling concerns are economic and architectural, not throughput:
meta() exposes input/output token limits and reset times on every response, including streams. We should log these per-request from day one rather than discovering limits during an incident. RateLimitException (429) gives us a typed hook for backoff.BatchIndividualResponse / BatchResult / BatchResultError for this).ephemeral5mInputTokens, ephemeral1hInputTokens), serviceTier, and server-tool counts make per-feature cost attribution feasible. Without this instrumentation, AI cost becomes an unmetered line item that surprises finance. Instrument it in Phase 1.Failure modes. Ranked by what I'd actually worry about:
ClientFake tests.RateLimitException, queue-based concurrency caps.(string) $response->getBody() for reliable stream reading is a reminder this area had real bugs. Mitigation: treat streams as resumable-or-degradable, always have a non-streaming fallback path, and surface partial output rather than erroring.Ramp-up. Small. An experienced PHP/Laravel engineer is productive in under a day: composer require, one factory call, one messages()->create(), and the IDE autocompletes the rest. The docs are genuinely good for a package this size — dedicated site, per-feature pages, version requirements, changelog, plus Context7/Laravel Boost entries for AI-assisted coding. The two things that need explicit onboarding are (a) the passthrough philosophy, so engineers understand why nothing type-checks their new parameters, and (b) ClientFake and OverrideStrategy semantics, so the test suite is written correctly from the start rather than retrofitted.
Recommendation. Proceed with a scoped pilot — one async or internal capability — behind our own adapter interface, pinned to a minor version, with ClientFake-based tests and meta()-based cost/limit logging from day one. Do not put this on a customer-facing blocking path, and do not add the sibling Laravel package, until the pilot demonstrates stability across at least one upgrade cycle. The technical fit is good; the maturity and support profile is what keeps this at a conditional rather than an approved-at-scale.
How can I help you explore Laravel packages today?