← 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 →