work-ledger

module
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: Apache-2.0

README

Motus Work Ledger

Motus records selected facts from command runs in a local SQLite ledger and connects them to findings you choose to keep. A finding can hold an explanation, constraint, workaround, decision, or next step. Developers and coding agents can search those findings later and inspect the run behind each one.

Use project documentation for information that should always be present. Use Motus when the specific run matters to the finding.

Motus runs on demand and requires no account, server, or vendor integration.

Install

Download a prebuilt archive for macOS, Linux, or Windows from the latest release. Each release includes SHA-256 checksums, SBOMs, and GitHub artifact attestations. Unpack the archive and place motus or motus.exe on your PATH.

If you have Go 1.26.5 or newer, you can install from source instead:

$ go install github.com/motus-os/work-ledger/cmd/motus@latest

Go places the binary in GOBIN, or in GOPATH/bin when GOBIN is unset. Confirm the installed command:

$ motus version
Verify a release archive

Replace ARCHIVE_NAME with the exact downloaded filename. Attestation verification uses the GitHub CLI.

On macOS:

$ grep "  ARCHIVE_NAME$" checksums.txt | shasum -a 256 -c -
$ gh attestation verify ARCHIVE_NAME --repo motus-os/work-ledger

On Linux:

$ grep "  ARCHIVE_NAME$" checksums.txt | sha256sum -c -
$ gh attestation verify ARCHIVE_NAME --repo motus-os/work-ledger

On Windows PowerShell:

$archive = "ARCHIVE_NAME"
$expected = (Get-Content checksums.txt | Where-Object { $_ -like "*  $archive" }).Split()[0]
$actual = (Get-FileHash $archive -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actual -ne $expected) { throw "checksum mismatch" }
gh attestation verify $archive --repo motus-os/work-ledger

The macOS binaries are not Apple-notarized. After the checksum and GitHub attestation pass, remove a browser-added quarantine flag if Gatekeeper blocks the extracted binary:

$ xattr -d com.apple.quarantine /path/to/motus

Before recording work, add .motus/ to the project's .gitignore. Finding text is content you submit, so review it before saving.

Record a run and add a finding

This example records a failed test, the explanation, and the successful check that resolved it. Replace npm test with any test, build, script, or tool you already run. Example IDs are shortened and output is abridged.

Record the command
$ motus wrap -- npm test
motus: recorded run_0370... (failure)

Motus shows the command's output normally, returns its exit status, and prints the next commands with the new run ID.

Add the finding

Finding text is read from a file or standard input, not from a command-line argument. Create finding.txt with one summary:

The generated file was stale. Generate before testing.
$ motus finding add --run run_0370... --file finding.txt
Recorded finding_1457... (open)

Use JSON when the likely cause and next step should be separate fields:

{
  "summary": "The generated file was stale.",
  "hypothesis": "Generation did not run before the test.",
  "next_step": "Generate the file, then rerun the test."
}
$ motus finding add --run run_0370... --format json --file finding.json
Recorded finding_1457... (open)

After the fix, run the check through Motus again:

$ motus wrap -- npm test
motus: recorded run_c588... (success)

Create closure.txt with a short note:

Generated the file before running the test.

Then link the finding to the successful run:

$ motus finding close finding_1457... --disposition resolved --run run_c588... --file closure.txt
Closed finding_1457... (resolved)

A resolved finding must link to a closed run whose recorded outcome is success. Motus does not determine whether that run fixed the finding. Use the closure note to explain the relationship. The original finding stays unchanged.

Find it later
$ motus finding list --query generated
FINDING ID       STATE     RECORDED (UTC)         ORIGIN RUN   SUMMARY
finding_1457...  resolved  2026-07-24T18:51:48Z  run_0370...  The generated file was stale.

$ motus finding show finding_1457...

The full view includes the authored finding, closure note, origin run, and resolving run.

Findings beyond failures

A failed command shows the complete lifecycle, but a finding can be attached to any closed run that gives it useful context. Use a finding to preserve a run-specific constraint, workaround, decision, or next step.

The current fields are deliberately small:

  • summary states the finding
  • hypothesis records a likely cause or explanation when useful
  • next_step records the action to try later

Leave enduring findings open while they remain useful. Resolve a finding when a recorded successful run addresses it. Dismiss it when it is incorrect, stale, or no longer useful, and state why in the closure note.

Use Motus with coding agents and CI

Call Motus from the workflow that already runs the command. People, coding agents, scripts, and CI use the same CLI.

Add guidance like this to the project's AGENTS.md or equivalent:

## Motus

- Search Motus findings before work where an earlier finding may help.
- Run meaningful tests, builds, scripts, and release checks through
  `motus wrap`.
- Add a finding when a run produced an explanation, constraint, workaround,
  decision, or next step worth reusing.
- Resolve a finding only with a successful recorded run that addresses it.

The caller decides what deserves a durable record. For unattended CI, pass an explicit state directory and persist or restore it when later jobs need the same runs and findings.

