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)
# 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 |
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.3.1.tar.gz
(64.7 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
mrsf-0.3.1-py3-none-any.whl
(40.9 kB
view details)
File details
Details for the file mrsf-0.3.1.tar.gz.
File metadata
- Download URL: mrsf-0.3.1.tar.gz
- Upload date:
- Size: 64.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c00c16bd227b55f451ad450de513bd9cf133041f08d1e6b020d5cf097ee73b4
|
|
| MD5 |
91773d855958e22805bbee7193b7184a
|
|
| BLAKE2b-256 |
20d1248eddcee04476b81832101e8b71a50b81a8b625916878eadf0437f19c36
|
File details
Details for the file mrsf-0.3.1-py3-none-any.whl.
File metadata
- Download URL: mrsf-0.3.1-py3-none-any.whl
- Upload date:
- Size: 40.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c654a0a5e108a903cbaacf5d19b8187061dcb224974aa678a7b3a3ad80647af0
|
|
| MD5 |
5928950f743272c0828edc98731c6f1a
|
|
| BLAKE2b-256 |
727384f3ee33277b6f54e054b9469c0213eb57e660a09df348cae158e16571fd
|