All notable changes to markupmarkdown are recorded here. Format follows Keep a Changelog; this project follows Semantic Versioning.
Nothing yet.
- Suggestion Apply button was permanently disabled. The anchored
comment-card list — the only place suggestions can appear — never
received the
onApplySuggestionhandler; it was wired to the doc-level list instead, where suggestions can't exist (no anchor). Apply now works on anchored suggestion cards.
- Auto-review notifications deep-link to the first suggestion.
Clicking the bell entry for a finished auto-review that produced
suggestions now lands directly on the first suggestion comment
(via the existing
?comment=IDdeep link) instead of the bare doc.
markupmarkdown 1.0. What started as Google-Docs-style commenting on markdown files is now a complete human+agent review platform: docs round-trip with GitHub, comments survive rewrites, reviews carry discrete states that gate pushes, suggestions apply in one click, named check policies enforce standards across doc collections, and agents are first-class reviewers — summonable individually, standing on every revision, fulfilled by the server itself, and auditable across an entire index — always with a human holding the accept/push keys. Everything below shipped since 0.6.0; see prior releases for the full arc.
- Agent activity status + notifications. You can now always tell what the auto-reviewer is doing. A ⚡ indicator in the top nav pulses while runs are in flight (with a count), and its dropdown lists the last 24h of summoned runs: running ("reviewing now…"), done with the outcome ("approved · no issues found", "requested changes · 3 suggestions"), or failed with the reason. Every run also lands a bell notification — including failures, which previously evaporated silently, and including runs where you own the reviewing token (the old fan-out treated your bot as "you" and suppressed the self-notification).
- Index-level agent audits. On any index, "Agent audit" summons
one of your tokens across every file matching a pattern (
_PRD, or empty for everything): one click mints review requests for each opened doc (max 50/run), auto-review tokens fulfill them within minutes, and results land as review states + suggestions on each doc. Per-user by design — you can only summon tokens you own, onto docs you can access. - Failing checks gate the push. Third push gate alongside
changes-requested reviews and unaccepted agent revisions: pushback
returns 409
checks_failingwhen the revision fails its doc checks, with the count advised up-front in the modal and the same force-override escape hatch. Checks inform; force decides.
The governance release: doc checks grew into a policy system, reviews became self-fulfilling, and the admin console learned who's doing what.
- Index-level policy application. On any index you created, a "Check policies" panel maps filename patterns to your named policies ("_PRD → PRD Standard"): live match preview with per-file exception unticks, one-click apply across every opened doc, and files not yet opened link automatically on first open — so the mapping stays true over time. Docs that already have checks are never overwritten, and rules can only reference policies the index creator owns.
- Policy name visible from the doc. The Checks button now carries the verdict inline — green "Checks ✓" or red "Checks ✗ 2" — with the governing policy's name in the tooltip; click for full detail. (Replaces the per-rule chip row, which crowded the doc header.)
- Non-owner safety in the checks editor. Opening Checks on a doc that follows someone ELSE's policy shows it locked — you can fork "for this doc only" but never write into another user's policy (server-enforced; the UI now matches).
-
Favicon rendered as a solid blob. A CSS-specificity bug inside the SVG (class fill overriding the frame's fill="none") painted the outline rectangle solid, covering the M↓ glyph. The canonical Markdown mark is back.
-
Named check policies. Save a rule set once ("PRD Standard") and apply it to any doc from a dropdown in the Checks editor. Docs LINK to the policy — improving it updates every linked doc instantly. Editing rules on a linked doc makes the blast radius explicit: the save button splits into "Save to 'PRD Standard' (N docs)" vs "This doc only" (which forks the doc to its own copy). "Save as reusable policy…" promotes any custom rule set; deleting a policy materializes its rules into every linked doc so nothing silently loses its checks. Empty docs offer one-click policy chips before the preset gallery.
-
Doc checks — CI-style lint rules per doc chain. Define rules once (a "Checks" button next to Request review): required sections, forbidden text (regex — e.g. ban a lowercase brand name), required text, max heading depth. Every revision renders pass/fail chips next to the review states, with failure details on hover. Rules anchor to the chain root and follow the doc through revisions; results are computed on demand so they can never go stale. Advisory for now — failing checks inform reviewers rather than gating the push.
-
Auto-review tokens — server-fulfilled reviews. Flag a token as auto-review and the backend itself answers review requests targeting it: Claude reads the doc (plus open discussion, so it doesn't repeat feedback), leaves up to 5 anchored suggestions with rationales, and sets an honest review state — all through the same internal paths an external agent uses, billed to the owner's stored Anthropic key. Event-driven (fulfillment starts seconds after the request is minted) with a 10-minute crash-recovery sweep; atomic per-request claims cap attempts at one per day. Combined with standing reviewers this completes CI-for-prose: save a revision, get a real review back in under a minute, no external agent or cron required.
-
Admin: recently active users with drill-down. Users ordered by most recent activity, with join date, docs (public/private counts), comments, and token counts. Clicking a row expands their PUBLIC docs inline; private docs surface only as a count — titles never leave the backend, and user emails are excluded from the payload entirely.
-
Admin: sortable public-docs table + Modified column. Click any column header to sort (click again to reverse); defaults to last-modified, newest first.
-
Suggestion diff preview. Suggested changes render as a tracked-changes inline word diff (removed words struck in red, insertions in green) with a Changes/Result toggle — you read the proposal in one pass instead of eyeballing two blocks.
-
Apply all suggestions. When 2+ open suggestions exist, a batch affordance appears in the comments header: one confirm, one new revision applying every suggestion top-down in document order. Conflicting suggestions (anchor consumed by an earlier one) are skipped, reported, and stay open.
POST /api/documents/:id/apply-suggestions. -
Exact-timestamp tooltips everywhere. All user-facing timestamps render through a semantic
<time>element: friendly short dates ("Jun 4", year only when not current) with the full local datetime on hover ("June 4, 2026, 2:41 PM EDT"). Dates always use the browser's local timezone — no setting needed.
Standing reviewers, fuzzy anchor recovery, the admin console, and a three-layer overhaul of drift-banner correctness — all driven by same-day live feedback.
- Standing reviewers ("CI for prose"). Subscribe a reviewer — human or one of your agent tokens — to a doc's revision chain; every new revision automatically mints a review request for them (the revision's own author is never asked to review their own work). One checkbox in the Request-review popover ("Also review every future revision") upgrades a one-shot request to a standing subscription. Standing reviewers render as ⟳ chips with one-click removal. Fan-out hooks cover all five revision-creation paths (manual edit, AI accept, apply-suggestion, MCP edit, MCP revise).
- Fuzzy anchor recovery. Comments survive upstream rewrites: when the anchored text changes (punctuation churn, a word swapped, a sentence reflowed), a conservative trigram matcher re-anchors the comment instead of orphaning it — requiring both a high absolute similarity AND a clear margin over the runner-up passage, so two similar paragraphs never steal each other's comments. Recovered anchors show a small "≈" hint with the original selection in the tooltip. Covers sync, merge, and revision carry-forward through one shared fallback. Suggestions stay strict: apply-suggestion still requires an exact anchor.
- Admin console at /admin. Superuser-only usage dashboard: headline counts (users, docs, public/private split, comments, reviews, suggestions, tokens), a 30-day docs-created chart, recent agent activity, and a recent-public-docs feed (private docs are excluded in the query, not the UI). Gated by a MARKUPMARKDOWN_ADMIN_LOGINS env allowlist, cookie-session only; non-admins get 404.
- Named review chips. The count-based summary badge ("1 changes requested (incl. you)") is gone — the ReviewBar now names names: "± You requested changes", "✓ Ali approved", with review notes as tooltips.
- Awaiting-review visibility. Pending review requests render as "awaiting " chips on the doc (cancelable), and the request popover disables already-requested people — no more blind re-requesting.
- Drift banner correctness, three layers. (1) The root's Ignore state now mirrors onto child revisions, so a dismissed banner stays dismissed chain-wide. (2) A child whose baseline already matches upstream (created from a merge/sync) no longer inherits the root's stale baseline. (3) Chain-level suppression: when the chain's LATEST revision matches the current upstream SHA (e.g. after a pushback, which re-baselines the pushed doc), older revisions show the normal "v1 of N" breadcrumb instead of nagging about an "upstream change" the chain itself produced.
- Blank-page crash on docs with zero reviews. GET /reviews returned JSON null for the empty case; the ReviewBar called .length on it and unmounted the page. Both ends fixed.
- Served /SKILL.md was stale (since June 4). The go:embed copy had never been synced with the canonical file — agents got pre-P0 docs. Synced, plus a test that fails the build on drift.
- Home-page pop-in. The four home lists fetch in parallel now, and the indexes section ghost-holds its space with a skeleton while loading.
Review requests: the coordination verb that makes reviewers summonable.
- Review requests. "Please review this" — targeting a human user
or one of your own agent tokens. Fulfillment is implicit: when the
reviewer sets a review state on the doc, any pending request they
hold auto-completes. No "submit review" step on either end.
POST /api/documents/:id/review-requests(reviewerLogin XOR tokenId, own-token guard),GET /api/me/review-requests,POST /api/review-requests/:id/dismiss.- New notification kinds:
review_request("X requested your review on …") andreview_state("X approved / requested changes") — the latter reaches completed-request requesters and the doc owner. - New MCP tool
list_review_requests— the poll surface agents use to learn they've been summoned. Humans get bell notifications; agents poll at session start (SKILL.md documents the loop). - UI: "Request review" popover in the ReviewBar (one click on a person or agent), "Reviews requested of you" queue at the top of the home page, bell rendering for both new kinds.
- Gate-aware pushback modal. The P0 push gates now have a UX: banners render when (and only when) a gate is blocking, the agent-proposed banner carries an inline one-click Accept, an override checkbox appears only while gated, and the 409 race (reviewer requests changes after the modal loaded) flips the banner on in place instead of dead-ending.
- False drift banner on child revisions. Two bugs in the
getDocument drift overlay: the root's Ignore state
(
source_drift_ignored_sha) was never mirrored onto children, so a dismissed banner re-fired on every revision; and a child whose own baseline already matched the current upstream SHA (created FROM that upstream via merge) still inherited the root's stale baseline — manufacturing drift with nothing to merge. - Served /SKILL.md was stale. The go:embed points at a copy in backend/internal/api/ that hadn't been synced since June 4 — agents reading the live SKILL.md got pre-P0 docs. Synced, plus a test that fails the build whenever the canonical and embedded copies drift.
Review-coordination release. The first batch of changes grounded in the 2026 research pass on collaborative markdown editing + agentic AI in doc collaboration (see Design influences in the README and CLAUDE.md §15–17).
- **Review-state coordination + push gates + agent-proposed revisions
- suggested changes.** Three coordinated primitives shipped together as the P0 recommendations from the research pass:
- Review states. Reviewers set
approved | changes_requested | commentedper doc revision — the discrete coordination vocabulary from GitHub PR reviews. Applies equally to humans and agents. New endpoints:PUT/DELETE /api/documents/:id/review,GET /api/documents/:id/reviews. Doc GET carries{ reviews, myReview }. New MCP toolset_review_state. - Push gates. The pushback flow returns 409 when (a) any
reviewer has
changes_requestedset, or (b) the current revision was agent-authored and hasn't been accepted.POST /pushbackbody acceptsforce: trueto override;GET /pushback/infoadvises the modal up-front so the UI renders Accept + a force checkbox instead of surprising the user on submit. - Agent-proposed revisions + accept. Any revision written under
a Bearer token (
edit_document,revise_with_ai accept=true,merge_from_github,apply_suggestion) lands withrevision_meta.accepted_at = nil. NewPOST /api/documents/:id/accept-revisionstamps it accepted — cookie session only, so a leaked token cannot self-accept. Doc GET carries anagentProposedflag. Direct port of the GitBook change-request pattern. - Suggested changes. Comments now carry an optional
suggestion: { replacement }field. The comment card renders the proposed replacement in a mono block + a one-click Apply button that creates a manual revision (replacinganchor.exact) and resolves the comment. New endpointPOST /api/comments/:id/apply-suggestion. New MCP tooladd_suggestioncombinesadd_comment+ suggestion stamping in one atomic call. Grounded in Brown & Parnin (ESEC/FSE '20) — timing, location, and actionability are what make inline suggestions land. - Frontend. New
ReviewBarcomponent near the top of the doc page: three-button state picker + agent-proposed banner + Accept button.CommentCardrenders the suggestion block + Apply. SSE subscribes to a newreviews-updatedevent so open viewers refresh live.
Big accumulated release covering gists as a first-class source kind, markdown indexes (with server-side caching + filename filter + owner pinning + human-URL canonicalization), the human-URL system, editor + comment card polish, source-drift + 3-way merge, the pushback (GitHub round-trip) flow, and the shift to a per-run MongoDB test container.
- Gists as a first-class source kind. Pasting a gist URL (or
navigating to
mumd.metavert.io/<owner>/<gist_id>/ the canonicalmumd.metavert.io/gist/<owner>/<gist_id>) now creates a fully- tracked doc — not just opaque content. NewSourceKinddiscriminator on the doc model (github_blob|gist|url|upload) cleans up the long-runningif doc.GitHubOwner != ""conditional sprawl. Gist docs carry the gist owner + id + commit SHA + filename + file count. The same source-drift banner that fires on github blob changes also fires on gist commits — drift is detected viaapi.github.com/gists/<id>'shistory[0].version, cached the same way + cleared via the same Ignore / Sync UI. Multi-file gists default to the first markdown file (lex-sorted fallback when no.mdexists); a "this gist has N other files" affordance below the title links out to the gist's GitHub page for picking a different one. The 49 existing docs were migrated in place bycmd/migrate-source-kind(per-docUpdateOne, idempotent) — the 4 known gist docs picked up their commit SHAs on the spot. - URL-swap trick now works without the hex regex. Editing
gist.github.comtomumd.metavert.io(orgithub.comtomumd.metavert.io) Just Works, because the/<owner>/<repo>resolver triescreateIndexfirst and falls back tocreateFromURL(gistURLFor(...))on a 404. Real repos still pay exactly one round-trip; gists pay two. The fragile 20-/32-char hex pattern matching is gone.
- Gist URLs ingest as markdown. Pasting
https://gist.github.com/{user}/{id}or navigating to the human-URL formmumd.metavert.io/{user}/{gist_id}failed with "you don't have access to that repo" (the resolver was treating the gist hash as a repo name, GitHub returned 404, the backend reported it as no-access). The URL system now recognizes gists end-to-end (above) — both entry points covered: home-form paste and direct navigation, plus the new canonical/gist/<owner>/<id>.
- Index items are cached server-side; explicit Refresh button. First
view of an index does a live GitHub spider; subsequent visits load
from a
index_itemsMongo cache (one row per index, items stored as JSON bytes for fast read). A new circular-arrow Refresh button in the index header re-spiders on demand and replaces the cache. Private items are filtered to the original scanner's audience so a cached org listing never leaks private file names to other viewers. Stops the "re-index every time I open the page" surprise. - Human-URL canonicalization re-enabled. The earlier blank-page
incident turned out to be an unrelated SSE-parser kind collision,
not the canonicalization itself. With that fixed,
replaceStateback to the human form is safe again:/i/:slugrewrites to/:owneror/:owner/:repoon mount, and/d/:idrewrites to/:owner/:repo/blob/:ref/:path. Verified live via Playwright —/i/331a2f341adce0c3lands in the address bar as/jonradoff. - Marketing + docs surface markdown indexes. README gains a
dedicated "Markdown indexes — organize a team's docs across all your
repos" section, the home page SEO title/description leads with
"across your repos", and metavert.io's marketing page (the
/markupmarkdownstandalone + the/projectscard) calls out indexes as a first-class feature. The framing throughout: paste one GitHub URL and a team gets a curated, filterable library of every.mdscattered across their projects. - Human-readable URL system. The SPA now accepts three URL shapes
as first-class addresses for GitHub markdown:
/owner/repo/blob/ref/path→ individual document (auto-clones if not yet ingested; otherwise resolves to the existing chain leaf)/owner/repo→ repo index/owner→ user or org index Sohttps://mumd.metavert.io/beamable/CrmDesign/blob/main/WINGMAN_PRD.mdJust Works as a shareable link. The legacy/d/:idand/i/:idURLs still resolve, but areplaceStateswaps them to the canonical human path on mount so the address bar always reads the way the user pasted it. Backed by a newGET /api/documents/by-sourceendpoint that deduplicates against existing docs (so two people pasting the same blob URL land on the same place — comments aggregate instead of fracturing across N parallel clones).
- Favicon. The canonical Markdown mark by Dustin Curtis (CC0,
used by GitHub / VS Code / CommonMark) centered in a 256×256
rounded square so it reads cleanly at 16×16 / 32×32. Dark-mode
aware via the
prefers-color-schememedia query in the SVG. - Live progress on index pages. The "you're staring at Loading…" problem during a big org spider is fixed three ways: (a) ProgressBanner renders from frame 1 (before the meta event arrives), (b) the home submit button reads "Looking up GitHub…" for index targets so the POST round-trip isn't dead air, (c) the banner now includes a live activity log of the last 8 scanned repos (newest at top, font-mono, fading opacity).
- Live progress + parallel scanning for index materialization. Org
and user-profile indexes now stream their results via an SSE channel
(
GET /api/indexes/:id/stream) so the user sees "Scanning 47/142 repos…" with a per-repo progress bar instead of staring at "Loading…" for 30 seconds while a 150-repo org spider runs. The per-repo fetches fan out across a worker pool of 8 — beamable's ~150 repos now complete in under 10 s instead of 60+. POST/api/indexesreturns the index meta immediately (no items) so the home-page form navigates straight to the index page, where progress UI takes over. PlainGET /api/indexes/:idstill materializes synchronously for API consumers and as a fallback if the stream errors. - Filename-filter tabs on index pages. Save up to 5 case-insensitive
substring filters (
claude.md,_PRD, etc.) as named chips along the top of the listing. An "All" chip is always present. Tabs are per-(browser, index) and persisted in localStorage; the last-active tab reopens on return. Each tab shows the match count next to its label. Hit × on a chip to remove it. - Pinned default filter (owner-only). The index creator can pin one
of their tabs (or "All") as the default view for share-link
visitors. First-time visitors land on the pinned filter; once they
pick their own tab, their localStorage choice takes over. Backed by
a new
defaultFilterfield on the Index model + adefaultFilterargument onPATCH /api/indexes/:id. Owner sees a pin/unpin button on each tab; everyone sees a filled pin icon on the pinned tab. - "Forget" button on docs + indexes. Hides an item from MY home
list without deleting it for everyone. Distinct from Delete (which
soft-deletes globally). Backed by a new
hidden_itemscollection keyed on(user_id, kind, item_id). For docs, the marker is keyed on the chain root so future revisions of a forgotten chain don't re-surface. Endpoints:POST /api/documents/:id/forget,POST /api/indexes/:id/forget. listDocuments + listMyIndexes filter against the marker so the action is local to the calling user. - Owner/repo pill on "Your documents" rows. Each doc entry now
carries a
owner/repochip next to the title so similarly-named files (PRD.md, README.md, …) are distinguishable at a glance instead of buried in the fine-print path line. GitHub-sourced docs only; uploads stay unchanged. - Markdown indexes — shareable listings of
.mdfiles anchored to a GitHub URL. Three target shapes are recognized at the home-page URL bar:github.com/owner/repo→ repo index (every.mdin the repo's git tree, one round-trip via the recursive trees API).github.com/owner→ user or org index, disambiguated via/users/{name}and folded into the right/users/.../reposor/orgs/.../reposlisting. Lists each repo's top-level.mdfiles alongside the repo it belongs to (grouped in the UI). Indexes live at their own stable URL (/i/{slug}), are shareable, and items are computed live on every view using the viewer's GitHub token — so different viewers may see different listings if their repo access differs. Private repo indexes re-verify access on every read; private repos in user/org listings are silently filtered to what the viewer can see (no leakage). Archived repos are excluded from user/org listings by default. The home page gains a "Your indexes" section above "Your documents" so a saved index is the natural jumping-off point for browsing a team's markdown library. Backend: newindexescollection + handlers atPOST/GET/PATCH/DELETE /api/indexes/:idandGET /api/me/indexes; new GitHub helpersLookupAccount,ListUserRepos,ListOrgRepos,ListRepoMarkdownFiles,ListRepoTopLevelMarkdown. Indexes are deduped per (creator, source) so a second POST returns the existing row instead of minting a duplicate. Clicking a file in the listing ingests it via the existingcreateFromURLflow and lands the user on the doc page so they can comment, edit, or push back.
- Prev/Next hunk navigation in the diff viewer. Both the
AI-revise preview and the 3-way merge diff get a
‹ Prev / Next ›pair plus aN / totalcounter in the diff toolbar. Each press smooth-scrolls the next changed section's sticky header to the top of the scroller (cleared for the diff toolbar's height), and the current hunk gets an accent-tinted header so it's obvious where you are. The "Rendered" tab hides the controls — they're meaningful only on the unified diff. Scratches the "I have to manually scroll to find each change" itch on long docs. Ignorebutton on the source-drift banner. Dismisses the banner for the current upstream SHA only — if a newer upstream commit shows up later, the banner returns. Pops a confirmation modal that spells out the implication ("we'll stop nudging you to merge, but a newer commit re-surfaces the banner") so it's not a one-click footgun. Backed by a newPOST /api/documents/:id/drift/ignoreendpoint that stamps asourceDriftIgnoredShaon the chain root; the existingSetDocumentSourceCheckclears the marker as soon as upstream moves past the ignored SHA.
- Direct-commit pushback clears the drift banner. After a
successful direct commit to the doc's tracking branch (the same
ref the doc was cloned from), the pushback handler stamps the new
blob SHA as the doc's
SourceSHAbaseline and broadcasts adoc-updatedevent. The next drift check sees us in sync and the banner disappears. PR mode + commits to non-tracking branches intentionally don't clear drift (the PR isn't merged; a sibling branch doesn't affect the tracked ref).
- Native markdown editor. Click Edit on any doc for a CodeMirror 6
editor with markdown syntax highlighting, light/dark theme (tracks the
app theme automatically), and
⌘Sto save your changes as a new revision. The editor runs in the same page scroll as view mode — no scroll-in-scroll. Comments stay anchored to their text spans as you edit; the sidebar tracks the same lines in real time. - Sticky formatting toolbar. Bold, italic, code, H1/H2/H3, bulleted list, numbered list, task list, blockquote, link, code block, HR. Both the action bar (Editing / Save / Cancel / Find / Show preview) and the formatting controls share one sticky frame that pins to the top of the editor column as you scroll through long documents.
- Find & replace inside the editor (
⌘F) with regex, case sensitivity, whole-word, and replace-all — the standard CodeMirror search panel. - Live side-by-side preview. Toggle Show preview to render the document on the right as you edit on the left.
- Smart wrap-toggle. Selecting
**bold**(with the markers included) and clicking B strips one layer instead of doubling up — for bold, italic, and code. Catches the common selection-overshoot pattern most markdown editors get wrong. - Push to GitHub. For docs cloned from a GitHub blob URL, click Push
to GitHub on any revision. Two modes: open a pull request from a
new branch (with prefilled title + body that reference the doc), or
commit directly to a branch you pick (typically
main). The OAuth token from your sign-in does the work — no separate PAT needed. Branch protection rules are enforced on GitHub's side and surfaced verbatim if they reject the push. - Manual revision API. New endpoint
POST /api/documents/:id/manual-revisionswrites editor saves as a new child doc, parented to the source doc — manual edits and AI revisions share the same versioning model. - Soft edit lock. Whoever clicks Edit first holds the lock; other viewers see a banner with the holder's display name and the Edit button disabled. Lock auto-releases on Save / Cancel / disconnect, broadcasts over the existing SSE hub.
- 3-way merge engine. When a doc has unsynced upstream changes AND local edits, the merge UI runs a 3-way diff against the original, the upstream version, and the local version — surfacing clean merges, manual conflicts, and a per-region pick-a-side UI.
- Comments carry through AI revision. Resolved comments applied via Revise with AI keep their threads on the new child doc, re-anchored against the revised text where the quoted span still appears.
- MCP Tier 1 + Tier 2 tools. Agents can now
edit_document,patch_comment_anchor,delete_comment,list_revisions,merge_document, andpush_to_github— the same actions the human UI exposes, with the same access checks, scope enforcement, and rate limits. - GitHub source-change detection — for docs cloned from GitHub, every open shows a banner the moment the upstream file has new commits. Comments still pinned to text that survived the edit are auto re-anchored on Sync; the rest move to a Comments without anchors section below the doc with a manual drag-select re-anchor flow.
- Doc-level comments — pin a comment to the whole document instead of a text span. Doc-level pins live in their own sidebar section and survive any source change.
- Manual re-anchor flow — pick an orphan comment, enter re-anchor mode, drag-select new text in the doc, click Re-anchor here in the popover. Or convert the comment to a doc-level pin in one click.
- Per-card Prev/Next strip — every comment card now has its own Prev/Next pair under the body, so you can step to an adjacent thread without scrolling back to the sticky bar at the top of the sidebar.
- In-document anchor links — clicking a Markdown link that points at a
same-doc heading (
[Section](#section-name)) smooth-scrolls to that heading instead of leaving the page. Headings clear the sticky header automatically viascroll-margin-top. - Open original action — when you're reading an AI-revised child doc and the upstream GitHub source has changed, the banner offers to jump to the original (where syncing makes sense) instead of clobbering the revision with raw upstream content.
- Live changelog (this file) and
CHANGELOG.mdlink in the README.
- Bell badge decrements as you read — viewing a comment now marks any pending notifications for that comment as read, regardless of whether you arrived via the bell. The badge stays honest as you scroll through unread threads.
- Submitting a comment no longer scrolls the page to the top. The fresh highlight colour is sufficient visual confirmation; the previous behaviour yanked you off the text you were just commenting on.
- Drift checks run on mount, on tab focus, and every 2 min while visible, with the server-side TTL dropped to 60 s. A teammate's upstream commit shows up within a couple minutes of your tab focusing instead of waiting for a page reload.
- Access re-verification on every drift check — busts the cached GitHub access state so a user removed from a private repo gets booted to the access-denied page within one check cycle.
- Re-anchor comparisons run against the rendered plain text (not the raw
markdown source), so comments anchored to text spanning a
**bold**,_italic_, or`code`boundary stay clean across upstream edits.
- Active comment text is now highlighted in the editor. Pressing Next
in edit mode paints the matched span with the same yellow background
the view-mode rendered markdown uses — implemented as a CodeMirror
StateField + Decoration that's driven by a
setActiveHighlightstate effect. The old "set a text selection" gesture wasn't visible enough (especially in dark mode and on an unfocused editor) and could be lost to keyboard navigation. Nextreliably scrolls to the next comment. Two compounding causes fixed: (a) both the Document.tsxactiveIdeffect and EditorPane's internal effect were callingwindow.scrollTo, fighting over the smooth-scroll target; (b) CodeMirror uses estimated line heights for content outside its render viewport, so a singlecoordsAtPosread could be tens to hundreds of pixels off. Now there's exactly one scroll driver (scrollAnchorIntoViewon the editor handle), and it takes a two-pass measurement: an instant nudge to the estimated target, then a smooth-scroll to the authoritative position once CM has had a frame to refine its height map. The page lands on the active comment's line every click.- Stacked off-viewport cards no longer push the active card off its
anchor. The cards-layout pass now filters to comments whose anchor
is within ±200 px of the viewport (plus the active card unconditionally).
Previously, a comment anchored above the viewport would clamp to
minTop = 0and stack with every other above-viewport card; their combined height pushed the active comment's card hundreds of pixels below its highlighted span. - Card runaway on
Nextin edit mode. Pressing Next would scroll the body so the editor anchor landed at the viewport, but the comment cards would march off into ever-largerstyle.topvalues, landing in empty space tens of thousands of pixels below the doc. Three compounding causes: (1) the sidebar's scroll-into-view fedsidebar.scrollTopback intocontainerRect.top, which amplifieddesiredTopon the next layout; (2) the anchored-cards container'sminHeightgrew with each pass, making the sidebar internally scrollable so the loop could continue; and (3) MCP-added agent comments all storeanchor.start = 0(text-substring anchoring resolved at render time), so the layout's sort fell through to insertion order — a card anchored near the top of the doc was stacked below cards anchored further down because it was inserted later. Fixes: dropped the sidebar scroll-into-view (the body-scroll already brings the right card into view), and the cards-layout pass now sorts by editor-anchor Y before relaxing. - Content column expands with the browser. Removed the
max-w-3xlcap (1024px effective) on the document column — view mode now usesmax-w-5xl, edit mode usesmax-w-none. The editor fills whatever space you give it, instead of wrapping early in a narrow strip and leaving the rest of the column blank. - Sticky toolbar pins correctly in long docs. The action + formatting
bar wasn't actually sticking in edit mode because the editor lived
inside an
overflow-y-autocolumn — CSS sticky bound to the column, not the viewport, so scrolling the page slid the bar off-screen. Removed the inner column scroll, made the comment sidebar viewport-sticky instead, and re-laid out anchored cards on body scroll via an rAF-throttled scroll listener. - Comment cards align with their highlighted line in edit mode. The
layout formula now computes
desiredTopagainst the anchored container's bounding rect, so the math is identical for view mode and edit mode. - Edit-mode active-comment scroll. Clicking Next on a comment now asks CodeMirror to scroll the anchored line into view in edit mode (instead of silently no-oping because the rendered DOM is gone).
- Comments whose quoted text spanned a Markdown formatting marker
(
**bold**, etc.) were incorrectly orphaned on Sync even when the underlying text was unchanged. Now matched against the rendered text. - Source-drift detection ignored child revisions, so a viewer reading an AI-revised doc never saw the banner when the original GitHub file changed. Drift now evaluates on the revision-chain root; children inherit the state and link back to the original for sync.
- Legacy docs (ingested before SHA tracking) were stamped with the current upstream SHA as baseline on first check, hiding any drift the upstream had already accumulated. Now we compute the git blob SHA of the stored content and compare against upstream — the banner appears immediately if the upstream has already moved on.
- Coverage badge stuck on unknown after the repo went public — CI uploads coverage tokenlessly now.
0.1.0 — 2026-06-03
Initial public release.
- Google-Docs-style commenting on any Markdown file. Paste a GitHub
URL or upload a local
.md— drag-select text in the rendered doc, leave a margin comment, get threaded replies, mark-as-done, reopen, edit, and delete. - Realtime sync between every open tab on the same doc via Server-Sent Events. Sub-second propagation; auto-reconnect.
- @-mentions with autocomplete scoped to the people who've actually opened this doc (commenters ∪ viewers). Bell icon shows an in-app notification with a deep link to the relevant comment.
- Unread filter with a count badge — only the threads that have new activity since your last visit, anchored on a per-(doc, user) view marker.
- Step through comments with
j/k(or↑/↓, or the floating Prev / Next bar). The position counter respects the active filter. - GitHub OAuth sign-in. Optional — use your avatar and display name automatically, and unlock private repo files. Private docs are gated on every read by re-verifying current GitHub access to the source repo; if you lose access, you stop seeing content (and the title) immediately.
- AI revision via Claude Opus 4.7. Bring your own Anthropic API key (stored encrypted at rest with AES-256-GCM, deletable any time). Pick which resolved comments to apply; watch Claude write the revised doc as live-streaming Markdown; word-level diff preview; saving creates a new child document so revisions form a tree.
- MCP server at
/mcpfor agents — read documents, leave threads anchored to text spans, reply to humans, resolve, and trigger AI revisions (with explicit human sign-off). The same access checks, rate limits, and validation apply as the REST API; no agent-only fast path. - Personal access tokens (
mmk_…) for scripts and agents, with scope (read/write/admin), optional expiry, label, and a per-token activity log. Stored as SHA-256 hashes; plaintext shown once at creation. - Agent identity badges — comments and replies written via a token get a visible bot badge; the token's owner shows on hover. Renaming a token updates everywhere it has commented (display fields resolve at read time).
- Soft-delete with 30-day recovery. Deleted docs sit in Trash and can be restored before a daily purge sweep removes them for good.
- Share dialog with explicit access copy (private docs warn you before you send the URL).
- Open Graph link unfurls so shared URLs look meaningful in Slack, iMessage, Discord, X. Private docs share a generic card so titles don't leak.
- Light / dark theme that respects your system preference.
/SKILL.md— canonical agent integration guide served as raw markdown (/SKILL.md,/skill.md, and/skillall work), embedded into the Go binary at compile time so the deployed URL is always in sync with the binary.