State directories and worktrees

By default, Motus uses .motus/ledger.db at the current Git root. Outside a Git repository, it uses .motus/ledger.db under the current directory. Override the state directory with --state-dir PATH or MOTUS_STATE_DIR.

Each clone and Git worktree has its own default Git root and therefore its own default ledger. Use the same explicit state directory only when separate workspaces should share records.

If a list is unexpectedly empty, check the current Git root and the selected state directory. Run motus doctor against that same directory before relying on its records.

Motus creates state directories with private POSIX permissions. SQLite may create ledger.db-wal and ledger.db-shm beside ledger.db. Back up, move, or remove the entire state directory as one unit while no Motus process is using it.

motus finding list --query TEXT matches query terms case-insensitively across the summary, hypothesis, next step, and closure note. Full IDs and hexadecimal ID fragments of at least eight characters are searchable; ordinary words search finding text rather than generated IDs. Results matching the complete query or more terms appear first; ties are newest-first. Add --state open, --state resolved, or --state dismissed to narrow the list. Use --limit, --offset, and --json for scripts and coding agents.

Search reads only the selected state directory. It does not search other clones, worktrees, or CI artifacts unless they use or restore that same state.

Run receipts

motus run receipt RUN_ID writes a deterministic, self-hashed JSON projection of one closed run using the schema motus.work-receipt.v1. Findings and finding closures are not part of a run receipt. Adding or closing a finding does not change the receipt bytes for the referenced run.

GitHub artifact attestations let you verify that a release archive was built by this repository's release workflow. They do not apply to ledger receipts, which are producer-controlled local records.

Stored data and privacy

Run records contain:

  • a random run ID and timestamps
  • the executable's base name and argument count
  • the Git repository name, commit, and pre-run dirty state when available
  • stdout and stderr byte and newline counts
  • exit code or terminating signal when available, and outcome
  • structured run events created by Motus

Motus does not store command argument values, wrapped-command stdin, raw stdout or stderr, environment variables, source files, prompts, or agent transcripts. Findings and closure notes are different: Motus stores the exact validated text you submit through a file or standard input. Motus has no ledger network client.

Command reference

motus wrap -- COMMAND [ARG ...]  Run a command and record selected facts
motus run list [OPTIONS]         List and filter recorded runs
motus run receipt RUN_ID         Write a JSON receipt for a closed run
motus finding add [OPTIONS]      Add a finding to a closed run
motus finding list [OPTIONS]     List and search findings
motus finding show FINDING_ID    Show a finding and its run context
motus finding close [OPTIONS]    Resolve or dismiss a finding
motus doctor [--json]            Check local ledger consistency
motus version                    Print version information
Wrapped command behavior

motus wrap starts the command directly, without a shell. It forwards stdin and copies stdout and stderr to their original destinations. Motus records byte and newline counts observed before the command finishes or Motus terminates it. Because output is copied through pipes, a program that checks for a terminal can format its output differently than it would when run directly. If an output destination closes, Motus stops the command tree and records a failure. The wrapped process keeps the same environment and operating-system capabilities it would have when run directly; Motus is not a sandbox.

Trust model

A receipt reports what the local ledger says about a run. Finding text comes from whoever submits it; Motus does not infer or verify it. SQLite rules block normal changes, and motus doctor checks current consistency, but anyone who controls the database file can replace those controls and rewrite the records.

Motus does not sign ledger records or observe commands independently. Receipts identify this boundary as "trust_model":"producer-controlled"; they do not establish that every relevant fact was recorded or that the work was correct. See SECURITY.md for the complete security model and ARCHITECTURE.md for the data flow and storage design.

Development

The normal checks use standard Go commands:

$ go test -race ./...
$ go vet ./...
$ go build ./cmd/motus

The default pull-request workflow runs once on Ubuntu. Release builds run the suite natively on Ubuntu, macOS, and Windows first; the same native check can also be started manually.

See CONTRIBUTING.md before proposing a change.

License

Apache License 2.0. See LICENSE. Binary archives also include the applicable third-party notices.

Directories

Path Synopsis
cmd
motus command
internal
buildinfo
Package buildinfo exposes release metadata injected by the build.
Package buildinfo exposes release metadata injected by the build.
capture
Package capture runs a child process while forwarding and measuring its output without retaining the output or command arguments.
Package capture runs a child process while forwarding and measuring its output without retaining the output or command arguments.
cli
Package cli implements the Motus command-line interface.
Package cli implements the Motus command-line interface.
gitmeta
Package gitmeta reads a small, bounded set of Git repository metadata.
Package gitmeta reads a small, bounded set of Git repository metadata.
ids
Package ids creates opaque identifiers for ledger records.
Package ids creates opaque identifiers for ledger records.
statepath
Package statepath resolves the one state directory used by the CLI.
Package statepath resolves the one state directory used by the CLI.
store
Package store provides the local, producer-controlled SQLite ledger.
Package store provides the local, producer-controlled SQLite ledger.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL