/ scripts / costs.py
costs.py
  1  #!/usr/bin/env python3
  2  """
  3  Sovereign OS - Cost & Value Tracking Display
  4  =============================================
  5  
  6  Quick view of costs and value attribution in sats and USD.
  7  Reads from FO-STATE.json, economics.yaml, and attention ledger.
  8  
  9  Usage:
 10      python3 scripts/costs.py              # Show costs
 11      python3 scripts/costs.py --value      # Show value attribution report
 12      python3 scripts/costs.py --session-hours 1.5  # Show session costs
 13      python3 scripts/costs.py --record "Built feature" 0.75 45  # Record work item
 14  """
 15  
 16  import json
 17  import sys
 18  from pathlib import Path
 19  from datetime import datetime
 20  
 21  # Paths
 22  SOVEREIGN_OS = Path(__file__).parent.parent
 23  FO_STATE = SOVEREIGN_OS / "sessions" / "FO-STATE.json"
 24  ECONOMICS = Path.home() / ".sovereign" / "economics.yaml"
 25  
 26  # Add parent to path for imports
 27  sys.path.insert(0, str(SOVEREIGN_OS))
 28  
 29  
 30  def load_fo_state():
 31      """Load FO-STATE.json."""
 32      if not FO_STATE.exists():
 33          return None
 34      with open(FO_STATE) as f:
 35          return json.load(f)
 36  
 37  
 38  def load_economics():
 39      """Load economics config."""
 40      if not ECONOMICS.exists():
 41          return None
 42      try:
 43          import yaml
 44          with open(ECONOMICS) as f:
 45              return yaml.safe_load(f)
 46      except ImportError:
 47          # Fallback: parse yaml manually for simple values
 48          config = {}
 49          with open(ECONOMICS) as f:
 50              for line in f:
 51                  if "hourly_rate_usd:" in line:
 52                      config["hourly_rate_usd"] = float(line.split(":")[1].strip())
 53                  elif "sats_per_hour:" in line:
 54                      config["sats_per_hour"] = int(line.split(":")[1].strip())
 55                  elif "btc_price_usd:" in line:
 56                      config["btc_price_usd"] = float(line.split(":")[1].strip())
 57          return {"operator": config}
 58  
 59  
 60  def sats_to_usd(sats: int, btc_price: float = 100000) -> float:
 61      """Convert sats to USD."""
 62      return round(sats / 100_000_000 * btc_price, 2)
 63  
 64  
 65  def format_sats(sats: int, btc_price: float = 100000) -> str:
 66      """Format sats with USD equivalent."""
 67      usd = sats_to_usd(sats, btc_price)
 68      return f"{sats:,} sats (${usd:,.2f})"
 69  
 70  
 71  def display_costs(session_hours: float = None):
 72      """Display current cost tracking."""
 73      fo_state = load_fo_state()
 74      economics = load_economics()
 75  
 76      btc_price = 100000
 77      sats_per_hour = 172110  # Default
 78      hourly_rate = 172.11
 79  
 80      if economics and "operator" in economics:
 81          op = economics["operator"]
 82          btc_price = op.get("btc_price_usd", btc_price)
 83          sats_per_hour = op.get("sats_per_hour", sats_per_hour)
 84          hourly_rate = op.get("hourly_rate_usd", hourly_rate)
 85  
 86      print()
 87      print("╔══════════════════════════════════════════════════════════════════╗")
 88      print("║              SOVEREIGN OS - COST TRACKING                        ║")
 89      print("║                   Bitcoin-Anchored Economy                       ║")
 90      print("╚══════════════════════════════════════════════════════════════════╝")
 91      print()
 92  
 93      # Operator attention pricing
 94      print("┌─────────────────────────────────────────────────────────────────┐")
 95      print("│ OPERATOR ATTENTION                                              │")
 96      print("├─────────────────────────────────────────────────────────────────┤")
 97      print(f"│ Hourly rate:     ${hourly_rate:,.2f}/hr = {sats_per_hour:,} sats/hr")
 98      print(f"│ Price source:    historical_market (Meta W-2 2024)")
 99      print(f"│ BTC price:       ${btc_price:,}")
