php-agentic/docs/architecture.md
Snider a2a9423ad6 security: fix SQL injection and add workspace scoping to MCP tools
- 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>
2026-01-29 12:21:01 +00:00

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:

  1. Created via MCP tool or template
  2. Activated to begin work
  3. Phases started/completed in order
  4. Plan auto-completes when all phases done
  5. 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:

  1. Session logs work as it progresses
  2. Before context ends, agent calls session_handoff
  3. Handoff notes capture summary, next steps, blockers
  4. Next agent calls session_resume to continue
  5. 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 classes
  • host-uk/core-tenant - Workspace, BelongsToWorkspace trait
  • host-uk/core-mcp - MCP infrastructure, CircuitBreaker