Markback
Comments for anything. In plain text. In git.
Markback is a tiny text format for leaving feedback on any file — text, code, images, PDFs — that lints, diffs, and lives next to the work. CLI, Python, Node, a browser editor, and a VS Code extension.
Start here
- Try it without installing — markback.org/try-it
- Install the CLI —
pip install markbackornpm install markbackjs - Read the format — Specification
- Comment from your editor — VS Code extension
- Point your coding agent at it —
skills/markback
Installation
pip install -e .
Quick start
Parse a Markback file
from markback import parse_file, parse_string
# Parse a file
result = parse_file("labels.mb")
for record in result.records:
print(f"{record.id}: {record.feedback}")
# Parse a string
text = """
@id example
Some content here.
<<< positive; good quality
"""
result = parse_string(text)
Write Markback files
from markback import Record, FileRef, write, append
# Write records to a file
records = [
Record(feedback="good", id="item-1", content="First item"),
Record(feedback="bad", id="item-2", content="Second item"),
]
write("output.mb", records)
# Append a single record
append("output.mb", Record(feedback="great", id="item-3", content="Third"))
Lint files
from markback import lint_file
result = lint_file("myfile.mb")
if result.has_errors:
for d in result.diagnostics:
print(d)
CLI usage
The CLI is available via markback or mb (shorthand).
Annotate files
# Single file — inline feedback, appends to myfile.txt.mb
mb myfile.txt "good; clear writing"
# URL target — derives sidecar from last path segment (or hostname)
mb https://example.com/blog/post.html "great explanation"
# → writes post.html.mb with @file https://example.com/blog/post.html
# Quote a passage by editing the .mb file directly: inline content
# under an @file header can be a full snapshot OR an excerpt.
# @file https://example.com/post.html
#
# the quick brown fox jumps over the lazy dog
# <<< awkward phrasing
# Multi-segment section: several comments on one source, no repeated headers.
# @file ./essay.txt
#
# the lazy fox
# <<< awkward
#
# weak ending
# <<< needs punch
# With input reference (what produced the file)
mb output.txt "accurate" --input prompt.txt
# With tags and attribution
mb file.txt "good" --tag "review p1" --by alice@example.com
# Multiple files — same feedback for all
mb *.jpg -f "approved"
# Interactive mode — steps through each file
mb *.jpg --print
# Sweep pattern — track issues across batches
mb *.txt -f "issue-A" --scope "issue-A issue-B" --covers "./*.txt"
Utility commands
# Lint
mb --lint myfile.mb
mb --lint --json ./data/
# List records
mb --list myfile.mb
# Statistics
mb --stats myfile.mb
# Normalize to canonical format
mb --normalize input.mb
mb --normalize --in-place input.mb
# Convert between formats
mb --convert --to multi -o output.mb input.mb
mb --convert --to compact -o output.mb input.mb
# Upgrade V1 files to V2
mb --upgrade *.mb # preview
mb --upgrade --apply --in-place *.mb # apply
File format
Headers
| Header | Purpose |
|---|---|
@id |
Record identifier (plain string) |
@reply-to |
The @id this record replies to |
@by |
Who provided feedback |
@action |
<verb> <timestamp> [actor] lifecycle event; repeatable |
@tag |
Space-separated tags |
@input |
What produced the content (e.g., a prompt) |
@file |
Path to the content being annotated |
Listed in canonical order. All are optional.
File-level headers (% prefix)
%markback 2
%scope issue-A issue-B
%covers ./gen/batch3/*.txt
Record examples
@id review-001
@by alice@company.com
@file ./src/auth.py:45-67
@tag security p0
<<< vulnerable; sql-injection in query builder
Compact label list
@file ./images/001.jpg <<< approved; scene=beach
@file ./images/002.jpg <<< rejected; too dark
Multi-segment section
Several comments on one source, without repeating the headers — write
successive content + <<< pairs with no --- between them:
@file ./essay.txt
the lazy fox
<<< awkward
weak ending
<<< needs punch
Two records, both on ./essay.txt. A --- ends the section.
Threading and lifecycle
@id c1
@action created 2026-06-17T10:00:00Z dan@example.com
@file ./login.py:42 <<< this branch never fires
---
@id c2
@reply-to c1
@file ./login.py:42 <<< it does — covered by test_login_edge()
Multi-line feedback
When the text right after <<< is exactly """, feedback runs until a line
whose only content is """:
@id c1
@file ./login.py:42
<<< """
This branch looks dead, but I want to double-check before
suggesting removal.
"""
Sidecar files
Content in report.pdf, annotation in report.pdf.mb:
@id report-001
<<< good; grade=B+
Sweep pattern
Track issues across batches with meaningful absence:
%markback 2
%scope issue-A issue-B
%covers ./gen/batch3/*.txt
@file ./gen/batch3/file2.txt <<< issue-B; tone is off
@file ./gen/batch3/file5.txt <<< issue-A; issue-B; both problems
Files matching %covers without annotations are implicitly clean for all %scope items.
V1 backward compatibility
V1 headers (@uri, @source, @prior) are automatically mapped to V2 equivalents with a W010 warning. The V2 parser reads V1 files transparently.
Development
pip install -e ".[dev]"
pytest
License
MIT
Metadata
Release files for markback 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| markback-0.3.1.tar.gz | 298.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| markback-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 327.1 kB
Release files / markback-0.3.1.tar.gz
| Download URL | markback-0.3.1.tar.gz |
|---|---|
| Size | 298.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
15ca49b4af39718113fb7849cec39880a7c866c89790175c93a604849634a9f1
|
|
BLAKE2b-256 checksum How to use checksums |
a88142e2b84ff45d2c843dc8e9945bc255bb765a3d8b3f1e48bd2fd522a2fb74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / markback-0.3.1-py3-none-any.whl
| Download URL | markback-0.3.1-py3-none-any.whl |
|---|---|
| Size | 28.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
37a45619133e6e160d87158516fabf9ef5913e1ea053aadf652273fb1aa1f568
|
|
BLAKE2b-256 checksum How to use checksums |
74c40c66498179905a9a0d2b1e569451bc21804a9eb1219423c7a5b52ccd3455
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|