#!/usr/bin/env python3 """ decide - Decision journal Track decisions, their reasoning, and outcomes. Learn from past choices. """ import json import sys from datetime import datetime from pathlib import Path WORKSPACE = Path("/home/wdjones/.openclaw/workspace") DECISIONS_FILE = WORKSPACE / "data" / "decisions.json" def load_decisions() -> list: """Load decisions.""" DECISIONS_FILE.parent.mkdir(parents=True, exist_ok=True) if DECISIONS_FILE.exists(): with open(DECISIONS_FILE) as f: return json.load(f) return [] def save_decisions(data: list): """Save decisions.""" with open(DECISIONS_FILE, 'w') as f: json.dump(data, f, indent=2) def new_decision(title: str, context: str = None): """Record a new decision.""" decisions = load_decisions() decision = { 'id': len(decisions) + 1, 'title': title, 'context': context, 'options_considered': [], 'reasoning': None, 'decided': datetime.now().isoformat(), 'outcome': None, 'outcome_date': None, 'lessons': None, 'status': 'pending', # pending, good, bad, mixed } decisions.append(decision) save_decisions(decisions) print(f"⚖️ Decision #{decision['id']}: {title}") print(" Add reasoning with: decide reason ") def add_reasoning(decision_id: int, reasoning: str): """Add reasoning to a decision.""" decisions = load_decisions() for d in decisions: if d['id'] == decision_id: d['reasoning'] = reasoning save_decisions(decisions) print(f"✓ Reasoning added to #{decision_id}") return print(f"Decision not found: #{decision_id}") def record_outcome(decision_id: int, outcome: str, status: str = 'mixed'): """Record the outcome of a decision.""" decisions = load_decisions() for d in decisions: if d['id'] == decision_id: d['outcome'] = outcome d['outcome_date'] = datetime.now().isoformat() d['status'] = status if status in ['good', 'bad', 'mixed'] else 'mixed' save_decisions(decisions) emoji = {'good': '✅', 'bad': '❌', 'mixed': '🔄'}[d['status']] print(f"{emoji} Outcome recorded for #{decision_id}") return print(f"Decision not found: #{decision_id}") def add_lesson(decision_id: int, lesson: str): """Add a lesson learned from a decision.""" decisions = load_decisions() for d in decisions: if d['id'] == decision_id: d['lessons'] = lesson save_decisions(decisions) print(f"📚 Lesson added to #{decision_id}") return print(f"Decision not found: #{decision_id}") def show_decision(decision_id: int): """Show details of a decision.""" decisions = load_decisions() for d in decisions: if d['id'] == decision_id: status_emoji = {'pending': '⏳', 'good': '✅', 'bad': '❌', 'mixed': '🔄'} print(f"\n⚖️ Decision #{d['id']}: {d['title']}") print("=" * 50) print(f"Status: {status_emoji.get(d['status'], '⏳')} {d['status']}") print(f"Date: {d['decided'][:10]}") if d.get('context'): print(f"\n📋 Context:\n {d['context']}") if d.get('reasoning'): print(f"\n🤔 Reasoning:\n {d['reasoning']}") if d.get('outcome'): print(f"\n📊 Outcome:\n {d['outcome']}") if d.get('lessons'): print(f"\n📚 Lessons:\n {d['lessons']}") print() return print(f"Decision not found: #{decision_id}") def list_decisions(show_all: bool = False): """List all decisions.""" decisions = load_decisions() if not show_all: decisions = [d for d in decisions if d['status'] == 'pending'] if not decisions: print("No decisions recorded" if show_all else "No pending decisions") return print(f"\n⚖️ Decisions ({len(decisions)})") print("=" * 50) status_emoji = {'pending': '⏳', 'good': '✅', 'bad': '❌', 'mixed': '🔄'} for d in decisions: emoji = status_emoji.get(d['status'], '⏳') print(f" {emoji} #{d['id']} {d['title'][:40]}") print(f" {d['decided'][:10]}") print() def review(): """Review decisions that need outcomes.""" decisions = load_decisions() pending = [d for d in decisions if d['status'] == 'pending'] if not pending: print("No decisions pending review") return print(f"\n📋 Decisions Pending Review ({len(pending)})") print("=" * 50) for d in pending: days = (datetime.now() - datetime.fromisoformat(d['decided'])).days print(f" #{d['id']} {d['title'][:40]}") print(f" {days} days ago — needs outcome") print("\nRecord outcomes with: decide outcome --good/--bad/--mixed") def main(): if len(sys.argv) < 2: print("Usage:") print(" decide new - Record a decision") print(" decide reason <id> <text> - Add reasoning") print(" decide outcome <id> <text> [--good/--bad/--mixed]") print(" decide lesson <id> <text> - Add lesson learned") print(" decide show <id> - Show decision details") print(" decide list [--all] - List decisions") print(" decide review - Review pending decisions") list_decisions() return cmd = sys.argv[1] if cmd == 'new' and len(sys.argv) > 2: title = ' '.join(sys.argv[2:]) new_decision(title) elif cmd == 'reason' and len(sys.argv) > 3: decision_id = int(sys.argv[2]) reasoning = ' '.join(sys.argv[3:]) add_reasoning(decision_id, reasoning) elif cmd == 'outcome' and len(sys.argv) > 3: decision_id = int(sys.argv[2]) status = 'mixed' args = sys.argv[3:] if '--good' in args: status = 'good' args.remove('--good') elif '--bad' in args: status = 'bad' args.remove('--bad') elif '--mixed' in args: args.remove('--mixed') outcome = ' '.join(args) record_outcome(decision_id, outcome, status) elif cmd == 'lesson' and len(sys.argv) > 3: decision_id = int(sys.argv[2]) lesson = ' '.join(sys.argv[3:]) add_lesson(decision_id, lesson) elif cmd == 'show' and len(sys.argv) > 2: show_decision(int(sys.argv[2])) elif cmd == 'list': list_decisions(show_all='--all' in sys.argv) elif cmd == 'review': review() else: print("Unknown command. Run 'decide' for help.") if __name__ == "__main__": main()