Google Docs-style comments and suggested edits, kept in Sidemark (MRSF) .review.yaml sidecars so your Markdown stays clean.
PluginsTypeScript · CSSGitHub @coddingtonbearOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Google Docs-style comments and suggested edits for Obsidian, kept in Sidemark (MRSF) .review.yaml sidecars so your Markdown stays clean.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Comments and edit suggestions for Obsidian notes, stored next to each note instead of inside it.
Select text and add a comment or suggest an edit. The passage is highlighted in the editor, and the discussion lives in a sidebar. Everything is saved to a sidecar file, Your Note.md.review.yaml, in the MRSF / Sidemark format. Your notes stay plain Markdown, and other tools see nothing unusual in them.Read the full README ↗Comments and edit suggestions for Obsidian notes, stored next to each note instead of inside it.
Select text and add a comment or suggest an edit. The passage is highlighted in the editor, and the discussion lives in a sidebar. Everything is saved to a sidecar file, Your Note.md.review.yaml, in the MRSF / Sidemark format. Your notes stay plain Markdown, and other tools see nothing unusual in them.
Most ways of commenting on Obsidian notes put the comments in the note: as hidden HTML, as CriticMarkup, or as a block at the end. Sidemark keeps them out of the note entirely, in a sidecar file that follows an open specification other tools already read and write. The same comments work with the Sidemark VS Code extension, the mrsf command-line tool, and the @mrsf/mcp server for AI assistants.
| Sidemark | Tandem Comments | Commentator (CriticMarkup) | Redline | SideNote | |
|---|---|---|---|---|---|
| Where comments live | .review.yaml sidecar | Block at the end of the note | Inline in the note | .review.md sidecar | Plugin data (data.json) |
| Note file untouched | ✅ | ⚠️ block appended | ❌ | ⚠️ adds ^block IDs | ✅ |
| Format shared with other tools | ✅ MRSF: VS Code, CLI, MCP | ⚠️ plain JSON | ✅ CriticMarkup | ⚠️ documented, Redline only | ❌ |
| Anchored to | Text range | Text range | Text range | Whole block | Text range |
| Follows edits | ✅ | ✅ | n/a | ✅ | ✅ |
| Replies | ✅ | ✅ | ✅ | ❌ | ? |
| Resolve / reopen | ✅ | ✅ | ? | ✅ | ⚠️ |
| Suggested edits | ✅ | ✅ | ✅ | ❌ | ❌ |
| Follows renames | ✅ | n/a | n/a | ✅ | ✅ |
Based on each project's documentation as of September 2026; "?" means it isn't documented. "n/a" means the comments are inside the note, so they move with the text anyway. Corrections are welcome.
[!NOTE] Sidemark is an unofficial fork of Leon Pawelzik's Tandem Comments, and would not have been possible without it. The difference is where comments are stored: Tandem keeps them in a block inside each note, and Sidemark uses MRSF sidecar files. If you're happy with comments stored inside your notes, use Tandem Comments.
selected_text and the current text in anchored_text.mrsf tool) are picked up live.document field; renaming a folder is handled too. Deleting a note moves its sidecar to the trash with it.[[wikilinks]] work and show hover previews.<Note> – Comments.md next to it. The export opens in a new tab; exporting again replaces the previous export.tandem-comments block into a sidecar.Sidemark is in the Obsidian community plugin directory: open Settings → Community plugins → Browse in Obsidian, search for Sidemark, then install and enable it.
To install it by hand instead, download main.js, manifest.json and styles.css from the latest release into <your vault>/.obsidian/plugins/sidemark/, then enable Sidemark under Settings → Community plugins.
If you use Obsidian Sync, turn on syncing of "other file types" so the .review.yaml files are synced.
… menu copies or deletes a comment.Sidecars follow MRSF v1.0. Sidemark adds a few extension fields, which MRSF tools keep intact:
| Field | Meaning |
|---|---|
x_prefix / x_suffix | Up to 20 characters before and after the quote, used to tell identical quotes apart. Together with selected_text, these match the prefix, exact and suffix of a W3C TextQuoteSelector, the quote anchoring Tandem Comments uses. |
x_suggestion | { replacement, result? } on a root comment with type: suggestion. An empty replacement suggests deleting the passage. The root's text is the optional explanation; result is accepted or declined once decided. |
x_tandem_id | The original ID of a comment converted from Tandem Comments. |
An example:
mrsf_version: "1.0"
document: Projects/Plan.md
comments:
- id: 0818f29c-400a-4124-8420-185d6fdc18fa
author: Adam
timestamp: 2026-09-16T08:53:51.151Z
text: Is this too cliché? See [[Style guide]]
resolved: false
line: 7
end_line: 7
start_column: 4
end_column: 15
selected_text: quick brown
anchored_text: QUICK brown
x_prefix: "The "
x_suffix: " fox jumps over the "
- id: 27f0f28c-0559-4c46-8951-5d2359b8bb6c
author: Claude
timestamp: 2026-09-16T08:54:12.000Z
text: Agreed, rewording.
resolved: false
reply_to: 0818f29c-400a-4124-8420-185d6fdc18fa
Where Sidemark deliberately differs from the spec:
resolved on each comment separately; the spec allows resolving them together.The plugin never rewrites a sidecar it can't fully parse. It shows the error in the sidebar and leaves the file alone. When it does write, unchanged parts keep their formatting and YAML comments.
Run MRSF tools from the vault root so document paths match:
npx @mrsf/cli list "Projects/Plan.md"
npx @mrsf/cli add "Projects/Plan.md" -a "Claude" -t "Consider a table here" -l 12 --selected-text "the three options"
npx @mrsf/cli reanchor "Projects/Plan.md"
Anything these tools write shows up in Obsidian immediately.
For Claude Code, open Settings → Sidemark → Claude Code and use Install skill. It writes a ready-made skill to ~/.claude/skills/sidemark-comments/SKILL.md that teaches Claude the sidecar format and this plugin's conventions — anchoring, threads, suggestions, and what to leave alone. Desktop only, since the skill is written outside the vault, and it replaces whatever is already at that path.
When Local REST API is installed (extension API version 3 or later), Sidemark adds a comments sub-resource to every note, at /vault/<note>/comments/ and /active/comments/. Requests need the API key, bodies are JSON, and changes show up in the sidebar immediately.
| Request | Does |
|---|---|
GET …/comments/ | Lists the note's threads: each thread's root, its replies, and where its passage is now (anchor). ?resolved=false or ?resolved=true filters them. |
GET …/comments/<id> | Returns the comment and the thread it belongs to. |
POST …/comments/ | Adds a comment. {"text": "…", "quote": "…"} anchors it on the passage quote; when the quote appears more than once, add "occurrence": 2 (counting from 1) to choose one. "author" sets the author; otherwise it's your author name in Sidemark. Add "replacement": "…" to suggest an edit instead (an empty string suggests deleting the passage); text is then its optional explanation. |
POST …/comments/<id>/replies | Adds a reply: {"text": "…", "author": "…"}. |
PATCH …/comments/<id> | {"text": "…"} edits the comment; add "expected_text" to have the edit refused (409) if someone changed it first. {"resolved": true} resolves the thread and false reopens it. |
DELETE …/comments/<id> | Deletes a thread's first comment together with the thread, or a single reply. |
POST …/comments/<id>/accept | Accepts a suggested edit: replaces its passage in the note and marks it accepted. Refused (409), changing nothing, when the passage can't be found, appears more than once, or has changed since the suggestion was made. |
POST …/comments/<id>/decline | Declines a suggested edit, leaving the note alone. |
curl -k -X POST -H "Authorization: Bearer <api key>" -H "Content-Type: application/json" \
--data '{"text": "Consider a table here", "quote": "the three options", "author": "Claude"}' \
"https://127.0.0.1:27124/vault/Projects/Plan.md/comments/"
Suggested edits are listed with the other threads. Accepting one over the API edits the note in its open editor when there is one, so Undo works there as it does for the sidebar's ✓; otherwise it edits the file. Either way, a decided suggestion follows the resolved threads setting: kept as resolved history, or removed. A comment file Sidemark can't parse is never written to; requests for its note answer 409 with the parse error. Only Markdown notes have comments; the routes answer 404 for any other file.
These routes, what they send, and their errors are described in the OpenAPI spec Local REST API serves at /openapi.yaml and /openapi.json, under the Sidemark Comments tag.
The same operations are MCP tools on Local REST API's MCP server, for assistants connected to it. Each takes the note's vault path as path; the rest of the arguments and the results are the REST API's.
| Tool | Does |
|---|---|
comments_list | GET …/comments/, with resolved: true or false to filter. |
comments_get | GET …/comments/<id> |
comments_add | POST …/comments/ |
comments_reply | POST …/comments/<id>/replies |
comments_update | PATCH …/comments/<id> |
comments_delete | DELETE …/comments/<id> |
comments_accept | POST …/comments/<id>/accept |
comments_decline | POST …/comments/<id>/decline |
A request the REST API would refuse comes back as a tool error carrying the same error body, so an assistant can correct it — pick an occurrence, say, or re-read a comment that changed.
Sidemark also adds comment events to Local REST API's event streams: comment-added, comment-edited, comment-resolved, comment-reopened, and comment-deleted, subscribed to at POST /events/sidemark/<event>/. Each sends the note's path, the comment's id, its thread (the id of the thread's first comment), and the comment's author, timestamp, and text (left out when it's deleted). A thread's resolving is reported once, for its first comment. Events come from comparing a note's comments before and after each change, so comments that arrive by sync, from the mrsf CLI, or from an edit to the YAML are reported too, as long as Sidemark had already read that note's comments; the first outside change to a note it hasn't read yet isn't.
mrsf validate for strict checks. (The MCP tools do check their own arguments, since Local REST API's MCP server takes zod schemas for them.)sidecar_root setting isn't supported yet.npm install
npm run build # type-check and bundle to main.js
npm run dev # rebuild on change
npm test # vitest
@mrsf/cli) come from MRSF by Wictor Wilén (MIT).