FAQ
The questions people ask before installing, and what to do when the hook, the notes, the summaries or the server are not doing what you expect, with the exact messages madelog prints.
Does it work with Cursor, Claude Code or Copilot?
Yes, through Git AI. madelog reads the attribution Git AI writes into refs/notes/ai at commit time, and Git AI supports Claude Code, Cursor, Codex, GitHub Copilot, Windsurf, Gemini, Amp, Droid, Pi, OpenCode, Cline, Continue, Firebender, Devin and the web and cloud variants of Claude and Codex. madelog never reads a tool's own logs. The tool name on the page is Git AI's name for it, with claude shown as claude-code and the Copilot variants as copilot.
For Claude Code it additionally looks up the session's first prompt in the transcript Claude Code keeps at ~/.claude/projects/<encoded directory>/<session id>.jsonl, cut to 500 characters, best effort. Other tools get "No prompt was recorded for this session" on the page. Without Git AI, commits and decisions are still recorded; only the AI sessions and the attribution section are missing, and the page says "No AI attribution was recorded for this project." See AI sessions.
Can it be faked?
Not after the fact, and that is the claim the badge makes. Every event carries the SHA-256 of the one before it, over the previous hash, the timestamp, the kind and the payload. Editing or removing any record changes the root; madelog verify shows exactly where:
chain broken at seq 3: hash does not match the event contents (18 events read)When you publish, the root is signed with your device key and stored by the server with the time it arrived; the badge links to that record and anyone can compare the two. A log rewritten later produces a different root and no longer matches the one the server holds. The server keeps every root it ever received for a slug, even after the page is taken down.
What the chain does not do is judge the content. You could write a misleading note; the chain would record faithfully that you wrote it, and when. Timestamps come from your machine's clock, so a wrong clock produces wrong times, not a broken chain. A company reads the page for how you worked over weeks, which is hard to invent in a day, not for a stamp that says "true". Concepts spells out what "confirmed" means.
What if I do not want to show prompts?
Then they are not shown. Prompts are captured only for Claude Code, only the first message of a session, only when the transcript is on your machine, and never when the text matches a privacy.redact pattern. Before anything is uploaded, madelog publish shows you every session in the preview; press h to hide one, and the page says "1 session hidden by the author before publishing" in its place. madelog hide <event-id> does the same from the shell. A hidden session stays in the chain, so hiding does not weaken the badge. madelog publish --local renders the page to a file first, so you can read exactly what would go out. Privacy lists every switch and the exact request body.
How much does it cost?
The CLI is open source under the MIT licence, and everything on your machine is free without limit. Publishing has two plans:
| Plan | Price | What it includes |
|---|---|---|
| Free | 0 € | Up to 3 published projects |
| Pro | 7 € a month, or 49 € a year | Unlimited published projects, madelog ask over your history, a custom domain for your pages, PDF export |
Pro is not available yet. In this version nothing is gated: the server has no plan check and no billing secret configured, the webhook answers 503, and madelog ask prints `madelog ask` is not available in this version with exit code 2. Self-hosting the server is free and documented under Self-hosting.
What does the company see?
One page, at a link you send. From top to bottom: what you set out to build and for whom, four figures (commits, decisions, AI sessions, days active), the delivered link and the tools you named; a timeline of commits, decisions and AI sessions with a diff excerpt or a prompt behind each point, and the weekly summaries under it, marked as generated where a model or the template wrote them; up to five moments the analysis picked out; the ratio of AI-proposed lines to lines written by hand, or a sentence saying no attribution was recorded; and the badge with the root, the timestamps and a link to the server's record. Page anatomy walks through each section.
The company sees nothing you hid, no private note, no file git ignores, no path or prompt your redact patterns caught, no commit author email, and nothing that was not in the preview you confirmed. The company needs no account and no software; the page is one HTML file that works with JavaScript off and prints on paper with the badge visible.
The hook is not firing
Commits happen but madelog log does not grow. In order:
madelog initwas run in this repository:.madelog/log.dbexists at the repository root. With the directory gone the hook returns silently..git/hooks/post-commitexists, is executable, and contains the two lines under# madelog-cli:post-commit. Runmadelog initagain to add them if a tool overwrote the file; an existing hook is kept and the lines are added once.madelogis on the PATH the hook runs with. The symptom is one line at every commit:.git/hooks/post-commit: line 5: madelog: command not found. GUI git clients and some editors start hooks with a minimal PATH. A per-project install avoids this because the hook calls.madelog/bin/madelogby its full path.core.hooksPathis not set to another directory:git config core.hooksPath. If it is, madelog's hook is in the wrong place; add the two lines to the hook in that directory.- The commit is not a duplicate, and git ran the hook. The hook records each commit sha once and records
HEADonly.git commit --no-verifystill runs post-commit hooks; operations that create commits without running them, such as some rebases, are not recorded.
To record a commit the hook missed while it was HEAD, run madelog hook post-commit by hand. The hook never fails a commit; a problem is printed to standard error at commit time, starting with madelog:.
AI sessions are missing
Commits are recorded, ai_session events are not.
- Git AI is installed and was running when the commit was made:
git notes --ref ai show HEADprints the note for the last commit. No note means Git AI attributed nothing, which is correct when no agent wrote lines in that commit. Commits made before Git AI was installed have no note and never will. - Recording is on: the newest
intentevent hasrecord_ai_sessions: trueinmadelog log --json. Runmadelog init --record-ai-sessionstogether with at least one of--what,--for-whomor--toolsto turn it on; without one of those,initleaves the intent as it is. - The notes ref exists in this clone:
git notes --ref ai list. Notes are not fetched by a normal clone; on a second machine rungit fetch origin '+refs/notes/ai:refs/notes/ai'. - The note is readable. An unparseable note is skipped with one line on standard error:
madelog: a Git AI note could not be read, so its AI sessions are skipped (<reason>). - The hook saw the note. The hook reads the note in the same run that records the commit, and a commit already in the log is skipped on later runs. A note that arrived after the hook ran therefore leaves that commit without a session event; the next commit is unaffected.
No Ollama
Summaries say "generated from the log" and madelog summarize prints one of:
no Ollama at http://localhost:11434; writing the summaries from the template
Ollama at http://localhost:11434 has no model `qwen3:4b`; writing the summaries from the template (run `ollama pull qwen3:4b` to use it)That is the template at work, and it is a valid state: nothing is wrong, and the page is honest about it. To use a model, install Ollama, pull the configured model with ollama pull qwen3:4b, and run madelog summarize --force to rewrite the weeks. If Ollama listens elsewhere, set madelog config set llm.host <url> for this repository, or OLLAMA_HOST for the whole machine. If you want the command to fail rather than fall back, set llm.provider to ollama; it then exits 1 with madelog: llm.provider is `ollama`, but nothing answers at http://localhost:11434. Start Ollama, or run `madelog config set llm.provider auto`.
A model that answers but not with JSON is also reported per week: week 2: qwen3:4b did not return a usable summary (the model did not answer with {"summary": ...} JSON: expected value at line 1 column 1); wrote the template instead. Smaller models sometimes do this; a larger model or a second --force run usually fixes it.
Publish says the signature was refused
madelog: the server did not accept this device's signature. Your device key at ~/.config/madelog/device.key does not match the key it has on file — register again from this machine, or publish from the machine that first published this page. The server said: signature does not verify for this deviceA 401 means the server's copy of the public key behind server.device_id does not match the key that signed the request. That happens when .madelog/config.toml was copied from another machine with its server.device_id, or when ~/.config/madelog/device.key was replaced. In the first case clear the id with madelog config set server.device_id "" and publish again; the server registers your key afresh. In the second case the page belongs to the old key: restore the key, or clear server.slug as well and publish to a new link.
madelog: that page belongs to another device. Publish from the machine that created it, or run `madelog unpublish` there first. The server said: this slug belongs to another deviceA 403 means the slug in server.slug was published by another device. Publish from that machine, run madelog unpublish there first, or clear server.slug here to get a new link.
Publish cannot reach the server
madelog: could not reach http://127.0.0.1:9/v1/devices: io: Connection refused (os error 61). Your page is written locally either way.The page is at .madelog/site/index.html regardless. Check madelog config get server.url and --server; a bare host is given https://, and an empty --server "" is refused with exit 2 rather than falling back to server.url. Pointing at a server that is not madelog, such as the landing site, ends with madelog: the server has nothing at that address (registering this device). A 5xx prints the server is having trouble. Try again in a minute; your page is already written locally.
The page is too big
madelog: the page is <size> MB and the server accepts 2.0 MB at most. It is written at /Users/ana/projects/ledger/.madelog/site/index.html; hide a session or two with `madelog hide` and publish again.The page carries every diff excerpt and every prompt. Excerpts are capped at 20 lines per file and prompts at 500 characters, so this takes thousands of commits; if you get there, hiding sessions is the only lever in this version.
madelog init again did something unexpected
A second madelog init only records something when you give it something to record. With none of --what, --for-whom or --tools it asks nothing, appends nothing and leaves intent.md alone: madelog is already recording in /Users/ana/projects/ledger/. Give any of the three and a new intent event is appended with your answers merged over the newest one — what you passed wins, what you left out carries over — and intent.md is rewritten to match. The old intent stays in the chain, and the page, the hook and madelog export all read the newest. The hook lines, the exclude entry and the device key are never duplicated.
Config file will not load
madelog: parsing /Users/ana/projects/ledger/.madelog/config.toml: TOML parse error at line 6, column 1
|
6 | temperature = 0.2
| ^^^^^^^^^^^
unknown field `temperature`, expected one of `provider`, `model`, `remote`Every command that reads the config stops on an unknown key or a TOML error, including the hook, which prints madelog: could not record this commit: parsing … and lets the commit through. Remove the key. The full key list is in Configuration.
--help exits with a code
madelog --help and madelog <command> --help exit 0 and print to standard output. madelog help <command> does the same. Exit 2 with a usage message means the arguments did not parse: a misspelled command, a flag that does not exist, or a missing argument; the message names it. Exit 2 with "not available in this version" is madelog ask or madelog model pull. Exit 1 is a command that ran and failed, with the reason on standard error. The full table is in Commands.