← All tools

rogerchappel/runledger

Popularity 65 Updated Development & Build

Local-first tamper-evident command run ledger for developers and agents.

githubauto-collected

Installation

A directly usable install command is not verified yet. Check the project documentation or releases.

RunLedger

RunLedger is a tiny local flight recorder for command-line work. It records what you ran, redacts obvious secrets, appends tamper-evident JSONL, and renders deterministic Markdown or JSON summaries you can paste into reviews.

It is for developers and agentic coding loops that need evidence without sending source code to a hosted dashboard.

Quick start

npm install
npm run build
node dist/src/index.js record -- npm test
node dist/src/index.js summarize .runledger/runs.jsonl --out REPORT.md
node dist/src/index.js verify .runledger/runs.jsonl --fail-on invalid

RunLedger has not had its first npm release yet. Until the first tagged release, use the source-checkout commands above. Tagged releases publish the @rogerchappel/runledger package to npm; after publication, install it with npm install --global @rogerchappel/runledger and use the preserved runledger binary instead of node dist/src/index.js.

Commands

Options that take values accept either --option value or --option=value. Unknown options and value-taking options without a value are rejected before a command runs or writes output.

record

Runs a command and appends one JSONL record. The command must follow a literal -- separator; any non-flag arguments before -- are rejected (exit 1) before anything runs or is written.

runledger record --ledger .runledger/runs.jsonl -- npm test

Each record includes command, cwd, timestamps, duration, exit code, stdout/stderr, previous hash, and record hash.

Writers to the same ledger are serialized with a sibling <ledger.lock directory. A writer revalidates the complete chain while holding that lock before it chooses prevHash and appends, so overlapping record processes preserve every completed run in a valid chain. Lock acquisition times out after 10 seconds without changing the ledger. If a process is killed while committing, verify that no record process still uses the ledger before manually removing the lock directory; the next record will revalidate the ledger before writing. RunLedger retains at most the first 1 MiB (1,048,576 bytes) of stdout and 1 MiB of stderr in each record while continuing to drain both child streams. When a stream exceeds that limit, its stored text ends with [runledger: truncated N bytes], where N is the exact number of omitted bytes. If the byte boundary intersects a multibyte UTF-8 character, that whole character is omitted and included in N, so stored output remains valid UTF-8. Truncation is applied before redaction, so secrets in retained text are still redacted and the marker is deterministic. If the operating system cannot launch the command (for example, because the executable does not exist), record still appends a failed record with exit code 1 and a diagnostic in stderr. The attempted command remains part of the hash chain, and later runs can append normally. By default, command output is buffered until the command finishes, then the same redacted stdout and stderr written to the record are forwarded to the terminal. Use --no-redact only when raw output is explicitly required; it is forwarded as the command runs in full, even when the stored copy is truncated, and stored without redaction.

summarize

Produces deterministic Markdown by default, or JSON with --format json.

runledger summarize examples/sample-runs.jsonl --out REPORT.md
runledger summarize examples/sample-runs.jsonl --format json

summarize verifies the ledger before rendering. For a valid ledger it writes a deterministic Markdown or JSON summary and exits 0. For malformed JSON, an invalid record schema, a broken previous-hash link, or a record-hash mismatch, it still writes the useful partial summary (with changed set to true), reports every concrete issue on stderr, and exits 2. When --out is used, the partial summary is written there while diagnostics remain on stderr. The accepted form is exactly one ledger path followed by options; unexpected positional arguments are rejected with exit code 1.

examples