Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Building a local commenting tool

2026-08-25

David: ran /clear

David: ran /model

βš™ Set model to Opus 5 and saved as your default for new sessions

David:

I think at this point what I'd like is to go through the text myself with a fine toothed comb. Can you prepare a commenting interface that renders the text roughly like it would on royal road, but allows me to select text and attach a comment to it, which will be saved in a text file that maps to the file containing the story being commented on. Make sure the format is robust enough to handle and recover from edits in the text (e.g. have both position - as line and column - and also the exact text selected for commenting) without losing the corresponding comment. In the interface I should also be able to see and edit previous comments in the interface.

You can do it as a local web-app or a swift UI as you prefer.

πŸ”§ Bash: ls && ls chapters | head -40 && ls chapters | wc -l && head -30 chapters/$(ls chapters |… (Inspect repo layout and chapter format)

βœ… 69 lines, 3294 chars

Building a local web app: a stdlib-Python server plus a Royal Road-ish reader with selection commenting.

10 tool calls

πŸ”§ Bash: mkdir -p redacted/tools/commenter && cat > redacted/tools/commenter/server.py <<'PY'…

βœ… 1 lines, 2 chars

πŸ”§ Bash: cat > redacted/tools/commenter/index.html <<'HTML' <!doctype html> <meta charset="utf-8…

βœ… 1 lines, 2 chars

πŸ”§ Bash: python3 - <<'PY' import sys, json, importlib.util spec=importlib.util.spec_from_file_loca…

βœ… 6 lines, 132 chars β€” 13 0 'Adventurers did come, occasion' / (1196, 1226, 'exact') / (1209, 1239, 'moved')

πŸ”§ Bash: (python3 tools/commenter/server.py --port 8791 --no-browser &) ; sleep 1; curl -s -o /dev…

βœ… 26 lines, 970 chars

πŸ”§ Bash: rm -rf comments && cat > tools/commenter/README.md <<'MD' # Commenting interface pyt…

βœ… 1 lines, 51 chars

Done β€” run it with:

python3 tools/commenter/server.py     # opens http://127.0.0.1:8777/

Interface (tools/commenter/, no dependencies): file list on the left (all markdown under chapters/, plans/, unpublished notes/, summaries/), the text in the middle rendered Royal-Road-ish (dark, serif, ~44rem column, italics/headings/scene breaks), comments on the right. Select text β†’ popup β†’ type β†’ ⌘⏎. Existing comments show as highlights; clicking either a highlight or a card links the two. Cards have Edit / Resolve / Delete, and a "resolved" toggle in the header.

Storage: comments/chapters/001-the-wrong-man.md.comments.json etc. β€” one JSON file mirroring each story file's path. Each comment holds a redundant anchor: line/col (+ end), the exact quote, and 48 chars of prefix/suffix.

Recovery after edits, resolved on every load and labelled on the card:

  1. exact β€” stored position still matches.
  2. moved β€” quote found elsewhere; ties broken by surrounding context, then proximity to the old offset.
  3. fuzzy β€” whitespace-insensitive match, or the longest still-unique prefix of the quote (i.e. the quoted prose itself was edited).
  4. orphaned β€” not found; the comment is kept and listed with its original quote and line, just not highlighted.

A re-anchor button rewrites stored line/columns to wherever things currently resolve, once you're happy with a round of edits. Verified the recovery paths against chapter 1 (insert-above β†’ moved, edit-inside-quote β†’ fuzzy, deleted text β†’ orphaned) and the save/edit/delete round-trip through the API.

David:

Minor: Can you render the divider lines more prominently. They're almost invisible right now.

πŸ”§ Bash: python3 - <<'PY' import re,pathlib p=pathlib.Path("tools/commenter/index.html"); t=p.read…

βœ… 3 lines, 299 chars

πŸ”§ Bash: git commit -qam "Commenter: render scene breaks as a visible dot divider Co-Authored-By:…

βœ… 1 lines, 63 chars β€” 135f4cb Commenter: render scene breaks as a visible dot divider

Scene breaks now render as a centred β€’ β€’ β€’ in light grey rather than a faint hairline. Reload the page to pick it up.

David:

It would also be nice if system messages rendered as royal road style blue boxes.

10 tool calls

πŸ”§ Bash: redacted sentence: unpublished prose

βœ… 13 lines, 383 chars

πŸ”§ Bash: grep -rhn "^>" chapters/*.md notes/*.md plans//*.md unpublished 2>/dev/null | grep -v "…

βœ… 10 lines, 1758 chars

πŸ”§ Bash: python3 - <<'PY' import pathlib p=pathlib.Path("tools/commenter/index.html"); t=p.read_te…

βœ… 71 lines, 3644 chars

πŸ”§ Bash: python3 - <<'PY' > /tmp/t.js import re,pathlib src=pathlib.Path("tools/commenter/index.ht…

βœ… 20 lines, 296 chars β€” quote blocks: 1 / { / "tag": "quote",

πŸ”§ Bash: rm -f /tmp/t.js; git commit -qam "Commenter: render System messages as Royal Road-style b…

βœ… 1 lines, 72 chars β€” f282804 Commenter: render System messages as Royal Road-style blue boxes

A run of consecutive > [...] lines now renders as a single centred blue panel β€” tinted background, blue border, soft glow, sans-serif blue text β€” the way Royal Road shows System boxes. Blockquotes that aren't all bracketed lines (the quoted prose in notes/) get ordinary quote styling instead.

Per-line source offsets are preserved through the grouping, so selecting text inside a System box still anchors correctly β€” verified against chapter 2's binding message.