← back to Chief Of Operations
add chief of operations oversight harness
9faff8947468321e9bef48c522e06d507d9e1d6d · 2026-09-17 08:33:09 -0700 · Steve Abrams
Files touched
A .gitignoreA README.mdA chief_ops.py
Diff
commit 9faff8947468321e9bef48c522e06d507d9e1d6d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 17 08:33:09 2026 -0700
add chief of operations oversight harness
---
.gitignore | 6 ++++
README.md | 13 ++++++++
chief_ops.py | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 119 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1e68042
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+__pycache__/
+*.pyc
+.env*
+*.log
+.DS_Store
+tmp/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3d68eb0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# Chief of Operations
+
+Local read-first harness for keeping the terminal operation on track.
+
+It checks the master `dot-screen-router`, the `desktop-dotbar` launch agent and health endpoint, Plannator (`:9772`), semantic terminal status, router evidence (`green_misplaced` / `attn_misplaced`), screenshot freshness, and archived legacy arrangers.
+
+```sh
+./chief_ops.py check
+./chief_ops.py arrange
+./chief_ops.py serve # http://127.0.0.1:9794
+```
+
+The Arrange action delegates to the existing master router through the desktop bar API. The harness does not delete, publish, or mutate fleet data.
diff --git a/chief_ops.py b/chief_ops.py
new file mode 100755
index 0000000..972ad34
--- /dev/null
+++ b/chief_ops.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+"""Chief of Operations: read-first oversight for layout, dotbar, tickets, and Plannator."""
+from __future__ import annotations
+import argparse, json, os, subprocess, time, urllib.request, urllib.error
+from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
+from pathlib import Path
+
+HOME = Path.home()
+ROUTER = HOME / '.claude/skills/dot-screen-router'
+DOTBAR = HOME / 'Projects/desktop-dotbar'
+STATUS = HOME / '.local/state/abrams-terminal-status/ttys016.json'
+TICKET = 'TK-11882-chief-of-operations-harness-for-terminal'
+SCREENSHOTS = [HOME/'Desktop/arrange-click-screen1.png', HOME/'Desktop/arrange-click-screen2.png']
+ARCHIVE = HOME/'.claude/skills/_disabled-layout-legacy-20260917'
+
+
+def cmd(args, timeout=4):
+ try:
+ p = subprocess.run(args, text=True, capture_output=True, timeout=timeout)
+ return p.returncode, (p.stdout or '').strip(), (p.stderr or '').strip()
+ except Exception as e:
+ return 1, '', str(e)
+
+
+def launchd(label):
+ rc, out, err = cmd(['launchctl','print',f'gui/{os.getuid()}/{label}'])
+ return {'name': label, 'ok': rc == 0 and 'state = running' in out, 'detail': next((x.strip() for x in out.splitlines() if x.strip().startswith('state =')), err or 'not loaded')}
+
+
+def http_health(port, path='/health'):
+ try:
+ with urllib.request.urlopen(f'http://127.0.0.1:{port}{path}', timeout=2) as r:
+ return {'ok': r.status == 200, 'body': json.loads(r.read().decode() or '{}')}
+ except Exception as e:
+ return {'ok': False, 'error': str(e)}
+
+
+def router_evidence():
+ log = ROUTER/'data/router.jsonl'
+ if not log.exists(): return {'ok': False, 'error': 'router evidence missing'}
+ rows=[]
+ for line in log.read_text(errors='replace').splitlines()[-40:]:
+ try: rows.append(json.loads(line))
+ except Exception: pass
+ rows=[r for r in rows if 'green_misplaced' in r]
+ last=rows[-1] if rows else {}
+ return {'ok': bool(rows) and last.get('green_misplaced') == 0 and last.get('attn_misplaced') == 0,
+ 'last': last, 'samples': len(rows), 'cellfails': sum(1 for x in log.read_text(errors='replace').splitlines()[-40:] if '"event":"cellfail"' in x)}
+
+
+def check():
+ status={}
+ if STATUS.exists():
+ try:
+ d=json.loads(STATUS.read_text()); status={'ok': d.get('state') == 'green', 'state': d.get('state'), 'title': d.get('title'), 'ticket': d.get('ticket')}
+ except Exception as e: status={'ok':False,'error':str(e)}
+ archived=[p.name for p in (ARCHIVE.iterdir() if ARCHIVE.exists() else [])]
+ screenshots=[]
+ for p in SCREENSHOTS:
+ age_s=(time.time()-p.stat().st_mtime) if p.exists() else None
+ screenshots.append({'path':str(p),'ok':bool(p.exists() and age_s is not None and age_s < 86400),'age_s':round(age_s) if age_s is not None else None})
+ checks={
+ 'terminal_status': status,
+ 'router_launchd': launchd('com.steve.dot-screen-router'),
+ 'dotbar_launchd': launchd('com.steve.desktop-dotbar'),
+ 'dotbar_health': http_health(9787),
+ 'plannator_health': http_health(9772),
+ 'router_evidence': router_evidence(),
+ 'legacy_conflicts_archived': {'ok': all(x in archived for x in ('arrange','tile-blue-right','tile-green-left')), 'items': archived},
+ 'screenshots': {'ok': all(x['ok'] for x in screenshots), 'items': screenshots},
+ }
+ checks['overall']={'ok': all(v.get('ok',False) for k,v in checks.items() if k not in ('terminal_status',) or v), 'checked_at':time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime())}
+ return checks
+
+
+def arrange():
+ try:
+ req=urllib.request.Request('http://127.0.0.1:9787/api/arrange', method='POST')
+ with urllib.request.urlopen(req, timeout=50) as r: return json.loads(r.read().decode())
+ except Exception as e: return {'ok':False,'error':str(e)}
+
+HTML='''<!doctype html><meta charset="utf-8"><title>Chief of Operations</title><style>body{font:15px -apple-system;background:#101318;color:#e9edf3;margin:32px}h1{margin:0 0 8px}.sub{color:#9aa4b2;margin-bottom:24px}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px}.card{background:#1b2029;border:1px solid #303947;border-radius:12px;padding:16px}.ok{color:#54d17a}.bad{color:#ff7676}.muted{color:#9aa4b2;font-size:12px;word-break:break-word}button{background:#315dff;color:white;border:0;border-radius:8px;padding:10px 14px;font-weight:700;cursor:pointer}pre{white-space:pre-wrap;font-size:12px;color:#c9d2df}</style><h1>Chief of Operations</h1><div class="sub">Read-first oversight for the master terminal router, desktop bar, Plannator, and evidence.</div><button onclick="arrange()">Arrange master now</button> <button onclick="load()">Refresh checks</button><div id="out" class="grid" style="margin-top:20px"></div><script>async function load(){let d=await fetch('/api/check').then(r=>r.json());out.innerHTML=Object.entries(d).map(([k,v])=>`<section class="card"><b class="${v.ok?'ok':'bad'}">${v.ok?'●':'●'} ${k}</b><pre>${JSON.stringify(v,null,2)}</pre></section>`).join('')}async function arrange(){let r=await fetch('/api/arrange',{method:'POST'}).then(r=>r.json());alert(JSON.stringify(r));load()}load();setInterval(load,10000)</script>'''
+
+class Handler(BaseHTTPRequestHandler):
+ def log_message(self,*args): pass
+ def do_GET(self):
+ if self.path == '/api/check': self.send_json(check()); return
+ self.send_response(200); self.send_header('Content-Type','text/html'); self.end_headers(); self.wfile.write(HTML.encode())
+ def do_POST(self):
+ if self.path == '/api/arrange': self.send_json(arrange()); return
+ self.send_error(404)
+ def send_json(self, data):
+ b=json.dumps(data, indent=2).encode(); self.send_response(200); self.send_header('Content-Type','application/json'); self.send_header('Content-Length',str(len(b))); self.end_headers(); self.wfile.write(b)
+
+def main():
+ ap=argparse.ArgumentParser(); ap.add_argument('action', choices=['check','arrange','serve'], nargs='?', default='check'); ap.add_argument('--port',type=int,default=9794); a=ap.parse_args()
+ if a.action=='check': print(json.dumps(check(), indent=2)); return
+ if a.action=='arrange': print(json.dumps(arrange(), indent=2)); return
+ print(f'Chief of Operations on http://127.0.0.1:{a.port}', flush=True); ThreadingHTTPServer(('127.0.0.1',a.port), Handler).serve_forever()
+if __name__=='__main__': main()
(oldest)
·
back to Chief Of Operations
·
classify sandbox health checks clearly c9fe16d →