diff --git a/Boot.php b/Boot.php
index 765b8b2..575cd41 100644
--- a/Boot.php
+++ b/Boot.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic;
+namespace Core\Mod\Agentic;
use Core\Events\AdminPanelBooting;
use Core\Events\ConsoleBooting;
@@ -53,7 +53,7 @@ class Boot extends ServiceProvider
'mcp'
);
- $this->app->singleton(\Core\Agentic\Services\AgenticManager::class);
+ $this->app->singleton(\Core\Mod\Agentic\Services\AgenticManager::class);
}
// -------------------------------------------------------------------------
diff --git a/Configs/AIConfig.php b/Configs/AIConfig.php
index a3a6e03..4224250 100644
--- a/Configs/AIConfig.php
+++ b/Configs/AIConfig.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Configs;
+namespace Core\Mod\Agentic\Configs;
use Core\Config\Config;
-use Core\Agentic\Services\AgenticManager;
+use Core\Mod\Agentic\Services\AgenticManager;
use Illuminate\Validation\Rule;
/**
diff --git a/Console/Commands/GenerateCommand.php b/Console/Commands/GenerateCommand.php
index 63f6f7d..46ac499 100644
--- a/Console/Commands/GenerateCommand.php
+++ b/Console/Commands/GenerateCommand.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Console\Commands;
+namespace Core\Mod\Agentic\Console\Commands;
use Illuminate\Console\Command;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentPlan;
use Mod\Content\Jobs\GenerateContentJob;
use Mod\Content\Models\ContentBrief;
use Mod\Content\Services\AIGatewayService;
diff --git a/Console/Commands/PlanCommand.php b/Console/Commands/PlanCommand.php
index f89e7aa..e40200c 100644
--- a/Console/Commands/PlanCommand.php
+++ b/Console/Commands/PlanCommand.php
@@ -2,11 +2,11 @@
declare(strict_types=1);
-namespace Core\Agentic\Console\Commands;
+namespace Core\Mod\Agentic\Console\Commands;
use Illuminate\Console\Command;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Services\PlanTemplateService;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Services\PlanTemplateService;
class PlanCommand extends Command
{
diff --git a/Console/Commands/TaskCommand.php b/Console/Commands/TaskCommand.php
index 10c2ed4..8d5f283 100644
--- a/Console/Commands/TaskCommand.php
+++ b/Console/Commands/TaskCommand.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Console\Commands;
+namespace Core\Mod\Agentic\Console\Commands;
use Illuminate\Console\Command;
-use Core\Agentic\Models\Task;
+use Core\Mod\Agentic\Models\Task;
class TaskCommand extends Command
{
diff --git a/Controllers/ForAgentsController.php b/Controllers/ForAgentsController.php
index 17f214a..467c524 100644
--- a/Controllers/ForAgentsController.php
+++ b/Controllers/ForAgentsController.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Controllers;
+namespace Core\Mod\Agentic\Controllers;
use Core\Front\Controller;
use Illuminate\Http\JsonResponse;
diff --git a/Facades/Agentic.php b/Facades/Agentic.php
index 0fedc01..be43cf2 100644
--- a/Facades/Agentic.php
+++ b/Facades/Agentic.php
@@ -2,21 +2,21 @@
declare(strict_types=1);
-namespace Core\Agentic\Facades;
+namespace Core\Mod\Agentic\Facades;
-use Core\Agentic\Services\AgenticManager;
+use Core\Mod\Agentic\Services\AgenticManager;
use Illuminate\Support\Facades\Facade;
/**
- * @method static \Core\Agentic\Services\AgenticProviderInterface provider(string $name = null)
- * @method static \Core\Agentic\Services\ClaudeService claude()
- * @method static \Core\Agentic\Services\GeminiService gemini()
- * @method static \Core\Agentic\Services\OpenAIService openai()
+ * @method static \Core\Mod\Agentic\Services\AgenticProviderInterface provider(string $name = null)
+ * @method static \Core\Mod\Agentic\Services\ClaudeService claude()
+ * @method static \Core\Mod\Agentic\Services\GeminiService gemini()
+ * @method static \Core\Mod\Agentic\Services\OpenAIService openai()
* @method static array availableProviders()
* @method static bool isAvailable(string $name)
* @method static void setDefault(string $name)
*
- * @see \Core\Agentic\Services\AgenticManager
+ * @see \Core\Mod\Agentic\Services\AgenticManager
*/
class Agentic extends Facade
{
diff --git a/Jobs/BatchContentGeneration.php b/Jobs/BatchContentGeneration.php
index bf33020..359e45e 100644
--- a/Jobs/BatchContentGeneration.php
+++ b/Jobs/BatchContentGeneration.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Jobs;
+namespace Core\Mod\Agentic\Jobs;
use Mod\Content\Models\ContentTask;
use Illuminate\Bus\Queueable;
diff --git a/Jobs/ProcessContentTask.php b/Jobs/ProcessContentTask.php
index 0a37531..dd0495e 100644
--- a/Jobs/ProcessContentTask.php
+++ b/Jobs/ProcessContentTask.php
@@ -2,9 +2,9 @@
declare(strict_types=1);
-namespace Core\Agentic\Jobs;
+namespace Core\Mod\Agentic\Jobs;
-use Core\Agentic\Services\AgenticManager;
+use Core\Mod\Agentic\Services\AgenticManager;
use Mod\Content\Models\ContentTask;
use Mod\Content\Services\ContentProcessingService;
use Core\Mod\Tenant\Services\EntitlementService;
diff --git a/Mcp/Prompts/AnalysePerformancePrompt.php b/Mcp/Prompts/AnalysePerformancePrompt.php
index 6792c55..e657fa3 100644
--- a/Mcp/Prompts/AnalysePerformancePrompt.php
+++ b/Mcp/Prompts/AnalysePerformancePrompt.php
@@ -1,6 +1,6 @@
getActiveSessions($context['workspace_id'] ?? null);
} else {
// Query with filters
- $query = \Core\Agentic\Models\AgentSession::query()
+ $query = \Core\Mod\Agentic\Models\AgentSession::query()
->orderBy('last_active_at', 'desc');
// Apply workspace filter if provided
diff --git a/Mcp/Tools/Agent/Session/SessionLog.php b/Mcp/Tools/Agent/Session/SessionLog.php
index 87980ff..68ea543 100644
--- a/Mcp/Tools/Agent/Session/SessionLog.php
+++ b/Mcp/Tools/Agent/Session/SessionLog.php
@@ -2,11 +2,11 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Session;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session;
use Core\Mod\Mcp\Dependencies\ToolDependency;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
-use Core\Agentic\Models\AgentSession;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Models\AgentSession;
/**
* Log an entry in the current session.
diff --git a/Mcp/Tools/Agent/Session/SessionReplay.php b/Mcp/Tools/Agent/Session/SessionReplay.php
index 28fd340..fe0f46b 100644
--- a/Mcp/Tools/Agent/Session/SessionReplay.php
+++ b/Mcp/Tools/Agent/Session/SessionReplay.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Session;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
-use Core\Agentic\Services\AgentSessionService;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Services\AgentSessionService;
/**
* Replay a session by creating a new session with the original's context.
diff --git a/Mcp/Tools/Agent/Session/SessionResume.php b/Mcp/Tools/Agent/Session/SessionResume.php
index fdc2bde..ee051ed 100644
--- a/Mcp/Tools/Agent/Session/SessionResume.php
+++ b/Mcp/Tools/Agent/Session/SessionResume.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Session;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session;
-use Core\Agentic\Services\AgentSessionService;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Services\AgentSessionService;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
/**
* Resume a paused or handed-off session.
diff --git a/Mcp/Tools/Agent/Session/SessionStart.php b/Mcp/Tools/Agent/Session/SessionStart.php
index e16550f..e89c3e4 100644
--- a/Mcp/Tools/Agent/Session/SessionStart.php
+++ b/Mcp/Tools/Agent/Session/SessionStart.php
@@ -2,13 +2,13 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Session;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session;
use Core\Mod\Mcp\Dependencies\ToolDependency;
use Illuminate\Support\Str;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Models\AgentSession;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentSession;
/**
* Start a new agent session for a plan.
diff --git a/Mcp/Tools/Agent/State/StateGet.php b/Mcp/Tools/Agent/State/StateGet.php
index 1bbddf4..e01974f 100644
--- a/Mcp/Tools/Agent/State/StateGet.php
+++ b/Mcp/Tools/Agent/State/StateGet.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\State;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\State;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
/**
* Get a workspace state value.
diff --git a/Mcp/Tools/Agent/State/StateList.php b/Mcp/Tools/Agent/State/StateList.php
index 1ece720..d4ff589 100644
--- a/Mcp/Tools/Agent/State/StateList.php
+++ b/Mcp/Tools/Agent/State/StateList.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\State;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\State;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
/**
* List all state values for a plan.
diff --git a/Mcp/Tools/Agent/State/StateSet.php b/Mcp/Tools/Agent/State/StateSet.php
index bb5a2f0..b231545 100644
--- a/Mcp/Tools/Agent/State/StateSet.php
+++ b/Mcp/Tools/Agent/State/StateSet.php
@@ -2,11 +2,11 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\State;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\State;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Models\AgentWorkspaceState;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentWorkspaceState;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
/**
* Set a workspace state value.
diff --git a/Mcp/Tools/Agent/Task/TaskToggle.php b/Mcp/Tools/Agent/Task/TaskToggle.php
index 2f4bef0..d7ec51d 100644
--- a/Mcp/Tools/Agent/Task/TaskToggle.php
+++ b/Mcp/Tools/Agent/Task/TaskToggle.php
@@ -2,12 +2,12 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Task;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Task;
use Core\Mod\Mcp\Dependencies\ToolDependency;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
-use Core\Agentic\Models\AgentPhase;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Models\AgentPhase;
+use Core\Mod\Agentic\Models\AgentPlan;
/**
* Toggle a task completion status.
diff --git a/Mcp/Tools/Agent/Task/TaskUpdate.php b/Mcp/Tools/Agent/Task/TaskUpdate.php
index dc2eba4..3a14534 100644
--- a/Mcp/Tools/Agent/Task/TaskUpdate.php
+++ b/Mcp/Tools/Agent/Task/TaskUpdate.php
@@ -2,12 +2,12 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Task;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Task;
use Core\Mod\Mcp\Dependencies\ToolDependency;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
-use Core\Agentic\Models\AgentPhase;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Models\AgentPhase;
+use Core\Mod\Agentic\Models\AgentPlan;
/**
* Update task details (status, notes).
diff --git a/Mcp/Tools/Agent/Template/TemplateCreatePlan.php b/Mcp/Tools/Agent/Template/TemplateCreatePlan.php
index 2d48576..ab5f009 100644
--- a/Mcp/Tools/Agent/Template/TemplateCreatePlan.php
+++ b/Mcp/Tools/Agent/Template/TemplateCreatePlan.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Template;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Template;
-use Core\Agentic\Services\PlanTemplateService;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Services\PlanTemplateService;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
/**
* Create a new plan from a template.
diff --git a/Mcp/Tools/Agent/Template/TemplateList.php b/Mcp/Tools/Agent/Template/TemplateList.php
index 9fc296c..429b9eb 100644
--- a/Mcp/Tools/Agent/Template/TemplateList.php
+++ b/Mcp/Tools/Agent/Template/TemplateList.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Template;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Template;
-use Core\Agentic\Services\PlanTemplateService;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Services\PlanTemplateService;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
/**
* List available plan templates.
diff --git a/Mcp/Tools/Agent/Template/TemplatePreview.php b/Mcp/Tools/Agent/Template/TemplatePreview.php
index a0423c5..606566a 100644
--- a/Mcp/Tools/Agent/Template/TemplatePreview.php
+++ b/Mcp/Tools/Agent/Template/TemplatePreview.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Mcp\Tools\Agent\Template;
+namespace Core\Mod\Agentic\Mcp\Tools\Agent\Template;
-use Core\Agentic\Services\PlanTemplateService;
-use Core\Agentic\Mcp\Tools\Agent\AgentTool;
+use Core\Mod\Agentic\Services\PlanTemplateService;
+use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool;
/**
* Preview a template with variables.
diff --git a/Middleware/AgentApiAuth.php b/Middleware/AgentApiAuth.php
index 2fdfd20..9bb39f1 100644
--- a/Middleware/AgentApiAuth.php
+++ b/Middleware/AgentApiAuth.php
@@ -2,12 +2,12 @@
declare(strict_types=1);
-namespace Core\Agentic\Middleware;
+namespace Core\Mod\Agentic\Middleware;
use Closure;
use Illuminate\Http\Request;
-use Core\Agentic\Models\AgentApiKey;
-use Core\Agentic\Services\AgentApiKeyService;
+use Core\Mod\Agentic\Models\AgentApiKey;
+use Core\Mod\Agentic\Services\AgentApiKeyService;
use Symfony\Component\HttpFoundation\Response;
/**
diff --git a/Models/AgentApiKey.php b/Models/AgentApiKey.php
index 92a1541..ec072f0 100644
--- a/Models/AgentApiKey.php
+++ b/Models/AgentApiKey.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Core\Mod\Tenant\Models\Workspace;
use Illuminate\Database\Eloquent\Model;
diff --git a/Models/AgentPhase.php b/Models/AgentPhase.php
index fd61d7b..b52b66a 100644
--- a/Models/AgentPhase.php
+++ b/Models/AgentPhase.php
@@ -2,13 +2,13 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\DB;
-use Core\Agentic\Database\Factories\AgentPhaseFactory;
+use Core\Mod\Agentic\Database\Factories\AgentPhaseFactory;
/**
* Agent Phase - individual phase within a plan.
diff --git a/Models/AgentPlan.php b/Models/AgentPlan.php
index 506ba19..fb13046 100644
--- a/Models/AgentPlan.php
+++ b/Models/AgentPlan.php
@@ -2,14 +2,14 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;
-use Core\Agentic\Database\Factories\AgentPlanFactory;
+use Core\Mod\Agentic\Database\Factories\AgentPlanFactory;
use Core\Mod\Tenant\Concerns\BelongsToWorkspace;
use Core\Mod\Tenant\Models\Workspace;
use Spatie\Activitylog\LogOptions;
diff --git a/Models/AgentSession.php b/Models/AgentSession.php
index e49453f..8ce68f5 100644
--- a/Models/AgentSession.php
+++ b/Models/AgentSession.php
@@ -2,14 +2,14 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Core\Mod\Tenant\Concerns\BelongsToWorkspace;
use Core\Mod\Tenant\Models\Workspace;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
-use Core\Agentic\Database\Factories\AgentSessionFactory;
+use Core\Mod\Agentic\Database\Factories\AgentSessionFactory;
use Ramsey\Uuid\Uuid;
/**
diff --git a/Models/AgentWorkspaceState.php b/Models/AgentWorkspaceState.php
index 5ec4008..ba6bebe 100644
--- a/Models/AgentWorkspaceState.php
+++ b/Models/AgentWorkspaceState.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
diff --git a/Models/Prompt.php b/Models/Prompt.php
index ee776f9..453168b 100644
--- a/Models/Prompt.php
+++ b/Models/Prompt.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Mod\Content\Models\ContentTask;
use Illuminate\Database\Eloquent\Factories\HasFactory;
diff --git a/Models/PromptVersion.php b/Models/PromptVersion.php
index 11d6a9d..b9be986 100644
--- a/Models/PromptVersion.php
+++ b/Models/PromptVersion.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Core\Mod\Tenant\Models\User;
use Illuminate\Database\Eloquent\Model;
diff --git a/Models/Task.php b/Models/Task.php
index f02cd53..7aa829c 100644
--- a/Models/Task.php
+++ b/Models/Task.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Illuminate\Database\Eloquent\Model;
use Core\Mod\Tenant\Concerns\BelongsToWorkspace;
diff --git a/Models/WorkspaceState.php b/Models/WorkspaceState.php
index 3ba5318..c3f7267 100644
--- a/Models/WorkspaceState.php
+++ b/Models/WorkspaceState.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Models;
+namespace Core\Mod\Agentic\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
diff --git a/Service/Boot.php b/Service/Boot.php
new file mode 100644
index 0000000..12fae90
--- /dev/null
+++ b/Service/Boot.php
@@ -0,0 +1,120 @@
+
+ */
+ public static array $listens = [
+ AdminPanelBooting::class => 'onAdminPanel',
+ ];
+
+ /**
+ * Bootstrap the service.
+ */
+ public function boot(): void
+ {
+ app(AdminMenuRegistry::class)->register($this);
+ }
+
+ /**
+ * Get the service definition for seeding platform_services.
+ */
+ public static function definition(): array
+ {
+ return [
+ 'code' => 'agentic',
+ 'module' => 'Agentic',
+ 'name' => 'Agentic',
+ 'tagline' => 'AI agent orchestration',
+ 'description' => 'Build and deploy AI agents with planning, tool use, and conversation capabilities.',
+ 'icon' => 'robot',
+ 'color' => 'violet',
+ 'marketing_domain' => null, // API service, no marketing site yet
+ 'website_class' => null,
+ 'entitlement_code' => 'core.srv.agentic',
+ 'sort_order' => 60,
+ ];
+ }
+
+ /**
+ * Admin menu items for this service.
+ *
+ * Agentic is positioned in the dashboard group (not services)
+ * as it's a cross-cutting AI capability, not a standalone product.
+ */
+ public function adminMenuItems(): array
+ {
+ return [
+ [
+ 'group' => 'dashboard',
+ 'priority' => 5,
+ 'entitlement' => 'core.srv.agentic',
+ 'item' => fn () => [
+ 'label' => 'Agentic',
+ 'icon' => 'robot',
+ 'color' => 'violet',
+ 'active' => request()->routeIs('hub.agents.*'),
+ 'children' => [
+ ['label' => 'Dashboard', 'icon' => 'gauge', 'href' => route('hub.agents.index'), 'active' => request()->routeIs('hub.agents.index')],
+ ['label' => 'Plans', 'icon' => 'list-check', 'href' => route('hub.agents.plans'), 'active' => request()->routeIs('hub.agents.plans*')],
+ ['label' => 'Sessions', 'icon' => 'messages', 'href' => route('hub.agents.sessions'), 'active' => request()->routeIs('hub.agents.sessions*')],
+ ['label' => 'Tool Analytics', 'icon' => 'chart-bar', 'href' => route('hub.agents.tools'), 'active' => request()->routeIs('hub.agents.tools*')],
+ ['label' => 'API Keys', 'icon' => 'key', 'href' => route('hub.agents.api-keys'), 'active' => request()->routeIs('hub.agents.api-keys*')],
+ ['label' => 'Templates', 'icon' => 'copy', 'href' => route('hub.agents.templates'), 'active' => request()->routeIs('hub.agents.templates*')],
+ ],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Register admin panel components.
+ */
+ public function onAdminPanel(AdminPanelBooting $event): void
+ {
+ // Service-specific admin routes could go here
+ // Components are registered by Core\Agentic
+ }
+
+ public function menuPermissions(): array
+ {
+ return [];
+ }
+
+ public function canViewMenu(?object $user, ?object $workspace): bool
+ {
+ return $user !== null;
+ }
+
+ public static function version(): ServiceVersion
+ {
+ return new ServiceVersion(1, 0, 0);
+ }
+
+ /**
+ * Service dependencies.
+ */
+ public static function dependencies(): array
+ {
+ return [];
+ }
+}
diff --git a/Services/AgentApiKeyService.php b/Services/AgentApiKeyService.php
index ddd6492..e58b70d 100644
--- a/Services/AgentApiKeyService.php
+++ b/Services/AgentApiKeyService.php
@@ -2,12 +2,12 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use Core\Mod\Tenant\Models\Workspace;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
-use Core\Agentic\Models\AgentApiKey;
+use Core\Mod\Agentic\Models\AgentApiKey;
/**
* Agent API Key Service.
diff --git a/Services/AgentDetection.php b/Services/AgentDetection.php
index fc19446..6c82a45 100644
--- a/Services/AgentDetection.php
+++ b/Services/AgentDetection.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
-use Core\Agentic\Models\AgentApiKey;
-use Core\Agentic\Support\AgentIdentity;
+use Core\Mod\Agentic\Models\AgentApiKey;
+use Core\Mod\Agentic\Support\AgentIdentity;
use Illuminate\Http\Request;
/**
diff --git a/Services/AgentSessionService.php b/Services/AgentSessionService.php
index 2e29688..1d4db30 100644
--- a/Services/AgentSessionService.php
+++ b/Services/AgentSessionService.php
@@ -2,12 +2,12 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Models\AgentSession;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentSession;
/**
* Agent Session Service - manages session persistence for agent continuity.
diff --git a/Services/AgentToolRegistry.php b/Services/AgentToolRegistry.php
index c3e64c9..252ae86 100644
--- a/Services/AgentToolRegistry.php
+++ b/Services/AgentToolRegistry.php
@@ -2,13 +2,13 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use Core\Mod\Api\Models\ApiKey;
use Core\Mod\Mcp\Dependencies\HasDependencies;
use Core\Mod\Mcp\Services\ToolDependencyService;
use Illuminate\Support\Collection;
-use Core\Agentic\Mcp\Tools\Agent\Contracts\AgentToolInterface;
+use Core\Mod\Agentic\Mcp\Tools\Agent\Contracts\AgentToolInterface;
/**
* Registry for MCP Agent Server tools.
diff --git a/Services/AgenticManager.php b/Services/AgenticManager.php
index caa1059..7130fd9 100644
--- a/Services/AgenticManager.php
+++ b/Services/AgenticManager.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use InvalidArgumentException;
diff --git a/Services/AgenticProviderInterface.php b/Services/AgenticProviderInterface.php
index bda87a1..3fe2590 100644
--- a/Services/AgenticProviderInterface.php
+++ b/Services/AgenticProviderInterface.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
interface AgenticProviderInterface
{
diff --git a/Services/AgenticResponse.php b/Services/AgenticResponse.php
index d6534cc..06ef4bc 100644
--- a/Services/AgenticResponse.php
+++ b/Services/AgenticResponse.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
class AgenticResponse
{
diff --git a/Services/ClaudeService.php b/Services/ClaudeService.php
index 83aaa8a..b852d02 100644
--- a/Services/ClaudeService.php
+++ b/Services/ClaudeService.php
@@ -2,13 +2,13 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use Generator;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
-use Core\Agentic\Services\Concerns\HasRetry;
-use Core\Agentic\Services\Concerns\HasStreamParsing;
+use Core\Mod\Agentic\Services\Concerns\HasRetry;
+use Core\Mod\Agentic\Services\Concerns\HasStreamParsing;
use RuntimeException;
class ClaudeService implements AgenticProviderInterface
diff --git a/Services/Concerns/HasRetry.php b/Services/Concerns/HasRetry.php
index 287e587..83d024f 100644
--- a/Services/Concerns/HasRetry.php
+++ b/Services/Concerns/HasRetry.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Services\Concerns;
+namespace Core\Mod\Agentic\Services\Concerns;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
diff --git a/Services/Concerns/HasStreamParsing.php b/Services/Concerns/HasStreamParsing.php
index c8d60e7..da5bbf5 100644
--- a/Services/Concerns/HasStreamParsing.php
+++ b/Services/Concerns/HasStreamParsing.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Services\Concerns;
+namespace Core\Mod\Agentic\Services\Concerns;
use Generator;
use Psr\Http\Message\StreamInterface;
diff --git a/Services/ContentService.php b/Services/ContentService.php
index 6bf92a4..8d022b7 100644
--- a/Services/ContentService.php
+++ b/Services/ContentService.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use Mod\Content\Models\ContentItem;
use Illuminate\Support\Facades\File;
diff --git a/Services/GeminiService.php b/Services/GeminiService.php
index 792c922..321445d 100644
--- a/Services/GeminiService.php
+++ b/Services/GeminiService.php
@@ -2,13 +2,13 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use Generator;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
-use Core\Agentic\Services\Concerns\HasRetry;
-use Core\Agentic\Services\Concerns\HasStreamParsing;
+use Core\Mod\Agentic\Services\Concerns\HasRetry;
+use Core\Mod\Agentic\Services\Concerns\HasStreamParsing;
use RuntimeException;
class GeminiService implements AgenticProviderInterface
diff --git a/Services/IpRestrictionService.php b/Services/IpRestrictionService.php
index 2032bfc..4409f4f 100644
--- a/Services/IpRestrictionService.php
+++ b/Services/IpRestrictionService.php
@@ -2,9 +2,9 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
-use Core\Agentic\Models\AgentApiKey;
+use Core\Mod\Agentic\Models\AgentApiKey;
/**
* IP Restriction Service.
diff --git a/Services/OpenAIService.php b/Services/OpenAIService.php
index de2d65f..1c5151d 100644
--- a/Services/OpenAIService.php
+++ b/Services/OpenAIService.php
@@ -2,13 +2,13 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
use Generator;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
-use Core\Agentic\Services\Concerns\HasRetry;
-use Core\Agentic\Services\Concerns\HasStreamParsing;
+use Core\Mod\Agentic\Services\Concerns\HasRetry;
+use Core\Mod\Agentic\Services\Concerns\HasStreamParsing;
use RuntimeException;
class OpenAIService implements AgenticProviderInterface
diff --git a/Services/PlanTemplateService.php b/Services/PlanTemplateService.php
index 87cb37a..7a7158c 100644
--- a/Services/PlanTemplateService.php
+++ b/Services/PlanTemplateService.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\Services;
+namespace Core\Mod\Agentic\Services;
-use Core\Agentic\Models\AgentPhase;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentPhase;
+use Core\Mod\Agentic\Models\AgentPlan;
use Core\Mod\Tenant\Models\Workspace;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
diff --git a/Support/AgentIdentity.php b/Support/AgentIdentity.php
index 0d4e7ce..9d134c1 100644
--- a/Support/AgentIdentity.php
+++ b/Support/AgentIdentity.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\Support;
+namespace Core\Mod\Agentic\Support;
/**
* Represents the identity of an AI agent making a request.
diff --git a/View/Blade/admin/templates.blade.php b/View/Blade/admin/templates.blade.php
index ae10250..56887e4 100644
--- a/View/Blade/admin/templates.blade.php
+++ b/View/Blade/admin/templates.blade.php
@@ -240,7 +240,7 @@
{{-- Variables --}}
@php
- $template = app(\Core\Agentic\Services\PlanTemplateService::class)->get($previewSlug);
+ $template = app(\Core\Mod\Agentic\Services\PlanTemplateService::class)->get($previewSlug);
$variables = $template['variables'] ?? [];
@endphp
@if(!empty($variables))
diff --git a/View/Modal/Admin/ApiKeyManager.php b/View/Modal/Admin/ApiKeyManager.php
index e76347c..a5ea272 100644
--- a/View/Modal/Admin/ApiKeyManager.php
+++ b/View/Modal/Admin/ApiKeyManager.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
use Core\Mod\Api\Models\ApiKey;
use Core\Mod\Tenant\Models\Workspace;
diff --git a/View/Modal/Admin/ApiKeys.php b/View/Modal/Admin/ApiKeys.php
index 35f72dc..f446eb4 100644
--- a/View/Modal/Admin/ApiKeys.php
+++ b/View/Modal/Admin/ApiKeys.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
use Core\Mod\Tenant\Models\Workspace;
use Illuminate\Contracts\View\View;
@@ -13,8 +13,8 @@ use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;
-use Core\Agentic\Models\AgentApiKey;
-use Core\Agentic\Services\AgentApiKeyService;
+use Core\Mod\Agentic\Models\AgentApiKey;
+use Core\Mod\Agentic\Services\AgentApiKeyService;
use Symfony\Component\HttpFoundation\StreamedResponse;
#[Title('API Keys')]
diff --git a/View/Modal/Admin/Dashboard.php b/View/Modal/Admin/Dashboard.php
index e6438ff..fdc0f6e 100644
--- a/View/Modal/Admin/Dashboard.php
+++ b/View/Modal/Admin/Dashboard.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Models\AgentSession;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentSession;
use Core\Mod\Mcp\Models\McpToolCallStat;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Cache;
diff --git a/View/Modal/Admin/PlanDetail.php b/View/Modal/Admin/PlanDetail.php
index ccc2d65..5a690df 100644
--- a/View/Modal/Admin/PlanDetail.php
+++ b/View/Modal/Admin/PlanDetail.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
-use Core\Agentic\Models\AgentPhase;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentPhase;
+use Core\Mod\Agentic\Models\AgentPlan;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
diff --git a/View/Modal/Admin/Plans.php b/View/Modal/Admin/Plans.php
index aefc156..cc96fd5 100644
--- a/View/Modal/Admin/Plans.php
+++ b/View/Modal/Admin/Plans.php
@@ -2,9 +2,9 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentPlan;
use Core\Mod\Tenant\Models\Workspace;
use Illuminate\Contracts\View\View;
use Illuminate\Pagination\LengthAwarePaginator;
diff --git a/View/Modal/Admin/Playground.php b/View/Modal/Admin/Playground.php
index d6aba3a..72687e4 100644
--- a/View/Modal/Admin/Playground.php
+++ b/View/Modal/Admin/Playground.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
use Core\Mod\Api\Models\ApiKey;
use Illuminate\Support\Facades\Http;
diff --git a/View/Modal/Admin/RequestLog.php b/View/Modal/Admin/RequestLog.php
index b9722b6..d298ec9 100644
--- a/View/Modal/Admin/RequestLog.php
+++ b/View/Modal/Admin/RequestLog.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
use Core\Mod\Mcp\Models\McpApiRequest;
use Livewire\Attributes\Layout;
diff --git a/View/Modal/Admin/SessionDetail.php b/View/Modal/Admin/SessionDetail.php
index af375bb..71c0b83 100644
--- a/View/Modal/Admin/SessionDetail.php
+++ b/View/Modal/Admin/SessionDetail.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection;
@@ -10,7 +10,7 @@ use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
-use Core\Agentic\Models\AgentSession;
+use Core\Mod\Agentic\Models\AgentSession;
#[Title('Session Detail')]
#[Layout('hub::admin.layouts.app')]
diff --git a/View/Modal/Admin/Sessions.php b/View/Modal/Admin/Sessions.php
index 776d910..0901e3c 100644
--- a/View/Modal/Admin/Sessions.php
+++ b/View/Modal/Admin/Sessions.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Models\AgentSession;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentSession;
use Core\Mod\Tenant\Models\Workspace;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Contracts\View\View;
diff --git a/View/Modal/Admin/Templates.php b/View/Modal/Admin/Templates.php
index e17a751..f93f3d4 100644
--- a/View/Modal/Admin/Templates.php
+++ b/View/Modal/Admin/Templates.php
@@ -2,9 +2,9 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
-use Core\Agentic\Services\PlanTemplateService;
+use Core\Mod\Agentic\Services\PlanTemplateService;
use Core\Mod\Tenant\Models\Workspace;
use Flux\Flux;
use Illuminate\Contracts\View\View;
diff --git a/View/Modal/Admin/ToolAnalytics.php b/View/Modal/Admin/ToolAnalytics.php
index 176ee93..0a9ca63 100644
--- a/View/Modal/Admin/ToolAnalytics.php
+++ b/View/Modal/Admin/ToolAnalytics.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
use Core\Mod\Tenant\Models\Workspace;
use Core\Mod\Mcp\Models\McpToolCall;
diff --git a/View/Modal/Admin/ToolCalls.php b/View/Modal/Admin/ToolCalls.php
index 793cbbf..069574f 100644
--- a/View/Modal/Admin/ToolCalls.php
+++ b/View/Modal/Admin/ToolCalls.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Core\Agentic\View\Modal\Admin;
+namespace Core\Mod\Agentic\View\Modal\Admin;
use Core\Mod\Tenant\Models\Workspace;
use Core\Mod\Mcp\Models\McpToolCall;
diff --git a/changelog/2026/jan/PORTING_PLAN.md b/changelog/2026/jan/PORTING_PLAN.md
new file mode 100644
index 0000000..a5e38ef
--- /dev/null
+++ b/changelog/2026/jan/PORTING_PLAN.md
@@ -0,0 +1,313 @@
+# Agentic Task System - Porting Plan
+
+MCP-powered workspace for persistent work plans that survive context limits and enable multi-agent collaboration.
+
+## Why this exists
+
+- **Context persistence** - Work plans persist across Claude sessions, surviving context window limits
+- **Multi-agent collaboration** - Handoff support between different agents (Opus, Sonnet, Haiku)
+- **Checkpoint verification** - Phase gates ensure work is complete before progressing
+- **Workspace state** - Shared key-value storage for agents to communicate findings
+
+## Source Location
+
+```
+/Users/snider/Code/lab/upstream/
+├── app/Models/
+│ ├── AgentPlan.php (6.1KB, ~200 lines)
+│ ├── AgentPhase.php (7.9KB, ~260 lines)
+│ ├── AgentSession.php (7.5KB, ~250 lines)
+│ └── WorkspaceState.php (2.1KB, ~70 lines)
+├── app/Console/Commands/
+│ ├── McpAgentServerCommand.php (42KB, ~1200 lines)
+│ ├── PlanCreateCommand.php (8.5KB)
+│ ├── PlanListCommand.php (1.8KB)
+│ ├── PlanShowCommand.php (4.0KB)
+│ ├── PlanStatusCommand.php (3.7KB)
+│ ├── PlanCheckCommand.php (5.7KB)
+│ └── PlanPhaseCommand.php (5.8KB)
+└── database/migrations/
+ └── 2025_12_31_000001_create_agent_tables.php
+```
+
+## Target Location
+
+```
+/Users/snider/Code/lab/host.uk.com/
+├── app/Models/Agent/ # New subdirectory
+│ ├── AgentPlan.php
+│ ├── AgentPhase.php
+│ ├── AgentSession.php
+│ └── WorkspaceState.php
+├── app/Console/Commands/Agent/ # New subdirectory
+│ ├── McpAgentServerCommand.php
+│ ├── PlanCreateCommand.php
+│ ├── PlanListCommand.php
+│ ├── PlanShowCommand.php
+│ ├── PlanStatusCommand.php
+│ ├── PlanCheckCommand.php
+│ └── PlanPhaseCommand.php
+├── database/migrations/
+│ └── 2025_12_31_100000_create_agent_tables.php
+└── tests/Feature/Agent/ # New subdirectory
+ ├── AgentPlanTest.php
+ ├── AgentPhaseTest.php
+ └── PlanCommandsTest.php
+```
+
+---
+
+## Phase 1: Database Migration
+
+Create the migration file with all four tables.
+
+### Tasks
+
+- [ ] Create migration `2025_12_31_100000_create_agent_tables.php`
+- [ ] Tables: `agent_plans`, `agent_phases`, `agent_sessions`, `workspace_states`
+- [ ] Run migration and verify schema
+
+### Source File
+
+Copy from: `upstream/database/migrations/2025_12_31_000001_create_agent_tables.php`
+
+### Schema Summary
+
+| Table | Purpose | Key Columns |
+|-------|---------|-------------|
+| `agent_plans` | Work plans with phases | slug, title, status, current_phase |
+| `agent_phases` | Individual phases | order, name, tasks (JSON), status, dependencies |
+| `agent_sessions` | Agent work sessions | session_id, agent_type, work_log, handoff_notes |
+| `workspace_states` | Shared key-value state | key, value (JSON), type |
+
+---
+
+## Phase 2: Eloquent Models
+
+Port all four models with namespace adjustment.
+
+### Tasks
+
+- [ ] Create `app/Models/Agent/` directory
+- [ ] Port `AgentPlan.php` - update namespace to `App\Models\Agent`
+- [ ] Port `AgentPhase.php` - update namespace and relationships
+- [ ] Port `AgentSession.php` - update namespace
+- [ ] Port `WorkspaceState.php` - update namespace
+
+### Namespace Changes
+
+```php
+// From (upstream)
+namespace App\Models;
+
+// To (host.uk.com)
+namespace App\Models\Agent;
+```
+
+### Relationship Updates
+
+Update all `use` statements:
+
+```php
+use Mod\Agentic\Models\AgentPlan;
+use Mod\Agentic\Models\AgentPhase;
+use Mod\Agentic\Models\AgentSession;
+use Mod\Agentic\Models\WorkspaceState;
+```
+
+### Key Methods to Verify
+
+**AgentPlan:**
+- `getCurrentPhase()` - proper orWhere scoping with closure
+- `generateSlug()` - race-condition safe unique slug generation
+- `checkAllPhasesComplete()` - completion verification
+
+**AgentPhase:**
+- `complete()` - wrapped in DB::transaction
+- `canStart()` - dependency checking
+- `isPending()`, `isCompleted()`, `isBlocked()`
+
+---
+
+## Phase 3: CLI Commands
+
+Port all plan management commands.
+
+### Tasks
+
+- [ ] Create `app/Console/Commands/Agent/` directory
+- [ ] Port `PlanCreateCommand.php` - markdown import support
+- [ ] Port `PlanListCommand.php` - list all plans with stats
+- [ ] Port `PlanShowCommand.php` - detailed plan view
+- [ ] Port `PlanStatusCommand.php` - status management
+- [ ] Port `PlanCheckCommand.php` - checkpoint verification
+- [ ] Port `PlanPhaseCommand.php` - phase management
+
+### Namespace Changes
+
+```php
+// From
+namespace App\Console\Commands;
+
+// To
+namespace App\Console\Commands\Agent;
+```
+
+### Command Signatures
+
+| Command | Signature | Purpose |
+|---------|-----------|---------|
+| `plan:create` | `plan:create {slug} {--title=} {--import=} {--activate}` | Create new plan |
+| `plan:list` | `plan:list {--status=}` | List all plans |
+| `plan:show` | `plan:show {slug} {--markdown}` | Show plan details |
+| `plan:status` | `plan:status {slug} {--set=}` | Get/set plan status |
+| `plan:check` | `plan:check {slug} {phase?}` | Verify phase completion |
+| `plan:phase` | `plan:phase {slug} {phase} {--status=} {--add-task=} {--complete-task=}` | Manage phases |
+
+---
+
+## Phase 4: MCP Agent Server
+
+Port the MCP server command with all tools and resources.
+
+### Tasks
+
+- [ ] Port `McpAgentServerCommand.php` (~1200 lines)
+- [ ] Update all model imports to use `Mod\Agentic\Models\*`
+- [ ] Register command in `Kernel.php` or auto-discovery
+- [ ] Test JSON-RPC protocol over stdio
+
+### MCP Tools (18 total)
+
+| Tool | Purpose |
+|------|---------|
+| `plan_create` | Create new plan with phases |
+| `plan_get` | Get plan by slug with all phases |
+| `plan_list` | List plans (optionally filtered) |
+| `plan_update` | Update plan status/metadata |
+| `phase_update` | Update phase status |
+| `phase_check` | **Checkpoint** - verify phase completion |
+| `task_add` | Add task to a phase |
+| `task_complete` | Mark task done |
+| `session_start` | Begin agent session |
+| `session_log` | Log action to session |
+| `session_artifact` | Log file artifact |
+| `session_handoff` | Prepare for agent handoff |
+| `session_resume` | Resume from previous session |
+| `session_complete` | Mark session completed |
+| `state_set` | Store workspace state |
+| `state_get` | Retrieve workspace state |
+| `state_list` | List all state keys |
+| `state_delete` | Delete state key |
+
+### MCP Resources (5 total)
+
+| Resource URI | Purpose |
+|--------------|---------|
+| `hosthub://plans` | List of all work plans |
+| `hosthub://plans/{slug}` | Full plan as markdown |
+| `hosthub://plans/{slug}/phase/{n}` | Phase tasks as checklist |
+| `hosthub://state/{plan}/{key}` | Specific state value |
+| `hosthub://sessions/{id}` | Session handoff context |
+
+---
+
+## Phase 5: Tests ✅
+
+Port and adapt tests for host.uk.com conventions.
+
+### Tasks
+
+- [x] Create `app/Mod/Agentic/Tests/Feature/` directory
+- [x] Create `AgentPlanTest.php` with factory support
+- [x] Create `AgentPhaseTest.php` with factory support
+- [x] Create `AgentSessionTest.php` with factory support
+- [x] Create model factories (`AgentPlanFactory`, `AgentPhaseFactory`, `AgentSessionFactory`)
+- [x] Run full test suite - 67 tests passing
+
+### Test Coverage
+
+- Model CRUD operations
+- Relationship integrity
+- Status transitions
+- Phase dependency checking
+- Command input/output
+- MCP protocol compliance (optional E2E)
+
+---
+
+## Phase 6: Documentation and Integration
+
+Finalise integration with host.uk.com.
+
+### Tasks
+
+- [ ] Add MCP server config to `mcp.json` example
+- [ ] Update `CLAUDE.md` with agentic task commands
+- [ ] Create feature documentation following `_TEMPLATE.md`
+- [ ] Add to route/command discovery if needed
+
+### MCP Configuration
+
+```json
+{
+ "mcpServers": {
+ "hosthub-agent": {
+ "command": "php",
+ "args": ["artisan", "mcp:agent-server"],
+ "cwd": "/Users/snider/Code/lab/host.uk.com"
+ }
+ }
+}
+```
+
+---
+
+## Verification Checklist
+
+After each phase, verify:
+
+- [ ] No syntax errors (`php artisan list` works)
+- [ ] Migrations run cleanly
+- [ ] Models can be instantiated
+- [ ] Commands appear in `php artisan list`
+- [ ] Tests pass (`php artisan test --filter=Agent`)
+
+---
+
+## Files to Copy (Summary)
+
+| Source | Target | Changes Required |
+|--------|--------|------------------|
+| `upstream/database/migrations/2025_12_31_000001_create_agent_tables.php` | `host.uk.com/database/migrations/2025_12_31_100000_create_agent_tables.php` | Rename only |
+| `upstream/app/Models/AgentPlan.php` | `host.uk.com/app/Models/Agent/AgentPlan.php` | Namespace |
+| `upstream/app/Models/AgentPhase.php` | `host.uk.com/app/Models/Agent/AgentPhase.php` | Namespace |
+| `upstream/app/Models/AgentSession.php` | `host.uk.com/app/Models/Agent/AgentSession.php` | Namespace |
+| `upstream/app/Models/WorkspaceState.php` | `host.uk.com/app/Models/Agent/WorkspaceState.php` | Namespace |
+| `upstream/app/Console/Commands/McpAgentServerCommand.php` | `host.uk.com/app/Console/Commands/Agent/McpAgentServerCommand.php` | Namespace + imports |
+| `upstream/app/Console/Commands/Plan*.php` (6 files) | `host.uk.com/app/Console/Commands/Agent/Plan*.php` | Namespace + imports |
+| `upstream/tests/Feature/Agent*.php` | `host.uk.com/tests/Feature/Agent/*.php` | Namespace |
+| `upstream/tests/Feature/PlanCommandsTest.php` | `host.uk.com/tests/Feature/Agent/PlanCommandsTest.php` | Namespace |
+
+---
+
+## Estimated Effort
+
+| Phase | Complexity | Notes |
+|-------|------------|-------|
+| 1. Migration | Low | Direct copy |
+| 2. Models | Low | Namespace changes only |
+| 3. CLI Commands | Medium | 7 files, namespace + import updates |
+| 4. MCP Server | Medium | Large file, many import updates |
+| 5. Tests | Low | Namespace changes |
+| 6. Documentation | Low | Config and docs |
+
+---
+
+## Related Services
+
+- `ContentProcessingService` - May benefit from agent tracking
+- `EntitlementService` - No direct relation
+- Existing `Task` model - Different purpose (simple tasks vs agent plans)
+
+See also: `/Users/snider/Code/lab/upstream/CLAUDE.md` for original implementation details.
diff --git a/changelog/2026/jan/TASK-006-agent-plans-admin-ui.md b/changelog/2026/jan/TASK-006-agent-plans-admin-ui.md
new file mode 100644
index 0000000..1826ace
--- /dev/null
+++ b/changelog/2026/jan/TASK-006-agent-plans-admin-ui.md
@@ -0,0 +1,2214 @@
+# TASK-006: Agent Plans Admin UI
+
+**Status:** all_phases_verified (Ready for human approval)
+**Created:** 2026-01-02
+**Last Updated:** 2026-01-02 23:45 by Claude Opus 4.5 (Verification Agent)
+**Assignee:** Claude Opus 4.5 (Implementation Agent)
+**Verifier:** Claude Opus 4.5 (Verification Agent)
+
+---
+
+## Critical Context (READ FIRST)
+
+**The agent infrastructure exists. Now we need visibility.**
+
+### What Already Exists
+
+The codebase has sophisticated agent workflow infrastructure:
+
+| Component | Location | Purpose |
+|-----------|----------|---------|
+| AgentPlan | `app/Models/Agent/AgentPlan.php` | Multi-phase work plans |
+| AgentPhase | `app/Models/Agent/AgentPhase.php` | Individual phases with tasks |
+| AgentSession | `app/Models/Agent/AgentSession.php` | Work sessions with handoff |
+| AgentWorkspaceState | `app/Models/Agent/AgentWorkspaceState.php` | Shared state storage |
+| McpToolCall | `app/Models/Mcp/McpToolCall.php` | Tool invocation logs |
+| McpToolCallStat | `app/Models/Mcp/McpToolCallStat.php` | Daily aggregates |
+| PlanTemplateService | `app/Services/Agent/PlanTemplateService.php` | Template-based plan creation |
+| MCP Registry | `routes/mcp.php` | Agent discovery endpoints |
+
+**What's Missing:** Admin UI to view, manage, and monitor all of this.
+
+### The Vision
+
+A Hades admin section that provides:
+1. **Plan Dashboard** — See all active plans across workspaces
+2. **Phase Tracking** — Visual progress through plan phases
+3. **Session Monitor** — Watch agent sessions in real-time
+4. **Tool Analytics** — MCP tool usage and performance
+5. **API Key Management** — Enable external agent access
+6. **Plan Templates** — Browse and create from templates
+
+This becomes the control tower for AI-stabilised hosting — where humans supervise agent work.
+
+---
+
+## Objective
+
+Build a comprehensive Agent Plans admin UI in the Hades section that surfaces all existing agent infrastructure. Enable operators to monitor, manage, and guide agent work across the platform.
+
+**"Done" looks like:**
+- Hades users can see all agent plans and their progress
+- Real-time session monitoring shows active agent work
+- MCP tool analytics reveal usage patterns
+- API keys allow external agents to create/update plans
+- Plan templates can be browsed and instantiated
+
+---
+
+## Acceptance Criteria
+
+### Phase 1: Plan Dashboard ✅
+
+- [x] AC1: Route `hub.agents.plans` shows all AgentPlans (filterable by workspace, status)
+- [x] AC2: Plan list shows: title, workspace, status, phase progress, last activity
+- [x] AC3: Plan detail view shows all phases with task checklists
+- [x] AC4: Phase progress displayed as visual percentage bar
+- [x] AC5: Can manually update plan status (activate, complete, archive)
+- [x] AC6: Can manually update phase status (start, complete, block, skip)
+
+### Phase 2: Session Monitor ✅
+
+- [x] AC7: Route `hub.agents.sessions` shows all AgentSessions
+- [x] AC8: Active sessions show real-time activity (polling or WebSocket)
+- [x] AC9: Session detail shows: work log, artifacts, handoff notes
+- [x] AC10: Can view session context summary and final summary
+- [x] AC11: Timeline view shows session sequence within a plan
+- [x] AC12: Can pause/resume/fail active sessions manually
+
+### Phase 3: Tool Analytics ✅
+
+- [x] AC13: Route `hub.agents.tools` shows MCP tool usage dashboard
+- [x] AC14: Top 10 tools by usage displayed
+- [x] AC15: Daily trend chart (calls per day, 30-day window)
+- [x] AC16: Server breakdown shows usage by MCP server
+- [x] AC17: Error rate and average duration displayed per tool
+- [x] AC18: Can drill down to individual tool calls with full params
+
+### Phase 4: API Key Management ✅
+
+- [x] AC19: Route `hub.agents.api-keys` manages agent API access
+- [x] AC20: Can create API keys scoped to workspace
+- [x] AC21: Keys have configurable permissions (read plans, write plans, execute tools)
+- [x] AC22: Key usage tracking (last used, call count)
+- [x] AC23: Can revoke keys immediately
+- [x] AC24: Rate limiting configuration per key
+
+### Phase 5: Plan Templates ✅
+
+- [x] AC25: Route `hub.agents.templates` lists available plan templates
+- [x] AC26: Template preview shows phases and variables
+- [x] AC27: Can create new plan from template with variable input
+- [x] AC28: Template categories displayed for organisation
+- [x] AC29: Can import custom templates (YAML upload)
+
+---
+
+## Implementation Checklist
+
+### Routes (`routes/web.php`)
+
+Add after line 164 (after Commerce routes), inside the hub group:
+
+```php
+// Agent Operations (Hades only)
+Route::prefix('agents')->name('agents.')->group(function () {
+ Route::get('/', \App\Livewire\Admin\Agent\Dashboard::class)->name('index');
+ Route::get('/plans', \App\Livewire\Admin\Agent\Plans::class)->name('plans');
+ Route::get('/plans/{slug}', \App\Livewire\Admin\Agent\PlanDetail::class)->name('plans.show');
+ Route::get('/sessions', \App\Livewire\Admin\Agent\Sessions::class)->name('sessions');
+ Route::get('/sessions/{id}', \App\Livewire\Admin\Agent\SessionDetail::class)->name('sessions.show');
+ Route::get('/tools', \App\Livewire\Admin\Agent\ToolAnalytics::class)->name('tools');
+ Route::get('/tools/calls', \App\Livewire\Admin\Agent\ToolCalls::class)->name('tools.calls');
+ Route::get('/api-keys', \App\Livewire\Admin\Agent\ApiKeys::class)->name('api-keys');
+ Route::get('/templates', \App\Livewire\Admin\Agent\Templates::class)->name('templates');
+});
+```
+
+- [x] Add route group `hub/agents`
+- [x] Route `hub.agents.index` → Dashboard (overview)
+- [x] Route `hub.agents.plans` → Plans (list)
+- [x] Route `hub.agents.plans.show` → PlanDetail (single plan by slug)
+- [x] Route `hub.agents.sessions` → Sessions (list) *(Phase 2)* ✅
+- [x] Route `hub.agents.sessions.show` → SessionDetail (single session) *(Phase 2)* ✅
+- [x] Route `hub.agents.tools` → ToolAnalytics (MCP stats) *(Phase 3)* ✅
+- [x] Route `hub.agents.tools.calls` → ToolCalls (detailed logs) *(Phase 3)* ✅
+- [x] Route `hub.agents.api-keys` → ApiKeys (key management) *(Phase 4)* ✅
+- [x] Route `hub.agents.templates` → Templates (template browser) *(Phase 5)* ✅
+
+### Livewire Components (`app/Livewire/Admin/Agent/`)
+
+**Create directory:** `mkdir -p app/Livewire/Admin/Agent`
+
+Each component should check `$this->authorize()` or `auth()->user()->isHades()` in mount().
+
+- [x] Create `Dashboard.php` — Overview with key metrics ✅
+ - Query: `AgentPlan::where('status', 'active')->count()`
+ - Query: `AgentSession::where('status', 'active')->count()`
+ - Query: `McpToolCallStat::getTopTools()`
+ - Query: `McpToolCallStat::getDailyTrend()`
+
+- [x] Create `Plans.php` — Plan list with filters ✅
+ - Properties: `$status`, `$workspace`, `$search`, `$perPage`
+ - Query: `AgentPlan::with(['workspace', 'agentPhases'])->filter()->paginate()`
+ - Methods: `activate()`, `archive()`, `delete()`
+
+- [x] Create `PlanDetail.php` — Single plan with phases ✅
+ - Property: `AgentPlan $plan` (route model binding via slug)
+ - Relationships: `$plan->agentPhases`, `$plan->sessions`, `$plan->states`
+ - Methods: `updatePhaseStatus()`, `completeTask()`, `addTask()`
+
+- [x] Create `Sessions.php` — Session list ✅
+ - Properties: `$status`, `$agentType`, `$planSlug`, `$workspace`, `$search`
+ - Query: `AgentSession::with(['plan', 'workspace'])->filter()->paginate()`
+ - Methods: `pause()`, `resume()`, `complete()`, `fail()`, `clearFilters()`
+
+- [x] Create `SessionDetail.php` — Single session with logs ✅
+ - Property: `AgentSession $session`
+ - Display: `$session->work_log`, `$session->artifacts`, `$session->handoff_notes`
+ - Methods: `pauseSession()`, `resumeSession()`, `completeSession()`, `failSession()`, `poll()`
+ - Polling: 5-second interval for active sessions (disabled when ended)
+
+- [x] Create `ToolAnalytics.php` — MCP usage charts ✅
+ - Query: `McpToolCallStat::getTopTools()`, `getDailyTrend()`, `getServerStats()`
+ - Chart data for Chart.js with daily trend visualization
+ - Filters: days (7/14/30), workspace, server
+
+- [x] Create `ToolCalls.php` — Tool call log browser ✅
+ - Properties: `$search`, `$server`, `$tool`, `$status`, `$workspace`, `$agentType`
+ - Query: `McpToolCall::with(['workspace'])->filter()->paginate()`
+ - Modal detail view for individual tool calls (AC18)
+
+- [x] Create `ApiKeys.php` — Key CRUD *(Phase 4)* ✅
+ - Methods: `createKey()`, `updateKey()`, `revokeKey()`
+ - Display plaintext key ONCE on creation
+ - Filters: workspace, status (active/revoked/expired)
+ - Edit modal for permissions and rate limit updates
+
+- [x] Create `Templates.php` — Template browser and instantiation *(Phase 5)* ✅
+ - Uses: `PlanTemplateService::list()`, `get()`, `createPlan()`, `previewTemplate()`
+ - Modal for variable input before instantiation
+ - YAML import with validation and preview
+ - Category filtering and search
+ - Template preview with phases and variables
+
+### Views (`resources/views/admin/livewire/agent/`)
+
+- [x] Create `dashboard.blade.php` ✅
+- [x] Create `plans.blade.php` ✅
+- [x] Create `plan-detail.blade.php` ✅
+- [x] Create `sessions.blade.php` *(Phase 2)* ✅
+- [x] Create `session-detail.blade.php` *(Phase 2)* ✅
+- [x] Create `tool-analytics.blade.php` *(Phase 3)* ✅
+- [x] Create `tool-calls.blade.php` *(Phase 3)* ✅
+- [x] Create `api-keys.blade.php` *(Phase 4)* ✅
+- [x] Create `templates.blade.php` *(Phase 5)* ✅
+
+### API Endpoints (`routes/api.php`)
+
+- [ ] Add API route group `api/v1/agents` with API key auth
+- [ ] `GET /api/v1/agents/plans` — List plans for workspace
+- [ ] `POST /api/v1/agents/plans` — Create plan (from template or raw)
+- [ ] `GET /api/v1/agents/plans/{slug}` — Get plan detail
+- [ ] `PATCH /api/v1/agents/plans/{slug}` — Update plan status
+- [ ] `POST /api/v1/agents/plans/{slug}/phases/{id}/tasks` — Add task to phase
+- [ ] `PATCH /api/v1/agents/plans/{slug}/phases/{id}/tasks/{name}` — Complete task
+- [ ] `POST /api/v1/agents/sessions` — Start new session
+- [ ] `PATCH /api/v1/agents/sessions/{id}` — Update session (log, artifacts, handoff)
+- [ ] `POST /api/v1/agents/sessions/{id}/complete` — End session with summary
+- [ ] `GET /api/v1/agents/templates` — List available templates
+- [ ] `POST /api/v1/agents/templates/{slug}/instantiate` — Create plan from template
+
+### Models & Migrations
+
+- [x] Create `AgentApiKey` model with: *(Phase 4)* ✅
+ - workspace_id, name, key (hashed), permissions (JSON)
+ - last_used_at, call_count, rate_limit
+ - expires_at, revoked_at
+ - Key methods: `generate()`, `findByKey()`, `hasPermission()`, `revoke()`, `recordUsage()`
+- [x] Migration for `agent_api_keys` table *(Phase 4)* ✅
+- [x] Add `api_key_id` to `agent_sessions` table (track which key started session) *(Phase 4)* ✅
+- [x] Add `api_key_id` to `mcp_tool_calls` table (track which key made call) *(Phase 4)* ✅
+
+### Services
+
+- [x] Create `AgentApiKeyService.php`: *(Phase 4)* ✅
+ - `create()`, `revoke()`, `validate()`
+ - `checkPermission()`, `checkPermissions()`, `recordUsage()`
+ - `isRateLimited()`, `getRateLimitStatus()`
+ - `authenticate()` — Full auth flow with rate limiting
+ - `updatePermissions()`, `updateRateLimit()`
+- [x] `PlanTemplateService.php` already has all needed methods *(Phase 5)* ✅
+ - `list()`, `get()`, `createPlan()`, `previewTemplate()`
+ - `getCategories()`, `getByCategory()`, `validateVariables()`
+ - YAML import handled directly in Livewire component
+
+### Sidebar Integration
+
+- [x] Add "Agents" group to Hades sidebar: ✅
+ ```
+ Agents
+ ├── Dashboard → hub.agents.index ✅
+ ├── Plans → hub.agents.plans ✅
+ ├── Sessions → hub.agents.sessions ✅ (Phase 2)
+ ├── Tool Analytics → hub.agents.tools ✅ (Phase 3)
+ ├── API Keys → hub.agents.api-keys (Phase 4)
+ └── Templates → hub.agents.templates (Phase 5)
+ ```
+- [x] Sessions link added to sidebar *(Phase 2)* ✅
+- [x] Sessions quick link activated in dashboard *(Phase 2)* ✅
+- [x] Add badge for plans needing attention (blocked phases) ✅
+- [x] Tool Analytics link added to sidebar *(Phase 3)* ✅
+- [x] Tool Analytics quick link activated in dashboard *(Phase 3)* ✅
+- [x] API Keys link added to sidebar *(Phase 4)* ✅
+- [x] Templates link added to sidebar *(Phase 5)* ✅
+- [x] Templates quick link activated in dashboard *(Phase 5)* ✅
+
+### Testing
+
+- [ ] Feature test: Plan list filters work
+- [ ] Feature test: Plan status transitions work
+- [ ] Feature test: Session creation and update work
+- [ ] Feature test: API key authentication works
+- [ ] Feature test: API key permissions enforced
+- [ ] Feature test: Rate limiting works
+- [ ] Feature test: Template instantiation works
+- [ ] Browser test: Dashboard loads with charts
+- [ ] Browser test: Real-time session updates work
+
+---
+
+## UI Specifications
+
+### Agent Dashboard (Overview)
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ Agent Operations [Refresh] │
+├─────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
+│ │ 12 │ │ 3 │ │ 847 │ │ 98.2% │ │
+│ │ Active │ │ Sessions │ │ Tool │ │ Success │ │
+│ │ Plans │ │ Today │ │ Calls │ │ Rate │ │
+│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
+│ │
+│ Recent Activity Tool Usage (7 days) │
+│ ┌─────────────────────────┐ ┌─────────────────────┐ │
+│ │ • Plan "content-gen" │ │ ▓▓▓▓▓▓▓▓░░ 80% │ │
+│ │ Phase 2 completed │ │ content_create │ │
+│ │ 2 minutes ago │ │ │ │
+│ │ │ │ ▓▓▓▓▓░░░░░ 50% │ │
+│ │ • Session opus-abc123 │ │ content_read │ │
+│ │ Started work on plan │ │ │ │
+│ │ 5 minutes ago │ │ ▓▓▓░░░░░░░ 30% │ │
+│ └─────────────────────────┘ │ search_docs │ │
+│ └─────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### Plan Detail View
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ Plan: Content Migration Status: Active│
+│ Workspace: main │
+├─────────────────────────────────────────────────────────────────┤
+│ │
+│ Progress: ████████████░░░░░░░░ 60% │
+│ │
+│ Phases: │
+│ ┌─────────────────────────────────────────────────────────────┐│
+│ │ ✓ Phase 1: Audit Existing Content [Completed] ││
+│ │ └─ 5/5 tasks complete ││
+│ ├─────────────────────────────────────────────────────────────┤│
+│ │ ● Phase 2: Migrate Blog Posts [In Progress] ││
+│ │ ├─ ✓ Export WordPress posts ││
+│ │ ├─ ✓ Transform to native format ││
+│ │ ├─ ○ Import to ContentItem ││
+│ │ └─ ○ Verify all posts render ││
+│ │ Progress: ██████░░░░ 50% ││
+│ ├─────────────────────────────────────────────────────────────┤│
+│ │ ○ Phase 3: Migrate Help Articles [Pending] ││
+│ │ └─ Waiting for Phase 2 ││
+│ └─────────────────────────────────────────────────────────────┘│
+│ │
+│ Sessions: │
+│ ┌─────────────────────────────────────────────────────────────┐│
+│ │ sess_abc123 │ opus │ Active │ Started 10m ago │ [View] ││
+│ │ sess_xyz789 │ sonnet │ Completed │ 2h duration │ [View] ││
+│ └─────────────────────────────────────────────────────────────┘│
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### Session Detail View
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ Session: sess_abc123 Agent: opus │
+│ Plan: Content Migration Status: Active │
+├─────────────────────────────────────────────────────────────────┤
+│ │
+│ Duration: 10m 23s Last Active: 30s ago │
+│ │
+│ Work Log: │
+│ ┌─────────────────────────────────────────────────────────────┐│
+│ │ 15:30:00 [info] Starting phase 2 execution ││
+│ │ 15:30:15 [success] Exported 47 WordPress posts ││
+│ │ 15:32:00 [info] Transforming post format... ││
+│ │ 15:35:22 [checkpoint] 25/47 posts transformed ││
+│ │ 15:38:45 [success] All posts transformed ││
+│ │ 15:39:00 [info] Beginning import to ContentItem... ││
+│ └─────────────────────────────────────────────────────────────┘│
+│ │
+│ Artifacts: │
+│ ┌─────────────────────────────────────────────────────────────┐│
+│ │ storage/exports/wp-posts.json │ created │ 15:30:15 ││
+│ │ app/Services/ContentImporter.php │ modified │ 15:35:22 ││
+│ └─────────────────────────────────────────────────────────────┘│
+│ │
+│ Handoff Notes: │
+│ ┌─────────────────────────────────────────────────────────────┐│
+│ │ Summary: Completed export and transformation phases. ││
+│ │ Next: Import remaining 22 posts, verify rendering. ││
+│ │ Blockers: None currently. ││
+│ └─────────────────────────────────────────────────────────────┘│
+│ │
+│ [Pause Session] [Complete Session] [Fail Session] │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## API Authentication
+
+### Key Generation
+
+```php
+// Create key
+$key = AgentApiKey::create([
+ 'workspace_id' => $workspace->id,
+ 'name' => 'Claude Code Integration',
+ 'permissions' => ['plans.read', 'plans.write', 'sessions.write'],
+ 'rate_limit' => 100, // per minute
+ 'expires_at' => now()->addYear(),
+]);
+
+// Returns unhashed key ONCE for user to copy
+return $key->plainTextKey; // ak_live_xxxxxxxxxxxx
+```
+
+### Key Usage
+
+```bash
+# External agent creates a plan
+curl -X POST https://host.uk.com/api/v1/agents/plans \
+ -H "Authorization: Bearer ak_live_xxxxxxxxxxxx" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "template": "content-migration",
+ "variables": {
+ "source": "wordpress",
+ "workspace": "main"
+ }
+ }'
+
+# Agent logs work to session
+curl -X PATCH https://host.uk.com/api/v1/agents/sessions/sess_abc123 \
+ -H "Authorization: Bearer ak_live_xxxxxxxxxxxx" \
+ -d '{
+ "work_log": {
+ "type": "checkpoint",
+ "message": "Completed 25/47 posts"
+ }
+ }'
+```
+
+### Permissions
+
+| Permission | Allows |
+|------------|--------|
+| `plans.read` | List and view plans |
+| `plans.write` | Create, update, archive plans |
+| `phases.write` | Update phase status, add/complete tasks |
+| `sessions.read` | List and view sessions |
+| `sessions.write` | Start, update, complete sessions |
+| `tools.read` | View tool analytics |
+| `templates.read` | List and view templates |
+| `templates.instantiate` | Create plans from templates |
+
+---
+
+## Dependencies
+
+- Flux UI components (cards, tables, charts)
+- Chart library for analytics (ApexCharts or Chart.js via Livewire)
+- Real-time updates (Livewire polling or Laravel Echo)
+- Existing agent models (AgentPlan, AgentPhase, AgentSession)
+- Existing MCP models (McpToolCall, McpToolCallStat)
+
+---
+
+## Integration with Existing Infrastructure
+
+### MCP Registry
+
+The existing MCP registry at `mcp.host.uk.com` provides agent discovery. The new API endpoints extend this with:
+- Plan management (create, track, complete)
+- Session logging (work log, artifacts, handoff)
+- State persistence (shared workspace state)
+
+### Entitlement Gating
+
+Future: Add entitlement features for agent access:
+- `agents.plans.create` — Can create agent plans
+- `agents.sessions.concurrent` — Max concurrent sessions
+- `agents.tools.calls` — Monthly tool call limit
+- `agents.api_keys` — Max API keys per workspace
+
+### External Agent Flow
+
+```
+External Agent (Claude Code, Cursor, etc.)
+ │
+ ├─ Discovers Host Hub via mcp.host.uk.com
+ │
+ ├─ Authenticates with API key
+ │
+ ├─ Creates plan from template
+ │ POST /api/v1/agents/plans
+ │
+ ├─ Starts session
+ │ POST /api/v1/agents/sessions
+ │
+ ├─ Logs work progress
+ │ PATCH /api/v1/agents/sessions/{id}
+ │
+ ├─ Completes tasks
+ │ PATCH /api/v1/agents/plans/{slug}/phases/{id}/tasks/{name}
+ │
+ └─ Completes session with handoff notes
+ POST /api/v1/agents/sessions/{id}/complete
+```
+
+---
+
+## Notes
+
+### Why API Keys (Not OAuth)
+
+For agent-to-agent communication:
+- OAuth is designed for human authorization flows
+- API keys are simpler for programmatic access
+- Keys can be scoped per workspace and permission
+- Rate limiting is straightforward
+- Revocation is immediate
+
+### Real-Time Considerations
+
+For session monitoring:
+- Start with Livewire polling (every 5 seconds)
+- Upgrade to WebSocket (Laravel Echo) if needed
+- Consider SSE for one-way updates (server → browser)
+
+### Multi-System Cooperation
+
+The API enables:
+1. **Claude Code** creates plan for Host Hub work
+2. **Cursor** picks up session for code changes
+3. **Host Hub AI** generates content as directed
+4. **Human** reviews in admin UI, approves or redirects
+
+Each system maintains its own context but shares state via the plan.
+
+---
+
+## Verification Results
+
+### Phase 1 Verification (2026-01-02 19:30)
+
+**Verification Agent:** Claude Opus 4.5
+**Verdict:** ✅ PASS - All Phase 1 acceptance criteria met
+
+#### AC1: Route `hub.agents.plans` shows all AgentPlans (filterable by workspace, status) ✅
+
+**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/Plans.php`
+
+**Evidence - Routes (lines 180-185):**
+```php
+Route::prefix('agents')->name('agents.')->group(function () {
+ Route::get('/', \App\Livewire\Admin\Agent\Dashboard::class)->name('index');
+ Route::get('/plans', \App\Livewire\Admin\Agent\Plans::class)->name('plans');
+ Route::get('/plans/{slug}', \App\Livewire\Admin\Agent\PlanDetail::class)->name('plans.show');
+});
+```
+
+**Evidence - Plans.php (lines 39-61):**
+```php
+public function plans(): LengthAwarePaginator
+{
+ $query = AgentPlan::with(['workspace', 'agentPhases'])
+ ->withCount('sessions');
+
+ if ($this->search) { ... }
+ if ($this->status) { $query->where('status', $this->status); }
+ if ($this->workspace) { $query->where('workspace_id', $this->workspace); }
+
+ return $query->latest('updated_at')->paginate($this->perPage);
+}
+```
+
+**Filters confirmed:** Search (title/slug/description), Status (draft/active/completed/archived), Workspace ✅
+
+#### AC2: Plan list shows: title, workspace, status, phase progress, last activity ✅
+
+**Method:** Code inspection of `resources/views/admin/livewire/agent/plans.blade.php`
+
+**Evidence - Table headers (lines 44-53):**
+```blade
+
Plan |
+Workspace |
+Status |
+Progress |
+Sessions |
+Last Activity |
+```
+
+**All required columns present:** ✅
+- Title (line 64): `{{ $plan->title }}`
+- Workspace (line 69): `{{ $plan->workspace?->name ?? 'N/A' }}`
+- Status (lines 71-86): Coloured badge with ucfirst status
+- Progress (lines 88-96): Visual bar + percentage + phases count
+- Last Activity (lines 100-102): `{{ $plan->updated_at->diffForHumans() }}`
+
+#### AC3: Plan detail view shows all phases with task checklists ✅
+
+**Method:** Code inspection of `resources/views/admin/livewire/agent/plan-detail.blade.php`
+
+**Evidence - Phases section (lines 66-183):**
+```blade
+
+ Phases
+ @foreach($this->phases as $phase)
+
+ @if($phase->tasks && count($phase->tasks) > 0)
+
+ @foreach($phase->tasks as $index => $task)
+
+ @endforeach
+
+ @endif
+ @endforeach
+
+```
+
+**Task checklist features:**
+- Checkbox toggle for completing tasks (line 143-156)
+- Completed tasks show strikethrough (line 158)
+- Optional task notes displayed (lines 159-161)
+- "Add Task" modal (lines 248-274) ✅
+
+#### AC4: Phase progress displayed as visual percentage bar ✅
+
+**Method:** Code inspection of views
+
+**Evidence - Plan-level progress (lines 29-56):**
+```blade
+
+```
+
+**Evidence - Phase-level progress (lines 96-102):**
+```blade
+@if($taskProgress['total'] > 0)
+
+ {{ $taskProgress['completed'] }}/{{ $taskProgress['total'] }}
+@endif
+```
+
+**Progress bars present at:**
+- Plan list (each row has progress bar + percentage)
+- Plan detail (overview card with large progress bar)
+- Each phase (task completion progress) ✅
+
+#### AC5: Can manually update plan status (activate, complete, archive) ✅
+
+**Method:** Code inspection of `Plans.php` and `PlanDetail.php`
+
+**Evidence - Plans.php (lines 103-122):**
+```php
+public function activate(int $planId): void {
+ $plan = AgentPlan::findOrFail($planId);
+ $plan->activate();
+}
+
+public function complete(int $planId): void {
+ $plan = AgentPlan::findOrFail($planId);
+ $plan->complete();
+}
+
+public function archive(int $planId): void {
+ $plan = AgentPlan::findOrFail($planId);
+ $plan->archive('Archived via admin UI');
+}
+```
+
+**Evidence - PlanDetail.php (lines 55-72):**
+```php
+public function activatePlan(): void { $this->plan->activate(); }
+public function completePlan(): void { $this->plan->complete(); }
+public function archivePlan(): void { $this->plan->archive('Archived via admin UI'); }
+```
+
+**UI buttons confirmed:**
+- Plans list: Dropdown menu with Activate/Complete/Archive/Delete (lines 108-122)
+- Plan detail: Header buttons for Activate/Complete/Archive (lines 17-26) ✅
+
+#### AC6: Can manually update phase status (start, complete, block, skip) ✅
+
+**Method:** Code inspection of `PlanDetail.php`
+
+**Evidence - Phase actions (lines 75-120):**
+```php
+public function startPhase(int $phaseId): void {
+ $phase = AgentPhase::findOrFail($phaseId);
+ if (! $phase->canStart()) { return; }
+ $phase->start();
+}
+
+public function completePhase(int $phaseId): void {
+ $phase = AgentPhase::findOrFail($phaseId);
+ $phase->complete();
+}
+
+public function blockPhase(int $phaseId): void {
+ $phase = AgentPhase::findOrFail($phaseId);
+ $phase->block('Blocked via admin UI');
+}
+
+public function skipPhase(int $phaseId): void {
+ $phase = AgentPhase::findOrFail($phaseId);
+ $phase->skip('Skipped via admin UI');
+}
+
+public function resetPhase(int $phaseId): void {
+ $phase = AgentPhase::findOrFail($phaseId);
+ $phase->reset();
+}
+```
+
+**Evidence - View dropdown (lines 106-128):**
+```blade
+
+ @if($phase->isPending())
+ Start Phase
+ @endif
+ @if($phase->isInProgress())
+ Complete Phase
+ Block Phase
+ @endif
+ @if($phase->isBlocked())
+ Unblock (Reset)
+ @endif
+ @if(!$phase->isCompleted() && !$phase->isSkipped())
+ Skip Phase
+ @endif
+ @if($phase->isCompleted() || $phase->isSkipped())
+ Reset to Pending
+ @endif
+
+```
+
+**All phase status actions available:** Start, Complete, Block, Skip, Reset ✅
+
+### Phase 1 Summary
+
+| AC | Description | Evidence | Status |
+|----|-------------|----------|--------|
+| AC1 | Route exists with filters | `routes/web.php:184`, `Plans.php` query builder | ✅ PASS |
+| AC2 | Plan list columns | `plans.blade.php` table with all 6 columns | ✅ PASS |
+| AC3 | Phases with task checklists | `plan-detail.blade.php:132-165` task list with checkboxes | ✅ PASS |
+| AC4 | Visual progress bars | Plan list + detail + per-phase progress | ✅ PASS |
+| AC5 | Plan status updates | `activate()`, `complete()`, `archive()` methods | ✅ PASS |
+| AC6 | Phase status updates | `startPhase()`, `completePhase()`, `blockPhase()`, `skipPhase()`, `resetPhase()` | ✅ PASS |
+
+**Additional Implementation Verified:**
+- Hades access control in all components (`checkHadesAccess()` in mount)
+- Sidebar integration (lines 520-576 in sidebar.blade.php)
+- Dashboard with stats and recent activity (`Dashboard.php`)
+- Task management (add task modal, complete task)
+- Session list in plan detail view
+
+**Phase 1 Status:** ✅ VERIFIED — Ready for human approval
+
+---
+
+### Phase 2 Verification (2026-01-02 20:00)
+
+**Verification Agent:** Claude Opus 4.5
+**Verdict:** ✅ PASS - All Phase 2 acceptance criteria met
+
+#### AC7: Route `hub.agents.sessions` shows all AgentSessions ✅
+
+**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/Sessions.php`
+
+**Evidence - Routes (lines 187-188):**
+```php
+Route::get('/sessions', \App\Livewire\Admin\Agent\Sessions::class)->name('sessions');
+Route::get('/sessions/{id}', \App\Livewire\Admin\Agent\SessionDetail::class)->name('sessions.show');
+```
+
+**Evidence - Sessions.php (lines 46-76):**
+```php
+public function sessions(): LengthAwarePaginator
+{
+ $query = AgentSession::with(['workspace', 'plan']);
+
+ if ($this->search) { ... }
+ if ($this->status) { $query->where('status', $this->status); }
+ if ($this->agentType) { $query->where('agent_type', $this->agentType); }
+ if ($this->workspace) { $query->where('workspace_id', $this->workspace); }
+ if ($this->planSlug) { $query->whereHas('plan', ...); }
+
+ return $query->latest('last_active_at')->paginate($this->perPage);
+}
+```
+
+**Filters confirmed:** Search, Status, Agent Type, Workspace, Plan ✅
+
+#### AC8: Active sessions show real-time activity (polling or WebSocket) ✅
+
+**Method:** Code inspection of `SessionDetail.php` and `session-detail.blade.php`
+
+**Evidence - Polling implementation (SessionDetail.php lines 27-41, 104-114):**
+```php
+public int $pollingInterval = 5000;
+
+public function mount(int $id): void
+{
+ // Disable polling for completed/failed sessions
+ if ($this->session->isEnded()) {
+ $this->pollingInterval = 0;
+ }
+}
+
+public function poll(): void
+{
+ $this->session->refresh();
+ if ($this->session->isEnded()) {
+ $this->pollingInterval = 0;
+ }
+}
+```
+
+**Evidence - View polling directive (session-detail.blade.php line 1):**
+```blade
+
+```
+
+**Polling behaviour:**
+- 5-second interval for active sessions
+- Automatically disabled when session ends
+- Refreshes session data on each poll ✅
+
+#### AC9: Session detail shows: work log, artifacts, handoff notes ✅
+
+**Method:** Code inspection of `session-detail.blade.php`
+
+**Evidence - Work Log (lines 143-188):**
+```blade
+
+
+ Work Log
+
+ @foreach($this->recentWorkLog as $entry)
+
+ @endforeach
+
+```
+
+**Evidence - Artifacts (lines 228-257):**
+```blade
+
+ Artifacts
+ @foreach($this->artifacts as $artifact)
+
+ @endforeach
+
+```
+
+**Evidence - Handoff Notes (lines 259-296):**
+```blade
+
+ Handoff Notes
+
+
+```
+
+**All three sections present with proper data display** ✅
+
+#### AC10: Can view session context summary and final summary ✅
+
+**Method:** Code inspection of `SessionDetail.php` and `session-detail.blade.php`
+
+**Evidence - Context Summary computed property (lines 69-73):**
+```php
+#[Computed]
+public function contextSummary(): ?array
+{
+ return $this->session->context_summary;
+}
+```
+
+**Evidence - Context Summary view (lines 110-141):**
+```blade
+@if($this->contextSummary)
+
+ Context Summary
+
+
+@endif
+```
+
+**Evidence - Final Summary view (lines 190-200):**
+```blade
+@if($session->final_summary)
+
+ Final Summary
+ {{ $session->final_summary }}
+
+@endif
+```
+
+**Both summary types displayed when present** ✅
+
+#### AC11: Timeline view shows session sequence within a plan ✅
+
+**Method:** Code inspection of `SessionDetail.php` and `session-detail.blade.php`
+
+**Evidence - Plan Sessions computed property (lines 75-85):**
+```php
+#[Computed]
+public function planSessions(): Collection
+{
+ if (! $this->session->agent_plan_id) {
+ return collect();
+ }
+ return AgentSession::where('agent_plan_id', $this->session->agent_plan_id)
+ ->orderBy('started_at')
+ ->get();
+}
+```
+
+**Evidence - Session Index (lines 87-102):**
+```php
+#[Computed]
+public function sessionIndex(): int
+{
+ // Returns 1-based index of current session in plan
+}
+```
+
+**Evidence - Timeline view (lines 71-105):**
+```blade
+@if($session->agent_plan_id && $this->planSessions->count() > 1)
+
+ Plan Timeline (Session {{ $this->sessionIndex }} of {{ $this->planSessions->count() }})
+
+ @foreach($this->planSessions as $index => $planSession)
+
+
+ @endforeach
+
+
+@endif
+```
+
+**Timeline shows:**
+- Session number in sequence (1 of N)
+- All sessions ordered by start time
+- Current session highlighted
+- Click to navigate to other sessions
+- Status indicators (active pulse, completed/failed colours) ✅
+
+#### AC12: Can pause/resume/fail active sessions manually ✅
+
+**Method:** Code inspection of `Sessions.php`, `SessionDetail.php`, and views
+
+**Evidence - Sessions.php list actions (lines 127-153):**
+```php
+public function pause(int $sessionId): void { $session->pause(); }
+public function resume(int $sessionId): void { $session->resume(); }
+public function complete(int $sessionId): void { $session->complete('...'); }
+public function fail(int $sessionId): void { $session->fail('...'); }
+```
+
+**Evidence - SessionDetail.php actions (lines 117-156):**
+```php
+public function pauseSession(): void { $this->session->pause(); }
+public function resumeSession(): void { $this->session->resume(); }
+public function completeSession(): void { $this->session->complete($this->completeSummary); }
+public function failSession(): void { $this->session->fail($this->failReason); }
+```
+
+**Evidence - Sessions list dropdown (sessions.blade.php lines 143-157):**
+```blade
+
+ @if($session->isActive())
+ Pause
+ @endif
+ @if($session->isPaused())
+ Resume
+ @endif
+ Complete
+ Fail
+
+```
+
+**Evidence - Session detail buttons (session-detail.blade.php lines 28-39):**
+```blade
+@if($session->isActive())
+
Pause
+@elseif($session->isPaused())
+
Resume
+@endif
+@if(!$session->isEnded())
+
Complete
+
Fail
+@endif
+```
+
+**Complete/Fail modals (lines 300-324):**
+- Complete modal with optional summary
+- Fail modal with reason input ✅
+
+### Phase 2 Summary
+
+| AC | Description | Evidence | Status |
+|----|-------------|----------|--------|
+| AC7 | Sessions route with filters | `routes/web.php:187-188`, `Sessions.php` query builder | ✅ PASS |
+| AC8 | Real-time polling | `wire:poll.5000ms`, disabled when session ends | ✅ PASS |
+| AC9 | Work log, artifacts, handoff notes | Three dedicated sections in `session-detail.blade.php` | ✅ PASS |
+| AC10 | Context and final summary | Computed properties + conditional display | ✅ PASS |
+| AC11 | Timeline view | Horizontal timeline with session sequence navigation | ✅ PASS |
+| AC12 | Manual session controls | Pause/Resume/Complete/Fail with modals | ✅ PASS |
+
+**Additional Implementation Verified:**
+- Hades access control in both components
+- Sidebar link at line 558 (`hub.agents.sessions`)
+- Dashboard quick link at line 160
+- Active session count indicator with animated pulse
+- Agent type badges (Opus/Sonnet/Haiku)
+- Status colour coding
+
+**Phase 2 Status:** ✅ VERIFIED — Ready for human approval
+
+---
+
+### Phase 3 Verification (2026-01-02 21:45)
+
+**Verification Agent:** Claude Opus 4.5
+**Verdict:** ✅ PASS - All Phase 3 acceptance criteria met
+
+#### AC13: Route `hub.agents.tools` shows MCP tool usage dashboard ✅
+
+**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/ToolAnalytics.php`
+
+**Evidence - Routes (lines 189-191):**
+```php
+/ Phase 3: Tool Analytics
+Route::get('/tools', \App\Livewire\Admin\Agent\ToolAnalytics::class)->name('tools');
+Route::get('/tools/calls', \App\Livewire\Admin\Agent\ToolCalls::class)->name('tools.calls');
+```
+
+**Evidence - ToolAnalytics.php (lines 17-18, 29-32):**
+```php
+#[Title('Tool Analytics')]
+class ToolAnalytics extends Component
+{
+ public function mount(): void
+ {
+ $this->checkHadesAccess();
+ }
+}
+```
+
+**Dashboard features:**
+- Stats cards: Total calls, Successful, Errors, Success rate, Unique tools (lines 51-111 in view)
+- Filters: Days (7/14/30/90), Workspace, Server (lines 15-48 in view)
+- Hades access control enforced ✅
+
+#### AC14: Top 10 tools by usage displayed ✅
+
+**Method:** Code inspection of `ToolAnalytics.php` and `tool-analytics.blade.php`
+
+**Evidence - ToolAnalytics.php (lines 77-88):**
+```php
+#[Computed]
+public function topTools(): Collection
+{
+ $workspaceId = $this->workspace ? (int) $this->workspace : null;
+ $tools = McpToolCallStat::getTopTools($this->days, 10, $workspaceId);
+
+ if ($this->server) {
+ $tools = $tools->filter(fn ($t) => $t->server_id === $this->server)->values();
+ }
+
+ return $tools->take(10);
+}
+```
+
+**Evidence - View (lines 168-236):**
+```blade
+
Top 10 Tools
+
+
+ | Tool | Server | Calls | Success Rate | Errors | Avg Duration |
+
+
+ @foreach($this->topTools as $tool)
+
+ @endforeach
+
+
+```
+
+**Top 10 tools displayed with:**
+- Tool name, Server ID
+- Total calls count
+- Success rate (colour-coded)
+- Error count
+- Average duration
+- Drill-down button ✅
+
+#### AC15: Daily trend chart (calls per day, 30-day window) ✅
+
+**Method:** Code inspection of `ToolAnalytics.php` and `tool-analytics.blade.php`
+
+**Evidence - ToolAnalytics.php (lines 90-96, 131-142):**
+```php
+#[Computed]
+public function dailyTrend(): Collection
+{
+ $workspaceId = $this->workspace ? (int) $this->workspace : null;
+ return McpToolCallStat::getDailyTrend($this->days, $workspaceId);
+}
+
+#[Computed]
+public function chartData(): array
+{
+ $trend = $this->dailyTrend;
+ return [
+ 'labels' => $trend->pluck('date')->map(fn ($d) => $d->format('M j'))->toArray(),
+ 'calls' => $trend->pluck('total_calls')->toArray(),
+ 'errors' => $trend->pluck('total_errors')->toArray(),
+ 'success_rates' => $trend->pluck('success_rate')->toArray(),
+ ];
+}
+```
+
+**Evidence - Chart.js integration (lines 272-346):**
+```blade
+
+
+```
+
+**Chart features:**
+- Line chart with Chart.js
+- Configurable window: 7/14/30/90 days (view line 19-24)
+- Shows Total Calls (violet) and Errors (red)
+- Dark mode support
+- Responsive design ✅
+
+#### AC16: Server breakdown shows usage by MCP server ✅
+
+**Method:** Code inspection of `ToolAnalytics.php` and `tool-analytics.blade.php`
+
+**Evidence - ToolAnalytics.php (lines 98-109):**
+```php
+#[Computed]
+public function serverStats(): Collection
+{
+ $workspaceId = $this->workspace ? (int) $this->workspace : null;
+ $stats = McpToolCallStat::getServerStats($this->days, $workspaceId);
+
+ if ($this->server) {
+ $stats = $stats->filter(fn ($s) => $s->server_id === $this->server)->values();
+ }
+
+ return $stats;
+}
+```
+
+**Evidence - View (lines 132-165):**
+```blade
+
Server Breakdown
+@foreach($this->serverStats as $serverStat)
+
+
{{ $serverStat->server_id }}
+
{{ number_format($serverStat->total_calls) }} calls
+
+
{{ $serverStat->unique_tools }} tools
+
{{ $serverStat->success_rate }}% success
+
+@endforeach
+```
+
+**Server breakdown shows:**
+- Server ID
+- Total call count
+- Visual progress bar (relative to max)
+- Unique tools count
+- Success rate (colour-coded) ✅
+
+#### AC17: Error rate and average duration displayed per tool ✅
+
+**Method:** Code inspection of `tool-analytics.blade.php`
+
+**Evidence - Top Tools table columns (lines 183-218):**
+```blade
+
Success Rate |
+
Errors |
+
Avg Duration |
+...
+
+ {{ $tool->success_rate }}%
+ |
+
+ @if($tool->total_errors > 0)
+ {{ number_format($tool->total_errors) }}
+ @else
+ 0
+ @endif
+ |
+
+ @if($tool->avg_duration)
+ {{ round($tool->avg_duration) < 1000 ? round($tool->avg_duration) . 'ms' : round($tool->avg_duration / 1000, 2) . 's' }}
+ @endif
+ |
+```
+
+**Error/duration display features:**
+- Success rate with colour coding (green ≥95%, amber ≥80%, red <80%)
+- Error count highlighted in red when >0
+- Duration formatted as ms or seconds
+- Recent Errors section (lines 238-269) shows last 10 failures ✅
+
+#### AC18: Can drill down to individual tool calls with full params ✅
+
+**Method:** Code inspection of `ToolCalls.php` and `tool-calls.blade.php`
+
+**Evidence - ToolCalls.php (lines 133-151):**
+```php
+#[Computed]
+public function selectedCall(): ?McpToolCall
+{
+ if (! $this->selectedCallId) {
+ return null;
+ }
+ return McpToolCall::with('workspace')->find($this->selectedCallId);
+}
+
+public function viewCall(int $id): void
+{
+ $this->selectedCallId = $id;
+}
+
+public function closeCallDetail(): void
+{
+ $this->selectedCallId = null;
+}
+```
+
+**Evidence - View modal (lines 155-244):**
+```blade
+@if($selectedCall)
+
+ {{ $selectedCall->tool_name }}
+
+
+
+
+ {{-- Input Parameters --}}
+ @if($selectedCall->input_params && count($selectedCall->input_params) > 0)
+
+
{{ json_encode($selectedCall->input_params, JSON_PRETTY_PRINT) }}
+
+ @endif
+
+ {{-- Error Details --}}
+ @if(!$selectedCall->success)
+
+ Code: {{ $selectedCall->error_code }}
+ {{ $selectedCall->error_message }}
+
+ @endif
+
+ {{-- Result Summary --}}
+ @if($selectedCall->result_summary && count($selectedCall->result_summary) > 0)
+ {{ json_encode($selectedCall->result_summary, JSON_PRETTY_PRINT) }}
+ @endif
+
+@endif
+```
+
+**Drill-down features:**
+- Modal with full tool call details
+- Input parameters (JSON pretty-printed)
+- Result summary (JSON pretty-printed)
+- Error details (code + message) for failed calls
+- Metadata: duration, agent type, workspace, timestamp
+- Session and Plan links for traceability
+- Filters: server, tool, status, workspace, agent type
+- Pagination with 25 per page ✅
+
+### Phase 3 Summary
+
+| AC | Description | Evidence | Status |
+|----|-------------|----------|--------|
+| AC13 | Tool usage dashboard route | `routes/web.php:190`, `ToolAnalytics.php` with Hades auth | ✅ PASS |
+| AC14 | Top 10 tools by usage | `topTools()` computed, table with 6 columns | ✅ PASS |
+| AC15 | Daily trend chart | Chart.js line chart, configurable 7-90 days | ✅ PASS |
+| AC16 | Server breakdown | `serverStats()` computed, progress bars, success rates | ✅ PASS |
+| AC17 | Error rate and duration | Table columns + colour-coded success rate | ✅ PASS |
+| AC18 | Drill-down to tool calls | Modal with input_params, result_summary, error_details | ✅ PASS |
+
+**Additional Implementation Verified:**
+- Hades access control in both components
+- Sidebar link at `hub.agents.tools`
+- Dashboard quick link to Tool Analytics
+- Drill-down links from Top Tools table
+- Recent Errors section in dashboard
+- Comprehensive filtering in ToolCalls
+- Pagination with proper links
+
+**Phase 3 Status:** ✅ VERIFIED — Ready for human approval
+
+---
+
+### Phase 3 Implementation Notes (2026-01-02 21:30)
+
+**Implementation Agent:** Claude Opus 4.5
+
+**Routes Added (`routes/web.php`):**
+- `hub.agents.tools` → ToolAnalytics dashboard
+- `hub.agents.tools.calls` → ToolCalls drill-down list
+
+**Livewire Components Created:**
+- `app/Livewire/Admin/Agent/ToolAnalytics.php` - Dashboard with stats, charts, filters
+- `app/Livewire/Admin/Agent/ToolCalls.php` - Paginated call list with modal detail
+
+**Views Created:**
+- `resources/views/admin/livewire/agent/tool-analytics.blade.php`
+- `resources/views/admin/livewire/agent/tool-calls.blade.php`
+
+**Phase 5:** Not yet implemented (commented out in routes)
+
+---
+
+### Phase 4 Implementation Notes (2026-01-02 22:30)
+
+**Implementation Agent:** Claude Opus 4.5
+
+**Route Added (`routes/web.php`):**
+- `hub.agents.api-keys` → ApiKeys management
+
+**Model Created:**
+- `app/Models/Agent/AgentApiKey.php`
+ - Key generation with `ak_` prefix + 32 random chars
+ - SHA-256 hashing for storage
+ - Permission constants: `PERM_PLANS_READ`, `PERM_PLANS_WRITE`, `PERM_PHASES_WRITE`, `PERM_SESSIONS_READ`, `PERM_SESSIONS_WRITE`, `PERM_TOOLS_READ`, `PERM_TEMPLATES_READ`, `PERM_TEMPLATES_INSTANTIATE`
+ - Status helpers: `isActive()`, `isRevoked()`, `isExpired()`
+ - Scopes: `active()`, `revoked()`, `expired()`, `forWorkspace()`
+
+**Migration Created:**
+- `database/migrations/2026_01_02_220000_create_agent_api_keys_table.php`
+ - Creates `agent_api_keys` table with key, permissions (JSON), rate_limit, call_count, timestamps
+ - Adds `agent_api_key_id` foreign key to `agent_sessions` and `mcp_tool_calls`
+
+**Service Created:**
+- `app/Services/Agent/AgentApiKeyService.php`
+ - `create()` — Generate new key with permissions and rate limit
+ - `validate()` — Validate plaintext key and return model
+ - `checkPermission()`, `checkPermissions()` — Verify access
+ - `recordUsage()` — Increment call count and cache for rate limiting
+ - `isRateLimited()`, `getRateLimitStatus()` — Rate limiting helpers
+ - `authenticate()` — Full auth flow returning structured result
+ - `revoke()`, `updatePermissions()`, `updateRateLimit()`
+
+**Livewire Component Created:**
+- `app/Livewire/Admin/Agent/ApiKeys.php`
+ - Stats: total, active, revoked, total calls
+ - Filters: workspace, status
+ - Create modal: name, workspace, permissions, rate limit, expiry
+ - Created key modal: shows plaintext key ONCE
+ - Edit modal: update permissions and rate limit
+ - Revoke action with immediate effect
+
+**View Created:**
+- `resources/views/admin/livewire/agent/api-keys.blade.php`
+
+**Sidebar Updated:**
+- Added API Keys link to Agents submenu
+
+**Phase 4 Status:** ✅ COMPLETE — Ready for verification
+
+---
+
+### Phase 4 Verification (2026-01-02 23:15)
+
+**Verification Agent:** Claude Opus 4.5
+**Verdict:** ✅ PASS - All Phase 4 acceptance criteria met
+
+#### AC19: Route `hub.agents.api-keys` manages agent API access ✅
+
+**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/ApiKeys.php`
+
+**Evidence - Route (routes/web.php line 193):**
+```php
+Route::get('/api-keys', \App\Livewire\Admin\Agent\ApiKeys::class)->name('api-keys');
+```
+
+**Evidence - Sidebar link (sidebar.blade.php line 568):**
+```blade
+
API Keys
+```
+
+**Evidence - Hades access control (ApiKeys.php lines 49-55):**
+```php
+public function mount(): void
+{
+ $this->checkHadesAccess();
+}
+
+private function checkHadesAccess(): void
+{
+ if (! auth()->user()?->isHades()) {
+ abort(403, 'Hades access required');
+ }
+}
+```
+
+**Route exists and is accessible only to Hades users** ✅
+
+#### AC20: Can create API keys scoped to workspace ✅
+
+**Method:** Code inspection of `ApiKeys.php` and `api-keys.blade.php`
+
+**Evidence - ApiKeys.php createKey() (lines 89-116):**
+```php
+public function createKey(): void
+{
+ $this->validate([
+ 'newKeyName' => 'required|string|max:255',
+ 'newKeyWorkspace' => 'required|exists:workspaces,id',
+ 'newKeyPermissions' => 'array',
+ 'newKeyRateLimit' => 'required|integer|min:1|max:10000',
+ ]);
+
+ $key = $this->apiKeyService->create(
+ workspace: (int) $this->newKeyWorkspace,
+ name: $this->newKeyName,
+ permissions: $this->newKeyPermissions,
+ rateLimit: $this->newKeyRateLimit,
+ expiresAt: $this->newKeyExpiry ? Carbon::parse($this->newKeyExpiry) : null
+ );
+
+ $this->createdKey = $key->plainTextKey;
+ // ...
+}
+```
+
+**Evidence - View workspace dropdown (api-keys.blade.php lines 211-221):**
+```blade
+
+ Select workspace...
+ @foreach($this->workspaces as $ws)
+ {{ $ws->name }}
+ @endforeach
+
+```
+
+**Evidence - AgentApiKey model (lines 113-118):**
+```php
+public function scopeForWorkspace($query, Workspace|int $workspace)
+{
+ $workspaceId = $workspace instanceof Workspace ? $workspace->id : $workspace;
+ return $query->where('workspace_id', $workspaceId);
+}
+```
+
+**Keys are scoped to workspace via foreign key and workspace selector** ✅
+
+#### AC21: Keys have configurable permissions (read plans, write plans, execute tools) ✅
+
+**Method:** Code inspection of `AgentApiKey.php` and view
+
+**Evidence - Permission constants (AgentApiKey.php lines 63-78):**
+```php
+public const PERM_PLANS_READ = 'plans.read';
+public const PERM_PLANS_WRITE = 'plans.write';
+public const PERM_PHASES_WRITE = 'phases.write';
+public const PERM_SESSIONS_READ = 'sessions.read';
+public const PERM_SESSIONS_WRITE = 'sessions.write';
+public const PERM_TOOLS_READ = 'tools.read';
+public const PERM_TEMPLATES_READ = 'templates.read';
+public const PERM_TEMPLATES_INSTANTIATE = 'templates.instantiate';
+```
+
+**Evidence - availablePermissions() (lines 83-95):**
+```php
+public static function availablePermissions(): array
+{
+ return [
+ self::PERM_PLANS_READ => 'List and view plans',
+ self::PERM_PLANS_WRITE => 'Create, update, archive plans',
+ self::PERM_PHASES_WRITE => 'Update phase status, add/complete tasks',
+ self::PERM_SESSIONS_READ => 'List and view sessions',
+ self::PERM_SESSIONS_WRITE => 'Start, update, complete sessions',
+ self::PERM_TOOLS_READ => 'View tool analytics',
+ self::PERM_TEMPLATES_READ => 'List and view templates',
+ self::PERM_TEMPLATES_INSTANTIATE => 'Create plans from templates',
+ ];
+}
+```
+
+**Evidence - View permission checkboxes (api-keys.blade.php lines 227-237):**
+```blade
+
+ @foreach(\Mod\Agentic\Models\AgentApiKey::availablePermissions() as $perm => $description)
+
+ @endforeach
+
+```
+
+**Evidence - Permission helpers (AgentApiKey.php lines 195-220):**
+```php
+public function hasPermission(string $permission): bool
+public function hasAnyPermission(array $permissions): bool
+public function hasAllPermissions(array $permissions): bool
+```
+
+**8 configurable permissions with checkboxes in create/edit modals** ✅
+
+#### AC22: Key usage tracking (last used, call count) ✅
+
+**Method:** Code inspection of model, service, and view
+
+**Evidence - Migration fields (migration lines 24-25):**
+```php
+$table->unsignedBigInteger('call_count')->default(0);
+$table->timestamp('last_used_at')->nullable();
+```
+
+**Evidence - AgentApiKey recordUsage() (lines 230-236):**
+```php
+public function recordUsage(): self
+{
+ $this->increment('call_count');
+ $this->update(['last_used_at' => now()]);
+ return $this;
+}
+```
+
+**Evidence - AgentApiKeyService recordUsage() (lines 79-91):**
+```php
+public function recordUsage(AgentApiKey $key): void
+{
+ $key->recordUsage();
+ // Increment rate limit counter in cache
+ $cacheKey = $this->getRateLimitCacheKey($key);
+ Cache::increment($cacheKey);
+ // ...
+}
+```
+
+**Evidence - View table columns (api-keys.blade.php lines 106-118):**
+```blade
+
{{ number_format($key->call_count) }} |
+
{{ $key->getLastUsedForHumans() }} |
+```
+
+**Evidence - Stats card (api-keys.blade.php lines 54-59):**
+```blade
+
{{ number_format($this->stats['total_calls']) }}
+
Total Calls
+```
+
+**Usage tracked via call_count + last_used_at, displayed in table and stats** ✅
+
+#### AC23: Can revoke keys immediately ✅
+
+**Method:** Code inspection of service, model, and Livewire component
+
+**Evidence - AgentApiKey revoke() (lines 223-228):**
+```php
+public function revoke(): self
+{
+ $this->update(['revoked_at' => now()]);
+ return $this;
+}
+```
+
+**Evidence - AgentApiKeyService revoke() (lines 129-135):**
+```php
+public function revoke(AgentApiKey $key): void
+{
+ $key->revoke();
+ // Clear rate limit cache
+ Cache::forget($this->getRateLimitCacheKey($key));
+}
+```
+
+**Evidence - ApiKeys.php revokeKey() (lines 118-128):**
+```php
+public function revokeKey(int $keyId): void
+{
+ $key = AgentApiKey::findOrFail($keyId);
+ $this->apiKeyService->revoke($key);
+ Flux::toast(
+ heading: 'API Key Revoked',
+ text: "Key '{$key->name}' has been revoked and can no longer be used.",
+ variant: 'warning',
+ );
+}
+```
+
+**Evidence - View revoke button (api-keys.blade.php line 133):**
+```blade
+
+ Revoke Key
+
+```
+
+**Evidence - isRevoked helper (AgentApiKey.php lines 184-187):**
+```php
+public function isRevoked(): bool
+{
+ return $this->revoked_at !== null;
+}
+```
+
+**Revocation sets revoked_at timestamp, clears cache, shows confirmation** ✅
+
+#### AC24: Rate limiting configuration per key ✅
+
+**Method:** Code inspection of model, service, and view
+
+**Evidence - Migration field (line 23):**
+```php
+$table->integer('rate_limit')->default(100); // Calls per minute
+```
+
+**Evidence - AgentApiKeyService rate limiting (lines 96-124):**
+```php
+public function isRateLimited(AgentApiKey $key): bool
+{
+ $cacheKey = $this->getRateLimitCacheKey($key);
+ $currentCalls = (int) Cache::get($cacheKey, 0);
+ return $currentCalls >= $key->rate_limit;
+}
+
+public function getRateLimitStatus(AgentApiKey $key): array
+{
+ $cacheKey = $this->getRateLimitCacheKey($key);
+ $currentCalls = (int) Cache::get($cacheKey, 0);
+ $remaining = max(0, $key->rate_limit - $currentCalls);
+ // ...
+ return [
+ 'limit' => $key->rate_limit,
+ 'remaining' => $remaining,
+ 'reset_in_seconds' => max(0, $ttl),
+ 'used' => $currentCalls,
+ ];
+}
+```
+
+**Evidence - authenticate() rate limiting check (lines 253-262):**
+```php
+if ($this->isRateLimited($key)) {
+ $status = $this->getRateLimitStatus($key);
+ return [
+ 'success' => false,
+ 'error' => 'rate_limited',
+ 'message' => 'Rate limit exceeded',
+ 'rate_limit' => $status,
+ ];
+}
+```
+
+**Evidence - View rate limit input (api-keys.blade.php lines 239-241):**
+```blade
+
+```
+
+**Evidence - Table column (api-keys.blade.php line 102):**
+```blade
+
{{ $key->rate_limit }}/min |
+```
+
+**Evidence - Edit modal rate limit (api-keys.blade.php lines 334-336):**
+```blade
+
+```
+
+**Rate limit configurable 1-10000 calls/min, enforced via Cache with 60s window** ✅
+
+### Phase 4 Summary
+
+| AC | Description | Evidence | Status |
+|----|-------------|----------|--------|
+| AC19 | Route manages API access | `routes/web.php:193`, Hades auth, sidebar link | ✅ PASS |
+| AC20 | Keys scoped to workspace | `workspace_id` FK, workspace dropdown in create modal | ✅ PASS |
+| AC21 | Configurable permissions | 8 permissions with checkboxes, `hasPermission()` helpers | ✅ PASS |
+| AC22 | Usage tracking | `call_count` + `last_used_at` fields, displayed in UI | ✅ PASS |
+| AC23 | Immediate revocation | `revoke()` sets timestamp, clears cache, confirmation dialog | ✅ PASS |
+| AC24 | Rate limiting per key | Configurable 1-10000/min, Cache-based enforcement | ✅ PASS |
+
+**Additional Implementation Verified:**
+- Hades access control in component
+- Sidebar link at line 568
+- Stats cards: total, active, revoked, total calls
+- Create modal shows plaintext key ONCE
+- Edit modal for permissions and rate limit updates
+- Key expiry support (optional)
+- Filter by workspace and status (active/revoked/expired)
+- Foreign keys added to `agent_sessions` and `mcp_tool_calls` for tracking
+
+**Phase 4 Status:** ✅ VERIFIED — Ready for human approval
+
+---
+
+### Phase 5 Implementation Notes (2026-01-02 23:45)
+
+**Implementation Agent:** Claude Opus 4.5
+
+**Route Added (`routes/web.php`):**
+- `hub.agents.templates` → Templates browser
+
+**Livewire Component Created:**
+- `app/Livewire/Admin/Agent/Templates.php`
+ - Uses existing `PlanTemplateService` for all template operations
+ - Template listing with category filter and search
+ - Preview modal showing phases, tasks, variables, guidelines
+ - Create plan modal with variable inputs and workspace selection
+ - YAML import modal with file upload, validation, and preview
+ - Delete template functionality
+
+**View Created:**
+- `resources/views/admin/livewire/agent/templates.blade.php`
+ - Stats cards: total templates, categories, total phases, with variables
+ - Grid layout for template cards
+ - Category colour coding
+ - Preview modal with full template details
+ - Create modal with variable input fields
+ - Import modal with drag-drop file upload
+
+**Sidebar Updated:**
+- Added Templates link to Agents submenu
+
+**Dashboard Updated:**
+- Templates quick link now active (was "Coming soon")
+
+**Existing Templates (5):**
+- `bug-fix.yaml` - Bug fix workflow
+- `code-review.yaml` - Code review process
+- `feature-port.yaml` - Feature porting
+- `new-feature.yaml` - New feature development
+- `refactor.yaml` - Code refactoring
+
+**Phase 5 Status:** ✅ COMPLETE — Ready for verification
+
+---
+
+### Phase 5 Verification (2026-01-02 23:45)
+
+**Verification Agent:** Claude Opus 4.5
+**Verdict:** ✅ PASS - All Phase 5 acceptance criteria met
+
+#### AC25: Route `hub.agents.templates` lists available plan templates ✅
+
+**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/Templates.php`
+
+**Evidence - Route (routes/web.php line 195):**
+```php
+Route::get('/templates', \App\Livewire\Admin\Agent\Templates::class)->name('templates');
+```
+
+**Evidence - Sidebar link (sidebar.blade.php lines 573-574):**
+```blade
+
+ Templates
+```
+
+**Evidence - Templates.php templates() computed property (lines 76-93):**
+```php
+#[Computed]
+public function templates(): Collection
+{
+ $templates = $this->templateService->list();
+
+ if ($this->category) {
+ $templates = $templates->filter(fn ($t) => $t['category'] === $this->category);
+ }
+
+ if ($this->search) {
+ $search = strtolower($this->search);
+ $templates = $templates->filter(fn ($t) => ...);
+ }
+
+ return $templates->values();
+}
+```
+
+**Evidence - View grid (templates.blade.php lines 60-149):**
+```blade
+
+ @foreach($this->templates as $template)
+
+
+
+ @endforeach
+
+```
+
+**5 templates available:** bug-fix, code-review, feature-port, new-feature, refactor ✅
+
+#### AC26: Template preview shows phases and variables ✅
+
+**Method:** Code inspection of `Templates.php` and `templates.blade.php`
+
+**Evidence - previewTemplate() computed property (Templates.php lines 107-115):**
+```php
+#[Computed]
+public function previewTemplate(): ?array
+{
+ if (! $this->previewSlug) {
+ return null;
+ }
+ return $this->templateService->previewTemplate($this->previewSlug, []);
+}
+```
+
+**Evidence - Preview modal phases (templates.blade.php lines 207-235):**
+```blade
+Phases ({{ count($this->previewTemplate['phases']) }})
+
+ @foreach($this->previewTemplate['phases'] as $index => $phase)
+
+
{{ $phase['order'] }}
+
{{ $phase['name'] }}
+ @if(!empty($phase['tasks']))
+
+ @foreach($phase['tasks'] as $task)
+ - {{ is_array($task) ? $task['name'] : $task }}
+ @endforeach
+
+ @endif
+
+ @endforeach
+
+```
+
+**Evidence - Preview modal variables table (templates.blade.php lines 237-274):**
+```blade
+@if(!empty($variables))
+ Variables
+
+
+ | Variable | Description | Default | Required |
+
+
+ @foreach($variables as $name => $config)
+
+ | {{ $name }} |
+ {{ $config['description'] ?? '-' }} |
+ {{ $config['default'] ?? '-' }} |
+ {{ $config['required'] ? 'Yes' : 'No' }} |
+
+ @endforeach
+
+
+@endif
+```
+
+**Preview shows:** Phases with order/name/tasks, Variables with name/description/default/required, Guidelines ✅
+
+#### AC27: Can create new plan from template with variable input ✅
+
+**Method:** Code inspection of `Templates.php` and `templates.blade.php`
+
+**Evidence - openCreateModal() (Templates.php lines 162-188):**
+```php
+public function openCreateModal(string $slug): void
+{
+ $template = $this->templateService->get($slug);
+ $this->createTemplateSlug = $slug;
+ $this->createTitle = $template['name'];
+ $this->createWorkspaceId = $this->workspaces->first()?->id ?? 0;
+
+ // Initialise variables with defaults
+ $this->createVariables = [];
+ foreach ($template['variables'] ?? [] as $name => $config) {
+ $this->createVariables[$name] = $config['default'] ?? '';
+ }
+ $this->showCreateModal = true;
+}
+```
+
+**Evidence - createPlan() (Templates.php lines 198-272):**
+```php
+public function createPlan(): void
+{
+ // Validate required variables
+ $this->validate([
+ 'createWorkspaceId' => 'required|exists:workspaces,id',
+ 'createTitle' => 'required|string|max:255',
+ ]);
+
+ // Add variable validation
+ foreach ($template['variables'] ?? [] as $name => $config) {
+ if ($config['required'] ?? false) {
+ $rules["createVariables.{$name}"] = 'required|string';
+ }
+ }
+
+ // Create the plan via service
+ $plan = $this->templateService->createPlan(
+ $this->createTemplateSlug,
+ $this->createVariables,
+ ['title' => $this->createTitle, 'activate' => $this->createActivate],
+ $workspace
+ );
+
+ // Redirect to new plan
+ $this->redirect(route('hub.agents.plans.show', $plan->slug), navigate: true);
+}
+```
+
+**Evidence - Create modal with variable inputs (templates.blade.php lines 319-341):**
+```blade
+@if(!empty($this->createTemplate['variables']))
+
Template Variables
+
+ @foreach($this->createTemplate['variables'] as $name => $config)
+
+ @endforeach
+
+@endif
+```
+
+**Create plan features:** Plan title, Workspace selection, Variable inputs, Activate immediately option, Live preview ✅
+
+#### AC28: Template categories displayed for organisation ✅
+
+**Method:** Code inspection of `Templates.php`, `PlanTemplateService.php`, and view
+
+**Evidence - categories() computed property (Templates.php lines 95-99):**
+```php
+#[Computed]
+public function categories(): Collection
+{
+ return $this->templateService->getCategories();
+}
+```
+
+**Evidence - PlanTemplateService getCategories() (lines 319-326):**
+```php
+public function getCategories(): Collection
+{
+ return $this->list()
+ ->pluck('category')
+ ->unique()
+ ->sort()
+ ->values();
+}
+```
+
+**Evidence - Category filter dropdown (templates.blade.php lines 45-50):**
+```blade
+
+ All Categories
+ @foreach($this->categories as $cat)
+ {{ ucfirst($cat) }}
+ @endforeach
+
+```
+
+**Evidence - Category badge in template cards (templates.blade.php lines 69-71):**
+```blade
+
+ {{ ucfirst($template['category']) }}
+
+```
+
+**Evidence - Category colour coding (Templates.php lines 436-446):**
+```php
+public function getCategoryColor(string $category): string
+{
+ return match ($category) {
+ 'development' => 'bg-blue-100 text-blue-700 ...',
+ 'maintenance' => 'bg-green-100 text-green-700 ...',
+ 'review' => 'bg-amber-100 text-amber-700 ...',
+ 'migration' => 'bg-purple-100 text-purple-700 ...',
+ 'custom' => 'bg-zinc-100 text-zinc-700 ...',
+ default => 'bg-violet-100 text-violet-700 ...',
+ };
+}
+```
+
+**Category features:** Filter dropdown, Colour-coded badges, Stats showing category count ✅
+
+#### AC29: Can import custom templates (YAML upload) ✅
+
+**Method:** Code inspection of `Templates.php` and `templates.blade.php`
+
+**Evidence - Import modal state (Templates.php lines 53-62):**
+```php
+public bool $showImportModal = false;
+public ?UploadedFile $importFile = null;
+public string $importFileName = '';
+public ?array $importPreview = null;
+public ?string $importError = null;
+```
+
+**Evidence - updatedImportFile() validation (Templates.php lines 293-351):**
+```php
+public function updatedImportFile(): void
+{
+ $content = file_get_contents($this->importFile->getRealPath());
+ $parsed = Yaml::parse($content);
+
+ // Validate basic structure
+ if (! is_array($parsed)) {
+ $this->importError = 'Invalid YAML format: expected an object.';
+ return;
+ }
+ if (! isset($parsed['name'])) {
+ $this->importError = 'Template must have a "name" field.';
+ return;
+ }
+ if (! isset($parsed['phases']) || ! is_array($parsed['phases'])) {
+ $this->importError = 'Template must have a "phases" array.';
+ return;
+ }
+
+ // Build preview
+ $this->importPreview = [
+ 'name' => $parsed['name'],
+ 'description' => $parsed['description'] ?? null,
+ 'category' => $parsed['category'] ?? 'custom',
+ 'phases_count' => count($parsed['phases']),
+ 'variables_count' => count($parsed['variables'] ?? []),
+ ];
+}
+```
+
+**Evidence - importTemplate() save (Templates.php lines 353-397):**
+```php
+public function importTemplate(): void
+{
+ $this->validate([
+ 'importFileName' => 'required|string|regex:/^[a-z0-9-]+$/|max:64',
+ ]);
+
+ $content = file_get_contents($this->importFile->getRealPath());
+ $targetPath = resource_path("plan-templates/{$this->importFileName}.yaml");
+
+ // Check for existing file
+ if (File::exists($targetPath)) {
+ $this->importError = 'A template with this filename already exists.';
+ return;
+ }
+
+ // Save the file
+ File::put($targetPath, $content);
+
+ Flux::toast(heading: 'Template Imported', ...);
+}
+```
+
+**Evidence - Import modal with file upload (templates.blade.php lines 381-476):**
+```blade
+
+ Import Template
+
+ {{-- File Upload --}}
+
+
+
+
+ {{-- Preview --}}
+ @if($importPreview)
+
+ - Name:
- {{ $importPreview['name'] }}
+ - Category:
- {{ $importPreview['category'] }}
+ - Phases:
- {{ $importPreview['phases_count'] }}
+ - Variables:
- {{ $importPreview['variables_count'] }}
+
+
+
+ @endif
+
+ Import Template
+
+```
+
+**Import features:** YAML file upload, Validation (structure, name, phases), Preview before import, Custom filename, Duplicate detection ✅
+
+### Phase 5 Summary
+
+| AC | Description | Evidence | Status |
+|----|-------------|----------|--------|
+| AC25 | Route lists templates | `routes/web.php:195`, `templates()` computed, grid layout | ✅ PASS |
+| AC26 | Preview shows phases/variables | `previewTemplate()`, modal with phases list + variables table | ✅ PASS |
+| AC27 | Create plan with variables | `createPlan()`, variable inputs in modal, validation | ✅ PASS |
+| AC28 | Categories displayed | `getCategories()`, filter dropdown, colour-coded badges | ✅ PASS |
+| AC29 | YAML import | `importTemplate()`, file upload, validation, preview | ✅ PASS |
+
+**Additional Implementation Verified:**
+- Hades access control in component (`checkHadesAccess()`)
+- Sidebar link at line 573
+- Dashboard quick link activated
+- Template deletion with confirmation
+- 5 templates available: bug-fix, code-review, feature-port, new-feature, refactor
+- Stats cards: total templates, categories, phases, with variables
+- Search functionality with debounce
+- Category colour coding for visual organisation
+
+**Phase 5 Status:** ✅ VERIFIED — Ready for human approval
+
+---
+
+## Implementation Hints (Added by Planning Agent)
+
+### Existing Code Reference
+
+**Agent models already exist** — don't recreate them:
+
+| Model | Location | Key Methods |
+|-------|----------|-------------|
+| `AgentPlan` | `app/Models/Agent/AgentPlan.php` | `getProgress()`, `getCurrentPhase()`, `activate()`, `complete()`, `archive()`, `toMcpContext()` |
+| `AgentPhase` | `app/Models/Agent/AgentPhase.php` | Status constants: `STATUS_PENDING`, `STATUS_IN_PROGRESS`, `STATUS_COMPLETED`, `STATUS_BLOCKED`, `STATUS_SKIPPED` |
+| `AgentSession` | `app/Models/Agent/AgentSession.php` | `start()`, `pause()`, `resume()`, `complete()`, `fail()`, `logAction()`, `prepareHandoff()`, `getDurationFormatted()` |
+| `McpToolCallStat` | `app/Models/Mcp/McpToolCallStat.php` | `getTopTools()`, `getDailyTrend()`, `getServerStats()` — these are ready-made for dashboards |
+
+### Hades Auth Pattern
+
+Follow existing pattern from other Hades-only components:
+
+```php
+// In mount() method
+public function mount(): void
+{
+ if (!auth()->user()?->isHades()) {
+ abort(403);
+ }
+ // ... rest of mount
+}
+```
+
+See examples: `PackageManager.php:21`, `FeatureManager.php:20`, `Platform.php:36`
+
+### Sidebar Integration
+
+Add to `resources/views/admin/components/sidebar.blade.php` **after line 376** (before the closing `` of the Hades section), using the existing pattern:
+
+```blade
+{{-- Agent Operations --}}
+
+
+
+
+
+
+```
+
+### Admin Layout Pattern
+
+Use existing admin layout:
+
+```php
+public function render()
+{
+ return view('admin.admin.agent.dashboard')
+ ->layout('admin.layouts.app', ['title' => 'Agent Dashboard']);
+}
+```
+
+### View Location
+
+Views go in `resources/views/admin/livewire/agent/` (matches other admin components)
+
+### Dashboard Queries (Ready to Use)
+
+```php
+// These methods already exist on McpToolCallStat
+$topTools = McpToolCallStat::getTopTools(days: 7, limit: 10);
+$dailyTrend = McpToolCallStat::getDailyTrend(days: 7);
+$serverStats = McpToolCallStat::getServerStats(days: 7);
+
+// AgentPlan queries
+$activePlans = AgentPlan::active()->with(['workspace', 'agentPhases'])->count();
+$activeSessions = AgentSession::active()->count();
+```
+
+### Routes Location
+
+Add after line 164 in `routes/web.php` (inside the hub group, after Commerce routes):
+
+```php
+// Check existing structure at lines 131-169 for context
+```
+
+---
+
+*This task creates the human interface for supervising AI agent operations.*
diff --git a/changelog/2026/jan/agentic-tasks-readme.md b/changelog/2026/jan/agentic-tasks-readme.md
new file mode 100644
index 0000000..0797800
--- /dev/null
+++ b/changelog/2026/jan/agentic-tasks-readme.md
@@ -0,0 +1,186 @@
+# Agentic Task System
+
+MCP-powered workspace for persistent work plans that survive context limits and enable multi-agent collaboration.
+
+## Why this exists
+
+- **Context persistence** - Work plans persist across Claude sessions, surviving context window limits
+- **Multi-agent collaboration** - Handoff support between different agents with shared state
+- **Checkpoint verification** - Phase gates ensure work is complete before progressing
+- **Structured planning** - Break complex tasks into phases with dependencies
+
+## Location
+
+```
+app/Models/Agent/AgentPlan.php
+app/Models/Agent/AgentPhase.php
+app/Models/Agent/AgentSession.php
+app/Models/Agent/WorkspaceState.php
+app/Console/Commands/Agent/McpAgentServerCommand.php
+```
+
+## Basic usage
+
+```bash
+# Create a new plan
+php artisan plan:create my-feature --title="Implement Feature X"
+
+# Import from markdown
+php artisan plan:create my-plan --import=PLAN.md --activate
+
+# List all plans
+php artisan plan:list
+php artisan plan:list --status=active
+
+# Show plan details
+php artisan plan:show my-plan
+php artisan plan:show my-plan --markdown
+
+# Check phase completion (checkpoint)
+php artisan plan:check my-plan
+php artisan plan:check my-plan 1 # Check specific phase
+
+# Manage phases
+php artisan plan:phase my-plan 1 --status=in_progress
+php artisan plan:phase my-plan 1 --add-task="Complete the migration"
+php artisan plan:phase my-plan 1 --complete-task=0
+```
+
+## Key methods
+
+### AgentPlan
+
+```php
+use Mod\Agentic\Models\AgentPlan;
+
+// Create a plan
+$plan = AgentPlan::create([
+ 'slug' => 'my-feature',
+ 'title' => 'Implement Feature X',
+ 'status' => AgentPlan::STATUS_ACTIVE,
+]);
+
+// Get current phase
+$phase = $plan->getCurrentPhase();
+// Returns: AgentPhase or null
+
+// Check completion
+$plan->checkAllPhasesComplete();
+// Returns: bool
+```
+
+### AgentPhase
+
+```php
+use Mod\Agentic\Models\AgentPhase;
+
+// Start a phase
+$phase->start();
+// Returns: self (status changed to in_progress)
+
+// Complete a phase (with transaction protection)
+$phase->complete();
+// Returns: self (status changed to completed, plan auto-completes if all done)
+
+// Check if phase can start (dependencies met)
+$phase->canStart();
+// Returns: bool
+```
+
+### WorkspaceState
+
+```php
+use Mod\Agentic\Models\WorkspaceState;
+
+// Store shared state
+WorkspaceState::setValue($plan, 'api_findings', ['endpoints' => 12]);
+
+// Retrieve state
+$value = WorkspaceState::getValue($plan, 'api_findings');
+// Returns: array or null
+```
+
+## Example: Checkpoint pattern
+
+The checkpoint pattern ensures agents verify previous work before progressing:
+
+```
+Agent: "Starting Phase 3"
+ ↓
+MCP: phase_check(plan_slug, phase=2)
+ ↓
+Returns: {
+ "complete": false,
+ "remaining_tasks": ["Task 2.4", "Task 2.5"],
+ "message": "Phase 2 not complete. 2 tasks remaining."
+}
+ ↓
+Agent: "Completing remaining Phase 2 tasks first..."
+```
+
+## Configuration
+
+MCP server configuration for Claude Code:
+
+```json
+{
+ "mcpServers": {
+ "hosthub-agent": {
+ "command": "php",
+ "args": ["artisan", "mcp:agent-server"],
+ "cwd": "/path/to/host.uk.com"
+ }
+ }
+}
+```
+
+## How it works
+
+```
+1. Plan created with phases (via CLI or MCP)
+2. Agent starts session and binds to plan
+3. Agent works through phases, logging actions
+4. Checkpoint verification before phase transitions
+5. Workspace state shared between agents
+6. Handoff notes preserved for context continuity
+```
+
+## MCP Tools
+
+| Tool | Purpose |
+|------|---------|
+| `plan_create` | Create new plan with phases |
+| `plan_get` | Get plan by slug with all phases |
+| `plan_list` | List plans (optionally filtered) |
+| `plan_update` | Update plan status/metadata |
+| `phase_update` | Update phase status |
+| `phase_check` | Verify phase completion |
+| `task_add` | Add task to a phase |
+| `task_complete` | Mark task done |
+| `session_start` | Begin agent session |
+| `session_log` | Log action to session |
+| `session_artifact` | Log file artifact |
+| `session_handoff` | Prepare for agent handoff |
+| `session_resume` | Resume from previous session |
+| `session_complete` | Mark session completed |
+| `state_set` | Store workspace state |
+| `state_get` | Retrieve workspace state |
+| `state_list` | List all state keys |
+| `state_delete` | Delete state key |
+
+## MCP Resources
+
+| URI | Purpose |
+|-----|---------|
+| `hosthub://plans` | List of all work plans |
+| `hosthub://plans/{slug}` | Full plan as markdown |
+| `hosthub://plans/{slug}/phase/{n}` | Phase tasks as checklist |
+| `hosthub://state/{plan}/{key}` | Specific state value |
+| `hosthub://sessions/{id}` | Session handoff context |
+
+## Related services
+
+- `Task` model - Simple task tracking (different purpose)
+- `ContentTask` model - Content generation tasks
+
+See also: `doc/dev-feat-docs/agentic-tasks/PORTING_PLAN.md` for implementation details.
diff --git a/changelog/2026/jan/code-review.md b/changelog/2026/jan/code-review.md
new file mode 100644
index 0000000..d32795e
--- /dev/null
+++ b/changelog/2026/jan/code-review.md
@@ -0,0 +1,107 @@
+# Agentic Module Review
+
+**Updated:** 2026-01-21 - OpenAI pricing, MCP token lookup, and Boot.php cleanup verified complete
+
+## Overview
+
+The Agentic module provides AI agent infrastructure for Host Hub, including:
+
+1. **Multi-provider AI abstraction** - Unified interface for Claude, Gemini, and OpenAI APIs
+2. **Agent work plans** - Structured task tracking with phases, dependencies, and progress
+3. **Session management** - Track agent work sessions for handoff and context recovery
+4. **API key management** - Workspace-scoped keys with permissions and rate limiting
+5. **Plan templates** - YAML-based reusable plan structures
+6. **Content generation pipeline** - Batch content generation with quality validation
+7. **Agent detection** - Identify AI agents from HTTP requests (Trees for Agents)
+8. **Admin dashboard** - Hades-only admin panel for monitoring agent operations
+
+## Production Readiness Score: 88/100 (was 85/100 - Additional improvements 2026-01-21)
+
+The module has solid foundational architecture. Critical issues fixed in Wave 2. All recommended improvements now implemented. OpenAI pricing, MCP token database lookup, and Boot.php cleanup completed.
+
+## Critical Issues (Must Fix)
+
+- [x] **Missing `agent_api_keys` table migration** - FIXED: Migration exists at `Migrations/2026_01_15_090000_create_agent_api_keys_table.php`.
+- [x] **Missing `tasks` table migration** - FIXED: Migration exists at `Migrations/2026_01_15_090001_create_tasks_table.php`. Task model updated with `BelongsToWorkspace` trait and `workspace_id` in fillable.
+- [x] **`AgenticResponse::estimateCost()` missing OpenAI pricing** - FIXED: Pricing array now includes GPT-4o, GPT-4o-mini, GPT-4-turbo, GPT-4, GPT-3.5-turbo, o1, o1-mini, and o1-preview models.
+- [x] **`AgentApiKey::getRecentCallCount()` is a stub** - FIXED: Now reads from cache key `agent_api_key_rate:{id}` which is incremented by `AgentApiKeyService::recordUsage()`.
+- [x] **`PlanCommand`/`TaskCommand` missing workspace scope** - FIXED: Both commands now require `--workspace=ID` option or authenticated user context. All queries scoped via `forWorkspace()` to prevent data leakage.
+
+## Recommended Improvements
+
+- [x] **Add retry logic to AI provider services** - FIXED: HasRetry trait added with exponential backoff for transient failures.
+- [x] **Stream parsing is fragile** - FIXED: HasStreamParsing trait added for robust chunked response handling.
+- [x] **ContentService uses hardcoded paths** - FIXED: `$batchPath`, `$promptPath`, `$draftsPath` now use config values.
+- [x] **AgentApiKeyService rate limit TTL is incorrect** - FIXED: Now uses `Cache::add()` with TTL to prevent race condition.
+- [x] **Missing validation on PlanTemplateService variable substitution** - FIXED: JSON escaping added to prevent data corruption from special characters.
+- [x] **Dashboard queries not optimised** - FIXED: `cacheWithLock` added to prevent cache stampede.
+- [x] **Add middleware for admin routes** - FIXED: RequireHades middleware now applied to `/hub/agents/*` routes.
+- [x] **Add request validation to ForAgentsController** - FIXED: Rate limiting and caching added.
+
+## Missing Features (Future)
+
+- [x] **MCP tool handlers commented out** - FIXED: `Boot::onMcpTools()` now has clean documentation explaining that agent tools are registered in Mcp module via AgentToolRegistry.
+- [x] **MCP token lookup not implemented** - FIXED: `AgentDetection::identifyFromMcpToken()` now supports opaque `ak_` prefix tokens with database lookup via `AgentApiKey::findByKey()`, plus structured `provider:model:secret` format.
+- [ ] **No tests for AgentApiKey model** - Unlike other models (AgentPlan, AgentPhase, AgentSession), AgentApiKey has no dedicated test file.
+- [ ] **No tests for AI provider services** - ClaudeService, GeminiService, OpenAIService have no unit tests.
+- [ ] **No tests for AgentApiKeyService** - Service has complex authentication logic but no tests.
+- [ ] **No tests for AgentDetection** - User-Agent pattern matching logic is untested.
+- [ ] **No tests for PlanTemplateService** - Variable substitution and plan creation untested.
+- [ ] **Missing admin panel tests for all Livewire components** - Only `UseCase/AdminPanelBasic.php` exists but may not execute (uses non-standard test syntax).
+- [ ] **GenerateCommand depends on Content module** - Uses `Mod\Content\Models\ContentBrief`, `Mod\Content\Jobs\GenerateContentJob`, etc. Should verify Content module is always loaded.
+
+## Test Coverage Assessment
+
+**Current test files:**
+- `Tests/Feature/AgentPlanTest.php` - 17 tests, good coverage of plan lifecycle
+- `Tests/Feature/AgentPhaseTest.php` - 17 tests, good coverage of phase operations
+- `Tests/Feature/AgentSessionTest.php` - 22 tests, thorough session tracking tests
+- `Tests/Feature/ContentServiceTest.php` - 4 tests, basic coverage using mocks
+- `Tests/UseCase/AdminPanelBasic.php` - UI acceptance tests (may not be functional)
+
+**Coverage gaps:**
+- No unit tests for any of the 11 services
+- No tests for 3 console commands
+- No tests for AgentApiKey model
+- No tests for Task model
+- No tests for admin Livewire components
+- No integration tests for AI provider APIs
+
+**Estimated coverage:** ~35% (models well-tested, services untested)
+
+## Security Concerns
+
+1. **API key stored as SHA-256 hash only** - No salt used in `AgentApiKey::generate()`. While SHA-256 is acceptable, using `password_hash()` with Argon2 would be more secure for credential storage.
+
+2. **Rate limiting bypass** - FIXED: `getRecentCallCount()` now reads from cache, making rate limiting functional when `AgentApiKeyService::recordUsage()` is called.
+
+3. **No input validation on plan/template variables** - `PlanTemplateService::substituteVariables()` uses regex replacement without sanitising input, potentially allowing injection.
+
+4. **Admin routes lack middleware** - FIXED: RequireHades middleware now applied to admin routes.
+
+5. **ForAgentsController exposes internal URLs** - Returns hardcoded URLs to MCP registry and documentation that could be enumerated by attackers.
+
+6. **TaskCommand uses FIELD() with unescaped values** - `orderByRaw("FIELD(priority, 'urgent', 'high', 'normal', 'low')")` - while current usage is safe (status/priority are validated), this pattern is SQL injection prone if extended.
+
+## Notes
+
+**Architecture:** Well-structured following the modular monolith pattern. Boot.php properly uses event listeners for lazy loading. Services are appropriately separated.
+
+**Code quality:** Consistent use of strict types, proper PHPDoc annotations, and Eloquent conventions. Factory pattern for test data is well implemented.
+
+**Dependencies on other modules:**
+- `Mod\Tenant` - Workspace model and BelongsToWorkspace trait
+- `Mod\Mcp` - McpToolCallStat for dashboard analytics
+- `Mod\Content` - ContentBrief, AIUsage, GenerateContentJob (in GenerateCommand)
+
+**Files reviewed:**
+- `/app/Mod/Agentic/Boot.php`
+- `/app/Mod/Agentic/config.php`
+- `/app/Mod/Agentic/Migrations/2026_01_15_100000_create_agentic_tables.php`
+- All 11 models in `/app/Mod/Agentic/Models/`
+- All 9 services in `/app/Mod/Agentic/Services/`
+- All 3 console commands in `/app/Mod/Agentic/Console/Commands/`
+- `/app/Mod/Agentic/Controllers/ForAgentsController.php`
+- `/app/Mod/Agentic/Routes/admin.php`
+- All 4 test files in `/app/Mod/Agentic/Tests/`
+- `/app/Mod/Agentic/View/Modal/Admin/Dashboard.php`
diff --git a/changelog/2026/jan/features.md b/changelog/2026/jan/features.md
new file mode 100644
index 0000000..5bdd1b6
--- /dev/null
+++ b/changelog/2026/jan/features.md
@@ -0,0 +1,72 @@
+# Core-Agentic - January 2026
+
+## Features Implemented
+
+### Agent Plans Admin UI (TASK-006)
+
+Complete admin interface for managing agent work plans.
+
+**Components:**
+- Plan list with status filters
+- Plan editor with phases
+- Phase management (add, edit, reorder)
+- Progress tracking
+- Session viewer
+
+**Files:**
+- `View/Modal/Admin/PlanManager.php`
+- `View/Modal/Admin/PlanEditor.php`
+- `View/Modal/Admin/PhaseEditor.php`
+
+---
+
+### Session Recovery/Replay
+
+Resume and replay agent sessions across context windows.
+
+**Methods:**
+- `getReplayContext()` - reconstruct session state
+- `createReplaySession()` - spawn continuation session
+- Checkpoint and decision tracking
+
+**MCP Tool:**
+- `session_replay` - replay tool for agents
+
+---
+
+### Agent API Keys
+
+Scoped API keys for agent authentication.
+
+**Features:**
+- Key generation with prefixes
+- Scope restrictions
+- Usage tracking
+- IP restrictions
+
+**Files:**
+- `Models/AgentApiKey.php`
+- `Services/AgentApiKeyService.php`
+- `Services/IpRestrictionService.php`
+
+---
+
+### MCP Usage Quotas
+
+Per-workspace usage limits for MCP operations.
+
+**Files:**
+- `Models/McpUsageQuota.php`
+- `Services/McpQuotaService.php`
+- Quota middleware
+- Entitlement feature integration
+
+---
+
+### Plan Templates
+
+Reusable plan templates for common workflows.
+
+**Files:**
+- `Services/PlanTemplateService.php`
+- Template MCP tools
diff --git a/composer.json b/composer.json
index 89a3dd6..15fe864 100644
--- a/composer.json
+++ b/composer.json
@@ -1,49 +1,50 @@
{
- "name": "host-uk/core-agentic",
- "description": "AI agent orchestration and MCP tools for Laravel",
- "keywords": [
- "ai",
- "agents",
- "mcp",
- "orchestration"
- ],
- "license": "EUPL-1.2",
- "require": {
- "php": "^8.2",
- "host-uk/core": "dev-main"
- },
- "require-dev": {
- "laravel/pint": "^1.18",
- "orchestra/testbench": "^9.0|^10.0",
- "pestphp/pest": "^3.0"
- },
- "autoload": {
- "psr-4": {
- "Core\\Agentic\\": ""
- }
- },
- "autoload-dev": {
- "psr-4": {
- "Core\\Agentic\\Tests\\": "Tests/"
- }
- },
- "extra": {
- "laravel": {
- "providers": [
- "Core\\Agentic\\Boot"
- ]
- }
- },
- "scripts": {
- "lint": "pint",
- "test": "pest"
- },
- "config": {
- "sort-packages": true,
- "allow-plugins": {
- "pestphp/pest-plugin": true
- }
- },
- "minimum-stability": "dev",
- "prefer-stable": true
+ "name": "host-uk/core-agentic",
+ "description": "AI agent orchestration and MCP tools for Laravel",
+ "keywords": [
+ "ai",
+ "agents",
+ "mcp",
+ "orchestration"
+ ],
+ "license": "EUPL-1.2",
+ "require": {
+ "php": "^8.2",
+ "host-uk/core": "dev-main"
+ },
+ "require-dev": {
+ "laravel/pint": "^1.18",
+ "orchestra/testbench": "^9.0|^10.0",
+ "pestphp/pest": "^3.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Core\\Mod\\Agentic\\": "",
+ "Core\\Service\\Agentic\\": "Service/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Core\\Mod\\Agentic\\Tests\\": "Tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Core\\Mod\\Agentic\\Boot"
+ ]
+ }
+ },
+ "scripts": {
+ "lint": "pint",
+ "test": "pest"
+ },
+ "config": {
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true
+ }
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true
}
diff --git a/routes/admin.php b/routes/admin.php
index 3f7a9f2..9458774 100644
--- a/routes/admin.php
+++ b/routes/admin.php
@@ -17,19 +17,19 @@ Route::prefix('hub')->name('hub.')->group(function () {
->middleware(['auth', RequireHades::class])
->group(function () {
// Phase 1: Plan Dashboard
- Route::get('/', \Core\Agentic\View\Modal\Admin\Dashboard::class)->name('index');
- Route::get('/plans', \Core\Agentic\View\Modal\Admin\Plans::class)->name('plans');
- Route::get('/plans/{slug}', \Core\Agentic\View\Modal\Admin\PlanDetail::class)->name('plans.show');
+ Route::get('/', \Core\Mod\Agentic\View\Modal\Admin\Dashboard::class)->name('index');
+ Route::get('/plans', \Core\Mod\Agentic\View\Modal\Admin\Plans::class)->name('plans');
+ Route::get('/plans/{slug}', \Core\Mod\Agentic\View\Modal\Admin\PlanDetail::class)->name('plans.show');
// Phase 2: Session Monitor
- Route::get('/sessions', \Core\Agentic\View\Modal\Admin\Sessions::class)->name('sessions');
- Route::get('/sessions/{id}', \Core\Agentic\View\Modal\Admin\SessionDetail::class)->name('sessions.show');
+ Route::get('/sessions', \Core\Mod\Agentic\View\Modal\Admin\Sessions::class)->name('sessions');
+ Route::get('/sessions/{id}', \Core\Mod\Agentic\View\Modal\Admin\SessionDetail::class)->name('sessions.show');
// Phase 3: Tool Analytics
- Route::get('/tools', \Core\Agentic\View\Modal\Admin\ToolAnalytics::class)->name('tools');
- Route::get('/tools/calls', \Core\Agentic\View\Modal\Admin\ToolCalls::class)->name('tools.calls');
+ Route::get('/tools', \Core\Mod\Agentic\View\Modal\Admin\ToolAnalytics::class)->name('tools');
+ Route::get('/tools/calls', \Core\Mod\Agentic\View\Modal\Admin\ToolCalls::class)->name('tools.calls');
// Phase 4: API Key Management
- Route::get('/api-keys', \Core\Agentic\View\Modal\Admin\ApiKeys::class)->name('api-keys');
+ Route::get('/api-keys', \Core\Mod\Agentic\View\Modal\Admin\ApiKeys::class)->name('api-keys');
// Phase 5: Plan Templates
- Route::get('/templates', \Core\Agentic\View\Modal\Admin\Templates::class)->name('templates');
+ Route::get('/templates', \Core\Mod\Agentic\View\Modal\Admin\Templates::class)->name('templates');
});
});
diff --git a/tests/Feature/AgentPhaseTest.php b/tests/Feature/AgentPhaseTest.php
index 70a703e..695fa69 100644
--- a/tests/Feature/AgentPhaseTest.php
+++ b/tests/Feature/AgentPhaseTest.php
@@ -2,11 +2,11 @@
declare(strict_types=1);
-namespace Core\Agentic\Tests\Feature;
+namespace Core\Mod\Agentic\Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
-use Core\Agentic\Models\AgentPhase;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentPhase;
+use Core\Mod\Agentic\Models\AgentPlan;
use Core\Mod\Tenant\Models\Workspace;
use Tests\TestCase;
diff --git a/tests/Feature/AgentPlanTest.php b/tests/Feature/AgentPlanTest.php
index 11f0cb8..e761704 100644
--- a/tests/Feature/AgentPlanTest.php
+++ b/tests/Feature/AgentPlanTest.php
@@ -2,11 +2,11 @@
declare(strict_types=1);
-namespace Core\Agentic\Tests\Feature;
+namespace Core\Mod\Agentic\Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
-use Core\Agentic\Models\AgentPhase;
-use Core\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentPhase;
+use Core\Mod\Agentic\Models\AgentPlan;
use Core\Mod\Tenant\Models\Workspace;
use Tests\TestCase;
diff --git a/tests/Feature/AgentSessionTest.php b/tests/Feature/AgentSessionTest.php
index 83034d6..de04589 100644
--- a/tests/Feature/AgentSessionTest.php
+++ b/tests/Feature/AgentSessionTest.php
@@ -2,11 +2,11 @@
declare(strict_types=1);
-namespace Core\Agentic\Tests\Feature;
+namespace Core\Mod\Agentic\Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
-use Core\Agentic\Models\AgentPlan;
-use Core\Agentic\Models\AgentSession;
+use Core\Mod\Agentic\Models\AgentPlan;
+use Core\Mod\Agentic\Models\AgentSession;
use Core\Mod\Tenant\Models\Workspace;
use Tests\TestCase;
diff --git a/tests/Feature/ContentServiceTest.php b/tests/Feature/ContentServiceTest.php
index b80c027..ee2e572 100644
--- a/tests/Feature/ContentServiceTest.php
+++ b/tests/Feature/ContentServiceTest.php
@@ -1,8 +1,8 @@