â back to Agent Cabinet
Build out both proposals LIVE: đ©ș Health Overlay (reads 6 DW canary latest.json, maps verdictsâofficers, tints nodes + status dots) + đž Cost Heatmap (reads cost-ledger.jsonl, appâofficer spend, ranks top spenders, node badges); /api/health + /api/cost; clear-overlay control
9634ba240e97c177cf30f105283fba5f66bf5c78 · 2026-06-16 16:45:36 -0700 · SteveStudio2
Files touched
M pyramid.htmlM server.js
Diff
commit 9634ba240e97c177cf30f105283fba5f66bf5c78
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Tue Jun 16 16:45:36 2026 -0700
Build out both proposals LIVE: đ©ș Health Overlay (reads 6 DW canary latest.json, maps verdictsâofficers, tints nodes + status dots) + đž Cost Heatmap (reads cost-ledger.jsonl, appâofficer spend, ranks top spenders, node badges); /api/health + /api/cost; clear-overlay control
---
pyramid.html | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
server.js | 53 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 124 insertions(+), 4 deletions(-)
diff --git a/pyramid.html b/pyramid.html
index 93bd843..7cba1c9 100644
--- a/pyramid.html
+++ b/pyramid.html
@@ -168,6 +168,22 @@
.m-list{font-size:12px}
.m-list .row{display:flex;justify-content:space-between;gap:10px;padding:6px 2px;border-bottom:1px solid #141b28}
.m-quote{font-style:italic;color:#9fb0c9;border-left:3px solid #6d34f4;padding:6px 12px;margin:10px 0;font-size:12px;background:rgba(109,52,244,.07)}
+ /* health + cost overlays */
+ .officer-node.h-up{border-color:#16a34a !important}
+ .officer-node.h-warn{border-color:#fbbf24 !important}
+ .officer-node.h-down{border-color:#ef4444 !important}
+ .health-dot{position:absolute;top:7px;right:8px;width:11px;height:11px;border-radius:50%;box-shadow:0 0 0 2px #0b0e14}
+ .health-dot.up{background:#34d399}.health-dot.warn{background:#fbbf24}.health-dot.down{background:#ef4444}.health-dot.na{background:#4b5563}
+ .cost-badge{position:absolute;top:7px;left:8px;font:800 9.5px ui-monospace,monospace;color:#fde68a;background:#3a2a05;border:1px solid #b8860b;border-radius:5px;padding:1px 5px}
+ .cost-bar{position:absolute;left:0;bottom:0;height:3px;background:linear-gradient(90deg,#f59e0b,#ef4444)}
+ #clear-overlay{position:fixed;bottom:20px;left:20px;z-index:140;background:#161d2c;border:1px solid #2b3650;color:#bcd0f0;border-radius:9px;padding:8px 14px;font-size:12px;cursor:pointer;display:none;box-shadow:0 6px 20px rgba(0,0,0,.5)}
+ #clear-overlay.show{display:block}
+ .hstat{display:inline-flex;align-items:center;gap:6px;font-size:12px;padding:3px 0}
+ .hstat .d{width:10px;height:10px;border-radius:50%}
+ .bar-row{display:flex;align-items:center;gap:8px;font-size:11.5px;margin:3px 0}
+ .bar-row .nm{width:170px;color:#cfd8e6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
+ .bar-row .bar{height:9px;border-radius:5px;background:linear-gradient(90deg,#6d34f4,#a78bfa)}
+ .bar-row .v{color:#fde68a;font:11px ui-monospace,monospace;min-width:52px;text-align:right}
</style>
</head>
<body>
@@ -219,6 +235,7 @@
</div>
<div id="toast"></div>
<div id="modal" class="modal-overlay"><div class="modal-box"><button class="modal-x" onclick="closeModal()">â</button><div id="modal-content" class="m-pad"></div></div></div>
+<button id="clear-overlay" onclick="clearOverlays()">â Clear overlay</button>
<script>
const OFF = [
@@ -570,8 +587,8 @@ const IDEAS=[
{icon:'đ', title:'Task Router â âWho handles this?â', live:true, render:'router', pitch:'Type any task; route it to the right officer â agent â skill, with one-click Run.'},
{icon:'đ§Ź', title:'Consolidation Advisor', live:true, render:'consol', pitch:'Surface skills shared across officers and recommend folds â per the cabinetâs own architecture rules.'},
{icon:'đ€', title:'Org Snapshot Export', live:true, render:'export', pitch:'Download the whole cabinet as JSON + Markdown for docs, diffs and sharing.'},
- {icon:'đ©ș', title:'Live Health Overlay', live:false, render:'health', pitch:'Tint each officer node by its domainâs current uptime / canary verdict â see whatâs on fire at a glance.'},
- {icon:'đž', title:'Cost / Usage Heatmap', live:false, render:'cost', pitch:'Size & tint nodes by invocation count or $ from the cost-ledger so the hot (and dead) agents pop.'},
+ {icon:'đ©ș', title:'Live Health Overlay', live:true, render:'health', pitch:'Tint each officer node by its domainâs current uptime / canary verdict â see whatâs on fire at a glance.'},
+ {icon:'đž', title:'Cost / Usage Heatmap', live:true, render:'cost', pitch:'Tint nodes & rank apps by $ from the cost-ledger so the hot (and dead) spenders pop.'},
];
function openIdeasGallery(){
const cards=IDEAS.map((id,i)=>`<div class="idea-card" onclick="openIdea(${i})"><div class="ic">${id.icon}</div><div class="t">${id.title}</div><div class="p">${id.pitch}</div><span class="tag ${id.live?'live':'prop'}">${id.live?'â LIVE':'â PROPOSAL'}</span></div>`).join('');
@@ -583,10 +600,11 @@ function openIdea(i){
if(id.render==='router') body=routerHTML();
else if(id.render==='consol') body=consolHTML();
else if(id.render==='export') body=exportHTML();
- else if(id.render==='health') body=`<div class="m-sub">Proposal. The cabinet server would read each DW canaryâs <code>data/latest.json</code> + the uptime probe and tint every officer node green / amber / red by its domainâs live verdict (Operations=fleet uptime, Commerce=scraper-canary, Compliance=leak-scanâŠ). One glance tells you which department is on fire.</div><div class="m-quote">Maps the abstract org chart onto real-time fleet health.</div>`;
- else if(id.render==='cost') body=`<div class="m-sub">Proposal. Pull <code>~/.claude/cost-ledger.jsonl</code> + invocation counts and scale each nodeâs size / heat by spend or usage â so expensive agents and never-run skills are obvious. Directly serves the architecture goal of retiring dead skills.</div><div class="m-quote">Turns the pyramid into a spend & usage heatmap.</div>`;
+ else body='<div id="idea-dyn" class="m-sub">Loading live dataâŠ</div>';
openModal(`<h2 class="m-h">${id.icon} ${id.title}</h2><div class="m-sub">${id.pitch}</div>${body}${ideaFooter(i)}`);
if(id.render==='router'){ const inp=document.getElementById('route-q'); if(inp){ inp.focus(); inp.addEventListener('keydown',e=>{ if(e.key==='Enter') routeTask(); }); } }
+ else if(id.render==='health') loadHealth();
+ else if(id.render==='cost') loadCost();
}
function queueIdea(i){ const id=IDEAS[i];
fetch('/api/queue-idea?title='+encodeURIComponent('[Cabinet] '+id.title)+'&summary='+encodeURIComponent(id.pitch)).then(r=>r.json())
@@ -620,6 +638,55 @@ function buildExport(){
function exportHTML(){ return `<div class="m-sub">Download the live cabinet structure (7 officers, all agents/skills, the ${SHARED.length} cross-officer shares + ${SUGGEST.length} suggestions).</div><div class="m-actions" style="border:none;padding:0;margin-top:6px"><button class="m-btn primary" onclick="dl('json')">⏠cabinet.json</button><button class="m-btn primary" onclick="dl('md')">⏠cabinet.md</button></div>`; }
function dl(kind){ const e=buildExport(); const blob=new Blob([kind==='json'?e.json:e.md],{type:'text/plain'}); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='cabinet.'+(kind==='json'?'json':'md'); a.click(); toast('⏠cabinet.'+kind+' downloaded'); }
+// Idea 4 â Live Health Overlay (real DW canary verdicts)
+let HEALTH=null, COST=null, _overlay=null;
+const HCOL={up:'#34d399',warn:'#fbbf24',down:'#ef4444',na:'#4b5563'};
+async function loadHealth(){
+ const box=document.getElementById('idea-dyn'); if(!box) return;
+ let d; try{ d=await(await fetch('/api/health')).json(); }catch(e){ box.innerHTML='<div class="dr-note">server unreachable â open via :9766/pyramid</div>'; return; }
+ HEALTH=d;
+ let h='<div style="margin:2px 0 12px">';
+ OFF.forEach(o=>{ const oi=d.officers[o.id]; const st=oi?oi.status:'na';
+ h+=`<div class="hstat"><span class="d" style="background:${HCOL[st]}"></span><b style="color:${o.col}">${o.nm.replace('VP ','')}</b> â <b>${st.toUpperCase()}</b>${oi?'<div style="color:#8a94a6;font-size:10.5px;margin:1px 0 4px 16px">'+oi.detail+'</div>':' <span style="color:#6b7280;font-size:10.5px">(no monitor)</span>'}</div>`; });
+ h+='</div><div class="m-actions" style="border:none;padding:0;margin:0"><button class="m-btn primary" onclick="applyHealth()">đ©ș Apply to pyramid</button><button class="m-btn ghost" onclick="clearOverlays()">Clear</button></div>';
+ box.innerHTML=h;
+}
+function applyHealth(){
+ if(!HEALTH) return; clearOverlays(true);
+ OFF.forEach(o=>{ if(!o._node) return; const oi=HEALTH.officers[o.id]; const st=oi?oi.status:'na';
+ o._node.classList.add('h-'+st);
+ const dot=document.createElement('span'); dot.className='health-dot '+st; dot.title=oi?oi.detail:'no monitor'; o._node.appendChild(dot); });
+ _overlay='health'; document.getElementById('clear-overlay').classList.add('show'); closeModal(); toast('đ©ș health overlay applied');
+}
+// Idea 5 â Cost / Usage Heatmap (real cost-ledger spend, appâofficer mapped)
+function appOfficer(app){ for(const o of OFF){ if(o.agents.includes(app)||o.skills.includes(app)||(o.scrapers||[]).includes(app)) return o.id; } return null; }
+async function loadCost(){
+ const box=document.getElementById('idea-dyn'); if(!box) return;
+ let d; try{ d=await(await fetch('/api/cost')).json(); }catch(e){ box.innerHTML='<div class="dr-note">server unreachable</div>'; return; }
+ if(!d.ok){ box.innerHTML='<div class="dr-note">'+(d.error||'no data')+'</div>'; return; }
+ COST=d;
+ const max=Math.max(...d.by_app.slice(0,10).map(a=>a.usd),0.0001);
+ let h=`<div class="m-sub" style="margin:2px 0 10px">Total <b style="color:#fde68a">$${d.total_usd}</b> over ${d.entries.toLocaleString()} calls · ${(d.first||'').slice(0,10)} â ${(d.last||'').slice(0,10)}</div><div style="font-size:11px;color:#8a94a6;margin-bottom:5px">Top spenders by app (âž mapped to officer where itâs a cabinet skill)</div>`;
+ d.by_app.slice(0,10).forEach(a=>{ const off=appOfficer(a.name);
+ h+=`<div class="bar-row"><span class="nm" title="${a.name}">${a.name}${off?' <span style="color:#8a94a6">âž '+offName(off)+'</span>':''}</span><span class="bar" style="width:${Math.max(4,a.usd/max*220)}px"></span><span class="v">$${a.usd.toFixed(2)}</span></div>`; });
+ h+='<div class="m-actions" style="border:none;padding:0;margin-top:12px"><button class="m-btn primary" onclick="applyCost()">đž Apply heatmap</button><button class="m-btn ghost" onclick="clearOverlays()">Clear</button></div>';
+ box.innerHTML=h;
+}
+function applyCost(){
+ if(!COST) return; clearOverlays(true);
+ const byOff={}; COST.by_app.forEach(a=>{ const off=appOfficer(a.name); if(off) byOff[off]=(byOff[off]||0)+a.usd; });
+ const max=Math.max(...Object.values(byOff),0.0001);
+ OFF.forEach(o=>{ if(!o._node) return; const usd=byOff[o.id]||0;
+ const badge=document.createElement('span'); badge.className='cost-badge'; badge.textContent='$'+usd.toFixed(2); o._node.appendChild(badge);
+ const bar=document.createElement('span'); bar.className='cost-bar'; bar.style.width=(usd>0?Math.max(8,usd/max*100):0)+'%'; o._node.appendChild(bar); });
+ _overlay='cost'; document.getElementById('clear-overlay').classList.add('show'); closeModal(); toast('đž cost heatmap applied (officer-mapped spend)');
+}
+function clearOverlays(silent){
+ document.querySelectorAll('.officer-node').forEach(n=>{ n.classList.remove('h-up','h-warn','h-down'); n.querySelectorAll('.health-dot,.cost-badge,.cost-bar').forEach(e=>e.remove()); });
+ document.getElementById('clear-overlay').classList.remove('show'); _overlay=null;
+ if(!silent) toast('overlay cleared');
+}
+
legend(); build(); timeline(); buildToolbar();
document.getElementById('pyramid').addEventListener('click', onNodeClick);
document.getElementById('xlines').addEventListener('click', e=>{ const t=e.target.closest('.sug-hit'); if(t) openSuggestion(t.dataset.key); });
diff --git a/server.js b/server.js
index 4b3bc28..0e41232 100644
--- a/server.js
+++ b/server.js
@@ -110,6 +110,31 @@ function gitCommitCabinet(s, cb) {
});
}
+// ââ Idea 4: Live Health Overlay â read DW canary verdicts, map to officers ââ
+const HEALTH_SOURCES = {
+ 'vp-operations': ['dw-uptime-probe', 'dw-backup-canary', 'dw-canary-meta-watchdog'],
+ 'vp-dw-commerce': ['dw-scraper-canary', 'dw-map-auditor'],
+ 'vp-compliance-policy': ['dw-leak-scanner'],
+};
+function readCanary(skill) {
+ try {
+ const j = JSON.parse(fs.readFileSync(path.join(HOME, '.claude', 'skills', skill, 'data', 'latest.json'), 'utf8'));
+ const ts = j.scanned_at || j.checked_at || null;
+ const down = (j.down || 0) + (j.leaking || 0);
+ const fail = (j.fail || 0);
+ const warn = (j.warn || 0) + (j.degraded || 0) + (j.unknown || 0);
+ const sev = (down > 0 || fail > 0) ? 'FAIL' : (warn > 0 ? 'WARN' : 'PASS');
+ const bits = [];
+ if (j.up != null) bits.push(j.up + ' up'); if (j.down) bits.push(j.down + ' down'); if (j.degraded) bits.push(j.degraded + ' degraded');
+ if (j.vendors != null) bits.push(j.vendors + ' vendors'); if (j.fail) bits.push(j.fail + ' fail'); if (j.warn) bits.push(j.warn + ' warn');
+ if (j.unknown) bits.push(j.unknown + ' unknown'); if (j.leaking != null) bits.push((j.leaking || 0) + ' leaking');
+ if (j.repos != null) bits.push(j.repos + ' repos'); if (j.canaries != null) bits.push(j.canaries + ' canaries');
+ const ageH = ts ? +((Date.now() - Date.parse(ts)) / 3.6e6).toFixed(1) : null;
+ return { skill, sev, ts, ageH, summary: bits.join(' · ') };
+ } catch (e) { return { skill, sev: 'NA', summary: 'no data' }; }
+}
+const officerStatus = (sev) => sev === 'FAIL' ? 'down' : sev === 'WARN' ? 'warn' : sev === 'PASS' ? 'up' : 'na';
+
function parseYaml(text) {
// Tiny YAML subset parser â good enough for cabinet.yaml's shape.
// Produces {president, cabinet:[{vp, domain, triggers:[], directors:[{skill?,subagent?,owns?}]}]}
@@ -631,6 +656,34 @@ const server = http.createServer((req, res) => {
cr.write(payload); cr.end();
return;
}
+ if (u.pathname === '/api/health') {
+ const canaries = {}, officers = {}, rank = { down: 3, warn: 2, up: 1, na: 0 };
+ for (const off in HEALTH_SOURCES) {
+ let worst = 'na'; const details = [];
+ HEALTH_SOURCES[off].forEach(sk => {
+ const c = readCanary(sk); canaries[sk] = c;
+ const st = officerStatus(c.sev); if (rank[st] > rank[worst]) worst = st;
+ details.push(sk + ': ' + c.sev + (c.summary ? ' (' + c.summary + ')' : ''));
+ });
+ officers[off] = { status: worst, detail: details.join(' · ') };
+ }
+ return J({ ok: true, generated_at: new Date().toISOString(), officers, canaries });
+ }
+ if (u.pathname === '/api/cost') {
+ let total = 0, n = 0, first = null, last = null; const byApp = {}, byVendor = {};
+ try {
+ const lines = fs.readFileSync(path.join(HOME, '.claude', 'cost-ledger.jsonl'), 'utf8').split('\n');
+ for (const ln of lines) {
+ if (!ln.trim()) continue; let j; try { j = JSON.parse(ln); } catch (e) { continue; }
+ const c = +j.cost_usd || 0; total += c; n++;
+ byApp[j.app || '?'] = (byApp[j.app || '?'] || 0) + c;
+ byVendor[j.vendor || '?'] = (byVendor[j.vendor || '?'] || 0) + c;
+ if (j.ts) { if (!first || j.ts < first) first = j.ts; if (!last || j.ts > last) last = j.ts; }
+ }
+ } catch (e) { return J({ ok: false, error: 'no cost-ledger' }); }
+ const sortObj = (o) => Object.entries(o).map(([k, v]) => ({ name: k, usd: +v.toFixed(4) })).sort((a, b) => b.usd - a.usd);
+ return J({ ok: true, total_usd: +total.toFixed(2), entries: n, first, last, by_app: sortObj(byApp).slice(0, 80), by_vendor: sortObj(byVendor).slice(0, 20) });
+ }
if (req.url === '/cabinet.yaml') {
try {
â 52c593f Pyramid: đĄ Ideas modals â 5 upgrade ideas as modals (Task R
·
back to Agent Cabinet
·
Add /activity viewer â live date/time timeline aggregating g 101c9bc â