- Replace orderByRaw with parameterised CASE statements - Add Task::scopeOrderByPriority() and scopeOrderByStatus() - Add AgentPlan::scopeOrderByStatus() - Add workspace validation to StateSet, StateGet, StateList tools - Add workspace validation to PlanGet, PlanList tools - Add SecurityTest.php with comprehensive isolation tests Fixes SEC-002, SEC-003 from security audit. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13 KiB
| title | description | updated |
|---|---|---|
| Architecture | Technical architecture of the core-agentic package | 2026-01-29 |
Architecture
The core-agentic package provides AI agent orchestration infrastructure for the Host UK platform. It enables multi-agent collaboration, persistent task tracking, and unified access to multiple AI providers.
Overview
┌─────────────────────────────────────────────────────────────────┐
│ MCP Protocol Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Plan │ │ Phase │ │ Session │ │ State │ ... tools │
│ │ Tools │ │ Tools │ │ Tools │ │ Tools │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼────────────┼────────────┼────────────┼──────────────────┘
│ │ │ │
┌───────┴────────────┴────────────┴────────────┴──────────────────┐
│ AgentToolRegistry │
│ - Tool registration and discovery │
│ - Permission checking (API key scopes) │
│ - Dependency validation │
│ - Circuit breaker integration │
└──────────────────────────────────────────────────────────────────┘
│
┌───────┴──────────────────────────────────────────────────────────┐
│ Core Services │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ AgenticManager │ │ AgentApiKey │ │ PlanTemplate │ │
│ │ (AI Providers) │ │ Service │ │ Service │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ IpRestriction │ │ Content │ │ AgentSession │ │
│ │ Service │ │ Service │ │ Service │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
│
┌───────┴──────────────────────────────────────────────────────────┐
│ Data Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐│
│ │ AgentPlan │ │ AgentPhase │ │ AgentSession│ │ AgentApiKey ││
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘│
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Workspace │ │ Task │ │
│ │ State │ │ │ │
│ └─────────────┘ └─────────────┘ │
└──────────────────────────────────────────────────────────────────┘
Core Concepts
Agent Plans
Plans represent structured work with phases, tasks, and progress tracking. They persist across agent sessions, enabling handoff between different AI models or instances.
AgentPlan
├── slug (unique identifier)
├── title
├── status (draft → active → completed/archived)
├── current_phase
└── phases[] (AgentPhase)
├── name
├── tasks[]
│ ├── name
│ └── status
├── dependencies[]
└── checkpoints[]
Lifecycle:
- Created via MCP tool or template
- Activated to begin work
- Phases started/completed in order
- Plan auto-completes when all phases done
- Archived for historical reference
Agent Sessions
Sessions track individual work periods. They enable context recovery when an agent's context window resets or when handing off to another agent.
AgentSession
├── session_id (prefixed unique ID)
├── agent_type (opus/sonnet/haiku)
├── status (active/paused/completed/failed)
├── work_log[] (chronological actions)
├── artifacts[] (files created/modified)
├── context_summary (current state)
└── handoff_notes (for next agent)
Handoff Flow:
- Session logs work as it progresses
- Before context ends, agent calls
session_handoff - Handoff notes capture summary, next steps, blockers
- Next agent calls
session_resumeto continue - Resume session inherits context from previous
Workspace State
Key-value state storage shared between sessions and plans. Enables agents to persist decisions, configurations, and intermediate results.
WorkspaceState
├── key (namespaced identifier)
├── value (any JSON-serialisable data)
├── type (json/markdown/code/reference)
└── category (for organisation)
MCP Tool Architecture
All MCP tools extend the AgentTool base class which provides:
Input Validation
protected function requireString(array $args, string $key, ?int $maxLength = null): string
protected function optionalInt(array $args, string $key, ?int $default = null): ?int
protected function requireEnum(array $args, string $key, array $allowed): string
Circuit Breaker Protection
return $this->withCircuitBreaker('agentic', function () {
// Database operations that could fail
return AgentPlan::where('slug', $slug)->first();
}, fn () => $this->error('Service unavailable', 'circuit_open'));
Dependency Declaration
public function dependencies(): array
{
return [
ToolDependency::contextExists('workspace_id', 'Workspace required'),
ToolDependency::toolCalled('session_start', 'Start session first'),
];
}
Tool Categories
| Category | Tools | Purpose |
|---|---|---|
plan |
plan_create, plan_get, plan_list, plan_update_status, plan_archive | Work plan management |
phase |
phase_get, phase_update_status, phase_add_checkpoint | Phase operations |
session |
session_start, session_end, session_log, session_handoff, session_resume, session_replay | Session tracking |
state |
state_get, state_set, state_list | Persistent state |
task |
task_update, task_toggle | Task completion |
template |
template_list, template_preview, template_create_plan | Plan templates |
content |
content_generate, content_batch_generate, content_brief_create | Content generation |
AI Provider Abstraction
The AgenticManager provides unified access to multiple AI providers:
$ai = app(AgenticManager::class);
// Use specific provider
$response = $ai->claude()->generate($system, $user);
$response = $ai->gemini()->generate($system, $user);
$response = $ai->openai()->generate($system, $user);
// Use by name (for configuration-driven selection)
$response = $ai->provider('gemini')->generate($system, $user);
Provider Interface
All providers implement AgenticProviderInterface:
interface AgenticProviderInterface
{
public function generate(string $systemPrompt, string $userPrompt, array $config = []): AgenticResponse;
public function stream(string $systemPrompt, string $userPrompt, array $config = []): Generator;
public function name(): string;
public function defaultModel(): string;
public function isAvailable(): bool;
}
Response Object
class AgenticResponse
{
public string $content;
public string $model;
public int $inputTokens;
public int $outputTokens;
public int $durationMs;
public ?string $stopReason;
public array $raw;
public function estimateCost(): float;
}
Authentication
API Key Flow
Request → AgentApiAuth Middleware → AgentApiKeyService::authenticate()
│
├── Validate key (SHA-256 hash lookup)
├── Check revoked/expired
├── Validate IP whitelist
├── Check permissions
├── Check rate limit
└── Record usage
Permission Model
// Permission constants
AgentApiKey::PERM_PLANS_READ // 'plans.read'
AgentApiKey::PERM_PLANS_WRITE // 'plans.write'
AgentApiKey::PERM_SESSIONS_WRITE // 'sessions.write'
// etc.
// Check permissions
$key->hasPermission('plans.write');
$key->hasAllPermissions(['plans.read', 'sessions.write']);
IP Restrictions
API keys can optionally restrict access by IP:
- Individual IPv4/IPv6 addresses
- CIDR notation (e.g.,
192.168.1.0/24) - Mixed whitelist
Event-Driven Boot
The module uses the Core framework's event-driven lazy loading:
class Boot extends ServiceProvider
{
public static array $listens = [
AdminPanelBooting::class => 'onAdminPanel',
ConsoleBooting::class => 'onConsole',
McpToolsRegistering::class => 'onMcpTools',
];
}
This ensures:
- Views only loaded when admin panel boots
- Commands only registered when console boots
- MCP tools only registered when MCP module initialises
Multi-Tenancy
All data is workspace-scoped via the BelongsToWorkspace trait:
- Queries auto-scoped to current workspace
- Creates auto-assign workspace_id
- Cross-tenant queries throw
MissingWorkspaceContextException
File Structure
core-agentic/
├── Boot.php # Service provider with event handlers
├── config.php # Module configuration
├── Migrations/ # Database schema
├── Models/ # Eloquent models
│ ├── AgentPlan.php
│ ├── AgentPhase.php
│ ├── AgentSession.php
│ ├── AgentApiKey.php
│ └── WorkspaceState.php
├── Services/ # Business logic
│ ├── AgenticManager.php # AI provider orchestration
│ ├── AgentApiKeyService.php # API key management
│ ├── IpRestrictionService.php
│ ├── PlanTemplateService.php
│ ├── ContentService.php
│ ├── ClaudeService.php
│ ├── GeminiService.php
│ └── OpenAIService.php
├── Mcp/
│ ├── Tools/Agent/ # MCP tool implementations
│ │ ├── AgentTool.php # Base class
│ │ ├── Plan/
│ │ ├── Phase/
│ │ ├── Session/
│ │ ├── State/
│ │ └── ...
│ ├── Prompts/ # MCP prompt definitions
│ └── Servers/ # MCP server configurations
├── Middleware/
│ └── AgentApiAuth.php # API authentication
├── Controllers/
│ └── ForAgentsController.php # Agent discovery endpoint
├── View/
│ ├── Blade/admin/ # Admin panel views
│ └── Modal/Admin/ # Livewire components
├── Jobs/ # Queue jobs
├── Console/Commands/ # Artisan commands
└── Tests/ # Pest test suites
Dependencies
host-uk/core- Event system, base classeshost-uk/core-tenant- Workspace, BelongsToWorkspace traithost-uk/core-mcp- MCP infrastructure, CircuitBreaker