[object Object]

← back to Chief Of Operations

steve_todo.py: one to-do list of blocked tickets grouped by blocker (TK-12235)

2445d4505cb2878643b14bb1db17e097c41b20bd · 2026-09-25 10:09:48 -0700 · Steve Abrams

Files touched

Diff

commit 2445d4505cb2878643b14bb1db17e097c41b20bd
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 25 10:09:48 2026 -0700

    steve_todo.py: one to-do list of blocked tickets grouped by blocker (TK-12235)
---
 scripts/steve_todo.py | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/scripts/steve_todo.py b/scripts/steve_todo.py
new file mode 100644
index 0000000..7d78c51
--- /dev/null
+++ b/scripts/steve_todo.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+"""One to-do list for Steve: every BLOCKED ticket, grouped by what it waits on (TK-12235). Read-only."""
+import json, re, time
+from pathlib import Path
+HOME=Path.home(); EV=HOME/'.claude/tickets/events.jsonl'; PA=HOME/'.claude/yolo-queue/pending-approval'
+T={}
+for l in open(EV, errors='replace'):
+    try: e=json.loads(l)
+    except Exception: continue
+    i=e.get('id'); ty=e.get('type')
+    if not i or ty=='read': continue
+    t=T.setdefault(i,{'id':i,'title':'','project':'','status':'open','last':'','last_ts':''})
+    if ty=='create': t['title']=e.get('title',''); t['project']=e.get('project','')
+    if ty=='status': t['status']=e.get('status')
+    txt=e.get('text') or e.get('body') or ''
+    if txt and ty in ('comment','action','note','create','status'): t['last']=txt; t['last_ts']=e.get('ts','')
+    elif e.get('ts'): t['last_ts']=e.get('ts')
+memos=[p.name for p in PA.glob('*.md')] if PA.exists() else []
+def memo_for(i):
+    n=i.split('-')[0]+'-'+i.split('-')[1]
+    return [m for m in memos if n in m][:2]
+def kind(t,m):
+    s=(t['title']+' '+t['last']).lower()
+    if re.search(r'password|credential|api key|token|oauth|login|sign.?in|2fa|re-?consent|secret',s): return '1 Password / login / key'
+    if re.search(r'!\s*(ssh|sudo|bash|launchctl)|paste|run this|console|click|in-app|app store connect|asc ',s): return '2 Paste or console click'
+    if m or re.search(r'pending-approval|approve|gated|memo',s): return '3 Approve a memo'
+    if re.search(r'decid|which|choose|question|clarif|confirm|ruling|\?',s): return '4 Decision from you'
+    return '5 Unclear - needs triage'
+B=[t for t in T.values() if t['status']=='blocked']
+groups={}
+for t in B:
+    m=memo_for(t['id']); groups.setdefault(kind(t,m),[]).append((t,m))
+out=[f"# Steve's to-do list — {len(B)} blocked tickets ({time.strftime('%Y-%m-%d %H:%M')})",'']
+for g in sorted(groups):
+    rows=sorted(groups[g],key=lambda x:x[0]['last_ts'],reverse=True)
+    out.append(f"## {g[2:]} ({len(rows)})")
+    for n,(t,m) in enumerate(rows,1):
+        short=t['id'].split('-')[0]+'-'+t['id'].split('-')[1]
+        hint=re.sub(r'\s+',' ',t['last'])[:160]
+        out.append(f"{n}. **{short}** [{t['project']}] {t['title'][:90]}")
+        out.append(f"   - last ({t['last_ts'][:10]}): {hint}")
+        if m: out.append(f"   - memo: {', '.join(m)}")
+    out.append('')
+dst=HOME/'Projects/chief-of-operations/state/steve-todo.md'; dst.write_text('\n'.join(out)+'\n')
+print(dst); print({g[2:]:len(v) for g,v in sorted(groups.items())})

← a27b564 remove auto_claim tk-take path entirely; queue --write print  ·  back to Chief Of Operations  ·  auto-data-snapshot: 2026-09-25T10:22:25 (4 data files) — sta 74f9655 →