100      print("└─────────────────────────────────────────────────────────────────┘")
101      print()
102  
103      # Session costs (if hours provided)
104      if session_hours:
105          attention_sats = int(session_hours * sats_per_hour)
106          claude_sats = 3333  # Approximate per-session allocation
107          total_sats = attention_sats + claude_sats
108  
109          print("┌─────────────────────────────────────────────────────────────────┐")
110          print(f"│ THIS SESSION ({session_hours:.1f} hours)                                       │")
111          print("├─────────────────────────────────────────────────────────────────┤")
112          print(f"│ Attention:       {format_sats(attention_sats, btc_price)}")
113          print(f"│ Claude:          {format_sats(claude_sats, btc_price)}")
114          print(f"│ TOTAL INVESTED:  {format_sats(total_sats, btc_price)}")
115          print("└─────────────────────────────────────────────────────────────────┘")
116          print()
117  
118      # Claude usage from FO-STATE
119      if fo_state and "costs" in fo_state:
120          costs = fo_state["costs"]
121          print("┌─────────────────────────────────────────────────────────────────┐")
122          print("│ CLAUDE USAGE (All Time)                                         │")
123          print("├─────────────────────────────────────────────────────────────────┤")
124  
125          if "tokens" in costs:
126              t = costs["tokens"]
127              print(f"│ Input tokens:    {t.get('input', 0):,}")
128              print(f"│ Output tokens:   {t.get('output', 0):,}")
129              print(f"│ Cache read:      {t.get('cache_read', 0):,}")
130              print(f"│ Total tokens:    {t.get('total', 0):,}")
131  
132          print("├─────────────────────────────────────────────────────────────────┤")
133  
134          if "sats" in costs and "usd" in costs:
135              s = costs["sats"]
136              u = costs["usd"]
137              print(f"│ Subscription:    {s.get('subscription_sats', 0):,} sats (${u.get('subscription', 0):.2f})")
138              print(f"│ API equivalent:  {s.get('api_sats', 0):,} sats (${u.get('api', 0):.2f})")
139              print(f"│ Infra value:     {s.get('infra_sats', 0):,} sats (${u.get('infra', 0):.2f})")
140  
141          if "savings" in costs:
142              sav = costs["savings"]
143              print("├─────────────────────────────────────────────────────────────────┤")
144              print(f"│ Savings vs API:  {sav.get('vs_api_sats', 0):,} sats (${sav.get('vs_api_usd', 0):.2f})")
145              print(f"│ Savings vs Infra:{sav.get('vs_infra_sats', 0):,} sats (${sav.get('vs_infra_usd', 0):.2f})")
146  
147          if "efficiency" in costs:
148              eff = costs["efficiency"]
149              print("├─────────────────────────────────────────────────────────────────┤")
150              print(f"│ Efficiency:      {eff.get('api_efficiency', 0)}x vs API | {eff.get('infra_efficiency', 0)}x vs infra")
151  
152          print(f"│ Last updated:    {costs.get('updated', 'unknown')[:19]}")
153          print("└─────────────────────────────────────────────────────────────────┘")
154  
155      print()
156  
157  
158  def display_value_report():
159      """Display value attribution report."""
160      try:
161          from core.attention.economics import AttentionEconomics
162          economics = AttentionEconomics()
163          print(economics.format_value_report())
164      except ImportError as e:
165          print(f"Error: Could not import economics module: {e}")
166          print("Make sure you're running from the Sovereign_OS directory.")
167      except Exception as e:
168          print(f"Error generating value report: {e}")
169  
170  
171  def record_work_item(description: str, v_score: float, duration_minutes: float):
172      """Record a work item with V-score."""
173      try:
174          from core.attention.economics import AttentionEconomics
175          economics = AttentionEconomics()
176  
177          # Get or start a session for CLI usage
178          session_id = f"cli-{datetime.now().strftime('%Y%m%d')}"
179          ledger = economics.get_today_ledger()
180  
181          if session_id not in ledger.sessions:
182              economics.start_session(session_id, context="cli")
183  
184          economics.record_work_item(
185              session_id=session_id,
186              description=description,
187              v_score=v_score,
188              duration_minutes=duration_minutes
189          )
190  
191          # Calculate value created
192          sats_per_hour = economics._config.get('operator', {}).get('sats_per_hour', 172110)
193          value_sats = int((duration_minutes / 60) * sats_per_hour * v_score)
194          cost_sats = int((duration_minutes / 60) * sats_per_hour)
195  
196          print()
197          print("┌─────────────────────────────────────────────────────────────────┐")
198          print("│ WORK ITEM RECORDED                                              │")
199          print("├─────────────────────────────────────────────────────────────────┤")
200          print(f"│ Description:  {description[:50]}")
201          print(f"│ V-Score:      {v_score:.2f}")
202          print(f"│ Duration:     {duration_minutes:.0f} minutes")
203          print("├─────────────────────────────────────────────────────────────────┤")
204          print(f"│ Cost:         {cost_sats:,} sats (attention invested)")
205          print(f"│ Value:        {value_sats:,} sats (V-weighted)")
206          print(f"│ ROI:          {v_score * 100:.0f}% of potential captured")
207          print("└─────────────────────────────────────────────────────────────────┘")
208          print()
209  
210      except ImportError as e:
211          print(f"Error: Could not import economics module: {e}")
212      except Exception as e:
213          print(f"Error recording work item: {e}")
214  
215  
216  if __name__ == "__main__":
217      session_hours = None
218  
219      if len(sys.argv) > 1:
220          if sys.argv[1] == "--value":
221              display_value_report()
222              sys.exit(0)
223  
224          elif sys.argv[1] == "--record" and len(sys.argv) >= 5:
225              # --record "description" v_score duration_minutes
226              description = sys.argv[2]
227              v_score = float(sys.argv[3])
228              duration_minutes = float(sys.argv[4])
229              record_work_item(description, v_score, duration_minutes)
230              sys.exit(0)
231  
232          elif sys.argv[1] == "--session-hours" and len(sys.argv) > 2:
233              session_hours = float(sys.argv[2])
234  
235          elif sys.argv[1] == "--help" or sys.argv[1] == "-h":
236              print(__doc__)
237              sys.exit(0)
238  
239          else:
240              try:
241                  session_hours = float(sys.argv[1])
242              except ValueError:
243                  print(f"Unknown option: {sys.argv[1]}")
244                  print(__doc__)
245                  sys.exit(1)
246  
247      display_costs(session_hours)