Workflow
One project over three weeks, day by day, from madelog init to the link you send. What you type, what gets recorded, and what the page makes of it.
This page follows ledger, a CLI that reconciles bank CSV exports against invoices, from the first commit on Monday 31 August 2026 to a published page on Thursday 17 September. The log listings, analysis and summaries are the real output of madelog 0.1.0 over that log. Times in the log are UTC; the developer is in Zagreb, two hours ahead.
Before the first commit
Install madelog, then set the repository up while the intent is fresh. The four answers become the headline of the page, so write them the way you would say them to a person.
$ curl -fsSL https://madelog.app/install.sh | sh
$ cd ~/projects/ledger && git init -b main
$ madelog init
What are you building? A CLI that reconciles bank CSV exports against invoices
Who is it for? A small accounting firm that closes its books by hand
Which AI tools do you use? (comma separated) claude-code, cursor
Record the AI sessions behind your commits? [Y/n] yNothing else to install. madelog reads the logs Claude Code and Codex already keep on your machine and matches the lines they wrote against the lines your commits added. A session it cannot attribute — Cursor, whose conversation bodies are encrypted — is still recorded as having happened.
Starting on a repository that already has a past
ledger starts from nothing. Most repositories do not. madelog init records whatever history is already there, without being asked:
$ madelog init
...
6 commits in this repository are not recorded yet.
recorded 6 commits, oldest first
from ff8a9fd to cd2619dEach backfilled commit carries the time git made it, so the page's timeline, date range, day count and weekly summaries all describe the months the project really took rather than the afternoon madelog was installed. What cannot be recovered is what was never written down: the AI sessions behind commits made weeks ago, because the tools' own logs are long gone, the gaps between commits as a wall-clock signal, and your reasons. The reasons you can still add, anchored where they belong:
$ madelog note --at 45fe301 "chose SQLite over Postgres: one binary, no service to run"
noted at 45fe301madelog status is the check that you are set up and caught up:
$ madelog status
repo /Users/ana/projects/ledger/
log 10 events chained commit 7, intent 1, summary 2
last commit 8385ec8 chore: split the CLI out of main
recorded 2026-09-18T11:42:25.405Z committed 2026-09-15T07:30:00Z
git every commit on this branch is recorded
hooks post-commit calls madelog
post-merge calls madelog
post-rewrite calls madelog
ai tools claude-code transcripts found in /Users/ana/.claude/projects, 3 sessions touch this repo
codex no rollouts in ~/.codex, so nothing to read
cursor Cursor keeps conversation bodies encrypted; madelog records that a session happened, 1 session touches this repo
copilot not installed
ai sessions recording
ollama off (llm.provider = none); summaries use the template
server https://madelog-server-production.up.railway.app
published not published
page /Users/ana/projects/ledger/.madelog/site/index.htmlWeek 1: 31 August to 6 September
Monday. Two commits: the skeleton at 09:12 UTC and, after a note, the SQLite store with its first migration. The note takes ten seconds and lands between the two commits, anchored to the first:
$ madelog note "chose SQLite over Postgres: one binary, no service to run"
noted at 162c5dbThat order matters later. A decision followed by a commit that opens a directory no earlier commit touched (migrations/) is what the analysis calls a direction change.
Tuesday. A Claude Code session writes src/import.rs. The hook records the commit, reads that session's transcript, finds 51 of the commit's 58 added lines there word for word, and appends one ai_session event with the session's first prompt. At 17:05 a fix to the same file: the importer dropped the last row of a file without a trailing newline. Nothing to type; the hook records both.
Wednesday. Three commits on src/matcher.rs inside 50 minutes, all with "wip: matching by amount" in the subject. The analysis will call this a retry.
Thursday. A report command, reverted an hour and a half later, and two notes. One of them is private:
$ madelog note "dropped the report command for now: the client only needs the matched list as CSV"
noted at 50f2f57
$ madelog note --private "ask Ivana whether the bank export can include the counterparty IBAN"
noted at 50f2f57 (private, never published)The private note is in the chain and in madelog log, marked (private). It is not in the summaries, not in the preview, not on the page.
Week 2: 7 to 13 September
Nothing until Thursday the 10th. Then one commit of 12 files and 444 lines: the matcher rewritten around a rules table. Six days of silence followed by a large commit is a stall in the analysis, and the longest stall becomes a moment on the page, with the length of the gap and the size of the commit that ended it.
Week 3: 14 to 20 September
Tuesday. Documentation. Wednesday. A note, then a Cursor session writes the CSV export. Cursor's session id is not a Claude Code transcript, so the event has no prompt; the page will say "No prompt was recorded for this session". Thursday. The release commit, and time to look at what was recorded.
$ madelog log
1 2026-08-31T09:00:00.000Z intent A CLI that reconciles bank CSV exports against invoices
2 2026-08-31T09:12:00.000Z commit 162c5db feat: project skeleton
3 2026-08-31T09:40:00.000Z decision 162c5db chose SQLite over Postgres: one binary, no service to run
4 2026-08-31T10:05:00.000Z commit d7448f4 feat: sqlite store and first migration
5 2026-09-01T14:20:00.000Z commit fb7eeec feat: csv import with BOM handling
6 2026-09-01T14:20:01.000Z ai_session fb7eeec claude-code: Write src/import.rs: read a bank CSV with columns amount, reference, booked_on into a Vec<Row>. Strip a UTF-8 BOM, skip the header, store amounts as integer cents.
7 2026-09-01T17:05:00.000Z commit d366a14 fix: importer dropped the last row when the file has no trailing newline
8 2026-09-02T10:00:00.000Z commit fcd9b5f wip: matching by amount
9 2026-09-02T10:25:00.000Z commit b17e06a wip: matching by amount and date
10 2026-09-02T10:50:00.000Z commit 1595716 wip: matching by amount and reference
11 2026-09-03T09:30:00.000Z commit ea23143 feat: report command
12 2026-09-03T11:00:00.000Z commit 50f2f57 Revert "feat: report command"
13 2026-09-03T11:10:00.000Z decision 50f2f57 dropped the report command for now: the client only needs the matched list as CSV
14 2026-09-03T11:12:00.000Z decision 50f2f57 ask Ivana whether the bank export can include the counterparty IBAN (private)
15 2026-09-10T09:00:00.000Z commit 72ddd54 feat: matcher rewrite with explicit rules and a rules table
16 2026-09-15T08:40:00.000Z commit b80d5ec docs: usage and the matching rules
17 2026-09-16T09:05:00.000Z decision b80d5ec kept the export in the same binary: a second tool means a second install for the client
18 2026-09-16T11:30:00.000Z commit a54c60b feat: export matched rows as csv
19 2026-09-16T11:30:01.000Z ai_session a54c60b cursor: (prompt not recorded)
20 2026-09-17T16:02:00.000Z commit f850c1c chore: release 0.1.0Twenty events in three weeks, of which you typed four. Check the chain, then run the analysis:
$ madelog verify
chain ok
20 events, root fee0947a2807ec497d534040725b20c26975e617c6c45fc9623b10f1a546ae62
$ madelog analyze
4 patterns in this log:
fix_after_ai fb7eeec d366a14 d366a14 reworked AI-written code in src/import.rs two hours after fb7eeec.
retry fcd9b5f b17e06a 1595716 Three commits in 50 minutes reworked the same file.
revert ea23143 50f2f57 Reverted 2 files changed in ea23143 one hour earlier.
stall 50f2f57 72ddd54 After six days without commits, 72ddd54 changed 12 files (444 lines).
recorded 4 new pattern events
4 moments for the page:
1. Fixing AI-written code in src/import.rs (fix_after_ai)
fb7eeec ("feat: csv import with BOM handling") carried AI-written lines in src/import.rs. Two hours later, d366a14 went back to the same code: "fix: importer dropped the last row when the file has no trai...". 51 lines in fb7eeec were written by the model.
2. A decision, then a new migrations/ (direction_change)
You wrote down a decision: "chose SQLite over Postgres: one binary, no service to run". The next commit, d7448f4, added 1 file under migrations/. It was called "feat: sqlite store and first migration".
3. A decision, then a new src/rules/ (direction_change)
You wrote down a decision: "dropped the report command for now: the client only needs the matched list as CSV". The next commit, 72ddd54, added 3 files under src/rules/. It was called "feat: matcher rewrite with explicit rules and a rules table".
4. Six days away, then 12 files at once (stall)
Nothing was committed for six days. Work restarted with 72ddd54 ("feat: matcher rewrite with explicit rules and a rules table"), touching 12 files and 444 lines. The next commit followed four days later.The retry and the revert are patterns but not moments: the page tells stories about fixes after AI, direction changes and stalls, and the summaries mention the rest. madelog publish runs analyze and summarize itself, so this step is optional; running it first lets you read the result without the preview in the way.
The summaries
Without Ollama, or with llm.provider = none, the template writes them:
$ madelog summarize
week 1 2026-08-31 to 2026-09-06 (generated) heuristic 01a0b382-67ed-7328-a588-dc65588b0c1e
In the week of 2026-08-31 you made 9 commits over 4 days. Most of the changes landed in src/main.rs, src/matcher.rs and Cargo.toml.
You wrote down 2 decisions: chose SQLite over Postgres: one binary, no service to run; dropped the report command for now: the client only needs the matched list as CSV.
week 2 2026-09-07 to 2026-09-13 (generated) heuristic 01a0b382-67ed-7328-a588-dc66939bf940
In the week of 2026-09-07 you made 1 commit over 1 day. Most of the changes landed in README.md, src/import.rs and src/main.rs.
No decisions were written down that week, and the analysis found no patterns.
week 3 2026-09-14 to 2026-09-20 (generated) heuristic 01a0b382-67ed-7328-a588-dc677b1e2c0f
In the week of 2026-09-14 you made 3 commits over 3 days. Most of the changes landed in src/export.rs, src/main.rs and README.md.
You wrote down 1 decision: kept the export in the same binary: a second tool means a second install for the client.
The analysis found 4 patterns that week: a fix after an AI session (d366a14 reworked AI-written code in src/import.rs two hours after fb7eeec); repeated attempts at the same files (Three commits in 50 minutes reworked the same file); a revert (Reverted 2 files changed in ea23143 one hour earlier); a stall (After six days without commits, 72ddd54 changed 12 files (444 lines)).
edit any of them with `madelog summary edit <id>`The four patterns are listed under week 3 because madelog analyze ran in week 3; a pattern event carries the timestamp of the run that found it. Week 2's paragraph reads thin because one commit is all there was. This is the moment to rewrite what reads wrong, in your own words:
$ madelog summary edit 01a0b382-67ed-7328-a588-dc66939bf940Your text replaces the template's on the page, with no "generated" marker.
Review and publish
madelog publish --local renders the page without sending anything, and madelog open puts it in front of you. Read it as the company will: the headline, the four figures, the timeline, the moments, the attribution bar (81 AI-proposed lines of 746, 11 %), the "Not yet published" badge. If a session should not be there, hide it now:
$ madelog log --json | grep -B4 '"kind": "ai_session"' | grep '"id"'
"id": "01a05d57-5a68-7075-b25a-15867fd58d96",
"id": "01a0a9fb-1aa8-7e72-a32c-06e6ee576225",
$ madelog hide 01a0a9fb-1aa8-7e72-a32c-06e6ee576225
hidden. The session stays in the chain; the page will say one session is hidden.Then publish. The preview opens first; Enter confirms it, q aborts and sends nothing.
$ madelog publish
...
page /Users/ana/projects/ledger/.madelog/site/index.html
verify https://madelog-server-production.up.railway.app/v1/verify/north-fable-4xt3
published https://madelog-server-production.up.railway.app/p/north-fable-4xt3
Send that link. `madelog unpublish` takes it down again.Send the link. The company needs no account and no software; the page is one file that works with JavaScript off, and "Check the root" on the badge opens the server's record.
After sending
Keep working. Every commit is still recorded — including the ones a git pull brings in, which post-merge catches, and the ones a rebase rewrites, which post-rewrite catches. madelog status tells you when something slipped past all three:
git 3 commits in git are not recorded — run `madelog backfill`and madelog doctor tells you why, which is usually a hook that another tool overwrote. madelog doctor --fix puts it back. When the project moves on, madelog publish again replaces the page at the same address with a new root, and the server keeps both roots in its history. When you want the page gone, madelog unpublish; when you want everything gone from your machine, rm -r .madelog and the hook lines, as described under Uninstall.
What to do more of: write a note whenever you choose between two things. The notes are the only part of the record in your voice, they anchor two of the three kinds of moment, and the summaries quote them.