madelogdocs

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.

I installed madelog halfway through a project. Is the history lost?

No. madelog backfill records the commits the repository already had, oldest first, with the same file statistics and diff excerpts the hook writes:

$ madelog backfill
7 commits in this repository are not recorded yet.
Record them now? [Y/n] y

recorded 7 commits, oldest first
  from 85801dd  to 8385ec8

Every backfilled event carries committed_at, the time git says the commit was made, alongside the ts that says when madelog recorded it. The page uses committed_at for the timeline, the header's date range, the day count and the weekly buckets, so a page built after a backfill describes the months the project took rather than the afternoon you installed madelog. The verification badge keeps using ts, because what it certifies is the chain.

What a backfill cannot recover 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 (secs_since_prev is left empty for backfilled commits, and the command says so), and your reasons. The reasons you can still add after the fact, anchored to the commit they belong to:

$ madelog note --at 45fe301 "chose SQLite over Postgres: one binary, no service to run"
noted at 45fe301

madelog status tells you at any time how many commits git has that the log does not.

How do I know madelog is set up correctly?

Two commands. madelog status is the one screen of facts — what is recorded, what is not, which binary each hook calls, which AI tools it can read and whether their sessions are being recorded, where the page is and whether it is newer than the log or than the one you published. madelog doctor is the check with verdicts:

$ madelog doctor
ok    log            17 events, chain verifies, root be71da247ec0
ok    post-commit    calls madelog
FAIL  post-merge     not installed — `madelog doctor --fix` reinstalls it
ok    post-rewrite   calls madelog
ok    git exclude    .madelog/ is excluded
ok    device key     /Users/ana/.config/madelog/device.key is there, mode 0600
ok    claude-code    transcripts found in /Users/ana/.claude/projects, 1 session touches this repo
warn  codex          no rollouts in ~/.codex, so nothing to read
ok    cursor         Cursor keeps conversation bodies encrypted; madelog records that a session happened, 1 session touches this repo
warn  copilot        not installed
ok    ai sessions    recording
ok    ollama         off by configuration (llm.provider = none)
ok    server         https://madelog-server-production.up.railway.app answers

madelog: 1 check failed — `madelog doctor --fix` repairs the hooks, the git exclude entry and the key mode

warn is for things madelog works without, and it does not change the exit code; only FAIL does, and the command then exits 1. madelog doctor --fix reinstalls missing or dangling hooks, puts .madelog/ back into .git/info/exclude and sets the device key to mode 0600. It never touches the log: a chain that a tool can repair would not be evidence of anything.

Does it work with Cursor, Claude Code or Copilot?

Yes, to different depths, and madelog is honest about which. It reads the logs those tools already keep on your machine; there is nothing to install.

  • Claude Code and Codex CLI write the model's exact output to disk, so madelog can compare it with what the commit contains: the first prompt, the model, the times, and per file how many lines the model wrote, how many survived unchanged and how many you rewrote.
  • Cursor 3.20 keeps conversation bodies encrypted or server-side, so a Cursor session on the page says that it happened, with its model and its times, and claims nothing else.
  • GitHub Copilot is detected and not read: its two stores have no published schema madelog has been able to verify against a real install, and guessing at one would put unverifiable numbers on the page.

With no AI tool on the machine, 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:

PlanPriceWhat it includes
Free0 €Up to 3 published projects
Pro7 € a month, or 49 € a yearUnlimited 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:

  1. madelog init was run in this repository: .madelog/log.db exists at the repository root. With the directory gone the hook returns silently.
  2. .git/hooks/post-commit exists, is executable, and contains the two lines under # madelog-cli:post-commit. madelog doctor checks this for all three hooks and madelog doctor --fix puts them back; madelog init run again does the same. An existing hook is kept and the lines are added once.
  3. madelog is 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/madelog by its full path.
  4. core.hooksPath is 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.
  5. The commit is not a duplicate, and git ran the hook. post-commit records each commit sha once and records HEAD only; post-merge does the same after a merge or a pull, and post-rewrite records the commits a rebase or a git commit --amend produces. git commit --no-verify still runs post-commit hooks.

A commit that got past all three — one a merge brought in behind the merge commit, for instance — is recorded by madelog backfill, which walks first parents from HEAD and picks up whatever the log is missing. madelog status counts them for you:

git          3 commits in git are not recorded — run `madelog backfill`

To record the commit that is HEAD right now, madelog hook post-commit by hand also works. None of the hooks can fail 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.

madelog capture answers this directly: it replays what the hook did for a commit and prints the sessions, the window and the per-file attribution, without recording anything.

$ madelog capture --commit 55e37d5
window   2026-09-18T11:53:37Z to 2026-09-18T12:48:43Z
found    1 session in that window

madelog status answers the rest in one line — ai sessions recording, or the reason it is not. Then, in order:

  • Recording is on. The newest intent event has record_ai_sessions: true in madelog log --json. Run madelog init --record-ai-sessions to turn it on; that records a new intent, and the hook follows the newest one.
  • The tool left a log madelog can read. madelog status lists all four with what it found. A Cursor or Copilot session will never carry attributed lines, by design.
  • The session wrote something in the window. The hook looks back to the previous commit, never more than 24 hours and never less than 5 minutes, and keeps each write on its own timestamp. A session that was idle through the whole window contributed nothing to that commit.
  • The lines are in this commit. A session that wrote a file is recorded against the commit that carries that file, not against every commit made the same day. If the work landed in another commit, look there.
  • The write was a write. A heredoc, a > redirect or sed -i leaves no structured record in any tool, so those lines count as yours. So do lines in a file git ignores.
  • The commit was not backfilled. madelog backfill attaches no sessions at all, and madelog init backfills on its first run.

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 device

A 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 device

A 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.

The page I published is older than the one on my disk

madelog status says so under published:

published    https://madelog-server-production.up.railway.app/p/north-fable-4xt3
             last sent 2026-09-18T09:14:02Z — the page on disk is newer; run `madelog publish` again

It compares the modification time of .madelog/site/index.html with server.published_at, which madelog publish writes after a successful upload. A local render — madelog publish --local, or madelog open on a repository with no page yet — leaves the file newer than the last publish, which is exactly what that line is for. Run madelog publish to send it, or ignore it: the link still works and still shows what you last sent.

--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.