Installation
One command per shell. System-wide by default, per project when you want nothing on your PATH, or from source with cargo. What each path writes to disk, and how to undo it.
madelog is one binary with no runtime dependencies. Git is required. Ollama is optional and adds model-written summaries instead of template ones. Your AI tools need nothing at all: madelog reads the logs Claude Code and Codex already keep. Every install path ends by running madelog onboard, which tells you what it found.
System-wide
The default. The script downloads the release archive for your platform from madelog.app/releases, checks its SHA-256 against the published SHA256SUMS, installs the binary and adds its directory to your shell's PATH if it is not there yet.
macOS and Linux:
$ curl -fsSL https://madelog.app/install.sh | shWindows, in PowerShell:
> irm https://madelog.app/install.ps1 | iexWhat the shell script does, in order:
- Refuses to run as root. Pass
--allow-rootto override. - Picks a target from
uname:aarch64-apple-darwin,x86_64-apple-darwin,x86_64-unknown-linux-gnuoraarch64-unknown-linux-gnu. Anything else stops with a message pointing atcargo install madelog. - Reads
https://madelog.app/releases/latestto learn the current version, downloads that version'sSHA256SUMS, finds the line formadelog-<version>-<target>.zip, downloads that archive and compares its SHA-256. A mismatch prints both hashes and stops; nothing is installed. - Unpacks the archive and moves the binary to
~/.local/bin/madelogwith mode 755. On macOS it also removes thecom.apple.quarantineattribute. - If
~/.local/binis not on your PATH, appends two lines to your shell's rc file: a comment# added by the madelog installerand the export. The file depends on$SHELL:~/.zshrcfor zsh,~/.bash_profilefor bash on macOS,~/.bashrcfor bash on Linux,~/.config/fish/config.fishfor fish (withfish_add_path),~/.profileotherwise. If the file already names the directory, nothing is appended. - Runs
madelog onboardwith the terminal as its input, so the questions reach you even though the script itself was piped throughsh.
The PowerShell script mirrors it: it refuses an elevated shell (-AllowRoot overrides), downloads the x86_64-pc-windows-msvc archive, checks the sum with Get-FileHash, installs to %LOCALAPPDATA%\madelog\bin\madelog.exe, runs Unblock-File on it, and adds that directory to your user PATH through [Environment]::SetEnvironmentVariable("Path", ..., "User"). On an ARM64 machine it installs the x64 build and tells you it runs under emulation.
Open a new shell afterwards if madelog is not found. PATH changes apply to new sessions only; the installer exports the directory into its own process so that madelog onboard can run, but your current shell does not see it.
Flags and variables
Flags go after sh -s -- on macOS and Linux, and as parameters to the script block on Windows.
| Shell flag | PowerShell parameter | Effect |
|---|---|---|
--project | -Project | Per-project install, described below |
--version X.Y.Z | -Version X.Y.Z | Install that release instead of the latest |
--no-onboard | -NoOnboard | Stop after installing; do not run madelog onboard |
--allow-root | -AllowRoot (alias -AllowAdmin) | Install anyway from a root or elevated shell |
-h, --help | Print the header of the script and exit 0 |
| Variable | Effect |
|---|---|
MADELOG_INSTALL_DIR | The system-wide destination directory. Default ~/.local/bin, or %LOCALAPPDATA%\madelog\bin |
MADELOG_SITE | The origin the site and its releases are served from. Default https://madelog.app; set it to install from a staging origin, in which case the one-liner is curl -fsSL <origin>/install.sh | MADELOG_SITE=<origin> sh |
MADELOG_INSTALL_URL | The releases directory itself, overriding <site>/releases. Either form holds a latest file naming the current version and one directory per version, so a local build is file:///path/to/releases |
$ curl -fsSL https://madelog.app/install.sh | sh -s -- --version 0.1.2 --no-onboard
madelog 0.1.0 for aarch64-apple-darwin
downloaded madelog-0.1.0-aarch64-apple-darwin.zip, sha256 verified
installed ~/.local/bin/madelog
~/.local/bin is on your PATHNothing else is written. The scripts send no telemetry and create no account.
Per project
For one repository only. The binary is installed to <repo>/.madelog/bin/madelog, git is told to ignore .madelog/ through .git/info/exclude, and the three hooks call the binary by its full path. Your PATH and your shell rc files are not touched. Run it inside the repository:
$ curl -fsSL https://madelog.app/install.sh | sh -s -- --project> & ([scriptblock]::Create((irm https://madelog.app/install.ps1))) -ProjectThe script finds the repository root with git rev-parse --show-toplevel and stops if you are not inside one. It ends with MADELOG_EXE=<repo>/.madelog/bin/madelog madelog onboard --project, which runs madelog init without asking the four questions. The hook lines it writes, one pair per hook:
# madelog-cli:post-commit - records this commit in .madelog/log.db
/Users/ana/projects/ledger/.madelog/bin/madelog hook post-commit || true# madelog-cli:post-merge - records the commit a merge or pull left at HEAD
/Users/ana/projects/ledger/.madelog/bin/madelog hook post-merge || true# madelog-cli:post-rewrite - records the commits a rebase or amend produced
/Users/ana/projects/ledger/.madelog/bin/madelog hook post-rewrite || trueBecause the questions were skipped, the intent event is empty and the page's headline falls back to "How ledger came together". To fill it in, run the binary by its path with all four answers:
$ .madelog/bin/madelog init --what "A CLI that reconciles bank CSV exports against invoices" \
--for-whom "A small accounting firm" --tools "claude-code, cursor" --record-ai-sessionsThat appends a new intent event; the page reads the newest one. To use the binary by hand for anything else, call it by its path or add .madelog/bin to your PATH for that shell.
On a repository that already has commits, follow the install with madelog backfill. Nothing before the install is in the log until you do, and madelog status will keep telling you so.
From source
With a Rust toolchain installed:
$ git clone https://github.com/vanjamodrinjak21/madelog
$ cd madelog
$ cargo install --path cli
$ madelog onboardcargo install puts the binary in ~/.cargo/bin, which the Rust installer already adds to your PATH. This is also the way in on a platform the release does not carry a build for: the install scripts report the release has no build for <target> and stop.
Check the install
$ madelog --version
madelog 0.1.2
$ madelog onboard
+---+
| +-+-+ madelog - Proof of Process
+-+-+ | Records how your project came together.
+---+
madelog records three things: the commits you make, the AI sessions that produced them, and the one-sentence decisions you write with `madelog note`.
All of it stays on this machine, in .madelog/log.db, until you run `madelog publish`.
No keystrokes, no screenshots, no files git ignores. `madelog export` hands you everything back as JSON.
git found /opt/homebrew/bin/git
ollama found /usr/local/bin/ollama
AI tools madelog can read:
claude-code: no transcripts in ~/.claude, so nothing to read
codex: no rollouts in ~/.codex, so nothing to read
cursor: no Cursor storage found, so nothing to read
copilot: not installed
Record every repository you commit in? [y/N] n
Only the repositories you run `madelog init` in, then.
You are not inside a git repository, so there is nothing to record yet.
Do this next:
git init
madelog initAnswering y to that question installs three hooks in ~/.config/madelog/hooks/ and points git's global core.hooksPath at them, so madelog gets a chance to record a commit in any repository you work in. Whatever core.hooksPath pointed at before is chained rather than replaced. Commands describes what those hooks do.
The banner is drawn with box characters when standard output is a terminal, TERM is not dumb, and your locale names UTF-8 (on Windows, when WT_SESSION is set, which Windows Terminal does). Otherwise it is drawn in ASCII, as above.
Inside a repository that madelog is already set up in, madelog doctor is the fuller check: it opens the log, verifies the chain, looks at all three hooks and the binary each one names, at the git exclude entry, at the mode of your device key, at which AI tools left a log it can read, and at whether Ollama and the server answer. It exits 1 if anything that matters is broken, and madelog doctor --fix repairs the hooks, the exclude entry and the key mode.
Verifying a download
Every release carries a SHA256SUMS file next to the archives. The install scripts check it for you. To check a download by hand, fetch the archive and the sums for a version and target, then compare:
$ v=0.1.0; t=aarch64-apple-darwin
$ curl -fsSLO https://madelog.app/releases/$v/madelog-$v-$t.zip
$ curl -fsSLO https://madelog.app/releases/$v/SHA256SUMS
$ shasum -a 256 -c --ignore-missing SHA256SUMS
madelog-0.1.0-aarch64-apple-darwin.zip: OKOn Linux use sha256sum -c --ignore-missing SHA256SUMS. In PowerShell, compute the hash and read the expected one from the file:
> (Get-FileHash .\madelog-0.1.0-x86_64-pc-windows-msvc.zip -Algorithm SHA256).Hash.ToLower()
> Select-String x86_64-pc-windows-msvc .\SHA256SUMSThe two 64-character hashes must match exactly. Each archive holds the binary and the MIT licence, nothing else. madelog.app/releases lists what the current version carries. 0.1.0 carries the four Unix targets — aarch64-apple-darwin, x86_64-apple-darwin, x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu. x86_64-pc-windows-msvc is not published yet, so install.ps1 reports the release has no build for x86_64-pc-windows-msvc and installs nothing; on Windows use cargo install until it is.
What is on disk after install
| Path | Written by | Purpose |
|---|---|---|
~/.local/bin/madelog | system-wide install | The binary. %LOCALAPPDATA%\madelog\bin\madelog.exe on Windows, ~/.cargo/bin/madelog after cargo install |
| one line in your shell rc | system-wide install, only when needed | Puts the binary's directory on PATH |
<repo>/.madelog/bin/madelog | per-project install | The binary, ignored by git |
~/.config/madelog/device.key | the first madelog init | 32-byte ed25519 secret key as 64 hex characters plus a newline, mode 0600 in a 0700 directory. Same path on every OS, including Windows (C:\Users\<you>\.config\madelog\device.key) |
<repo>/.madelog/ | madelog init | log.db, config.toml, intent.md, later site/index.html |
<repo>/.git/hooks/post-commit | madelog init | Two lines appended, or a new file with #!/bin/sh on top |
<repo>/.git/hooks/post-merge | madelog init | The same, for the commit a merge or pull leaves at HEAD |
<repo>/.git/hooks/post-rewrite | madelog init | The same, for the commits a rebase or amend produces |
<repo>/.git/info/exclude | madelog init | One line, .madelog/ |
Uninstall
macOS and Linux:
$ rm ~/.local/bin/madelog # or ~/.cargo/bin/madelog after cargo install
$ rm -r ~/.config/madelog # the device key; read the note below firstThen remove the two lines the installer added to your rc file, if it added any:
$ grep -n "madelog" ~/.zshrc # or ~/.bashrc, ~/.bash_profile, ~/.profile, config.fishPowerShell:
> Remove-Item -Recurse "$env:LOCALAPPDATA\madelog"
> Remove-Item -Recurse "$HOME\.config\madelog"
> $p = [Environment]::GetEnvironmentVariable("Path", "User")
> [Environment]::SetEnvironmentVariable("Path", (($p -split ";") -notmatch "madelog" -join ";"), "User")Per repository, from its root:
$ rm -r .madelog # the log, the config, the rendered page, a per-project binary
$ for h in post-commit post-merge post-rewrite; do
> sed -i.bak "/# madelog-cli:$h/,+1d" .git/hooks/$h
> done
$ sed -i.bak '/^\.madelog\/$/d' .git/info/excludeEach hook file keeps whatever it held before madelog added its two lines. A hook that is left behind is harmless: the line ends in || true, so a missing binary cannot fail a commit. You will see .git/hooks/post-commit: line 5: madelog: command not found on every commit until you remove the line. With the binary present but .madelog/ gone, the hook exits 0 and prints nothing.
The device key in ~/.config/madelog/device.key signs every publish. If you delete it and later reinstall, the new key is a new device to the server, and a page published with the old key can no longer be replaced or taken down from this machine: the server answers 401 to the old device id and 403 to a new one. Keep the key, or take the page down with madelog unpublish first. Configuration has the details.