vibe-receipts
Health Gecti
- License Γ’β¬β License: MIT
- Description Γ’β¬β Repository has a description
- Active repo Γ’β¬β Last push 0 days ago
- Community trust Γ’β¬β 15 GitHub stars
Code Uyari
- network request Γ’β¬β Outbound network request in receipts.py
- network request Γ’β¬β Outbound network request in skills/vibe-receipts/scripts/receipts.py
- process.env Γ’β¬β Environment variable access in tools/printer/build.mjs
Permissions Gecti
- Permissions Γ’β¬β No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
π§Ύ Receipts for your vibe coding β how many hours did you really work with Claude? Measured from your own prompts, with commits as proof.
π§Ύ vibe-receipts
How long did that "2-hour project" actually take?
vibe-receipts turns your Claude Code history into a shareable work-time receipt: the hours you really
spent, measured from your own prompts, and what those tokens would cost on the API.

Demo from 100% synthetic data (demo/make_demo.py) Β· full report
Your prompts are the clock. Your commits are the proof of what you built.
One Python file, zero dependencies, everything runs on your machine. Point it at any folder you used Claude Code in (a git repo or not) and get:
- a receipt card (PNG) to share: working time, prompts, agents, tokens, model mix, commits and the token value
- a full HTML report with your prompt rhythm, the break threshold and why, a sensitivity table and a daily commit log
- a daily CSV for timesheets and invoices
Who is this for?
- Freelancers and consultants who build with Claude Code and bill by the hour: a daily CSV and
a per-day commit log for the timesheet, measured instead of guessed. - Vibe coders who want to know what that weekend project really took, in hours and in tokens.
- Anyone who wants to show their work: one image and a caption, ready to post.
It measures your own work from your own Claude Code logs, on your machine. It can't see what
other people did, or work you did outside Claude Code.
Install
Works in Claude Code: the CLI, the desktop app's Code tab and the IDE extensions. It doesn't work in
a claude.ai chat, because it reads the Claude Code logs on your machine.
As a skill (copy one folder)
git clone --depth 1 https://github.com/sahmett/vibe-receipts /tmp/vibe-receipts
mkdir -p ~/.claude/skills && cp -r /tmp/vibe-receipts/skills/vibe-receipts ~/.claude/skills/
Open a new Claude Code session and it's there. To use it in one project only, copy the folder to that
project's .claude/skills/ instead.
Or as a plugin (easy updates)
/plugin marketplace add sahmett/vibe-receipts
/plugin install vibe-receipts@vibe-receipts
Then just ask Claude:
- "How many hours did I work on this repo this week?"
- "Give me the receipts for June."
- "Make a timesheet of my commits for the client invoice."
The skill turns your question into the right date range and author filter, runs the script,
and tells you the headline number, your rhythm, the busiest days, and what got done each day.
[!IMPORTANT]
Claude Code deletes session logs after 30 days by default, and with them your receipts.
To keep them, add"cleanupPeriodDays": 36500to~/.claude/settings.json.
Or run it directly
git clone https://github.com/sahmett/vibe-receipts
python3 vibe-receipts/receipts.py ~/code/my-project
Outputs go to ~/vibe-receipts/ (<repo>-receipt.png, <repo>-report.html, <repo>-daily.csv, and the receipt as data in archive/),
never into the analysed repo. The PNG is rendered with your local Chrome/Chromium in headless mode
(CHROME=/path/to/browser to pick one, --no-png to skip it). --built "mobile app" says what you
built on the receipt (the skill fills it in from your README), and --name shows another project
name, handy for client work.
Requirements
- Python 3.9 or newer, standard library only
- Claude Code session logs in
~/.claude/projects(the CLI and the desktop app both write them) - Optional: git for commits and lines of code, and Chrome, Chromium, Edge or Brave for the
receipt PNG and video; ffmpeg makes the video's MP4 play everywhere
Share your receipt
Every run prints a Share: line, a ready-made caption for the PNG:
βIt's a 2-hour project.β 11h 5m later, $138.14 of tokens. π§Ύ github.com/sahmett/vibe-receipts #vibereceipts
Post it with #vibereceipts. We'd love to see yours.
The share kit
Every run also writes ~/vibe-receipts/<repo>-share.md: a ready post per platform, filled in with that
receipt's numbers. Three short posts for X, Threads and Bluesky (the joke, the numbers, what Claude read and
wrote), one for LinkedIn with two [ ] lines left for your own takeaways, and a caption for the video on Reels,
TikTok and Shorts, with a few tips on posting. With --share every post carries the link that previews as
your receipt. In Claude Code, just say "share my receipt".
Or as a video
--video (or ask Claude for "a video of my receipt") also writes <repo>-receipt.mp4: a vertical
1080Γ1920 clip for Reels, TikTok and Shorts. Your receipt prints out of a thermal printer line by line,
with the printer's sound, gets torn off, and ends on your total and the share line. The printer is
drawn with the anatomy isometric kit
(tools/printer/build.mjs, only needed to change it). It takes about 15
seconds, because Chrome records the animation in real time.
It needs nothing beyond the Chrome that renders the PNG. If ffmpeg is installed, the clip is
re-encoded to constant-frame-rate H.264/AAC, which every platform accepts; without it you get what
Chrome recorded (MP4, or WebM on older browsers).
All your receipts on one board
Every run also keeps its receipt as data in ~/vibe-receipts/archive/ (one JSON file per project and
date range; a rerun of the same range replaces it). --board turns the archive into~/vibe-receipts/board.html, a black-and-white page with two views:
- Printer: your newest receipt printing out of the isometric thermal printer.
- Board: every receipt as a card in three columns (to bill, billed, personal), with the totals on
top, a 90-day / this-month filter and a drawer with the full receipt.
python3 receipts.py ~/code/client-app --client Northwind --board # lands in "to bill"
python3 receipts.py --board # rebuild the board from the archive only
--client names the client and --status due|paid|personal picks the column; both are kept for later runs
of the same range. Dragging a card to another column on the page is remembered in that browser.
The public site, slipt-phi.vercel.app, shows the same page with example
receipts. Drag your ~/vibe-receipts/archive folder (or its JSON files) onto it to see your own: the files
are read in the browser and kept there until you go back to the examples; nothing is uploaded.
Share one receipt as a link
--link prints a link that opens the receipt on the site, printing out of the printer:
python3 receipts.py . --link
# Link: https://slipt-phi.vercel.app/#r=bVLBjtow...
The receipt (its numbers and labels, without the client or the board column) is compressed into the part
after #, which browsers never send to the server, so no server keeps it. The project name is in it: use--name to show another one. A preview of the link in a chat app shows the site's card, not the receipt.
For a post, --share makes a link whose preview is the receipt: the project, its total time and the receipt
itself, drawn on a 1200Γ630 card:
python3 receipts.py . --share
# Share link: https://slipt-phi.vercel.app/r/bVLBjtow...
Here the receipt is in the path (/r/...), so the site's server reads it to draw that card and the page's
title. It stores nothing: there is no database, the link is the receipt. The same fields as --link go in.
The site is built by tools/site/build.py: the page, plus api/r.js (the /r/... page with the receipt's
own tags) and api/og.js (its card, with @vercel/og and the Geist fonts in tools/site/fonts, OFL).
Invoices and timesheets
Receipts archived with --client can be billed together. With no repo, --invoice collects that client's
receipts still "to bill" and writes an A4 page, as HTML and (with Chrome) PDF, to ~/vibe-receipts/invoices/:
python3 receipts.py --invoice Northwind --rate 85 --currency EUR --bill-from "Your Name\nYour address"
python3 receipts.py --invoice Northwind --since 2026-10-01 --until 2026-10-31 # no rate: a timesheet
python3 receipts.py --invoice Northwind --rate 1500 --tax 20 --mark-billed --board
- Page 1: who it is from and to, one line per receipt (project, period, hours, with a rate its amount) and
the totals, with--taxadded on top. - After it: every receipt's own days or weeks with their time, its break threshold, and a line on how the
time was measured, so the client can see where the hours come from. - Numbers: this year's next one (
2026-001,2026-002, β¦) unless you pass--number. --mark-billed: moves those receipts to the board's "billed" column;--status paidbills those instead.
Your year, wrapped
--wrapped turns a year of the archive into a story you tap through, like a year-in-review, and a
1080Γ1920 picture of its last card to post:
python3 receipts.py --wrapped # this year: ~/vibe-receipts/wrapped-2026.html and wrapped-2026.png
python3 receipts.py --wrapped 2025
The cards: your total time, month by month, where the hours went (every project on one receipt), the hour
of the day you prompt most, your busiest day and longest streak, the project that was "a 2-hour project",
what Claude read and wrote, your vibe type, and the year on one receipt with a caption to copy. A card is
left out when the archive has nothing for it.
Receipts made by this version also archive their minutes and prompts per day, a weekday Γ hour count of
your prompts, the token counts and the model mix, which the clock, busiest-day and streak cards need.
Older receipts only have their lines (a day, week, month or quarter each); their time is spread over
those dates, so the months stay right. None of this goes into --link or --share links.
How it works
Working time = gaps between your prompts
Claude Code logs every session in ~/.claude/projects/<project>/*.jsonl. vibe-receipts keeps only
the records you put in:
- messages you typed
- your answers to Claude's
AskUserQuestionquestions (those are your decisions)
Claude's replies, tool calls and results, subagent traffic, compaction summaries, IDE/system
injections, background-task notifications and "interrupted" markers are not prompts.
A gap between two consecutive prompts that is within your break threshold counts as work,
because waiting for Claude, reviewing its output and deciding what to ask next is the work.
A longer gap is a break and is dropped.
10:00 you: "add auth"
10:03 you: "use magic links" β +3 min
10:09 you: answer to a question β +6 min
10:51 you: "now the tests" β 42 min gap > threshold β break, not counted
10:54 you: "fix the flaky one" β +3 min
= 12 min
Your break threshold is learned from your rhythm
There is no fixed idle timeout. vibe-receipts looks at all the gaps between your prompts and applies
Tukey's outlier rule, the rule box plots use:
threshold = Q3 + 1.5 Γ IQR (Q1, Q3 = 25th / 75th percentile of your gaps, IQR = Q3 β Q1)
A gap that is unusually long for you is a break. A project where Claude runs long tasks between
your prompts gets a higher threshold, but never above 30 min: past half an hour we count it as a
break for anyone. With fewer than 20 gaps there is not enough data, so it uses 15 min. The report
and the receipt say which case applied, and the report shows Q1 / median / Q3 / P90 and a
sensitivity table (5 β 60 min). Want a fixed one? --break 20, or ask Claude to "recalculate with
20 minutes".
Commits add context
Commits don't decide the hours. They show what got built: commit count, effective lines of code
(weighted: code Γ1.0 Β· config Γ0.4 Β· docs / vendored / generated Γ0; CODE LINES on the receipt),
lines per hour, minutes per commit and a daily commit log.
No git? Still works. If the folder is not a git repo, has no commits in the range, or git is
not installed, the hours and token value are measured as usual. The receipt simply leaves commits
out and the report says why. vibe-receipts never talks to GitHub; it only reads local git history.
Token value β what you paid
TOKEN VALUE estimates what the recorded usage would cost at Anthropic API list prices
(PRICES in receipts.py). It is not your Claude subscription cost. It covers:
- input and output, per model
- cache reads, and cache writes at 1.25Γ input (5-minute cache) or 2Γ (1-hour cache)
- fast mode at 2Γ
- subagents
The report breaks it down and shows what it would have cost without the prompt cache. Responses
from models missing from PRICES are left out and the value is shown as β₯.
The full report
Every receipt comes with a full HTML report: the headline numbers, how your gaps between prompts
spread out, how much the total moves if the break threshold changes, what the tokens are worth and
which models wrote them, a daily table and a daily commit log.

Highlights from the synthetic demo report Β· see the whole report
Privacy
Everything runs locally. vibe-receipts reads your Claude Code transcripts and git history on your
machine and writes its outputs to ~/vibe-receipts/. It never uploads your prompts, code, logs or
reports. The only network request is the receipt card (and the video) loading its font from
Google Fonts while it is rendered. The video is recorded by a local headless Chrome talking to a
throwaway server on 127.0.0.1.
Options
| Flag | Meaning |
|---|---|
repo |
folder to analyse, git repo or not (default .) |
--since / --until |
day range YYYY-MM-DD, applied to both prompts and commits (default: the days your prompts cover, so older commits are left out) |
--author |
only this author's commits (git log --author pattern) |
--break MIN |
fixed break threshold in minutes (default: learned from your rhythm); --idle is the old name |
--built |
what the project is, 1β3 words, shown on the receipt |
--name |
project name shown in the report and on the receipt |
--lang en|tr |
report language (default: from $LANG, else English) |
--transcripts DIR |
Claude log folder, overrides auto-detection (repeatable, e.g. for a repo cloned in two places) |
--out DIR |
output folder (default ~/vibe-receipts) |
--no-png |
skip the receipt PNG |
--video |
also make <repo>-receipt.mp4, the receipt printing out of a thermal printer (1080Γ1920) |
--board |
also rebuild board.html from every archived receipt; with no repo, only rebuild it |
--client |
client of this receipt, shown on the board |
--status |
board column: due, paid or personal (default: due with a client, else personal) |
--link |
also print a link that opens this receipt on the public site (the receipt rides in the # part) |
--invoice CLIENT |
with no repo: that client's "to bill" receipts as an invoice (--rate, --currency, --tax) or a timesheet, HTML and PDF |
--wrapped [YEAR] |
with no repo: the year from the archive as a story, wrapped-<year>.html and .png (default: this year) |
--mark-billed |
with --invoice: move the billed receipts to the board's "billed" column |
--share |
also print a link whose preview shows this receipt (the receipt rides in the path; nothing is stored) |
Constants at the top of receipts.py: IDLE (fallback threshold), CAP, MIN_GAPS, SENS
(thresholds in the sensitivity table), PRICES, CODE_W, VENDOR_RE / GEN_RE (excluded file
patterns), and SESSION_GAP / SESSION_MIN / SESSION_SPAN for the commit estimate.
No session logs? Estimated from commits
For a repo with no Claude logs, the hours are estimated from commit sessions: one author's commits
less than 60 min apart form a session, and each session counts about 48 min plus 5% of its length.
These numbers were fitted on 112 days of Claude-assisted solo work in 7 repos, where prompt-measured
hours were known; for a repo left out of the fit the estimate was off by 15% on average. The receipt
says it is an estimate. Work without any commits stays invisible to it.
Full report as an image
The receipt PNG is made for you. To turn the full HTML report into a long JPEG too:
bash to_jpg.sh ~/vibe-receipts/<repo>-report.html # macOS + Google Chrome + Pillow
FAQ
Is the token value what I paid?No. It is what the same usage would cost at Anthropic API list prices. A Claude subscription costs
something else. See Token value β what you paid.
- Claude Code deletes session logs after 30 days by default. Older work is gone unless you set
"cleanupPeriodDays"(see Install). - Logs are stored by folder path. If you moved or renamed the project, point at the old logs with
--transcripts ~/.claude/projects/<old-path-with-dashes>. - If you walk away while Claude works, that gap counts as a break once it passes your break threshold
(30 min at most).--break 45counts longer gaps as work.
The card is rendered with a local Chrome, Chromium, Edge or Brave. If none is found, the run says so
and writes the card as HTML next to the report. Set CHROME=/path/to/browser to pick one.
No. The hours come from your prompts. Git only adds commits and lines of code, and vibe-receipts
never talks to GitHub.
By default the date range is the days your prompts cover, so the period, commits and lines describe
the same work as the hours. Use --since / --until to choose the range yourself.
Yes, but then the hours are an estimate from commit sessions, not a measurement. See
No session logs?.
Repo layout
.claude-plugin/ plugin + marketplace manifests
skills/vibe-receipts/
βββ SKILL.md when and how Claude runs it
βββ scripts/
βββ receipts.py analysis, HTML report, receipt card, video
βββ printer.json the printer in the video and on the board (built by tools/printer)
βββ board_template.html the board page --board fills in
βββ invoice.py --invoice: a client's receipts as an invoice or a timesheet
βββ share.py the share kit: a ready post per platform for each receipt
βββ wrapped.py --wrapped: the year's numbers from the archive
βββ wrapped_template.html the story page --wrapped fills in
βββ to_jpg.sh report β JPEG
receipts.py, to_jpg.sh shortcuts (symlinks)
demo/make_demo.py rebuilds the synthetic demo above (--video for the clip)
tools/printer/build.mjs draws the printer with the anatomy isometric kit
License
MIT, see LICENSE.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi