Turn messy, monolithic Laravel services into clean, testable, observable pipelines. Sentinels transforms your 300-line service classes into focused agents that you can compose, test, and debug with surgical precision. When something breaks at 3 AM, you'll know exactly which step failed and why.
// 😰 Before: One massive, untestable method
class OrderService {
public function processOrder($order) {
// 200+ lines of mixed concerns that all live in your head
$this->validateInventory($order); // What if this fails?
$this->processPayment($order); // Where's the logging?
$this->updateInventory($order); // How do you test this?
$this->sendNotifications($order); // Why did this break?
$this->updateAnalytics($order); // Good luck debugging!
// When it breaks, where do you even start looking?
}
}
// 🚀 After: Clean, testable, traceable pipeline
$result = Sentinels::pipeline()
->pipe(new ValidateInventoryAgent()) // ✅ Single responsibility
->pipe(new ProcessPaymentAgent()) // ✅ Individual error handling
->pipe(new UpdateInventoryAgent()) // ✅ Easy to test in isolation
->pipe(new SendNotificationAgent()) // ✅ Automatic correlation IDs
->pipe(new UpdateAnalyticsAgent()) // ✅ Built-in performance metrics
->through($order);
// Every step is logged, timed, and traceable. Debug like a detective. 🕵️♂️
Need true parallel processing? Just add one word:
// 🔄 Synchronous (good for quick operations)
$result = Sentinels::pipeline()
->mode('parallel')
->pipe(new ApiCallAgent()) // Takes 2 seconds
->pipe(new DatabaseAgent()) // Takes 1 second
->pipe(new EmailServiceAgent()) // Takes 3 seconds
->through($data);
// Total time: ~6 seconds (sequential simulation)
// ⚡ Asynchronous (blazing fast for I/O operations)
$result = Sentinels::pipeline()
->mode('parallel')
->async() // 👈 Only difference - one word!
->pipe(new ApiCallAgent()) // All three run
->pipe(new DatabaseAgent()) // in parallel on
->pipe(new EmailServiceAgent()) // separate workers
->through($data);
// Total time: ~3 seconds (true parallel execution)
// Use results exactly the same way - transparent!
echo $result->payload; // Auto-waits, then works like sync
echo $result->getElapsedTime(); // See the performance difference
echo $result->correlationId; // Same observability features
// Power users get monitoring for free
if ($result->isAsync()) {
echo "Progress: " . $result->getProgress() . "%";
echo "Batch ID: " . $result->getBatchId();
}
The Laravel Way: Same mental model, same API, same error handling. Async execution is transparent - no callbacks, promises, or new patterns to learn. Taylor Otwell would approve! 🎉
The Problem: Your services are becoming monsters. A simple "process order" method somehow became 300 lines of tangled logic. Testing is a nightmare. Debugging production issues feels like archaeology. Sound familiar?
The Solution: Break complex workflows into focused agents that do one thing brilliantly. Get observability, error recovery, and conditional logic for free.
// Instead of this monolithic service...
class OrderProcessor
{
public function process($order) {
$this->validateOrder($order);
$this->checkInventory($order);
$this->processPayment($order);
$this->sendNotification($order);
// 200+ lines of tightly coupled logic...
}
}
// You get this clean, testable pipeline...
$result = Sentinels::pipeline()
->pipe(new ValidateOrderAgent())
->pipe(new CheckInventoryAgent())
->pipe(new ProcessPaymentAgent())
->pipe(new SendNotificationAgent())
->through($order);
- Debug Like a Detective: Every request gets a correlation ID that traces through your entire pipeline
- Test with Confidence: Each agent is isolated, focused, and easy to mock
- Scale Intelligently: Route tasks based on content, not just linear execution
- Stay in Laravel: Built specifically for Laravel's patterns and ecosystem
composer require vampires/sentinels
php artisan vendor:publish --tag=sentinels-config
# Generate your agent
php artisan make:agent ProcessOrderAgent
# It creates this focused class
class ProcessOrderAgent extends BaseAgent
{
protected function handle(Context $context): Context
{
$order = $context->payload;
// Do your processing here
$processedOrder = $this->processOrder($order);
return $context->with($processedOrder);
}
}
// Simple processing
$result = Sentinels::process($order, new ProcessOrderAgent());
// Or build a pipeline
$result = Sentinels::pipeline()
->pipe(new ValidateOrderAgent())
->pipe(new ProcessOrderAgent())
->pipe(new SendEmailAgent())
->through($order);
// That's it! Every step is now logged, timed, and traceable. 🎉
Ready for more? Let's dive into the problems this solves...
// ❌ The 500-line service method that haunts your dreams
class OrderService {
public function processOrder($order) {
// 🔥 This method has EVERYTHING:
$this->validateStuff($order); // 50 lines of validation
$this->chargePayment($order); // 75 lines of payment logic
$this->doShipping($order); // 40 lines of shipping
$this->sendEmails($order); // 60 lines of notifications
$this->updateAnalytics($order); // 35 lines of tracking
// Testing this? Good luck. Debugging? Therapy time. 😵💫
}
}
// ✅ Clean, focused, debuggable pipeline
$result = Sentinels::pipeline()
->pipe(new ValidateOrderAgent()) // ✅ 25 lines, one job
->pipe(new ChargePaymentAgent()) // ✅ Testable in isolation
->pipe(new HandleShippingAgent()) // ✅ Mock external APIs easily
->pipe(new SendNotificationAgent()) // ✅ Individual error handling
->pipe(new TrackAnalyticsAgent()) // ✅ Single responsibility
->through($order);
// Each step is focused, testable, and debuggable. Your future self will thank you. 🙏
// ❌ Production breaks at 3 AM. The log says:
Log::error("Something broke in order processing");
// 😰 Which of the 15 steps failed? What data caused it?
// Where do you even start looking? Time to wake up the entire team...
// ✅ Sentinels gives you DETECTIVE-LEVEL debugging:
// Every request gets a correlation ID that traces through EVERYTHING:
[2024-01-15 03:07:43] INFO: Agent starting
• agent: ValidateOrderAgent
• correlation_id: req_789abc123
• user_id: 12345
• input_state: {...}
[2024-01-15 03:07:44] ERROR: Agent failed
• agent: ProcessPaymentAgent ⬅️ FOUND THE CULPRIT!
• correlation_id: req_789abc123
• error: "Card declined: insufficient funds"
• execution_time: 1.2s
// Now you know EXACTLY what broke, for which user, and why.
// Fix it in 5 minutes instead of 2 hours. 😎
// ❌ You have similar workflows everywhere, but they're all different:
class BlogProcessor {
public function process($post) {
$this->validateContent($post); // 30 lines of validation
$this->optimizeImages($post); // 45 lines of image processing
$this->generateSEO($post); // 25 lines of SEO logic
}
}
class ProductProcessor {
public function process($product) {
$this->validateContent($product); // Copy-pasted (but slightly different)
$this->optimizeImages($product); // Copy-pasted (with bugs)
$this->generateSEO($product); // Copy-pasted (missing features)
}
}
// Result: 6 different validation methods. When you fix a bug, you fix it in 6 places. 😭
// ✅ Write once, reuse everywhere:
$contentPipeline = [
new ValidateContentAgent(), // Works for ANY content
new OptimizeImagesAgent(), // Handles all image types
new GenerateSEOAgent(), // SEO for everything
];
// Same agents, different contexts
$blogResult = Sentinels::pipeline()->pipes($contentPipeline)->through($blogPost);
$productResult = Sentinels::pipeline()->pipes($contentPipeline)->through($product);
$pageResult = Sentinels::pipeline()->pipes($contentPipeline)->through($landingPage);
// One bug fix updates EVERYWHERE. One improvement benefits ALL workflows. 🎉
These are the core pain points that drive developers to Sentinels. But what makes Sentinels different from other solutions?
-
🕵️♀️ Debug Like a Detective: Every request gets a correlation ID that follows it through your entire pipeline. When something breaks, you'll know exactly which agent failed, for which user, and why. No more mysterious exceptions!
-
🎯 Write Agents, Not Services: Each agent does ONE thing brilliantly. 50 lines instead of 500. Test in isolation. Mock with confidence. Your code reviews will thank you.
-
🚦 Smart Routing That Actually Works: Route based on content, not just sequence. Premium users get the VIP pipeline. Failed payments get the retry flow. Same codebase, intelligent decisions.
-
⚡ Transparent Async Execution: Add
->async()
and get true parallel processing. No new mental models - async works exactly like sync. Auto-waiting properties, same error handling, same API. Taylor Otwell-approved simplicity. -
📊 Production Insights for Free: Built-in metrics, performance tracking, and error correlation. See which agents are slow, which fail most, and optimize based on real data.
-
🛠️ Laravel Developer Experience:
make:agent
,make:pipeline
, built-in testing helpers, facade support. Feels native because it is native. -
🔀 Conditional Logic That Makes Sense: Branch, merge, loop, and compose pipelines. Handle complex business logic without drowning in if-statements.
-
⚙️ Zero-Configuration Laravel Integration: Works with your service container, events, middleware, and queues. Add it to existing projects in minutes.
Sounds interesting? Here are the types of problems Sentinels is designed to solve:
Here are the most compelling ways you could use Sentinels to transform your complex workflows:
// Process user input through multiple AI analysis steps
$result = Sentinels::pipeline()
->pipe(new ContentModerationAgent()) // Check for harmful content
->pipe(new LanguageDetectionAgent()) // Detect input language
->pipe(new IntentClassificationAgent()) // Classify user intent
->pipe(new ResponseGenerationAgent()) // Generate appropriate response
->pipe(new QualityAssuranceAgent()) // Validate response quality
->through($userMessage);
// Send notifications to multiple channels in parallel
$result = Sentinels::pipeline()
->mode('parallel')
->async() // 👈 True parallel delivery!
->pipe(new EmailNotificationAgent()) // Send email
->pipe(new SMSNotificationAgent()) // Send SMS
->pipe(new PushNotificationAgent()) // Send push notification
->pipe(new SlackNotificationAgent()) // Send to Slack
->through($notificationRequest);
// All channels processed simultaneously, results aggregated automatically
echo "Notifications sent: " . count($result->payload);
echo "Delivery rate: " . $result->getSuccessRate() . "%";
// Transform data through validation, enrichment, and normalization
Sentinels::pipeline()
->pipe(new DataValidationAgent()) // Validate incoming data structure
->pipe(new DuplicationDetectionAgent()) // Remove or flag duplicates
->pipe(new DataEnrichmentAgent()) // Add external data (geo, demographics)
->pipe(new NormalizationAgent()) // Standardize formats and units
->pipe(new QualityScoreAgent()) // Assign data quality scores
->pipe(new DatabaseInsertAgent()) // Persist to appropriate tables
->through($rawDataBatch);
// Process order validation steps in parallel for faster checkout
$orderResult = Sentinels::pipeline()
->mode('parallel')
->async() // 👈 Parallel validation
->pipe(new InventoryCheckAgent()) // Check stock availability
->pipe(new PaymentValidationAgent()) // Validate payment method
->pipe(new FraudDetectionAgent()) // Run fraud analysis
->pipe(new TaxCalculationAgent()) // Calculate taxes
->through($orderData);
// All validations run simultaneously, results available immediately
if ($orderResult->hasErrors()) {
return $orderResult->errors; // Show validation failures
}
// Continue with fulfillment after validation passes
$fulfillmentResult = Sentinels::pipeline()
->pipe(new PaymentProcessingAgent()) // Process payment
->pipe(new InventoryAllocationAgent()) // Reserve inventory
->pipe(new ShippingLabelAgent()) // Generate shipping
->through($orderResult->payload);
echo "Order processed in " . $orderResult->getElapsedTime() . " seconds";
Why These Patterns Work So Well:
- 🔍 Pinpoint Failures: When step 3 of 8 fails, you know immediately which agent and why
- 🧪 Test with Confidence: Mock external APIs, test edge cases, verify each step independently
- 🔀 Handle Complexity: Premium customers? VIP pipeline. Failed payment? Retry flow. Same codebase.
- ⚡ Transparent Async: Add
->async()
for true parallel execution. Same API, better performance. No callbacks or promises to learn. - 📊 Progressive Monitoring: Simple by default, detailed batch statistics available for power users and ops teams
Ready to see the potential impact on your team? Here's the strategic value Sentinels is designed to deliver:
// Before: Monolithic, hard-to-navigate codebase
app/
├── Services/
│ └── OrderService.php (2,000+ lines mixing everything)
// After: Clear, domain-focused agents
app/
├── Agents/
│ ├── Order/
│ │ ├── ValidateInventoryAgent.php (50 lines, single purpose)
│ │ ├── CalculatePricingAgent.php (75 lines, focused)
│ │ └── ProcessPaymentAgent.php (60 lines, testable)
│ └── Shared/
│ ├── NotificationAgent.php (reusable across domains)
│ └── AuditLogAgent.php (shared infrastructure)
- Multiple developers can work on different agents simultaneously without conflicts
- Clear interfaces between agents prevent integration issues
- Independent testing allows for confident refactoring
- New team members can understand workflows visually through pipeline definitions
- Each agent is self-documenting with its name and single responsibility
- Correlation IDs make it easy to trace issues in production
// Built-in metrics provide business insights
Event::listen(PipelineCompleted::class, function ($event) {
// Track conversion funnel metrics
Metrics::increment('orders.processed');
Metrics::timing('orders.processing_time', $event->getExecutionTime());
// Identify bottlenecks in real-time
if ($event->getExecutionTime() > 5000) {
Alert::send('Slow order processing detected');
}
});
- Granular error handling prevents total system failures
- Retry policies reduce transient failure impact
- Audit trails provide compliance documentation
- Add new steps without rewriting entire workflows
- A/B test different pipeline configurations
- Quick iterations on business logic changes
// Rich telemetry out of the box
$pipeline = Sentinels::pipeline()
->withMetrics() // Automatic performance metrics
->withTracing() // Distributed tracing support
->withLogging() // Structured logging
->pipe(new ProcessOrderAgent())
->through($order);
// Integrates with monitoring tools
// - Prometheus metrics
// - OpenTelemetry traces
// - ELK stack logs
- Feature flags can control individual agent behavior
- Canary deployments for specific pipeline branches
- Rollback is as simple as reverting agent logic
// Different execution strategies for different needs
Sentinels::pipeline()
->mode('parallel') // Use multiple CPU cores
->queue('high-priority') // Dedicated queue resources
->timeout(30) // Prevent resource hogging
->pipe($agents)
->through($data);
- Single Responsibility enforced by agent design
- Dependency Injection through Laravel container
- Interface Segregation with focused contracts
- Open/Closed Principle - extend by adding agents
class AgentQualityTest extends TestCase
{
public function test_all_agents_have_tests()
{
$agents = glob('app/Agents/**/*Agent.php');
foreach ($agents as $agentFile) {
$testFile = str_replace('app/', 'tests/Unit/', $agentFile);
$testFile = str_replace('.php', 'Test.php', $testFile);
$this->assertFileExists($testFile,
"Missing test for {$agentFile}");
}
}
}
- Start simple with synchronous pipelines
- Scale to async processing without code changes
- Evolve to distributed systems using same patterns
The agent-based architecture pattern is designed to deliver:
- Faster debugging through correlation tracing and isolated failures
- Accelerated development with focused, testable components
- Higher test coverage achieved through isolated units
- Fewer production incidents from better error isolation and recovery
- Easier onboarding with clear, single-purpose components
Install Sentinels via Composer:
composer require vampires/sentinels
Publish the configuration file (optional):
php artisan vendor:publish --tag=sentinels-config
Everything in Sentinels revolves around the Context object - an immutable container that carries your data and metadata through the entire pipeline:
// Context is immutable - each operation returns a new instance
$original = Context::create('data');
$modified = $original->with('new data');
$withMeta = $modified->withMetadata('key', 'value');
// Rich metadata support
$context = $context
->withTag('processed')
->withCorrelationId('req-123')
->withTraceId('trace-456');
Agents have a rich lifecycle with hooks for custom behavior:
class MyAgent extends BaseAgent
{
protected function beforeExecute(Context $context): Context
{
// Setup, logging, authentication
return $context->withMetadata('started_at', now());
}
protected function handle(Context $context): Context
{
// Your main logic here
return $context->with($processedData);
}
protected function afterExecute(Context $original, Context $result): Context
{
// Cleanup, metrics, post-processing
return $result->withMetadata('completed_at', now());
}
protected function onError(Context $context, \Throwable $exception): Context
{
// Error handling and recovery
return $context->addError($exception->getMessage());
}
}
Sentinels supports multiple execution modes:
// Sequential (default)
$pipeline->mode('sequential')->pipe($agent1)->pipe($agent2);
// Parallel execution
$pipeline->mode('parallel')->pipe($agent1)->pipe($agent2);
// Map/Reduce for collections
$pipeline->mode('map_reduce')->pipe($transformAgent);
// Conditional branching
$pipeline->branch(
fn($ctx) => $ctx->hasTag('special'),
$specialPipeline,
$normalPipeline
);
Route contexts to different agents based on content:
use Vampires\Sentinels\Contracts\RouterContract;
$router = app(RouterContract::class);
// Route based on payload type
$router->addTypeRoute('string', new StringProcessor());
$router->addTypeRoute('array', new ArrayProcessor());
// Route based on content patterns
$router->addPatternRoute('/^email:/', new EmailAgent());
$router->addPatternRoute('/^sms:/', new SmsAgent());
// Route based on metadata
$router->addMetadataRoute('type', 'urgent', new UrgentProcessor());
use Vampires\Sentinels\Core\RetryPolicy;
class ResilientAgent extends BaseAgent
{
public function getRetryPolicy(): RetryPolicy
{
return RetryPolicy::exponential(
attempts: 3,
baseDelay: 1000,
maxDelay: 10000
);
}
protected function handle(Context $context): Context
{
// This will retry with exponential backoff on failure
return $context->with($this->callExternalAPI());
}
}
use Vampires\Sentinels\Events\AgentStarted;
use Vampires\Sentinels\Events\PipelineCompleted;
// Listen to agent execution events
Event::listen(AgentStarted::class, function ($event) {
Log::info('Agent started', [
'agent' => $event->agentName,
'correlation_id' => $event->getCorrelationId(),
'trace_id' => $event->getTraceId(),
]);
});
// Monitor pipeline completion
Event::listen(PipelineCompleted::class, function ($event) {
Metrics::timing('pipeline.duration', $event->getExecutionTime());
});
Sentinels provides comprehensive testing utilities:
use Vampires\Sentinels\Facades\Sentinels;
class AgentTest extends TestCase
{
public function test_agent_processes_correctly()
{
// Use test helpers
$context = $this->createTestContext('input');
$agent = new MyAgent();
$result = $agent($context);
$this->assertEquals('expected', $result->payload);
$this->assertTrue($result->hasMetadata('processed'));
}
public function test_with_fake_agents()
{
Sentinels::fake();
Sentinels::process('input', MyAgent::class);
Sentinels::assertAgentRan(MyAgent::class);
}
}
Configure Sentinels in config/sentinels.php
:
return [
'default_mode' => PipelineMode::Sequential,
'agents' => [
'discovery' => [
'enabled' => true,
'paths' => ['app/Agents', 'app/Pipelines'],
],
'execution' => [
'timeout' => 30,
'memory_limit' => '128M',
],
],
'observability' => [
'events' => ['enabled' => true],
'metrics' => ['enabled' => true],
'tracing' => ['enabled' => env('SENTINELS_TRACING', false)],
],
'queue' => [
'connection' => 'default',
'queue' => 'sentinels',
],
];
Sentinels provides helpful Artisan commands:
# Generate agents and pipelines
php artisan make:agent ProcessPaymentAgent
php artisan make:pipeline OrderFulfillmentPipeline
# List agents and view statistics
php artisan sentinels:list
php artisan sentinels:list --stats
Feature | Laravel Pipeline | Job Chains | Events/Listeners | Sentinels |
---|---|---|---|---|
Purpose | Data transformations | Async task chains | Event-driven actions | Agent orchestration |
Dynamic Routing | ❌ | ❌ | ❌ | ✅ Content-based |
Rich Context | Basic payload | Job properties | Event data | ✅ Immutable with metadata |
Observability | None | Job status only | Scattered logs | ✅ Comprehensive tracing |
Error Recovery | Exception bubbling | Retry attempts | Manual handling | ✅ Policies & strategies |
Conditional Logic | ❌ | Linear only | Event-based | ✅ Branch & merge |
Testing | Manual mocks | Queue faking | Event faking | ✅ Built-in assertions |
Debugging | Stack traces | Queue logs | Event logs | ✅ Correlation IDs |
Performance | Synchronous only | Queue overhead | Event overhead | ✅ Sync/async unified |
Complexity | Simple | Medium | High (scattered) | Medium (structured) |
Scenario | Use This | Why | Example |
---|---|---|---|
Simple data transformation | Laravel Pipeline | Minimal overhead, built-in | $users->pipe(new FilterActive())->pipe(new FormatNames()) |
Background job processing | Job Chains | Laravel native, good for simple async | ProcessPayment::chain([SendEmail::class, UpdateStats::class]) |
System-wide event reactions | Events/Listeners | Loose coupling, multiple handlers | UserRegistered → Email, Analytics, CRM sync |
Multi-step business workflows | Sentinels | Observability, error recovery | Order processing, content workflows |
AI/ML processing pipelines | Sentinels | Context preservation, branching | LLM chains, image processing |
Complex ETL operations | Sentinels | Conditional routing, monitoring | Data validation, enrichment, storage |
API orchestration | Sentinels | Retry policies, correlation | Third-party integrations, webhooks |
Content processing workflows | Sentinels | Dynamic routing, reusability | CMS publishing, media processing |
// When you have workflows like this:
$result = Sentinels::pipeline()
->pipe(new ValidateDataAgent()) // Step 1: Validate
->branch( // Step 2: Conditional logic
fn($ctx) => $ctx->hasTag('premium'),
$premiumPipeline, // Premium user flow
$standardPipeline // Standard user flow
)
->pipe(new AuditLogAgent()) // Step 3: Always audit
->through($userRequest);
// When you need to track data through complex flows:
$context = Context::create($orderData)
->withMetadata('user_id', $userId)
->withMetadata('request_id', $requestId)
->withTag('high-priority');
// Every agent can access and enrich this context
// Full traceability from start to finish
// When failures must be graceful and recoverable:
$agent = new ExternalAPIAgent();
$agent->setRetryPolicy(RetryPolicy::exponential(
attempts: 3,
baseDelay: 1000,
maxDelay: 30000
));
// Automatic retries with backoff
// Context preserved across retries
// Detailed error reporting
// When multiple developers work on the same workflow:
class PaymentProcessingTest extends TestCase
{
public function test_payment_flow()
{
Sentinels::fake();
// Test just your agent in isolation
$result = PaymentPipeline::process($orderContext);
Sentinels::assertAgentRan(ValidateCardAgent::class);
Sentinels::assertAgentRan(ChargePaymentAgent::class);
}
}
❌ Simple, one-step transformations → Use Laravel Pipeline
❌ Fire-and-forget background jobs → Use Job Chains
❌ System events with multiple listeners → Use Events/Listeners
❌ Rapid prototyping → Use simple Service classes
❌ Performance is critical over maintainability → Use optimized custom solutions
Sentinels embraces Laravel's core philosophy while extending its capabilities for complex workflows:
Just like Laravel makes common tasks enjoyable, Sentinels makes complex workflows manageable:
// Laravel's expressive syntax
User::where('active', true)->get();
// Sentinels' equally expressive pipelines
Sentinels::pipeline()
->pipe(new ValidateUserAgent())
->pipe(new ProcessUserAgent())
->through($userData);
Sentinels follows Laravel's patterns, so everything feels familiar:
// Generate an agent just like any Laravel component
php artisan make:agent ProcessOrderAgent
// Agents follow Laravel's naming conventions
app/Agents/ProcessOrderAgent.php // Just like Controllers, Models, etc.
tests/Unit/ProcessOrderAgentTest.php // Standard test location
Like Laravel provides everything you need for web apps, Sentinels provides everything for workflows:
- Artisan commands for code generation
- Testing utilities that feel like Laravel's
- Event system integration out of the box
- Queue support with zero configuration
Start simple, add complexity only when needed:
// Level 1: Simple agent execution
Sentinels::process($data, new MyAgent());
// Level 2: Basic pipeline
Sentinels::pipeline()
->pipe(new Agent1())
->pipe(new Agent2())
->through($data);
// Level 3: Advanced features when you need them
Sentinels::pipeline()
->mode('parallel')
->withRetries(3)
->onQueue('priority')
->pipe(new ComplexAgent())
->branch($condition, $truePipeline, $falsePipeline)
->through($data);
Testing Sentinels feels just like testing Laravel:
class OrderPipelineTest extends TestCase
{
public function test_order_processing()
{
// Familiar Laravel testing patterns
Sentinels::fake();
// Process with confidence
$result = OrderPipeline::process($order);
// Laravel-style assertions
Sentinels::assertAgentRan(ValidateOrderAgent::class);
$this->assertTrue($result->isSuccessful());
}
}
Just as Eloquent makes database relationships intuitive, Sentinels makes workflow relationships clear:
// Laravel: Define model relationships
class Order extends Model {
public function items() {
return $this->hasMany(OrderItem::class);
}
}
// Sentinels: Define workflow relationships
class OrderPipeline {
public static function build() {
return Pipeline::create()
->pipe(new ValidateOrderAgent())
->hasMany(ItemPipeline::class) // Process each item
->pipe(new FinalizeOrderAgent());
}
}
Sentinels doesn't replace Laravel patterns—it enhances them:
Laravel Pattern | Sentinels Enhancement |
---|---|
Service Providers | Agent discovery and registration |
Facades | Sentinels:: facade for clean syntax |
Middleware | Agent middleware for cross-cutting concerns |
Events | Pipeline events for observability |
Jobs | Async agent execution |
Validation | Context validation in agents |
Container | Dependency injection in agents |
Like Laravel, Sentinels is designed to evolve with community needs:
- Open architecture for custom agent types
- Extensible routing strategies
- Pluggable metrics providers
- Future community agent packages support
// Vision: Future community agents could work like Laravel packages
// composer require community/sentinels-ai-agents
// composer require community/sentinels-payment-agents
// The architecture supports this pattern:
Sentinels::pipeline()
->pipe(new YourCustomAgent())
->pipe(new AnotherCustomAgent())
->through($data);
Sentinels is Laravel for workflows - bringing the same joy, productivity, and elegance to complex processing that Laravel brings to web development.
We welcome contributions! Please see CONTRIBUTING.md for details.
If you discover any security-related issues, please email [email protected] instead of using the issue tracker.
Sentinels is open-sourced software licensed under the MIT license.
Built with ❤️ for the Laravel community
Sentinels v0.1.0 - Agent-first task orchestration for Laravel