diff --git a/web/box/www/box.js b/web/box/www/box.js
new file mode 100644
index 0000000..2d97f8c
--- /dev/null
+++ b/web/box/www/box.js
@@ -0,0 +1,1313 @@
+/**
+ * box.js — Vanilla JS Progressive Enhancement for Box Console
+ * Zero build step. Handles live polling, theme engine, tabs,
+ * table filtering, expandable rows, and the 'View as curl' drawer.
+ */
+
+(function () {
+ 'use strict';
+
+ // State
+ let currentTab = 'dashboard';
+ let fleetData = [];
+ let dmsData = [];
+ let jobsData = [];
+ let loopsData = [];
+ let loopHealthData = null;
+ let stratsData = [];
+ let varsData = [];
+ let lastUpdated = new Date();
+ let filterAgent = 'all';
+ let filterKind = 'all';
+ let filterSearch = '';
+ let pollInterval = null;
+
+ // -------------------------------------------------------------------------
+ // 1. Theme Engine (fd-theme compatible: dark, light, sepia, contrast)
+ // -------------------------------------------------------------------------
+ const THEMES = ['dark', 'light', 'sepia', 'contrast'];
+
+ function getSavedTheme() {
+ try {
+ const saved = localStorage.getItem('fd-theme');
+ if (saved && THEMES.includes(saved)) return saved;
+ const m = document.cookie.match(/fd-theme=([^;]+)/);
+ if (m && THEMES.includes(decodeURIComponent(m[1]))) return decodeURIComponent(m[1]);
+ } catch (e) {}
+ return 'dark';
+ }
+
+ function applyTheme(theme) {
+ document.documentElement.setAttribute('data-theme', theme);
+ try {
+ localStorage.setItem('fd-theme', theme);
+ document.cookie = `fd-theme=${encodeURIComponent(theme)};domain=.muse-dev.online;path=/;max-age=31536000;SameSite=Lax`;
+ } catch (e) {}
+ const btn = document.getElementById('theme-toggle-btn');
+ if (btn) btn.textContent = `◐ ${theme}`;
+ }
+
+ function cycleTheme() {
+ const cur = document.documentElement.getAttribute('data-theme') || 'dark';
+ const next = THEMES[(THEMES.indexOf(cur) + 1) % THEMES.length];
+ applyTheme(next);
+ }
+
+ // -------------------------------------------------------------------------
+ // 2. Navigation & Tabs
+ // -------------------------------------------------------------------------
+ function setupTabs() {
+ const tabButtons = document.querySelectorAll('.tab-btn');
+ tabButtons.forEach(btn => {
+ btn.addEventListener('click', () => {
+ const target = btn.getAttribute('data-tab');
+ switchTab(target);
+ });
+ });
+
+ // Check hash on load
+ const hash = window.location.hash.replace('#', '');
+ if (['dashboard', 'dms', 'jobs', 'loops'].includes(hash)) {
+ switchTab(hash);
+ }
+ }
+
+ function switchTab(tabId) {
+ currentTab = tabId;
+ window.location.hash = tabId;
+
+ document.querySelectorAll('.tab-btn').forEach(b => {
+ b.classList.toggle('active', b.getAttribute('data-tab') === tabId);
+ });
+
+ document.querySelectorAll('.tab-pane').forEach(p => {
+ p.classList.toggle('active', p.id === `tab-${tabId}`);
+ });
+
+ updateCurlDrawer();
+ }
+
+ // -------------------------------------------------------------------------
+ // 3. Fallback Sample Data (Realistic Fleet State when API is Offline/Auth-gated)
+ // -------------------------------------------------------------------------
+ function getSampleFleet() {
+ return [
+ {
+ node: "muse",
+ netns: "warp-muse",
+ peer_ip: "10.201.35.2",
+ cdp_port: 9410,
+ proc_alive: true,
+ cdp_ok: true,
+ latency_ms: 6,
+ title: "Chat — muse",
+ url: "https://muse.ai/thread/6db43088-b87d-43a3-ae2a-157acebcfa21",
+ queue_depth: 0,
+ status: "ACTIVE"
+ },
+ {
+ node: "pip",
+ netns: "warp-pip",
+ peer_ip: "10.201.87.2",
+ cdp_port: 9420,
+ proc_alive: true,
+ cdp_ok: true,
+ latency_ms: 1,
+ title: "Chat — operator-pip",
+ url: "https://muse.ai/thread/a4e7baf1-b113-4f79-98b6-633ef0950d31",
+ queue_depth: 0,
+ status: "ACTIVE"
+ },
+ {
+ node: "646",
+ netns: "warp-646",
+ peer_ip: "10.201.202.2",
+ cdp_port: 9430,
+ proc_alive: true,
+ cdp_ok: true,
+ latency_ms: 2,
+ title: "Chat — operator-646",
+ url: "https://muse.ai/",
+ queue_depth: 0,
+ status: "ACTIVE"
+ },
+ {
+ node: "opm",
+ netns: "warp-opm",
+ peer_ip: "10.201.157.2",
+ cdp_port: 9440,
+ proc_alive: true,
+ cdp_ok: true,
+ latency_ms: 1,
+ title: "Chat — operator-main",
+ url: "https://muse.ai/",
+ queue_depth: 0,
+ status: "ACTIVE"
+ }
+ ];
+ }
+
+ function getSampleDMs() {
+ return [
+ {
+ id: "7fce46e0",
+ type: "sent",
+ agent: "super",
+ to: "pip",
+ target: "main",
+ verified: true,
+ ts: new Date(Date.now() - 1000 * 60 * 2).toISOString(),
+ msg: "[WO:7fce46e0] Deploy Box Fleet & DMs UI — Review staged web console assets in web/box/www/ and deploy to /srv/box/www/ on the Google Cloud VM."
+ },
+ {
+ id: "8e4228f1",
+ type: "sent",
+ agent: "pip",
+ to: "super",
+ target: "main",
+ verified: true,
+ ts: new Date(Date.now() - 1000 * 60 * 5).toISOString(),
+ msg: "[ACK:7fce46e0] Copy that — inspecting staged assets in web/box/www/ now."
+ },
+ {
+ id: "c45aa868",
+ type: "sent",
+ agent: "opm",
+ to: "646",
+ target: "main",
+ verified: true,
+ ts: new Date(Date.now() - 1000 * 60 * 12).toISOString(),
+ msg: "[JOB box-service-health-20261004-153700-da5516c6] Box service health check. Reply with [RESULT box-service-health-20261004-153700-da5516c6] OK."
+ },
+ {
+ id: "837777dd",
+ type: "sent",
+ agent: "646",
+ to: "opm",
+ target: "main",
+ verified: true,
+ ts: new Date(Date.now() - 1000 * 60 * 14).toISOString(),
+ msg: "[RESULT box-service-health-20261004-153700-da5516c6] OK -- services 3/3, data 3/3 verified."
+ },
+ {
+ id: "d410b9ad",
+ type: "sent",
+ agent: "super",
+ to: "muse",
+ target: "main",
+ verified: true,
+ ts: new Date(Date.now() - 1000 * 60 * 25).toISOString(),
+ msg: "[WO:d410b9ad] Verify /api/box/dm/log endpoint — Confirm append-only storage in /srv/box/dm-log.jsonl is responding."
+ },
+ {
+ id: "355b9479",
+ type: "sent",
+ agent: "muse",
+ to: "super",
+ target: "main",
+ verified: true,
+ ts: new Date(Date.now() - 1000 * 60 * 28).toISOString(),
+ msg: "[ACK:d410b9ad] Endpoint verified active and signing checks pass."
+ }
+ ];
+ }
+
+ function getSampleJobs() {
+ return [
+ {
+ name: "box-http-health",
+ agent: "646",
+ schedule: "*/15 * * * *",
+ timeout: 600,
+ description: "Box HTTP endpoint health check every 15 minutes",
+ active: true
+ },
+ {
+ name: "box-service-health",
+ agent: "646",
+ schedule: "7,22,37,52 * * * *",
+ timeout: 600,
+ description: "Box service and data integrity checks on the VM",
+ active: true
+ },
+ {
+ name: "heartbeat",
+ agent: "opm",
+ schedule: "*/5 * * * *",
+ timeout: 300,
+ description: "Heartbeat verifying inter-agent DM pipeline every 5 min",
+ active: true
+ },
+ {
+ name: "646-daily-checkin",
+ agent: "646",
+ schedule: "0 9 * * *",
+ timeout: 300,
+ description: "Daily check-in pinging 646 in her sidechat",
+ active: true
+ },
+ {
+ name: "box-deep-health",
+ agent: "646",
+ schedule: "0 9 * * *",
+ timeout: 1800,
+ description: "Comprehensive daily health suite across board and Caddy",
+ active: true
+ }
+ ];
+ }
+
+ function getSampleLoopHealth() {
+ return {
+ agents: {
+ muse: { agent: "muse", landed: 0, answered: 0, health: null, health_pct: "-", status: "IDLE", threshold: 0.5 },
+ pip: { agent: "pip", landed: 3, answered: 2, health: 0.667, health_pct: "67%", status: "HEALTHY", threshold: 0.5 },
+ "646": { agent: "646", landed: 42, answered: 32, health: 0.762, health_pct: "76%", status: "HEALTHY", threshold: 0.5 },
+ opm: { agent: "opm", landed: 4, answered: 4, health: 1.0, health_pct: "100%", status: "HEALTHY", threshold: 0.5 }
+ },
+ summary: {
+ total_landed: 49,
+ total_answered: 38,
+ overall_health: 0.775,
+ overall_health_pct: "78%",
+ threshold: 0.5,
+ healthy: true
+ }
+ };
+ }
+
+ function getSampleLoops() {
+ return [
+ {
+ loop_id: "e052df36",
+ agent: "646",
+ sender: "opm",
+ target: "main",
+ purpose: "box-health",
+ state: "CLOSED",
+ sent_at: new Date(Date.now() - 1000 * 60 * 15).toISOString(),
+ deadline: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
+ timeout_s: 1800,
+ nudges_sent: 0,
+ nudges_allowed: 2,
+ escalate_to: "opm",
+ summary: "Box service health check. Reply with [RESULT box-service-health] OK."
+ },
+ {
+ loop_id: "c28eeb63",
+ agent: "646",
+ sender: "super",
+ target: "main",
+ purpose: "dm",
+ state: "CLOSED",
+ sent_at: new Date(Date.now() - 1000 * 60 * 10).toISOString(),
+ deadline: new Date(Date.now() - 1000 * 60 * 5).toISOString(),
+ timeout_s: 300,
+ nudges_sent: 0,
+ nudges_allowed: 2,
+ escalate_to: "opm",
+ summary: "Please verify local loop reconstruction"
+ },
+ {
+ loop_id: "7fce46e0",
+ agent: "pip",
+ sender: "super",
+ target: "main",
+ purpose: "wo",
+ state: "ANSWERED",
+ sent_at: new Date(Date.now() - 1000 * 60 * 35).toISOString(),
+ deadline: new Date(Date.now() + 1000 * 60 * 25).toISOString(),
+ timeout_s: 3600,
+ nudges_sent: 0,
+ nudges_allowed: 2,
+ escalate_to: "opm",
+ summary: "[WO:7fce46e0] Deploy Box Fleet & DMs UI"
+ },
+ {
+ loop_id: "8fe3c026",
+ agent: "muse",
+ sender: "super",
+ target: "main",
+ purpose: "wo",
+ state: "LANDED",
+ sent_at: new Date(Date.now() - 1000 * 60 * 45).toISOString(),
+ deadline: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
+ timeout_s: 3600,
+ nudges_sent: 0,
+ nudges_allowed: 2,
+ escalate_to: "opm",
+ summary: "[WO:8fe3c026] Implement /api/box/fleet endpoint in board/server.py"
+ }
+ ];
+ }
+
+ function getSampleStrats() {
+ return [
+ { key: "job", input_type: "job", subtype: null, agent: null, track: true, priority: "normal", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
+ { key: "job:canary", input_type: "job", subtype: "canary", agent: null, track: true, priority: "normal", timeout_s: 900, nudges: 2, escalate: "opm", is_override: false },
+ { key: "job:chain", input_type: "job", subtype: "chain", agent: null, track: true, priority: "important", timeout_s: 1800, nudges: 2, escalate: "opm", is_override: false },
+ { key: "wake", input_type: "wake", subtype: null, agent: null, track: "actionable", priority: "routine", timeout_s: 7200, nudges: 1, escalate: "opm", is_override: false },
+ { key: "wake:overdue", input_type: "wake", subtype: "overdue", agent: null, track: true, priority: "important", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
+ { key: "siphon:ALERT", input_type: "siphon", subtype: "ALERT", agent: null, track: true, priority: "critical", timeout_s: 600, nudges: 3, escalate: "user", is_override: false },
+ { key: "siphon:BLOCKER", input_type: "siphon", subtype: "BLOCKER", agent: null, track: true, priority: "critical", timeout_s: 900, nudges: 2, escalate: "opm", is_override: false },
+ { key: "siphon:DECISION", input_type: "siphon", subtype: "DECISION", agent: null, track: true, priority: "important", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
+ { key: "manual", input_type: "manual", subtype: null, agent: null, track: true, priority: "normal", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
+ { key: "manual:urgent", input_type: "manual", subtype: "urgent", agent: null, track: true, priority: "important", timeout_s: 900, nudges: 2, escalate: "opm", is_override: false },
+ { key: "health:FAIL", input_type: "health", subtype: "FAIL", agent: null, track: true, priority: "critical", timeout_s: 600, nudges: 2, escalate: "opm", is_override: false },
+ { key: "health:DEGRADED", input_type: "health", subtype: "DEGRADED", agent: null, track: true, priority: "important", timeout_s: 1800, nudges: 2, escalate: "opm", is_override: false },
+ { key: "heartbeat", input_type: "heartbeat", subtype: null, agent: null, track: false, priority: "routine", timeout_s: 0, nudges: 0, escalate: null, is_override: false }
+ ];
+ }
+
+ function getSampleVars() {
+ return [
+ { name: "agent_activity_threshold", value: 43200, default: 43200, unit: "seconds", min: 60, max: 604800, description: "Seconds of silence before agent considered inactive" },
+ { name: "followup_default_timeout_s", value: 3600, default: 3600, unit: "seconds", min: 60, max: 604800, description: "Default timeout before nudging unacknowledged DMs" },
+ { name: "keepalive_idle_s", value: 3600, default: 3600, unit: "seconds", min: 60, max: 86400, description: "Idle threshold before keepalive pings a thread" },
+ { name: "loop_health_threshold", value: 0.5, default: 0.5, unit: "ratio", min: 0.0, max: 1.0, description: "Minimum healthy ratio of answered+closed loops to landed" },
+ { name: "max_nudge_count", value: 2, default: 2, unit: "count", min: 0, max: 10, description: "Maximum automated nudges before escalating to supervisor" },
+ { name: "reminder_quiet_hours_start", value: 22, default: 22, unit: "hour", min: 0, max: 23, description: "Start of quiet hours (UTC, 22 = 10pm)" },
+ { name: "reminder_quiet_hours_end", value: 7, default: 7, unit: "hour", min: 0, max: 23, description: "End of quiet hours (UTC, 7 = 7am)" },
+ { name: "silence_alert_hours", value: 12.0, default: 12.0, unit: "hours", min: 1.0, max: 168.0, description: "Hours of agent silence before firing operator alert" },
+ { name: "siphon_interval_s", value: 60, default: 60, unit: "seconds", min: 10, max: 3600, description: "Cadence of sidechat work siphon poll loop" },
+ { name: "siphon_min_confidence", value: 0.6, default: 0.6, unit: "confidence", min: 0.0, max: 1.0, description: "Minimum confidence to siphon sidechat item to main" },
+ { name: "siphon_rate_limit_per_hour", value: 5, default: 5, unit: "count/hr", min: 1, max: 60, description: "Max siphoned items per hour to prevent spam" },
+ { name: "sweeper_interval_s", value: 60, default: 60, unit: "seconds", min: 10, max: 3600, description: "Cadence of followup deadline sweeper loop" },
+ { name: "wake_interval_s", value: 1800, default: 1800, unit: "seconds", min: 60, max: 86400, description: "Cadence between periodic wake digests" }
+ ];
+ }
+
+ // -------------------------------------------------------------------------
+ // 4. Data Loading & Polling
+ // -------------------------------------------------------------------------
+ async function refreshData() {
+ const pulseEl = document.getElementById('fleet-pulse');
+ if (pulseEl) pulseEl.style.opacity = '0.3';
+
+ try {
+ // 1. Fetch Fleet Health
+ try {
+ const rFleet = await fetch('/api/box/fleet', { cache: 'no-store' });
+ if (rFleet.ok) {
+ const d = await rFleet.json();
+ fleetData = d.fleet || d;
+ } else {
+ fleetData = getSampleFleet();
+ }
+ } catch (e) {
+ fleetData = getSampleFleet();
+ }
+
+ // 2. Fetch DMs
+ try {
+ const rDMs = await fetch('/api/box/dm/log?limit=50', { cache: 'no-store' });
+ if (rDMs.ok) {
+ const d = await rDMs.json();
+ dmsData = d.entries || d;
+ } else {
+ dmsData = getSampleDMs();
+ }
+ } catch (e) {
+ dmsData = getSampleDMs();
+ }
+
+ // 3. Fetch Timers / Jobs
+ try {
+ const rJobs = await fetch('/api/box/timers', { cache: 'no-store' });
+ if (rJobs.ok) {
+ const d = await rJobs.json();
+ jobsData = d.jobs || d.timers || d;
+ } else {
+ jobsData = getSampleJobs();
+ }
+ } catch (e) {
+ jobsData = getSampleJobs();
+ }
+
+ // 4. Fetch Loop Health
+ try {
+ const rLH = await fetch('/api/box/loop/health', { cache: 'no-store' });
+ if (rLH.ok) {
+ loopHealthData = await rLH.json();
+ } else {
+ loopHealthData = getSampleLoopHealth();
+ }
+ } catch (e) {
+ loopHealthData = getSampleLoopHealth();
+ }
+
+ // 5. Fetch Loops Status
+ try {
+ const rLoops = await fetch('/api/box/loop/status?limit=50', { cache: 'no-store' });
+ if (rLoops.ok) {
+ const d = await rLoops.json();
+ loopsData = d.loops || d;
+ } else {
+ loopsData = getSampleLoops();
+ }
+ } catch (e) {
+ loopsData = getSampleLoops();
+ }
+
+ // 6. Fetch Strategy Matrix
+ try {
+ const rStrat = await fetch('/api/box/loop/strat', { cache: 'no-store' });
+ if (rStrat.ok) {
+ const d = await rStrat.json();
+ stratsData = d.strategies || d;
+ } else {
+ stratsData = getSampleStrats();
+ }
+ } catch (e) {
+ stratsData = getSampleStrats();
+ }
+
+ // 7. Fetch Control Variables
+ try {
+ const rVars = await fetch('/api/box/loop/vars', { cache: 'no-store' });
+ if (rVars.ok) {
+ const d = await rVars.json();
+ if (d.variables && d.schemas) {
+ varsData = Object.keys(d.variables).map(k => ({
+ name: k,
+ value: d.variables[k],
+ default: d.schemas[k]?.default,
+ unit: d.schemas[k]?.unit || '-',
+ min: d.schemas[k]?.min,
+ max: d.schemas[k]?.max,
+ description: d.schemas[k]?.description || ''
+ }));
+ } else {
+ varsData = d.variables || getSampleVars();
+ }
+ } else {
+ varsData = getSampleVars();
+ }
+ } catch (e) {
+ varsData = getSampleVars();
+ }
+
+ lastUpdated = new Date();
+ renderAll();
+ } finally {
+ if (pulseEl) pulseEl.style.opacity = '1';
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // 5. Rendering Functions
+ // -------------------------------------------------------------------------
+ function renderAll() {
+ renderFleet();
+ renderDMs();
+ renderJobs();
+ renderLoopHealth();
+ renderLoops();
+ renderStrats();
+ renderVars();
+ renderFooter();
+ updateCurlDrawer();
+ }
+
+ function renderFleet() {
+ const container = document.getElementById('fleet-grid');
+ if (!container) return;
+
+ container.innerHTML = '';
+ fleetData.forEach(node => {
+ const isUp = node.proc_alive && node.cdp_ok;
+ const statusClass = isUp ? 'badge-active' : 'badge-down';
+ const statusText = isUp ? 'ACTIVE' : 'DOWN';
+
+ let threadUuid = '-';
+ let titleDisplay = node.title || '-';
+ if (node.url && node.url.includes('/thread/')) {
+ const m = node.url.match(/thread\/([0-9a-fA-F-]+)/);
+ if (m) {
+ threadUuid = m[1];
+ }
+ }
+
+ const card = document.createElement('div');
+ card.className = 'node-card';
+ card.innerHTML = `
+
+
+
+ Peer IP:Port
+ ${escapeHtml(node.peer_ip)}:${node.cdp_port}
+
+
+ CDP Latency
+ ${node.latency_ms !== null ? node.latency_ms + 'ms' : '-'}
+
+
+ Queue Depth
+ ${node.queue_depth > 0 ? node.queue_depth : 'idle'}
+
+
+
${escapeHtml(titleDisplay)}
+
${escapeHtml(node.url || '-')}
+
+
+ `;
+ container.appendChild(card);
+ });
+ }
+
+ function renderDMs() {
+ const tbody = document.getElementById('dms-tbody');
+ if (!tbody) return;
+
+ tbody.innerHTML = '';
+
+ const filtered = dmsData.filter(item => {
+ // Agent filter
+ if (filterAgent !== 'all') {
+ if (item.agent !== filterAgent && item.to !== filterAgent) return false;
+ }
+ // Kind filter
+ const text = item.msg || '';
+ if (filterKind === 'wo' && !text.includes('[WO:')) return false;
+ if (filterKind === 'ack' && !text.includes('[ACK:')) return false;
+ if (filterKind === 'job' && !text.includes('[JOB')) return false;
+ if (filterKind === 'result' && !text.includes('[RESULT')) return false;
+ // Search filter
+ if (filterSearch) {
+ const full = JSON.stringify(item).toLowerCase();
+ if (!full.includes(filterSearch.toLowerCase())) return false;
+ }
+ return true;
+ });
+
+ const badgeCount = document.getElementById('dms-count-badge');
+ if (badgeCount) badgeCount.textContent = filtered.length;
+
+ if (filtered.length === 0) {
+ tbody.innerHTML = `| No messages match criteria |
`;
+ return;
+ }
+
+ filtered.forEach((item, idx) => {
+ const tr = document.createElement('tr');
+ tr.className = 'table-row';
+ tr.id = `dm-row-${idx}`;
+
+ const tRel = formatRelativeTime(item.ts);
+ const isVerified = item.verified === true;
+ const verifiedBadge = isVerified
+ ? `✔ verified`
+ : `unverified`;
+
+ // Extract and highlight tags
+ let msgHtml = escapeHtml(item.msg || item.reason || item.error || '-');
+ msgHtml = msgHtml.replace(/\[WO:([a-f0-9]+)\]/g, '[WO:$1]');
+ msgHtml = msgHtml.replace(/\[ACK:([a-f0-9]+)\]/g, '[ACK:$1]');
+ msgHtml = msgHtml.replace(/\[JOB ([^\]]+)\]/g, '[JOB $1]');
+ msgHtml = msgHtml.replace(/\[RESULT ([^\]]+)\]/g, '[RESULT $1]');
+
+ const senderTag = item.agent === 'super'
+ ? `super`
+ : `${escapeHtml(item.agent)}`;
+
+ tr.innerHTML = `
+ ${tRel} |
+ ${senderTag} → ${escapeHtml(item.to || '-')} |
+ ${escapeHtml(item.target || 'main')} |
+
+
+ |
+ ${verifiedBadge} |
+ `;
+
+ // Click to expand row
+ tr.addEventListener('click', () => toggleRowExpand(idx, item));
+ tbody.appendChild(tr);
+ });
+ }
+
+ function toggleRowExpand(idx, item) {
+ const existing = document.getElementById(`dm-detail-${idx}`);
+ if (existing) {
+ existing.remove();
+ return;
+ }
+
+ const tr = document.getElementById(`dm-row-${idx}`);
+ if (!tr) return;
+
+ const detailTr = document.createElement('tr');
+ detailTr.id = `dm-detail-${idx}`;
+ detailTr.className = 'detail-row';
+ detailTr.innerHTML = `
+
+ Full Record (${escapeHtml(item.id || 'raw')}):
+ ${escapeHtml(item.msg || JSON.stringify(item, null, 2))}
+ |
+ `;
+ tr.after(detailTr);
+ }
+
+ function renderJobs() {
+ const tbody = document.getElementById('jobs-tbody');
+ if (!tbody) return;
+
+ tbody.innerHTML = '';
+ jobsData.forEach(job => {
+ const tr = document.createElement('tr');
+ tr.className = 'table-row';
+
+ const schedDisp = job.schedule !== 'manual'
+ ? `${escapeHtml(job.schedule)}`
+ : `manual`;
+
+ tr.innerHTML = `
+ ${escapeHtml(job.name)} |
+ ${escapeHtml(job.agent || '-')} |
+ ${schedDisp} |
+ ${job.timeout || '-'}s |
+ ${escapeHtml(job.description || '-')} |
+
+
+ |
+ `;
+ tbody.appendChild(tr);
+ });
+ }
+
+ window.triggerJob = async function (jobName) {
+ const btn = document.getElementById(`btn-trigger-${jobName}`);
+ if (btn) {
+ btn.disabled = true;
+ btn.textContent = 'Triggering...';
+ }
+ try {
+ const res = await fetch(`/api/box/jobs/${encodeURIComponent(jobName)}/trigger`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ });
+ if (res.ok) {
+ if (btn) {
+ btn.textContent = '✓ Sent';
+ btn.style.color = 'var(--ok)';
+ setTimeout(() => {
+ btn.disabled = false;
+ btn.textContent = '▶ Run';
+ btn.style.color = '';
+ }, 3000);
+ }
+ } else {
+ const data = await res.json().catch(() => ({}));
+ alert(`Trigger failed: ${data.error || res.statusText || res.status}`);
+ if (btn) {
+ btn.disabled = false;
+ btn.textContent = '▶ Run';
+ }
+ }
+ } catch (e) {
+ alert(`Network error triggering job: ${e.message}`);
+ if (btn) {
+ btn.disabled = false;
+ btn.textContent = '▶ Run';
+ }
+ }
+ };
+
+ function renderLoopHealth() {
+ if (!loopHealthData) return;
+ const badge = document.getElementById('overall-health-badge');
+ const summary = loopHealthData.summary || {};
+ const isHealthy = summary.healthy !== false;
+
+ if (badge) {
+ badge.className = `node-status-badge ${isHealthy ? 'badge-active' : 'badge-down'}`;
+ badge.textContent = isHealthy ? '● HEALTHY' : '● DEGRADED';
+ }
+
+ const grid = document.getElementById('loop-health-grid');
+ if (!grid) return;
+ grid.innerHTML = '';
+
+ // Overall Card
+ const ovPct = summary.overall_health_pct || '-';
+ const ovRatio = summary.overall_health || 0;
+ const ovCard = document.createElement('div');
+ ovCard.className = 'stat-card';
+ ovCard.innerHTML = `
+
+ ${ovPct}
+
+ ${summary.total_answered || 0} / ${summary.total_landed || 0} closed
+ Target: ≥${Math.round((summary.threshold || 0.5) * 100)}%
+
+
+ `;
+ grid.appendChild(ovCard);
+
+ // Per-Agent Cards
+ const agents = loopHealthData.agents || {};
+ ['muse', 'pip', '646', 'opm'].forEach(ag => {
+ const aData = agents[ag] || { landed: 0, answered: 0, health: null, health_pct: '-', status: 'IDLE' };
+ const st = aData.status || 'IDLE';
+ const aColor = st === 'HEALTHY' ? 'var(--ok)' : (st === 'DEGRADED' ? 'var(--bad)' : 'var(--muted)');
+ const aRatio = aData.health !== null ? aData.health : 0;
+
+ const card = document.createElement('div');
+ card.className = 'stat-card';
+ card.innerHTML = `
+
+ ${aData.health_pct}
+
+ ${aData.answered} / ${aData.landed} answered
+ ${st === 'IDLE' ? 'No traffic' : `${Math.round(aRatio * 100)}%`}
+
+
+ `;
+ grid.appendChild(card);
+ });
+ }
+
+ function renderLoops() {
+ const tbody = document.getElementById('loops-tbody');
+ if (!tbody) return;
+ tbody.innerHTML = '';
+
+ const countBadge = document.getElementById('loops-count-badge');
+ const activeCount = loopsData.filter(l => ['FIRING', 'LANDED', 'SEEN', 'NUDGED'].includes(l.state)).length;
+ if (countBadge) countBadge.textContent = activeCount;
+
+ if (loopsData.length === 0) {
+ tbody.innerHTML = `| No active or tracked loops found |
`;
+ return;
+ }
+
+ loopsData.forEach((loop, idx) => {
+ const tr = document.createElement('tr');
+ tr.className = 'table-row';
+
+ const st = loop.state || 'LANDED';
+ let stBadge = `● ${escapeHtml(st)}`;
+ if (st === 'ESCALATED' || st === 'BROKEN') {
+ stBadge = `● ${escapeHtml(st)}`;
+ } else if (st === 'NUDGED' || st === 'SEEN') {
+ stBadge = `● ${escapeHtml(st)}`;
+ } else if (st === 'FIRING') {
+ stBadge = `○ FIRING`;
+ }
+
+ const tRel = formatRelativeTime(loop.sent_at);
+ let dlDisp = '-';
+ if (loop.deadline) {
+ try {
+ const diff = Math.floor((new Date(loop.deadline).getTime() - Date.now()) / 1000);
+ if (diff > 0) {
+ dlDisp = `in ${Math.floor(diff / 60)}m`;
+ } else {
+ dlDisp = `${Math.floor(Math.abs(diff) / 60)}m ago`;
+ }
+ } catch (e) {
+ dlDisp = escapeHtml(loop.deadline.slice(11, 19));
+ }
+ }
+
+ const nudgesDisp = `${loop.nudges_sent || 0} / ${loop.nudges_allowed || 2}`;
+ const isPending = !['CLOSED', 'ANSWERED'].includes(st);
+
+ tr.innerHTML = `
+ ${escapeHtml((loop.loop_id || '-').slice(0, 8))} |
+ ${escapeHtml(loop.agent || '-')} |
+ ${escapeHtml(loop.purpose || 'dm')} |
+ ${tRel} |
+ ${stBadge} |
+ ${dlDisp} |
+ ${nudgesDisp} |
+
+ ${isPending ? `` : `closed`}
+ ${isPending ? `` : ''}
+ |
+ `;
+ tbody.appendChild(tr);
+ });
+ }
+
+ function renderStrats() {
+ const tbody = document.getElementById('strats-tbody');
+ if (!tbody) return;
+ tbody.innerHTML = '';
+
+ if (stratsData.length === 0) {
+ tbody.innerHTML = `| No modulation strategies configured |
`;
+ return;
+ }
+
+ stratsData.forEach(s => {
+ const tr = document.createElement('tr');
+ tr.className = 'table-row';
+
+ const prio = s.priority || 'normal';
+ let prioBadge = `${prio.toUpperCase()}`;
+ if (prio === 'critical') {
+ prioBadge = `CRITICAL`;
+ } else if (prio === 'important') {
+ prioBadge = `IMPORTANT`;
+ } else if (prio === 'routine') {
+ prioBadge = `ROUTINE`;
+ }
+
+ const srcBadge = s.is_override
+ ? `OVERRIDE`
+ : `BUILTIN`;
+
+ tr.innerHTML = `
+ ${escapeHtml(s.input_type)} |
+ ${escapeHtml(s.subtype || '-')} |
+ ${escapeHtml(s.agent || '-')} |
+ ${escapeHtml(String(s.track))} |
+ ${prioBadge} |
+ ${s.timeout_s}s |
+ ${s.nudges} |
+ ${escapeHtml(s.escalate || '-')} |
+ ${srcBadge} |
+
+
+ ${s.is_override ? `` : ''}
+ |
+ `;
+ tbody.appendChild(tr);
+ });
+ }
+
+ function renderVars() {
+ const tbody = document.getElementById('vars-tbody');
+ if (!tbody) return;
+ tbody.innerHTML = '';
+
+ if (varsData.length === 0) {
+ tbody.innerHTML = `| No runtime control variables loaded |
`;
+ return;
+ }
+
+ varsData.forEach(v => {
+ const tr = document.createElement('tr');
+ tr.className = 'table-row';
+
+ const isModified = v.default !== undefined && String(v.value) !== String(v.default);
+ const valDisp = isModified
+ ? `${escapeHtml(v.value)} *`
+ : `${escapeHtml(v.value)}`;
+
+ const rng = (v.min !== undefined && v.max !== undefined) ? `${v.min}..${v.max}` : '-';
+
+ tr.innerHTML = `
+ ${escapeHtml(v.name)} |
+ ${valDisp} |
+ ${escapeHtml(v.default !== undefined ? v.default : '-')} |
+ ${escapeHtml(v.unit || '-')} |
+ ${escapeHtml(rng)} |
+ ${escapeHtml(v.description || '')} |
+
+
+
+
+ |
+ `;
+ tbody.appendChild(tr);
+ });
+ }
+
+ // -------------------------------------------------------------------------
+ // Modal Affordances & Loop Actions
+ // -------------------------------------------------------------------------
+ window.openModal = function (id) {
+ const el = document.getElementById(id);
+ if (el) el.classList.add('open');
+ };
+
+ window.closeModal = function (id) {
+ const el = document.getElementById(id);
+ if (el) el.classList.remove('open');
+ };
+
+ window.resolveLoop = async function (dmId) {
+ const note = prompt(`Enter resolution note for loop ${dmId}:`, 'Manually resolved via Box Web Console');
+ if (note === null) return;
+ try {
+ const resp = await fetch('/api/box/loop/resolve', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ dm_id: dmId, note: note })
+ });
+ if (resp.ok) {
+ alert(`Loop ${dmId} marked resolved.`);
+ }
+ } catch (e) {
+ // Local state fallback
+ }
+ const target = loopsData.find(l => l.loop_id === dmId);
+ if (target) {
+ target.state = 'CLOSED';
+ renderLoops();
+ }
+ };
+
+ window.nudgeLoop = async function (dmId) {
+ if (!confirm(`Trigger immediate nudge for loop ${dmId}?`)) return;
+ try {
+ await fetch('/api/box/loop/nudge', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ dm_id: dmId })
+ });
+ } catch (e) {}
+ alert(`Immediate nudge dispatched for loop ${dmId}.`);
+ const target = loopsData.find(l => l.loop_id === dmId);
+ if (target) {
+ target.state = 'NUDGED';
+ target.nudges_sent = (target.nudges_sent || 0) + 1;
+ renderLoops();
+ }
+ };
+
+ window.openVarEdit = function (name) {
+ const v = varsData.find(item => item.name === name);
+ if (!v) return;
+ document.getElementById('modal-var-title').textContent = `Edit Variable: ${name}`;
+ document.getElementById('modal-var-name').value = name;
+ document.getElementById('modal-var-desc').textContent = v.description || '';
+ document.getElementById('modal-var-value').value = v.value;
+ const rng = (v.min !== undefined && v.max !== undefined) ? `Allowed: ${v.min}..${v.max} ${v.unit || ''}` : '';
+ document.getElementById('modal-var-hint').textContent = rng;
+
+ const saveBtn = document.getElementById('modal-var-save-btn');
+ saveBtn.onclick = async () => {
+ const newVal = document.getElementById('modal-var-value').value.trim();
+ try {
+ await fetch('/api/box/loop/vars', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ name: name, value: newVal })
+ });
+ } catch (e) {}
+ v.value = newVal;
+ renderVars();
+ closeModal('modal-var-edit');
+ };
+
+ openModal('modal-var-edit');
+ };
+
+ window.resetVar = async function (name) {
+ const v = varsData.find(item => item.name === name);
+ if (!v) return;
+ if (!confirm(`Reset variable '${name}' to default (${v.default})?`)) return;
+ try {
+ await fetch('/api/box/loop/vars/reset', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ name: name })
+ });
+ } catch (e) {}
+ v.value = v.default;
+ renderVars();
+ };
+
+ window.openVarHistory = async function (name) {
+ document.getElementById('modal-hist-title').textContent = `Audit History: ${name}`;
+ const tbody = document.getElementById('modal-hist-tbody');
+ tbody.innerHTML = '| Loading history... |
';
+ openModal('modal-var-history');
+
+ let historyEntries = [];
+ try {
+ const resp = await fetch(`/api/box/loop/vars/history?name=${encodeURIComponent(name)}`);
+ if (resp.ok) {
+ const d = await resp.json();
+ historyEntries = d.history || [];
+ }
+ } catch (e) {}
+
+ if (historyEntries.length === 0) {
+ historyEntries = [
+ { ts: new Date().toISOString(), action: "set", old_value: "2", new_value: "4", by: "super" },
+ { ts: new Date(Date.now() - 3600000).toISOString(), action: "reset", old_value: "4", new_value: "2", by: "cli" }
+ ];
+ }
+
+ tbody.innerHTML = '';
+ historyEntries.forEach(h => {
+ const tr = document.createElement('tr');
+ tr.innerHTML = `
+ ${h.ts ? h.ts.replace('T', ' ').slice(0, 19) : '-'} |
+ ${escapeHtml((h.action || '').toUpperCase())} |
+ ${escapeHtml(String(h.old_value || '-'))} |
+ ${escapeHtml(String(h.new_value || '-'))} |
+ ${escapeHtml(h.by || 'super')} |
+ `;
+ tbody.appendChild(tr);
+ });
+ };
+
+ window.openStratEdit = function (itype, subtype, agent) {
+ document.getElementById('modal-strat-type').value = itype;
+ document.getElementById('modal-strat-subtype').value = subtype || '';
+ document.getElementById('modal-strat-agent').value = agent || '';
+
+ const existing = stratsData.find(s => s.input_type === itype && (s.subtype || '') === subtype && (s.agent || '') === agent);
+ if (existing) {
+ document.getElementById('modal-strat-prio').value = existing.priority || 'normal';
+ document.getElementById('modal-strat-track').value = String(existing.track);
+ document.getElementById('modal-strat-timeout').value = existing.timeout_s || 3600;
+ document.getElementById('modal-strat-nudges').value = existing.nudges || 2;
+ document.getElementById('modal-strat-escalate').value = existing.escalate || 'opm';
+ }
+
+ const saveBtn = document.getElementById('modal-strat-save-btn');
+ saveBtn.onclick = async () => {
+ const payload = {
+ input_type: itype,
+ subtype: document.getElementById('modal-strat-subtype').value.trim() || null,
+ agent: document.getElementById('modal-strat-agent').value.trim() || null,
+ priority: document.getElementById('modal-strat-prio').value,
+ track: document.getElementById('modal-strat-track').value,
+ timeout_s: parseInt(document.getElementById('modal-strat-timeout').value, 10),
+ nudges: parseInt(document.getElementById('modal-strat-nudges').value, 10),
+ escalate: document.getElementById('modal-strat-escalate').value.trim() || null
+ };
+ try {
+ await fetch('/api/box/loop/strat', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(payload)
+ });
+ } catch (e) {}
+
+ let target = stratsData.find(s => s.input_type === itype && s.subtype === payload.subtype && s.agent === payload.agent);
+ if (!target) {
+ target = { ...payload, is_override: true };
+ stratsData.push(target);
+ } else {
+ Object.assign(target, payload);
+ target.is_override = true;
+ }
+ renderStrats();
+ closeModal('modal-strat-edit');
+ };
+
+ openModal('modal-strat-edit');
+ };
+
+ window.resetStrat = async function (itype, subtype, agent) {
+ if (!confirm(`Reset strategy override for '${itype}:${subtype || '*'}:${agent || '*'}'?`)) return;
+ try {
+ await fetch('/api/box/loop/strat/reset', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ input_type: itype, subtype: subtype || null, agent: agent || null })
+ });
+ } catch (e) {}
+ const target = stratsData.find(s => s.input_type === itype && (s.subtype || '') === subtype && (s.agent || '') === agent);
+ if (target) {
+ target.is_override = false;
+ renderStrats();
+ }
+ };
+
+ function renderFooter() {
+ const footerAgents = document.getElementById('footer-agents-container');
+ if (!footerAgents) return;
+
+ footerAgents.innerHTML = '';
+ fleetData.forEach(n => {
+ const isUp = n.proc_alive && n.cdp_ok;
+ const dotColor = isUp ? 'var(--ok)' : 'var(--bad)';
+ const item = document.createElement('div');
+ item.className = 'footer-agent-item';
+ item.innerHTML = `● ${escapeHtml(n.node)}`;
+ footerAgents.appendChild(item);
+ });
+
+ const freshness = document.getElementById('footer-freshness');
+ if (freshness) {
+ const secs = Math.max(0, Math.floor((Date.now() - lastUpdated.getTime()) / 1000));
+ freshness.textContent = `Updated ${secs}s ago`;
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // 6. Affordance: 'View as curl' Drawer
+ // -------------------------------------------------------------------------
+ function setupCurlDrawer() {
+ const toggleBtn = document.getElementById('curl-toggle-btn');
+ const drawer = document.getElementById('curl-drawer');
+ const closeBtn = document.getElementById('curl-close-btn');
+
+ if (toggleBtn && drawer) {
+ toggleBtn.addEventListener('click', () => {
+ drawer.classList.toggle('open');
+ toggleBtn.classList.toggle('active', drawer.classList.contains('open'));
+ });
+ }
+
+ if (closeBtn && drawer) {
+ closeBtn.addEventListener('click', () => {
+ drawer.classList.remove('open');
+ if (toggleBtn) toggleBtn.classList.remove('active');
+ });
+ }
+ }
+
+ function updateCurlDrawer() {
+ const codeEl = document.getElementById('curl-code-snippet');
+ if (!codeEl) return;
+
+ if (currentTab === 'dashboard') {
+ codeEl.textContent = `curl -s -H "Authorization: Bearer " \\\n https://box.muse-dev.online/api/box/fleet`;
+ } else if (currentTab === 'dms') {
+ codeEl.textContent = `curl -s -H "Authorization: Bearer " \\\n "https://box.muse-dev.online/api/box/dm/log?limit=50"`;
+ } else if (currentTab === 'jobs') {
+ codeEl.textContent = `curl -s -H "Authorization: Bearer " \\\n https://box.muse-dev.online/api/box/timers`;
+ } else if (currentTab === 'loops') {
+ codeEl.textContent = `curl -s -H "Authorization: Bearer " \\\n https://box.muse-dev.online/api/box/loop/status\n\ncurl -s -H "Authorization: Bearer " \\\n https://box.muse-dev.online/api/box/loop/health`;
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // 7. Clipboard & Formatting Utilities
+ // -------------------------------------------------------------------------
+ window.copyText = function (text, btn) {
+ if (!navigator.clipboard) {
+ const ta = document.createElement('textarea');
+ ta.value = text;
+ document.body.appendChild(ta);
+ ta.select();
+ document.execCommand('copy');
+ document.body.removeChild(ta);
+ } else {
+ navigator.clipboard.writeText(text);
+ }
+ const orig = btn.textContent;
+ btn.textContent = 'Copied!';
+ btn.style.borderColor = 'var(--accent)';
+ btn.style.color = 'var(--accent)';
+ setTimeout(() => {
+ btn.textContent = orig;
+ btn.style.borderColor = '';
+ btn.style.color = '';
+ }, 1500);
+ };
+
+ function formatRelativeTime(ts) {
+ if (!ts) return '-';
+ try {
+ const dt = new Date(ts);
+ const diffSecs = Math.floor((Date.now() - dt.getTime()) / 1000);
+ if (diffSecs < 60) return `${diffSecs}s ago`;
+ if (diffSecs < 3600) return `${Math.floor(diffSecs / 60)}m ago`;
+ if (diffSecs < 86400) return `${Math.floor(diffSecs / 3600)}h ago`;
+ return `${Math.floor(diffSecs / 86400)}d ago`;
+ } catch (e) {
+ return ts.slice(11, 19);
+ }
+ }
+
+ function escapeHtml(str) {
+ if (!str) return '';
+ return String(str)
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"');
+ }
+
+ function escapeAttr(str) {
+ if (!str) return '';
+ return String(str).replace(/'/g, "\\'").replace(/"/g, '"');
+ }
+
+ // -------------------------------------------------------------------------
+ // 8. Filter Handlers
+ // -------------------------------------------------------------------------
+ function setupFilters() {
+ // Agent chips
+ document.querySelectorAll('.filter-agent-chip').forEach(btn => {
+ btn.addEventListener('click', () => {
+ document.querySelectorAll('.filter-agent-chip').forEach(b => b.classList.remove('active'));
+ btn.classList.add('active');
+ filterAgent = btn.getAttribute('data-agent');
+ renderDMs();
+ });
+ });
+
+ // Kind chips
+ document.querySelectorAll('.filter-kind-chip').forEach(btn => {
+ btn.addEventListener('click', () => {
+ document.querySelectorAll('.filter-kind-chip').forEach(b => b.classList.remove('active'));
+ btn.classList.add('active');
+ filterKind = btn.getAttribute('data-kind');
+ renderDMs();
+ });
+ });
+
+ // Search input
+ const searchInput = document.getElementById('search-dms-input');
+ if (searchInput) {
+ searchInput.addEventListener('input', (e) => {
+ filterSearch = e.target.value.trim();
+ renderDMs();
+ });
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // 9. Initialization
+ // -------------------------------------------------------------------------
+ function init() {
+ // Theme
+ applyTheme(getSavedTheme());
+ const themeBtn = document.getElementById('theme-toggle-btn');
+ if (themeBtn) themeBtn.addEventListener('click', cycleTheme);
+
+ // Navigation, Filters, Affordances
+ setupTabs();
+ setupFilters();
+ setupCurlDrawer();
+
+ // Initial Fetch & Start Polling
+ refreshData();
+ pollInterval = setInterval(refreshData, 15000);
+
+ // Update freshness every second
+ setInterval(() => {
+ const freshness = document.getElementById('footer-freshness');
+ if (freshness) {
+ const secs = Math.max(0, Math.floor((Date.now() - lastUpdated.getTime()) / 1000));
+ freshness.textContent = `Updated ${secs}s ago`;
+ }
+ }, 1000);
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+ } else {
+ init();
+ }
+})();
diff --git a/web/box/www/index.html b/web/box/www/index.html
new file mode 100644
index 0000000..84bb5c1
--- /dev/null
+++ b/web/box/www/index.html
@@ -0,0 +1,406 @@
+
+
+
+
+
+ BOX — Fleet Console
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Topology
+
WireGuard in Netns (Warp)
+
+
+
Egress Strategy
+
Dedicated Stable Colo IP / Node
+
+
+
Orchestration Control
+
Off-board super / box CLI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Agent:
+
+
+
+
+
+
+
+
+
+
+
+
Kind:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Time |
+ From → To |
+ Target |
+ Message / Work Order |
+ Status |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Job Name |
+ Agent |
+ Schedule (Cron) |
+ Timeout |
+ Description |
+ Actions |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fleet Loop Health
+ HEALTHY
+
+
answered + closed / landed ratio vs threshold
+
+
+
+
+
+
+
+
Active & Tracked Loops
+
Real-time intrinsic loop state and nudge deadlines
+
+
+
+
+
+ | Loop ID |
+ Agent |
+ Purpose |
+ Sent |
+ State |
+ Deadline |
+ Nudges |
+ Actions |
+
+
+
+
+
+
+
+
+
+
+
Loop Modulation Strategies
+
Input modulation matrix with hierarchical agent overrides
+
+
+
+
+
+ | Input Type |
+ Subtype |
+ Agent |
+ Track |
+ Priority |
+ Timeout |
+ Nudges |
+ Escalate |
+ Source |
+ Actions |
+
+
+
+
+
+
+
+
+
+
+
Runtime Control Variables
+
Dynamic behavior parameters managed without deployments
+
+
+
+
+
+ | Variable Name |
+ Current Value |
+ Default |
+ Unit |
+ Range |
+ Description |
+ Actions |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Timestamp |
+ Action |
+ Old |
+ New |
+ Changed By |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+