{"id":51437825,"url":"https://github.com/momoraul/lupen","last_synced_at":"2026-07-05T09:00:29.765Z","repository":{"id":365551590,"uuid":"1272526867","full_name":"momoraul/Lupen","owner":"momoraul","description":"Itemized cost receipts for Claude Code and Codex — by turn, verified, local.","archived":false,"fork":false,"pushed_at":"2026-07-05T08:07:33.000Z","size":8281,"stargazers_count":32,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-05T08:07:37.141Z","etag":null,"topics":["ai","ai-coding","anthropic","claude","claude-code","cli","codex","cost-tracking","developer-tools","llm","macos","menubar","openai-codex","swift","token-usage","vibe-coding"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/momoraul.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-17T17:38:25.000Z","updated_at":"2026-07-05T07:25:09.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/momoraul/Lupen","commit_stats":null,"previous_names":["momoraul/lupen"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/momoraul/Lupen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/momoraul%2FLupen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/momoraul%2FLupen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/momoraul%2FLupen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/momoraul%2FLupen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/momoraul","download_url":"https://codeload.github.com/momoraul/Lupen/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/momoraul%2FLupen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35148606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-coding","anthropic","claude","claude-code","cli","codex","cost-tracking","developer-tools","llm","macos","menubar","openai-codex","swift","token-usage","vibe-coding"],"created_at":"2026-07-05T09:00:17.925Z","updated_at":"2026-07-05T09:00:29.743Z","avatar_url":"https://github.com/momoraul.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003c!-- Self-contained dark-navy plate: renders as-is on light AND dark pages. --\u003e\n  \u003cimg src=\"docs/branding/lupen-github-banner.png\" alt=\"Lupen\" width=\"543\"\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003eSee what every Claude Code and Codex session actually costs — itemized, verified, local.\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003eLupen recomputes your spend straight from the raw Claude Code and Codex logs — broken down by turn, step, and sub-agent, checked against the tokens, and never leaving your Mac.\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/macOS-26%2B-blue?logo=apple\" alt=\"macOS 26+\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Swift-6-orange?logo=swift\" alt=\"Swift 6\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"MIT License\"\u003e\n  \u003ca href=\"https://github.com/momoraul/Lupen/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/momoraul/Lupen/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/momoraul/Lupen/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/momoraul/Lupen?include_prereleases\u0026label=release\" alt=\"Latest release\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/demo.gif\" alt=\"Lupen drilling from a session total down through its turns, steps, and sub-agents — every row priced\" width=\"860\"\u003e\n\u003c/p\u003e\n\n\u003c!-- Hero is a ≤5 MB looping GIF (drill-down through priced rows), recorded on synthetic demo data. Swap docs/demo.gif to update. --\u003e\n\n\u003e **Install:** `brew install --cask momoraul/lupen/lupen` — or grab the [signed DMG](https://github.com/momoraul/Lupen/releases/latest). Requires macOS 26 (Tahoe) on Apple Silicon.\n\n---\n\n## What it shows\n\nYour AI coding spend says `$50 today`. Which provider was it? Which session?\nWhich turn? Which sub-agent or tool loop? A daily total can't answer that, so\nLupen breaks the number down and recomputes each cost from the raw tokens.\n\n- **Provider-scoped totals** — `$50 today · Claude Code · 12 sessions · 84 turns`. Claude Code and Codex stay in separate modes instead of one mixed list.\n- **Cost per Turn, Step, SkillGroup, and SubAgent**, where the data allows it.\n- **Recomputed, then diffed** — each cost is recomputed from raw tokens and the public price table and compared to the reported total, so any difference is shown rather than assumed.\n- **Origin-tagged attachments** — every file, image, and URL is labelled by where it entered the context.\n- **Sub-agent cost** rolls up into the parent turn and stays attributable on its own.\n\n## Gallery\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\" valign=\"top\"\u003e\n      \u003ca href=\"docs/screenshots/00-hero.png\"\u003e\u003cimg src=\"docs/screenshots/00-hero.png\" alt=\"Drilling from a session total down through its turns, a skill group, and three sub-agents — every row priced\"\u003e\u003c/a\u003e\n      \u003csub\u003e\u003cb\u003eThe itemized receipt.\u003c/b\u003e Drill from a session total down to each turn, skill group, and sub-agent — every row priced and attributable on its own.\u003c/sub\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"50%\" valign=\"top\"\u003e\n      \u003ca href=\"docs/screenshots/04-attachments.png\"\u003e\u003cimg src=\"docs/screenshots/04-attachments.png\" alt=\"Attachments tab grouping an inline image, tool inputs, tool outputs, and a URL by where each entered the context\"\u003e\u003c/a\u003e\n      \u003csub\u003e\u003cb\u003eOrigin-tagged attachments.\u003c/b\u003e Every file, image, and URL is labelled by where it entered the context.\u003c/sub\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\" valign=\"top\"\u003e\n      \u003ca href=\"docs/screenshots/03-reports.png\"\u003e\u003cimg src=\"docs/screenshots/03-reports.png\" alt=\"Reports view with per-provider daily spend sparkline cards\"\u003e\u003c/a\u003e\n      \u003csub\u003e\u003cb\u003eDaily spend, per provider.\u003c/b\u003e Cost, sessions, turns, and tokens over time.\u003c/sub\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"50%\" valign=\"top\"\u003e\n      \u003ca href=\"docs/screenshots/05-codex.png\"\u003e\u003cimg src=\"docs/screenshots/05-codex.png\" alt=\"Searching past sessions with a right-click menu to resume one in its CLI\"\u003e\u003c/a\u003e\n      \u003csub\u003e\u003cb\u003eSearchable and resumable.\u003c/b\u003e Find a past session by any prompt it contains, then pick up right where you left off.\u003c/sub\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Key features\n\n- **Provider mode** — Choose Claude Code or Codex. Lupen shows only that provider's sessions, conversations, dropdown totals, reports, diagnostics, and verification results.\n- **Cost drift verification** — Run the **Verify Usage** window to recompute every cost from raw tokens and the public price table, then diff it against the reported total; any difference is flagged. Claude Code is checked against its per-request totals; Codex gets an independent local verifier over rollout `token_count` events.\n- **Search and resume** — Full-text search finds a session by any prompt it contains (across every turn), plus its project and slug. Reopen any result in Claude Code (or Codex) to pick up where you left off — Lupen runs `claude --resume` / `codex resume` in a new Terminal window, or copies the command for you.\n- **Turn boundaries that match Anthropic's API** — Lupen uses `stop_reason` to mark Turn boundaries instead of timestamps. Tool-use loops stay inside one Turn instead of fragmenting into a dozen rows.\n- **Codex rollout support** — Lupen reads `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`, normalizes cached input, preserves reasoning tokens, handles cumulative token deltas, and watches new day folders live.\n- **Sub-agent cost rollup** — When a Turn spawns sub-agents, their cost rolls up into the parent in the outline but stays separately attributable in the detail pane. The aggregate and the per-agent figures come from the same source, so they stay consistent.\n- **Origin-tagged attachment tracking** — File paths, image bytes, and URLs are classified by where they entered the conversation (inline prompt, tool input, tool output, reply, …) so you can see what's filling the context window.\n- **5-hour limit tracking** — A Bayesian estimate of `$ per 1 % of limit consumed` across your last 7 days, surfaced in the menu-bar icon's ring tint (yellow at 70 %, orange at 90 %, red at 100 %).\n- **Scriptable `lupen` CLI** — The same app binary is a command line over the same local index: every report as a table, `--json`, or `--csv`, plus `verify` / `budget` exit-code gates for a CI step or commit hook. See [Command line](#command-line).\n- **Zero network** — Lupen only reads local Claude Code and Codex files on disk. No API keys, no telemetry, no cloud sync.\n\n## Install\n\n```bash\nbrew install --cask momoraul/lupen/lupen\n```\n\n…or grab the signed DMG from the [latest release](https://github.com/momoraul/Lupen/releases/latest). Both are notarized and keep themselves up to date via Sparkle.\n\n### Build from source\n\n```bash\ngit clone https://github.com/momoraul/Lupen.git\ncd Lupen\ncp Config/Local.xcconfig.example Config/Local.xcconfig  # set DEVELOPMENT_TEAM\nxcodebuild build -project Lupen.xcodeproj -scheme Lupen -destination 'platform=macOS'\nopen ~/Library/Developer/Xcode/DerivedData/Lupen-*/Build/Products/Debug/Lupen.app\n```\n\n## Command line\n\nThe app binary doubles as a `lupen` CLI — same local index the menu-bar app\nbuilds, every report scriptable and local:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/branding/lupen-cli.svg\" alt=\"lupen skills --last 30d — a per-skill cost table with RUNS, COST, $/run, and top model columns\" width=\"620\"\u003e\n\u003c/p\u003e\n\n```bash\nlupen skills --last 30d            # per-skill cost, $/run, top model\nlupen top --by sessions --limit 5  # the costliest sessions\nlupen budget --over 20 --last 7d   # exit 4 if this week ran over $20\nlupen verify                       # exit 4 if any cost drifts from the recomputed truth\nlupen daily --json | jq            # any report as JSON / CSV\n```\n\nThe full command set, grouped:\n\n| | Commands |\n|---|---|\n| **Spend** | `summary` (default) · `daily` / `weekly` / `monthly` |\n| **Breakdowns** | `skills` · `models` · `projects` · `top` |\n| **Find \u0026 resume** | `search \u003ctext\u003e` · `resume \u003csession-id\u003e` |\n| **Guards** (exit-code gates for CI) | `verify` · `budget --over \u003cusd\u003e` · `statusline` |\n| **Index \u0026 setup** | `refresh` · `config` · `install-cli` |\n\nEvery reporting command takes `--provider`, a period (`--last 30d` / `--month\n2026-06` / `--since … --until …`), and `--json` / `--csv` — except `verify`,\nwhich audits the whole corpus and ignores the period.\n\nHomebrew installs put `lupen` on your PATH automatically;\non a DMG or source build, run `lupen install-cli` once. Full reference — every\nflag and exit code: [docs/CLI.md](docs/CLI.md).\n\n## Why I built this\n\nA single Claude Code session once cost me more than the rest of the day combined,\nand the daily total couldn't tell me which turn — or which runaway sub-agent —\nate the money. Lupen is the itemized receipt I wanted: every turn priced, and\nevery price checked against the raw tokens, without anything leaving my Mac.\n\n## Privacy\n\nLupen reads local session files on your Mac:\n\n- Claude Code: `~/.claude/projects/**/*.jsonl`\n- Codex: `$CODEX_HOME/sessions/**/rollout-*.jsonl` or `~/.codex/sessions/**/rollout-*.jsonl`\n\nIt makes **zero network requests**. No telemetry, no analytics, no cloud sync.\nYour conversations, prompts, file paths, and attachments never leave your\nmachine. The `Info.plist` carries no `NSAppTransportSecurity` block because\nLupen opens no sockets — you can confirm this with Little Snitch or any\noutbound-connection monitor.\n\nDetailed model: [SECURITY.md](SECURITY.md).\n\n## Requirements\n\n- macOS 26 (Tahoe) or later, Apple Silicon\n- Xcode 26 with Swift 6 (build from source only)\n- An active Claude Code or Codex installation with local session data\n\n## Docs\n\n- [`docs/CLAUDE-CODE-TOKEN-GUIDE.md`](docs/CLAUDE-CODE-TOKEN-GUIDE.md) — `~/.claude/projects/` JSONL schema + token-field interpretation.\n- [`docs/CODEX-LOCAL-DATA.md`](docs/CODEX-LOCAL-DATA.md) — `~/.codex/sessions/` rollout JSONL schema + token-field interpretation.\n- [`docs/TOKEN-BILLING-EXPLAINED.md`](docs/TOKEN-BILLING-EXPLAINED.md) — How Anthropic's token counts, cache savings, and billable totals relate.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the workflow, commit style,\nand how to file a bug with a sanitised JSONL repro.\n\n## License\n\nMIT. Copyright © 2026 jaden (@momoraul). See [LICENSE](LICENSE).\n\nLupen is an independent project. It is **not affiliated with Anthropic or\nOpenAI**; it only reads local log files written to your machine.\n\n## Acknowledgments\n\n- [Sparkle](https://sparkle-project.org) — auto-update framework (MIT).\n- [GRDB.swift](https://github.com/groue/GRDB.swift) — SQLite toolkit for the on-device index (MIT).\n\n## Changelog\n\n### v0.8.0 — _2026-07-05_\n\nA turn waterfall timeline, recovered parallel tool calls, and a unified cost color.\n\n- **Turn waterfall timeline** — each turn's activity now renders as a swimlane\n  timeline you can click to jump into, with instant tooltips.\n- **Parallel tool calls recovered** — expanding a turn no longer drops tool calls\n  that ran in parallel.\n- **Consistent cost color** — the \"attention\" orange for costs is unified into a\n  single token so it reads the same across every surface.\n\n### v0.7.0 — _2026-06-29_\n\nMultiple session sources, weekly/monthly reports, and a faster, friendlier Conversation tab.\n\n- **Multiple session sources** — index Claude Code / Codex sessions from more\n  than one root and switch between them; sources are added and managed in\n  Settings.\n- **Weekly \u0026 monthly reports** — the Reports Overview now buckets by Day, Week,\n  or Month, each with a period-over-period delta, for long-term trends and\n  monthly expense reporting.\n- **Appearance setting** — pick System, Light, or Dark independently of macOS.\n- **In-conversation Find (⌘F)** — search within the open conversation with match\n  navigation and highlighting.\n- **Per-card Copy** — every conversation card (and code block) has a\n  hover-revealed Copy button with copy confirmation.\n- **Menu-bar action menu** — right-click the menu-bar item for quick actions.\n- **Self-healing index** — File → Check Index Integrity… runs an on-demand\n  SQLite integrity check and repairs a corrupt index in place.\n- **Stability** — removed force-unwraps on hot and launch paths so corrupt input\n  degrades gracefully instead of crashing the app or CLI.\n\n### v0.6.3 — _2026-06-24_\n\nA calmer Conversation tab and a more reliable menu bar.\n\n- **Conversation tab redesign** — quiet cards (a hairline border + faint fill so\n  the dialogue leads instead of competing with boxes), receding headers, and an\n  accent-bordered selected step; body typography, reading width, and code/table\n  legibility were tuned alongside.\n- **Cleaner attachment indicator** — a single legible paperclip marks turns with\n  image attachments (instead of one glyph per image), and it stays readable on\n  the selected row in both light and dark mode.\n- **Menu bar** — clicking the menu-bar item now reliably brings the window to the\n  front, and idle days show a clear \"$0\" instead of a near-invisible dimmed amount.\n\n### v0.6.2 — _2026-06-23_\n\nUrgent CLI crash fix plus more accurate Codex usage verification.\n\n- **CLI crash fix** — the `lupen` CLI no longer crashes on launch (a SIGTRAP\n  that hit 100% of CLI runs); logging now bootstraps safely from any thread.\n- **Codex Verify Usage accuracy** — stops false-positive \"missing usage\"\n  reports, fixes generated-turn request-id matching, and adds error/warning\n  severity to the Verify Costs filter and the `verify` CLI gate.\n\n### v0.6.1 — _2026-06-22_\n\nFixes a freeze on very large turns and cold-launch selection.\n\n- **Large-turn performance** — the Conversation tab no longer freezes on\n  multi-thousand-step turns; long runs of supporting activity (tools, thinking)\n  fold into a collapsed group so the card count stays bounded.\n- **Cold-launch selection** — the first session is now auto-selected on a cold\n  launch with a proper focus ring, instead of opening with nothing selected.\n\n### v0.6.0 — _2026-06-21_\n\nReimagines the Conversation tab as a rich Turn reader.\n\n- **Conversation rich reader** — a selected Turn now renders as a card stack\n  (prompt → thinking → tools → reply) instead of two plain-text blocks, with\n  rich markdown (headings, lists, code blocks with copy, tables, quotes) and\n  multi-line selection.\n- **Curation** — thinking and tool calls collapse into one-line disclosures you\n  can expand; interrupted / API-error / compacted turns show a clear status\n  banner instead of \"(no response available)\".\n- **Readability** — prompts and replies stand out as cards while side content\n  (thinking, tools) fades into indented lines; the selected step is highlighted\n  and scrolled into view.\n\n### v0.5.0 — _2026-06-21_\n\nAdds a storage manager and sharpens the Codex sidebar.\n\n- **Manage Sessions \u0026 Storage window** (⌘⇧M) — browse and clean up Claude Code\n  and Codex sessions by disk usage, with Lupen cache inspection (index / WAL /\n  snapshot) and a read-only all-disk view. Deletion is trash-only with an\n  allowlist + Undo; auth/config/state files are hard-blocked.\n- **Codex first-prompt titles** — sessions without a `session_index.jsonl`\n  thread name now show their first user prompt instead of the raw id prefix.\n- **Zero-cost session hiding** — low-signal $0 sessions (Codex\n  auto-review/guardian, idle) collapse behind a small `(N)` toggle per project\n  group; active, selected, and no-cost-aggregate sessions stay visible.\n- **Cost recoloring** — cost ≥ $1 reads orange (softer on dark), N/A reads\n  slate, sub-$1 stays dim; colors adapt per light/dark and invert on selection.\n\n### v0.4.1 — _2026-06-20_\n\nMaintenance release — cost-accuracy fixes and a clearer cost in the sidebar.\n\n- Per-session cost now has a dedicated, compression-resistant sidebar label —\n  the title truncates first so the cost stays visible, with the same confidence\n  tinting as the turn rows.\n- Codex: sessions backed by valid rollout JSONL now appear in the sidebar even\n  when they're missing from `session_index.jsonl`, matching the local Codex view.\n- Verify Costs: `usage` blocks that omit input/output tokens are kept (coerced\n  to 0) instead of silently dropping the line — fixes an undercount versus the\n  ground-truth scan.\n- Codex usage verifier: fold `last`-only token events into the running total so\n  the verifier matches the importer.\n- Codex: bound memory when importing/verifying oversized single-piece rollouts,\n  preventing an out-of-memory spike on very large sessions.\n\n### v0.4.0 — _2026-06-18_\n\nFirst release of the `lupen` command line — the app binary doubles as a\nscriptable CLI over the same local index the menu-bar app builds.\n\n- **`lupen` CLI** — `summary`, `daily` / `weekly` / `monthly`, `skills`,\n  `models`, `projects`, `top`, `search` / `resume`, `verify`, `budget`,\n  `statusline`, `refresh`, `config`, `install-cli`.\n- Every report as a table, `--json`, or `--csv`; `--provider` and the period\n  flags (`--last` / `--month` / `--since`+`--until`) throughout.\n- `verify` (exit 4 on cost drift) and `budget --over` (exit 4) make CI or\n  commit-hook cost gates.\n- Homebrew installs put `lupen` on your PATH automatically; DMG / source\n  builds run `lupen install-cli` once.\n- Log window is now a DEBUG-only diagnostic (hidden in release builds).\n\n### v0.3.0 — _2026-06-17_\n\nFirst public release. Highlights:\n\n- Session → Turn → Step → SkillGroup → SubAgent outline with per-row cost and 4-way token breakdown\n- Provider mode for Claude Code and Codex\n- Codex rollout JSONL parsing with cached-input normalization, reasoning tokens, cumulative dedup, fork replay handling, and live watching\n- `CostVerifier` / `Verify Usage` — provider-aware independent scans for local accounting confidence\n- 5-hour-limit tracking with Bayesian shrinkage (`$ per 1 % limit`) and severity-tinted menu-bar icon\n- Origin-tagged attachment classification with inline image preview\n- Snapshot cache for incremental launch (full reparse only when the schema bumps)\n- Sparkle 2 auto-update, with a signed appcast hosted on GitHub Pages\n- Status-item rendered as a single attributed run — no icon-text gap on macOS 26\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmomoraul%2Flupen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmomoraul%2Flupen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmomoraul%2Flupen/lists"}