{"definition_raw":"---\nid: spend-ingest\nname: Daily cost-telemetry ingest (hermes + CLI transcripts)\nschedule: \"20 4 * * *\"\nenabled: true\ncriticality: medium\nrun_as: script\ncommand: python3 ~/workspace/mission-control/scripts/spend_ingest.py\ntimeout: 600\ndescription: MC-4942 U5a \u2014 feeds the spend ledger (state/spend/spend.json) that /cost and the Home budget chip read. Lane 1 reads ~/.hermes/state.db ended sessions (read-only, actual/estimated cost). Lane 2 incrementally parses ~/.claude/projects/**/*.jsonl usage blocks (per-file byte-offset watermark in state/spend/ingest_state.json, message-id dedup). Idempotent; second run ingests only new data (~2s). Without this task the ledger goes stale and the UI freshness stamp shows it (\"Ledger through <day>\") \u2014 absence reads as no-data, never $0.\nruntime_profile: direct_python\nnotify_to: elmar\n---\n\n**OVERRIDES runtime profile:** uses `direct_python` (plain Python, no model) because the script only reads sqlite/JSONL and writes spend.json \u2014 it never invokes the `claude` CLI or any LLM API.\n\nManual run / backfill:\n\n```bash\npython3 ~/workspace/mission-control/scripts/spend_ingest.py --since 2026-06-01\n```\n","id":"spend-ingest","last_run":{"duration_s":2.810477,"log_path":"/home/lucienne/workspace/logs/task-runs/spend-ingest/413548.log","output":"{\n  \"cli_transcripts\": {\n    \"by_day\": {\n      \"2026-06-12\": {\n        \"api\": 0.0271,\n        \"subscription_equivalent\": 108.7855,\n        \"units\": 542.0,\n        \"unknown\": 0.0\n      },\n      \"2026-06-13\": {\n        \"subscription_equivalent\": 10.0601,\n        \"units\": 47.0\n      }\n    },\n    \"new_units\": 589\n  },\n  \"dry_run\": false,\n  \"hermes\": {\n    \"by_day\": {\n      \"2026-06-12\": {\n        \"subscription_equivalent\": 102.3897,\n        \"units\": 106.0\n      },\n      \"2026-06-13\": {\n        \"subscription_equivalent\": 4.5748,\n        \"units\": 11.0\n      }\n    },\n    \"new_units\": 117\n  },\n  \"ran_at\": \"2026-06-13T02:20:04+00:00\",\n  \"through_day\": \"2026-06-13\"\n}\n","started_at":"2026-06-13T04:20:01.306559+02:00","status":"completed"},"next_run":"2026-06-14 04:20","next_run_iso":"2026-06-14T04:20:00+02:00","runs":[{"duration_s":2.810477,"finished_at":"2026-06-13T04:20:04.119471+02:00","id":413548,"log_path":"/home/lucienne/workspace/logs/task-runs/spend-ingest/413548.log","output":"{\n  \"cli_transcripts\": {\n    \"by_day\": {\n      \"2026-06-12\": {\n        \"api\": 0.0271,\n        \"subscription_equivalent\": 108.7855,\n        \"units\": 542.0,\n        \"unknown\": 0.0\n      },\n      \"2026-06-13\": {\n        \"subscription_equivalent\": 10.0601,\n        \"units\": 47.0\n      }\n    },\n    \"new_units\": 589\n  },\n  \"dry_run\": false,\n  \"hermes\": {\n    \"by_day\": {\n      \"2026-06-12\": {\n        \"subscription_equivalent\": 102.3897,\n        \"units\": 106.0\n      },\n      \"2026-06-13\": {\n        \"subscription_equivalent\": 4.5748,\n        \"units\": 11.0\n      }\n    },\n    \"new_units\": 117\n  },\n  \"ran_at\": \"2026-06-13T02:20:04+00:00\",\n  \"through_day\": \"2026-06-13\"\n}\n","started_at":"2026-06-13T04:20:01.306559+02:00","status":"completed","task_id":"spend-ingest","task_name":"spend-ingest"},{"duration_s":3.532431,"finished_at":"2026-06-12T04:20:04.808629+02:00","id":409381,"log_path":"/home/lucienne/workspace/logs/task-runs/spend-ingest/409381.log","output":"{\n  \"cli_transcripts\": {\n    \"by_day\": {\n      \"2026-06-11\": {\n        \"api\": 0.0042,\n        \"subscription_equivalent\": 97.2527,\n        \"units\": 3363.0,\n        \"unknown\": 0.0\n      },\n      \"2026-06-12\": {\n        \"subscription_equivalent\": 10.1927,\n        \"units\": 39.0\n      }\n    },\n    \"new_units\": 3402\n  },\n  \"dry_run\": false,\n  \"hermes\": {\n    \"by_day\": {\n      \"2026-06-11\": {\n        \"subscription_equivalent\": 50.7066,\n        \"units\": 73.0\n      },\n      \"2026-06-12\": {\n        \"subscription_equivalent\": 3.4598,\n        \"units\": 10.0\n      }\n    },\n    \"new_units\": 83\n  },\n  \"ran_at\": \"2026-06-12T02:20:04+00:00\",\n  \"through_day\": \"2026-06-12\"\n}\n","started_at":"2026-06-12T04:20:01.273464+02:00","status":"completed","task_id":"spend-ingest","task_name":"spend-ingest"},{"duration_s":2.146631,"finished_at":"2026-06-11T09:12:03.341926+02:00","id":405874,"log_path":"/home/lucienne/workspace/logs/task-runs/spend-ingest/405874.log","output":"{\n  \"cli_transcripts\": {\n    \"by_day\": {\n      \"2026-06-11\": {\n        \"subscription_equivalent\": 3.6206,\n        \"units\": 88.0,\n        \"unknown\": 0.0\n      }\n    },\n    \"new_units\": 88\n  },\n  \"dry_run\": false,\n  \"hermes\": {\n    \"by_day\": {},\n    \"new_units\": 0\n  },\n  \"ran_at\": \"2026-06-11T07:12:03+00:00\",\n  \"through_day\": \"2026-06-11\"\n}\n","started_at":"2026-06-11T09:12:01.191981+02:00","status":"completed","task_id":"spend-ingest","task_name":"spend-ingest"}],"runs_limit":20,"schedule":"20 4 * * *","schedule_label":{"description":"Daily at 04:20","is_custom":false,"label":"Daily","sort":4,"sort_time":"04:20"},"stats":{"avg_duration":2.8298463333333337,"completed":3,"failed":0,"timeout":0,"total":3},"task":{"_description":"**OVERRIDES runtime profile:** uses `direct_python` (plain Python, no model) because the script only reads sqlite/JSONL and writes spend.json \u2014 it never invokes the `claude` CLI or any LLM API.\n\nManual run / backfill:\n\n```bash\npython3 ~/workspace/mission-control/scripts/spend_ingest.py --since 2026-06-01\n```","_file":"spend-ingest.md","_path":"/home/lucienne/workspace/tasks/spend-ingest.md","command":"python3 ~/workspace/mission-control/scripts/spend_ingest.py","criticality":"medium","description":"MC-4942 U5a \u2014 feeds the spend ledger (state/spend/spend.json) that /cost and the Home budget chip read. Lane 1 reads ~/.hermes/state.db ended sessions (read-only, actual/estimated cost). Lane 2 incrementally parses ~/.claude/projects/**/*.jsonl usage blocks (per-file byte-offset watermark in state/spend/ingest_state.json, message-id dedup). Idempotent; second run ingests only new data (~2s). Without this task the ledger goes stale and the UI freshness stamp shows it (\"Ledger through <day>\") \u2014 absence reads as no-data, never $0.","enabled":true,"id":"spend-ingest","name":"Daily cost-telemetry ingest (hermes + CLI transcripts)","notify_to":"elmar","run_as":"script","runtime_profile":"direct_python","schedule":"20 4 * * *","timeout":600}}
