Add Agent Command Centers - /agent/[id] with vertical sections
This commit is contained in:
@@ -0,0 +1,439 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
const AGENT_CONFIG: Record<string, { name: string; avatar: string; color: string; role: string; description: string }> = {
|
||||||
|
horus: { name: "Horus", avatar: "👁️", color: "#ff7bc0", role: "Master Orchestrator", description: "Command center, delegates tasks, manages all agents" },
|
||||||
|
thoth: { name: "Thoth", avatar: "🧠", color: "#8b5cf6", role: "Strategy & Research", description: "SiteMente planning, research, analysis" },
|
||||||
|
"thoth-trading": { name: "Thoth Trading", avatar: "📈", color: "#f59e0b", role: "Market Research", description: "Crypto market analysis and research" },
|
||||||
|
ptah: { name: "Ptah", avatar: "🏗️", color: "#10b981", role: "Dev & Ops", description: "Development, deployment, technical implementation" },
|
||||||
|
seshat: { name: "Seshat", avatar: "📜", color: "#ec4899", role: "Content & SEO", description: "Content strategy, SEO, marketing copy" },
|
||||||
|
anubis: { name: "Anubis", avatar: "🐺", color: "#6366f1", role: "Outreach & Growth", description: "Lead generation, client acquisition" },
|
||||||
|
sekhmet: { name: "Sekhmet", avatar: "⚔️", color: "#ef4444", role: "Risk Management", description: "Trade execution and risk" },
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Task {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
status: string;
|
||||||
|
priority: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RecurringTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
enabled: boolean;
|
||||||
|
schedule: { type: string; time?: string; dayOfWeek?: number };
|
||||||
|
taskTemplate: { title: string; description: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExecutionLog {
|
||||||
|
id: string;
|
||||||
|
taskTitle: string;
|
||||||
|
startedAt: string;
|
||||||
|
status: string;
|
||||||
|
output?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChangeLogEntry {
|
||||||
|
id: string;
|
||||||
|
date: string;
|
||||||
|
type: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BrainownNote {
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AgentCenterPage({ params }: { params: { id: string } }) {
|
||||||
|
const router = useRouter();
|
||||||
|
const agentId = params.id;
|
||||||
|
const agent = AGENT_CONFIG[agentId] || { name: agentId, avatar: "🤖", color: "#666", role: "Agent", description: "" };
|
||||||
|
|
||||||
|
const [tasks, setTasks] = useState<Task[]>([]);
|
||||||
|
const [templates, setTemplates] = useState<RecurringTemplate[]>([]);
|
||||||
|
const [logs, setLogs] = useState<ExecutionLog[]>([]);
|
||||||
|
const [changelog, setChangelog] = useState<ChangeLogEntry[]>([]);
|
||||||
|
const [brainownNotes, setBrainownNotes] = useState<BrainownNote[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
// Accordion state
|
||||||
|
const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({
|
||||||
|
tasks: true,
|
||||||
|
recurring: true,
|
||||||
|
logs: true,
|
||||||
|
changelog: true,
|
||||||
|
brainown: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Brainown editing
|
||||||
|
const [editingNote, setEditingNote] = useState<string | null>(null);
|
||||||
|
const [noteContent, setNoteContent] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchAllData();
|
||||||
|
}, [agentId]);
|
||||||
|
|
||||||
|
const fetchAllData = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
// Fetch tasks for this agent
|
||||||
|
try {
|
||||||
|
const tRes = await fetch("/api/tasks");
|
||||||
|
if (tRes.ok) {
|
||||||
|
const allTasks = await tRes.json();
|
||||||
|
const agentTasks = allTasks.filter((t: any) => t.assignee === agentId || t.project === getAgentProject(agentId));
|
||||||
|
setTasks(agentTasks);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
// Fetch recurring templates for this agent
|
||||||
|
try {
|
||||||
|
const rRes = await fetch("/api/recurring");
|
||||||
|
if (rRes.ok) {
|
||||||
|
const allTemplates = await rRes.json();
|
||||||
|
const agentTemplates = allTemplates.filter((t: any) => t.agent === agentId);
|
||||||
|
setTemplates(agentTemplates);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
// Fetch execution logs for this agent
|
||||||
|
try {
|
||||||
|
const lRes = await fetch(`/api/execution-logs?agent=${agentId}&limit=20`);
|
||||||
|
if (lRes.ok) {
|
||||||
|
setLogs(await lRes.json());
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
// Fetch changelog for this agent
|
||||||
|
try {
|
||||||
|
const cRes = await fetch(`/api/changelog?agent=${agentId}&limit=20`);
|
||||||
|
if (cRes.ok) {
|
||||||
|
setChangelog(await cRes.json());
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
// Fetch brainown notes for this agent
|
||||||
|
try {
|
||||||
|
const bRes = await fetch(`/api/agent-outputs?agent=${agentId}`);
|
||||||
|
if (bRes.ok) {
|
||||||
|
const dates = await bRes.json();
|
||||||
|
const notes: BrainownNote[] = [];
|
||||||
|
for (const date of dates.slice(0, 10)) {
|
||||||
|
const noteRes = await fetch(`/api/agent-outputs?agent=${agentId}&date=${date}`);
|
||||||
|
if (noteRes.ok) {
|
||||||
|
const note = await noteRes.json();
|
||||||
|
if (note.content) {
|
||||||
|
notes.push({ date, content: note.content });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setBrainownNotes(notes);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAgentProject = (id: string): string => {
|
||||||
|
const projectMap: Record<string, string> = {
|
||||||
|
thoth: "sitemente",
|
||||||
|
"thoth-trading": "trading",
|
||||||
|
ptah: "infrastructure",
|
||||||
|
seshat: "sitemente",
|
||||||
|
anubis: "sitemente",
|
||||||
|
sekhmet: "trading",
|
||||||
|
};
|
||||||
|
return projectMap[id] || "sitemente";
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSection = (section: string) => {
|
||||||
|
setExpandedSections(prev => ({ ...prev, [section]: !prev[section] }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleTemplate = async (templateId: string, enabled: boolean) => {
|
||||||
|
await fetch("/api/recurring", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ action: "toggle", templateId, enabled })
|
||||||
|
});
|
||||||
|
fetchAllData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const runNow = async (templateId: string) => {
|
||||||
|
await fetch("/api/recurring", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ action: "run-now", templateId })
|
||||||
|
});
|
||||||
|
fetchAllData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveNote = async (date: string) => {
|
||||||
|
await fetch("/api/agent-outputs", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ action: "save", agent: agentId, date, content: noteContent })
|
||||||
|
});
|
||||||
|
setEditingNote(null);
|
||||||
|
fetchAllData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case "running": return "text-yellow-400";
|
||||||
|
case "completed": return "text-green-400";
|
||||||
|
case "failed": return "text-red-400";
|
||||||
|
default: return "text-white/50";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPriorityColor = (priority: string) => {
|
||||||
|
switch (priority) {
|
||||||
|
case "critical": return "text-red-400";
|
||||||
|
case "high": return "text-orange-400";
|
||||||
|
case "medium": return "text-yellow-400";
|
||||||
|
default: return "text-white/50";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="p-6 flex items-center justify-center min-h-[400px]">
|
||||||
|
<div className="text-white/50">Loading {agent.name}...</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-4 md:p-6">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex items-center gap-4 mb-6">
|
||||||
|
<button
|
||||||
|
onClick={() => router.back()}
|
||||||
|
className="p-2 bg-white/10 rounded-lg hover:bg-white/20 transition"
|
||||||
|
>
|
||||||
|
←
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
className="w-16 h-16 rounded-full flex items-center justify-center text-3xl"
|
||||||
|
style={{ backgroundColor: agent.color + "20", border: `2px solid ${agent.color}` }}
|
||||||
|
>
|
||||||
|
{agent.avatar}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold" style={{ color: agent.color }}>
|
||||||
|
{agent.name}
|
||||||
|
</h1>
|
||||||
|
<p className="text-white/70">{agent.role}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-white/50 mb-6">{agent.description}</p>
|
||||||
|
|
||||||
|
{/* Vertical Sections - Accordion Style */}
|
||||||
|
<div className="space-y-4">
|
||||||
|
|
||||||
|
{/* 📋 TASKS */}
|
||||||
|
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
|
||||||
|
<button
|
||||||
|
onClick={() => toggleSection("tasks")}
|
||||||
|
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<span className="font-semibold">📋 TASKS</span>
|
||||||
|
<span className="text-white/50">{expandedSections.tasks ? "▲" : "▼"}</span>
|
||||||
|
</button>
|
||||||
|
{expandedSections.tasks && (
|
||||||
|
<div className="p-4 pt-0 space-y-2">
|
||||||
|
{tasks.length === 0 ? (
|
||||||
|
<p className="text-white/50 text-sm">No tasks assigned</p>
|
||||||
|
) : (
|
||||||
|
tasks.map((task) => (
|
||||||
|
<div key={task.id} className="p-3 bg-white/5 rounded flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<span className={getPriorityColor(task.priority)}>[{task.priority}]</span>
|
||||||
|
<span className="ml-2">{task.title}</span>
|
||||||
|
</div>
|
||||||
|
<span className={`text-xs px-2 py-1 rounded ${
|
||||||
|
task.status === "done" ? "bg-green-500/20 text-green-400" :
|
||||||
|
task.status === "in_progress" ? "bg-yellow-500/20 text-yellow-400" :
|
||||||
|
"bg-white/10 text-white/50"
|
||||||
|
}`}>
|
||||||
|
{task.status}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 🔄 RECURRING */}
|
||||||
|
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
|
||||||
|
<button
|
||||||
|
onClick={() => toggleSection("recurring")}
|
||||||
|
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<span className="font-semibold">🔄 RECURRING</span>
|
||||||
|
<span className="text-white/50">{expandedSections.recurring ? "▲" : "▼"}</span>
|
||||||
|
</button>
|
||||||
|
{expandedSections.recurring && (
|
||||||
|
<div className="p-4 pt-0 space-y-3">
|
||||||
|
{templates.length === 0 ? (
|
||||||
|
<p className="text-white/50 text-sm">No recurring tasks</p>
|
||||||
|
) : (
|
||||||
|
templates.map((template) => (
|
||||||
|
<div key={template.id} className="p-3 bg-white/5 rounded">
|
||||||
|
<div className="flex justify-between items-start mb-2">
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">{template.taskTemplate.title}</span>
|
||||||
|
<p className="text-xs text-white/50">{template.taskTemplate.description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={() => runNow(template.id)}
|
||||||
|
className="px-2 py-1 bg-brand-pink/80 hover:bg-brand-pink rounded text-xs"
|
||||||
|
>
|
||||||
|
▶ Run
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => toggleTemplate(template.id, !template.enabled)}
|
||||||
|
className={`px-2 py-1 rounded text-xs ${
|
||||||
|
template.enabled ? "bg-green-600" : "bg-white/10"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{template.enabled ? "ON" : "OFF"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-white/40">
|
||||||
|
{template.schedule.type === "hourly" ? "Hourly" :
|
||||||
|
template.schedule.time ? `Daily @ ${template.schedule.time}` :
|
||||||
|
template.schedule.type}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 📊 EXECUTION LOGS */}
|
||||||
|
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
|
||||||
|
<button
|
||||||
|
onClick={() => toggleSection("logs")}
|
||||||
|
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<span className="font-semibold">📊 EXECUTION LOGS</span>
|
||||||
|
<span className="text-white/50">{expandedSections.logs ? "▲" : "▼"}</span>
|
||||||
|
</button>
|
||||||
|
{expandedSections.logs && (
|
||||||
|
<div className="p-4 pt-0 space-y-2">
|
||||||
|
{logs.length === 0 ? (
|
||||||
|
<p className="text-white/50 text-sm">No execution logs</p>
|
||||||
|
) : (
|
||||||
|
logs.slice(0, 10).map((log) => (
|
||||||
|
<div key={log.id} className="p-3 bg-white/5 rounded flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">{log.taskTitle}</span>
|
||||||
|
<p className="text-xs text-white/50">
|
||||||
|
{new Date(log.startedAt).toLocaleString()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span className={`text-xs px-2 py-1 rounded ${getStatusColor(log.status)} bg-white/10`}>
|
||||||
|
{log.status}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 📝 CHANGE LOG */}
|
||||||
|
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
|
||||||
|
<button
|
||||||
|
onClick={() => toggleSection("changelog")}
|
||||||
|
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<span className="font-semibold">📝 CHANGE LOG</span>
|
||||||
|
<span className="text-white/50">{expandedSections.changelog ? "▲" : "▼"}</span>
|
||||||
|
</button>
|
||||||
|
{expandedSections.changelog && (
|
||||||
|
<div className="p-4 pt-0 space-y-2">
|
||||||
|
{changelog.length === 0 ? (
|
||||||
|
<p className="text-white/50 text-sm">No changes recorded</p>
|
||||||
|
) : (
|
||||||
|
changelog.slice(0, 10).map((entry) => (
|
||||||
|
<div key={entry.id} className="p-3 bg-white/5 rounded">
|
||||||
|
<div className="flex justify-between items-start">
|
||||||
|
<span className="text-xs px-2 py-0.5 rounded bg-purple-500/20 text-purple-400">
|
||||||
|
{entry.type.replace("_", " ")}
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-white/40">
|
||||||
|
{new Date(entry.date).toLocaleDateString()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="mt-1 text-sm">{entry.description}</p>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 🧠 BRAINOWN */}
|
||||||
|
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
|
||||||
|
<button
|
||||||
|
onClick={() => toggleSection("brainown")}
|
||||||
|
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<span className="font-semibold">🧠 BRAINOWN</span>
|
||||||
|
<span className="text-white/50">{expandedSections.brainown ? "▲" : "▼"}</span>
|
||||||
|
</button>
|
||||||
|
{expandedSections.brainown && (
|
||||||
|
<div className="p-4 pt-0 space-y-3">
|
||||||
|
{brainownNotes.length === 0 ? (
|
||||||
|
<p className="text-white/50 text-sm">No notes yet</p>
|
||||||
|
) : (
|
||||||
|
brainownNotes.map((note) => (
|
||||||
|
<div key={note.date} className="p-3 bg-white/5 rounded">
|
||||||
|
<div className="flex justify-between items-start mb-2">
|
||||||
|
<span className="text-sm font-medium">📝 {note.date}</span>
|
||||||
|
{editingNote === note.date ? (
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button onClick={() => saveNote(note.date)} className="text-green-400 text-xs">Save</button>
|
||||||
|
<button onClick={() => setEditingNote(null)} className="text-white/50 text-xs">Cancel</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={() => { setEditingNote(note.date); setNoteContent(note.content); }}
|
||||||
|
className="text-brand-pink text-xs"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{editingNote === note.date ? (
|
||||||
|
<textarea
|
||||||
|
value={noteContent}
|
||||||
|
onChange={(e) => setNoteContent(e.target.value)}
|
||||||
|
className="w-full h-32 bg-black/30 border border-white/20 rounded p-2 text-white text-sm"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<pre className="text-xs text-white/70 whitespace-pre-wrap">{note.content}</pre>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
import { Agent, AgentTeam, defaultTeams } from "@/lib/council/types";
|
import { Agent, AgentTeam, defaultTeams } from "@/lib/council/types";
|
||||||
|
|
||||||
const STORAGE_KEY = "horus:council";
|
const STORAGE_KEY = "horus:council";
|
||||||
|
|
||||||
export default function Council() {
|
export default function Council() {
|
||||||
|
const router = useRouter();
|
||||||
const [teams, setTeams] = useState<AgentTeam[]>(defaultTeams);
|
const [teams, setTeams] = useState<AgentTeam[]>(defaultTeams);
|
||||||
const [selectedTeam, setSelectedTeam] = useState<string | null>(null);
|
const [selectedTeam, setSelectedTeam] = useState<string | null>(null);
|
||||||
const [runningTask, setRunningTask] = useState<string>("");
|
const [runningTask, setRunningTask] = useState<string>("");
|
||||||
@@ -144,6 +146,14 @@ export default function Council() {
|
|||||||
|
|
||||||
<p className="text-sm text-white/60 mb-3">{agent.description}</p>
|
<p className="text-sm text-white/60 mb-3">{agent.description}</p>
|
||||||
|
|
||||||
|
{/* Open Agent Command Center */}
|
||||||
|
<button
|
||||||
|
onClick={() => router.push(`/agent/${agent.id}`)}
|
||||||
|
className="w-full mb-3 px-3 py-2 bg-white/10 hover:bg-white/20 border border-white/20 rounded-lg text-sm text-center transition"
|
||||||
|
>
|
||||||
|
🧑💼 Open {agent.name} Command Center
|
||||||
|
</button>
|
||||||
|
|
||||||
{/* Task Input */}
|
{/* Task Input */}
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "changelog-1772208908682",
|
||||||
|
"date": "2026-02-27T16:15:08.682Z",
|
||||||
|
"agent": "horus",
|
||||||
|
"type": "new_feature",
|
||||||
|
"description": "BMHQ Upgrade: Added Auto-Run, Execution Logs, Change Log, and Brainown panels to Mission Control",
|
||||||
|
"version": "1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "thoth-daily-research",
|
||||||
|
"name": "Thoth - Daily SiteMente Research",
|
||||||
|
"description": "Research market trends, competitors, and opportunities",
|
||||||
|
"agent": "thoth",
|
||||||
|
"project": "sitemente",
|
||||||
|
"schedule": {
|
||||||
|
"type": "daily",
|
||||||
|
"time": "09:00",
|
||||||
|
"timezone": "Europe/Madrid"
|
||||||
|
},
|
||||||
|
"taskTemplate": {
|
||||||
|
"title": "Daily SiteMente Research",
|
||||||
|
"description": "Research: competitors, AI trends, pricing, local businesses",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
"preInstructions": "Focus on: 1) Competitor changes, 2) New AI features, 3) Local lead opportunities",
|
||||||
|
"enabled": false,
|
||||||
|
"runCount": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ptah-infra-monitor",
|
||||||
|
"name": "Ptah - Infrastructure Monitoring",
|
||||||
|
"description": "Check server health, uptime, and security",
|
||||||
|
"agent": "ptah",
|
||||||
|
"project": "infrastructure",
|
||||||
|
"schedule": {
|
||||||
|
"type": "hourly",
|
||||||
|
"timezone": "Europe/Madrid"
|
||||||
|
},
|
||||||
|
"taskTemplate": {
|
||||||
|
"title": "Infra Health Check",
|
||||||
|
"description": "Check: CPU, memory, disk, services, SSL certs, security logs",
|
||||||
|
"priority": "critical"
|
||||||
|
},
|
||||||
|
"preInstructions": "Report any issues immediately to Horus",
|
||||||
|
"enabled": false,
|
||||||
|
"runCount": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "seshat-content-pipeline",
|
||||||
|
"name": "Seshat - Content Pipeline",
|
||||||
|
"description": "Generate and schedule content",
|
||||||
|
"agent": "seshat",
|
||||||
|
"project": "sitemente",
|
||||||
|
"schedule": {
|
||||||
|
"type": "daily",
|
||||||
|
"time": "09:00",
|
||||||
|
"timezone": "Europe/Madrid"
|
||||||
|
},
|
||||||
|
"taskTemplate": {
|
||||||
|
"title": "Daily Content Development",
|
||||||
|
"description": "Create: blog post, social content, newsletter draft",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
"preInstructions": "Focus on SEO, value for local businesses",
|
||||||
|
"enabled": false,
|
||||||
|
"runCount": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "anubis-outreach-scan",
|
||||||
|
"name": "Anubis - Outreach Opportunities",
|
||||||
|
"description": "Find new leads and opportunities",
|
||||||
|
"agent": "anubis",
|
||||||
|
"project": "sitemente",
|
||||||
|
"schedule": {
|
||||||
|
"type": "weekly",
|
||||||
|
"dayOfWeek": 1,
|
||||||
|
"time": "10:00",
|
||||||
|
"timezone": "Europe/Madrid"
|
||||||
|
},
|
||||||
|
"taskTemplate": {
|
||||||
|
"title": "Weekly Outreach Scan",
|
||||||
|
"description": "Find: new restaurants, clinics, real estate agencies to contact",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
"preInstructions": "Focus on Benalmádena and Costa del Sol area",
|
||||||
|
"enabled": false,
|
||||||
|
"runCount": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "thoth-trading-market",
|
||||||
|
"name": "Thoth Trading - Market Scan",
|
||||||
|
"description": "Scan crypto markets for opportunities",
|
||||||
|
"agent": "thoth-trading",
|
||||||
|
"project": "trading",
|
||||||
|
"schedule": {
|
||||||
|
"type": "hourly",
|
||||||
|
"timezone": "Europe/Madrid"
|
||||||
|
},
|
||||||
|
"taskTemplate": {
|
||||||
|
"title": "Market Scan",
|
||||||
|
"description": "Check: BTC, ETH, SOL prices and trends",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
"preInstructions": "Report significant moves (>5%)",
|
||||||
|
"enabled": false,
|
||||||
|
"runCount": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sekhmet-risk-alerts",
|
||||||
|
"name": "Sekhmet - Risk Alerts",
|
||||||
|
"description": "Monitor trading positions and risk",
|
||||||
|
"agent": "sekhmet",
|
||||||
|
"project": "trading",
|
||||||
|
"schedule": {
|
||||||
|
"type": "hourly",
|
||||||
|
"timezone": "Europe/Madrid"
|
||||||
|
},
|
||||||
|
"taskTemplate": {
|
||||||
|
"title": "Risk Check",
|
||||||
|
"description": "Check: open positions, drawdown, risk levels",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
"preInstructions": "Alert if drawdown >10% or positions at risk",
|
||||||
|
"enabled": false,
|
||||||
|
"runCount": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user