Skip to main content

CLI and library for the Markdown Review Sidecar Format (MRSF / Sidemark)

Project description

mrsf — Markdown Review Sidecar Format (Python)

Python CLI and SDK for the MRSF (Sidemark) specification. A 1:1 port of the Node.js @mrsf/cli package.

Installation

pip install mrsf

CLI Usage

# Validate sidecar files
mrsf validate docs/*.review.yaml
mrsf validate --strict README.md

# Add a comment
mrsf add README.md --author "Alice" --text "Fix this" --line 10

# Re-anchor after edits
mrsf reanchor docs/
mrsf reanchor --staged --force
mrsf reanchor --dry-run --threshold 0.8

# List comments
mrsf list docs/
mrsf list --open --severity high --json

# Resolve/unresolve
mrsf resolve doc.md.review.yaml abc123
mrsf resolve doc.md.review.yaml abc123 --undo

# Check anchor health
mrsf status docs/
mrsf status --json

# Create empty sidecar
mrsf init README.md

# Rename document + sidecar
mrsf rename old.md new.md

# Watch for changes
mrsf watch docs/ --reanchor --force

Global Options

Option Description
--cwd <dir> Working directory
--config <path> Path to .mrsf.yaml config
-q, --quiet Suppress non-essential output
-v, --verbose Detailed diagnostic output
--no-color Disable color output

SDK Usage

import mrsf

# Parse a sidecar file
doc = mrsf.parse_sidecar("README.md.review.yaml")

# Iterate comments
for comment in doc.comments:
    print(f"{comment.author}: {comment.text} (line {comment.line})")

# Add a comment
opts = mrsf.AddCommentOptions(
    author="Alice",
    text="Consider rephrasing this section",
    line=42,
    selected_text="The quick brown fox",
    type="suggestion",
    severity="medium",
)
new_comment = mrsf.add_comment(doc, opts)

# Add a comment with tool-specific x_* metadata
bot_opts = mrsf.AddCommentOptions(
    author="review-bot",
    text="Needs a second pass",
    line=12,
    extensions={
        "x_source": "review-bot",
        "x_score": 0.91,
        "x_labels": ["needs-review", "docs"],
    },
)
mrsf.add_comment(doc, bot_opts)

# Write back (preserves YAML formatting)
mrsf.write_sidecar("README.md.review.yaml", doc)

# Validate
result = mrsf.validate(doc)
if not result.valid:
    for err in result.errors:
        print(f"Error: {err.message}")

# Re-anchor after edits
results = mrsf.reanchor_document(doc, document_lines)
for r in results:
    print(f"{r.comment_id}: {r.status} ({r.reason})")

# Discover sidecar for a document
sidecar_path = mrsf.discover_sidecar("docs/guide.md")

# Fuzzy text matching
score = mrsf.combined_score("original text", "edited text")
matches = mrsf.fuzzy_search("search text", ["line 1", "line 2", "line 3"])

API Reference

Parsing

Function Description
parse_sidecar(path) Parse a .review.yaml or .review.json file
parse_sidecar_content(content, format) Parse sidecar from string content
read_document_lines(path) Read document lines for anchoring

Writing

Function Description
write_sidecar(path, doc) Write with round-trip YAML preservation
to_yaml(doc) Serialize to YAML string
to_json(doc) Serialize to JSON string
compute_hash(text) SHA-256 hash for selected_text_hash
sync_hash(comment) Sync hash with current selected_text

Comments

Function Description
add_comment(doc, opts) Add a new comment
resolve_comment(doc, id) Mark comment as resolved
unresolve_comment(doc, id) Mark comment as unresolved
remove_comment(doc, id, opts) Remove with reply promotion (§9.1)
filter_comments(comments, filter) Filter by status/author/type/severity
get_threads(comments) Group into reply threads
summarize(comments) Aggregate statistics

AddCommentOptions accepts an optional extensions map. Keys must start with x_, and entries are written back to the sidecar as flat x_* fields on the comment.

Validation

Function Description
validate(doc) Validate an MrsfDocument in memory
validate_file(path) Validate a sidecar file on disk

Re-anchoring

Function Description
reanchor_comment(comment, lines, opts) Re-anchor a single comment
reanchor_document(doc, lines, opts) Re-anchor all comments in a document
reanchor_file(path, opts) High-level file-based re-anchor

Discovery

Function Description
discover_sidecar(doc_path) Find sidecar for a document
discover_all_sidecars(root) Find all sidecars in a directory
find_workspace_root(cwd) Find workspace root (.mrsf.yaml or .git)
load_config(root) Load .mrsf.yaml configuration

Fuzzy Matching

Function Description
exact_match(needle, haystack) Find exact substring matches
normalized_match(needle, haystack) Whitespace-normalized matching
fuzzy_search(needle, lines) Multi-line fuzzy search with scoring
combined_score(a, b) Combined similarity score (0.0–1.0)

Git Integration

Function Description
is_git_available() Check if git is on PATH
find_repo_root(cwd) Find .git root directory
get_current_commit(root) Get HEAD commit SHA
get_diff(commit, path, root) Get unified diff output
get_line_shift(commit, path, line, root) Compute line shift from diff

Data Types

@dataclass
class MrsfDocument:
    mrsf_version: str
    document: str
    comments: list[Comment]

@dataclass
class Comment:
    id: str
    author: str
    timestamp: str
    text: str
    resolved: bool = False
    line: int | None = None
    end_line: int | None = None
    selected_text: str | None = None
    selected_text_hash: str | None = None
    type: str | None = None
    severity: str | None = None  # "low" | "medium" | "high"
    reply_to: str | None = None
    commit: str | None = None
    # ... plus start_column, end_column, anchored_text

Requirements

  • Python ≥ 3.10
  • Dependencies: click, jsonschema, ruamel.yaml, rapidfuzz, rich, watchdog

Development

cd python
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# Run tests
pytest -v

# Lint
ruff check src/ tests/

# Type check
mypy src/mrsf/

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mrsf-0.4.0.tar.gz (66.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mrsf-0.4.0-py3-none-any.whl (42.0 kB view details)

Uploaded Python 3

File details

Details for the file mrsf-0.4.0.tar.gz.

File metadata

  • Download URL: mrsf-0.4.0.tar.gz
  • Upload date:
  • Size: 66.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for mrsf-0.4.0.tar.gz
Algorithm Hash digest
SHA256 9148ffa391a4bc121ce95806ad3ed995c4fca06be99fc34b4a61ebffc365875c
MD5 557d73bd3d8f416770e81e1e8833fa12
BLAKE2b-256 864aaccf74ef4ead8e25e34bf9593fd11aab292b2d1a5f25831fe1dca0113a41

See more details on using hashes here.

File details

Details for the file mrsf-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: mrsf-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 42.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for mrsf-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cb67c6859a0750578fd45bca53ce576a97b413e277658c15cf768c9164ace88d
MD5 3907ed7ae45a0c9de660c318fdaf889f
BLAKE2b-256 c1042123af85d7d9e33156be41e69928b8fe1eb23cf949cf2040f4e047ea6c73

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page