gabriel / muse public
blame.md markdown
90 lines 2.7 KB
Raw
sha256:cb2da6c61116ad1ab98d03747c21d6f66485839c7b4efd7d0124db0f8aa14e41 refactor(harmony): move auto_apply + record_resolutions int… Sonnet 4.6 minor ⚠ breaking 24 days ago

muse blame — line-level attribution for text files

muse blame shows which commit last modified each line of a text file tracked in state/. It is the universal, domain-agnostic attribution tool — the core VCS equivalent of git blame.

For domain-specific attribution, see:

  • muse midi note-blame — per-bar attribution in MIDI tracks
  • muse code blame — per-symbol attribution in code files

Usage

muse blame README.md
muse blame --ref v1.0.0 docs/design.md
muse blame --porcelain state/config.toml | jq '.commit_id'
muse blame --short 8 src/main.py

Options

Flag Default Description
--ref, -r HEAD Commit or branch to blame from
--porcelain, -p false Emit JSON objects instead of human-readable output
--short 12 Length of commit SHA prefix to display

Output (human-readable)

cccccccc0000  (Test User       2026-03-19)   1  hello world

Columns:

  • Commit SHA prefix (12 chars by default)
  • Author name (padded)
  • Date (YYYY-MM-DD)
  • Line number (right-aligned)
  • Line content

Output (--porcelain)

One JSON object per line:

{"lineno": 1, "commit_id": "cccccccc…", "author": "Test User", "committed_at": "2026-03-19T14:22:01+00:00", "message": "initial commit", "content": "hello world"}

How attribution works

The blame algorithm walks the commit graph backwards from the requested ref:

  1. Every line in the file at HEAD is initially attributed to HEAD.
  2. For each ancestor commit, a unified diff is computed between the ancestor's version and its child's.
  3. Lines that appear unchanged in both versions are re-attributed to the ancestor — the older commit that first introduced them.
  4. Lines that were added by a commit remain attributed to that commit.

This is equivalent to Git's blame algorithm for linear histories. For merge commits, the algorithm chooses the first parent to keep attribution clean.

Agent workflows

Find who introduced a bug

muse blame --porcelain src/parser.py \
  | jq 'select(.content | test("legacy_mode")) | .commit_id' \
  | sort -u

Audit a configuration file

muse blame config/production.toml

Annotate every line with its commit

muse blame --porcelain README.md > blame-report.jsonl

Limitations

  • Only text files are supported. Binary files (images, MIDI, etc.) should use domain-specific blame commands.
  • The walk follows the first-parent chain for merge commits. To attribute across both parents, use muse midi note-blame or muse code blame which are domain-aware.

Exit codes

Code Meaning
0 Success
1 File not found at the specified ref, or ref not found
File History 2 commits
sha256:cb2da6c61116ad1ab98d03747c21d6f66485839c7b4efd7d0124db0f8aa14e41 refactor(harmony): move auto_apply + record_resolutions int… Sonnet 4.6 minor 24 days ago
sha256:596a4963c21debb14d9ef51e23c2ca9f825b602ab8585f69caca35eb81bcac77 chore(harmony): baseline audit — Phase 0 of issue #16 Sonnet 4.6 28 days ago