@henryavila/mdprobe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,404 @@
1
+ ![mdprobe](header.png)
2
+
3
+ # mdprobe
4
+
5
+ **The missing link between AI coding agents and human review.**
6
+
7
+ AI agents generate specs, docs, and RFCs — but you need to actually *read* them, *annotate* them, and *send structured feedback back*. mdprobe closes that loop: it renders markdown in the browser, lets you annotate inline, and returns structured YAML that agents can parse and act on.
8
+
9
+ It works standalone too — as a markdown viewer with live reload and persistent annotations for any review workflow.
10
+
11
+ [Install](#install) | [Quick Start](#quick-start) | [Features](#features) | [CLI Reference](#cli-reference) | [Library API](#library-api) | [Schema](#annotation-schema) | [AI Integration](#ai-agent-integration)
12
+
13
+ ---
14
+
15
+ ## What is mdprobe?
16
+
17
+ A CLI tool that turns markdown files into a review environment in your browser.
18
+
19
+ ```
20
+ AI Agent writes spec.md ──> mdprobe spec.md --once ──> Human reviews & annotates ──> spec.annotations.yaml ──> Agent reads feedback
21
+ ```
22
+
23
+ ### The problem
24
+
25
+ AI agents produce markdown output (specs, architecture docs, RFCs) but have no way to get **structured, line-level feedback** from humans. You either paste comments back into chat (losing context) or approve blindly.
26
+
27
+ ### The solution
28
+
29
+ mdprobe renders your markdown with full GFM, syntax highlighting, Mermaid diagrams and math, then lets you select text and add annotations — `bug`, `question`, `suggestion`, `nitpick` — that are saved as a YAML sidecar. In `--once` mode, the agent's process blocks until you finish reviewing, then reads the annotations programmatically.
30
+
31
+ It also works as a standalone tool for any markdown review workflow — no AI required.
32
+
33
+ ### Three workflows
34
+
35
+ | Workflow | Command | Use case |
36
+ |----------|---------|----------|
37
+ | **View** | `mdprobe spec.md` | Render complex markdown in the browser with live reload |
38
+ | **Review** | `mdprobe spec.md --once` | Agent blocks until human finishes annotating, then reads feedback |
39
+ | **Embed** | `import { createHandler }` | Mount mdprobe inside your own Node.js server or tool |
40
+
41
+ Annotations are stored as plain YAML — readable by humans, parseable by machines, and version-controllable with git.
42
+
43
+ ---
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ npm install -g @henryavila/mdprobe
49
+ ```
50
+
51
+ Or use directly with npx:
52
+
53
+ ```bash
54
+ npx @henryavila/mdprobe spec.md
55
+ ```
56
+
57
+ ### Requirements
58
+
59
+ - Node.js 20+
60
+ - A browser (auto-opens on macOS, Linux, and WSL)
61
+
62
+ ---
63
+
64
+ ## Quick Start
65
+
66
+ ### View a file
67
+
68
+ ```bash
69
+ mdprobe README.md
70
+ ```
71
+
72
+ Opens the rendered markdown in your browser. Edit the file in your editor — the browser updates instantly.
73
+
74
+ ### View a directory
75
+
76
+ ```bash
77
+ mdprobe docs/
78
+ ```
79
+
80
+ Discovers all `.md` files recursively and shows a file picker.
81
+
82
+ ### Review mode (blocking)
83
+
84
+ ```bash
85
+ mdprobe spec.md --once
86
+ ```
87
+
88
+ The process **blocks** until you click "Finish Review" in the UI. Annotations are saved to `spec.annotations.yaml`. Useful for AI agents that need human feedback before continuing.
89
+
90
+ ### Configure your name
91
+
92
+ ```bash
93
+ mdprobe config author "Your Name"
94
+ ```
95
+
96
+ Your name is attached to every annotation and reply. On first use, mdprobe will prompt you interactively.
97
+
98
+ ---
99
+
100
+ ## Features
101
+
102
+ ### Markdown Rendering
103
+
104
+ - **GFM** — tables, task lists, strikethrough, autolinks
105
+ - **Syntax highlighting** — all languages via highlight.js
106
+ - **Mermaid diagrams** — rendered client-side
107
+ - **Math/LaTeX** — via KaTeX (inline and display)
108
+ - **Frontmatter** — YAML and TOML (parsed and stripped from output)
109
+ - **Raw HTML** — passthrough with allowlist
110
+ - **Images** — served from the markdown file's directory
111
+
112
+ ### Live Reload
113
+
114
+ File changes are detected via chokidar and pushed to the browser over WebSocket. Debounced at 100ms to avoid flicker during rapid saves. Scroll position is preserved across reloads.
115
+
116
+ ### Annotations
117
+
118
+ Select any text in the rendered markdown to open the annotation popover:
119
+
120
+ - **4 tags**: `bug`, `question`, `suggestion`, `nitpick` — color-coded pills
121
+ - **Threaded replies** — discuss annotations inline
122
+ - **Resolve/reopen** — mark items as handled
123
+ - **Persistent** — saved to `.annotations.yaml` sidecar (YAML format, git-friendly)
124
+ - **Draggable popover** — move the form to read the content underneath
125
+ - **Keyboard shortcuts** — `Ctrl+Enter` to save, `Esc` to close
126
+
127
+ ### Section Approval
128
+
129
+ Every heading in your document gets approve/reject buttons:
130
+
131
+ - **Symmetric cascade** — approving a parent approves all children; rejecting or resetting does the same
132
+ - **Indeterminate state** — when children have mixed statuses, the parent shows a visual indicator
133
+ - **Approve All / Clear All** — bulk operations for the entire document
134
+
135
+ ### Drift Detection
136
+
137
+ When the source markdown changes after annotations were created, mdprobe shows a warning banner. This prevents stale annotations from going unnoticed.
138
+
139
+ ### Themes
140
+
141
+ Five built-in themes based on the Catppuccin palette:
142
+
143
+ | Theme | Style |
144
+ |-------|-------|
145
+ | **Mocha** | Dark (default) |
146
+ | **Macchiato** | Dark, warm |
147
+ | **Frappe** | Dark, deep blue |
148
+ | **Latte** | Light |
149
+ | **Light** | Pure white |
150
+
151
+ ### Keyboard Shortcuts
152
+
153
+ | Key | Action |
154
+ |-----|--------|
155
+ | `[` | Toggle left panel (files + TOC) |
156
+ | `]` | Toggle right panel (annotations) |
157
+ | `\` | Toggle both panels (focus mode) |
158
+ | `j` / `k` | Next / previous annotation |
159
+ | `?` | Show help overlay |
160
+ | `Ctrl+Enter` | Save annotation |
161
+ | `Esc` | Close popover / modal |
162
+
163
+ ### Export
164
+
165
+ Export annotations in four formats:
166
+
167
+ ```bash
168
+ mdprobe export spec.md --report # Markdown review report
169
+ mdprobe export spec.md --inline # HTML comments inserted into source
170
+ mdprobe export spec.md --json # Plain JSON
171
+ mdprobe export spec.md --sarif # SARIF 2.1.0 (for CI/CD integration)
172
+ ```
173
+
174
+ Also available via the HTTP API: `GET /api/export?path=spec.md&format=json`
175
+
176
+ ---
177
+
178
+ ## CLI Reference
179
+
180
+ ```
181
+ mdprobe [files...] [options]
182
+
183
+ Options:
184
+ --port <n> Port number (default: 3000, auto-increments if busy)
185
+ --once Review mode — blocks until human finishes
186
+ --no-open Don't auto-open browser
187
+ --help, -h Show help
188
+ --version, -v Show version
189
+
190
+ Subcommands:
191
+ config [key] [value] Manage configuration
192
+ export <path> [format-flag] Export annotations
193
+ install --plugin Install Claude Code skill
194
+ ```
195
+
196
+ ### Config
197
+
198
+ ```bash
199
+ mdprobe config # Show all configuration
200
+ mdprobe config author # Show current author
201
+ mdprobe config author "Name" # Set author
202
+ ```
203
+
204
+ Configuration is stored in `~/.mdprobe.json`.
205
+
206
+ ---
207
+
208
+ ## Library API
209
+
210
+ ### Embedding in your own server
211
+
212
+ ```javascript
213
+ import { createHandler } from '@henryavila/mdprobe'
214
+
215
+ const handler = createHandler({
216
+ resolveFile: (req) => '/path/to/file.md',
217
+ listFiles: () => [
218
+ { id: 'spec', path: '/docs/spec.md', label: 'Specification' },
219
+ { id: 'adr', path: '/docs/adr.md', label: 'Architecture Decision' },
220
+ ],
221
+ basePath: '/review',
222
+ author: 'Review Bot',
223
+ onComplete: (result) => {
224
+ console.log(`Review done: ${result.annotations} annotations`)
225
+ },
226
+ })
227
+
228
+ import http from 'node:http'
229
+ http.createServer(handler).listen(3000)
230
+ ```
231
+
232
+ ### Working with annotations programmatically
233
+
234
+ ```javascript
235
+ import { AnnotationFile } from '@henryavila/mdprobe/annotations'
236
+
237
+ // Load existing annotations
238
+ const af = await AnnotationFile.load('spec.annotations.yaml')
239
+
240
+ // Query
241
+ const open = af.getOpen()
242
+ const bugs = af.getByTag('bug')
243
+ const mine = af.getByAuthor('Henry')
244
+
245
+ // Mutate
246
+ af.add({
247
+ selectors: {
248
+ position: { startLine: 10, startColumn: 1, endLine: 10, endColumn: 40 },
249
+ quote: { exact: 'selected text', prefix: '', suffix: '' },
250
+ },
251
+ comment: 'This needs clarification',
252
+ tag: 'question',
253
+ author: 'Henry',
254
+ })
255
+ af.resolve(bugs[0].id)
256
+
257
+ // Persist
258
+ await af.save('spec.annotations.yaml')
259
+
260
+ // Export
261
+ import { exportJSON, exportSARIF } from '@henryavila/mdprobe/export'
262
+ const json = exportJSON(af)
263
+ const sarif = exportSARIF(af, 'spec.md')
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Annotation Schema
269
+
270
+ Annotations are stored in YAML sidecar files (`<filename>.annotations.yaml`):
271
+
272
+ ```yaml
273
+ version: 1
274
+ source: spec.md
275
+ source_hash: "sha256:abc123..."
276
+ sections:
277
+ - heading: Introduction
278
+ level: 2
279
+ status: approved
280
+ - heading: Requirements
281
+ level: 2
282
+ status: pending
283
+ annotations:
284
+ - id: "a1b2c3d4"
285
+ selectors:
286
+ position:
287
+ startLine: 15
288
+ startColumn: 1
289
+ endLine: 15
290
+ endColumn: 42
291
+ quote:
292
+ exact: "The system shall support concurrent users"
293
+ prefix: ""
294
+ suffix: ""
295
+ comment: "How many concurrent users? Need a number."
296
+ tag: question
297
+ status: open
298
+ author: Henry
299
+ created_at: "2026-04-08T10:30:00.000Z"
300
+ updated_at: "2026-04-08T10:30:00.000Z"
301
+ replies:
302
+ - author: Alice
303
+ comment: "Target is 500 concurrent."
304
+ created_at: "2026-04-08T11:00:00.000Z"
305
+ ```
306
+
307
+ A JSON Schema is available at `@henryavila/mdprobe/schema.json` for validation.
308
+
309
+ ### Tags
310
+
311
+ | Tag | Meaning | SARIF Severity |
312
+ |-----|---------|----------------|
313
+ | `bug` | Something is wrong | error |
314
+ | `question` | Needs clarification | note |
315
+ | `suggestion` | Improvement idea | warning |
316
+ | `nitpick` | Minor style/wording | note |
317
+
318
+ ---
319
+
320
+ ## AI Agent Integration
321
+
322
+ mdprobe ships with a Claude Code skill that teaches the AI when and how to use it.
323
+
324
+ ### Install the skill
325
+
326
+ ```bash
327
+ mdprobe install --plugin
328
+ ```
329
+
330
+ ### Agent workflow
331
+
332
+ 1. Agent writes a spec/document to a `.md` file
333
+ 2. Agent launches `mdprobe spec.md --once` (blocks)
334
+ 3. Human reviews in the browser, adds annotations
335
+ 4. Human clicks "Finish Review"
336
+ 5. Agent reads `spec.annotations.yaml` and addresses each annotation
337
+
338
+ ```javascript
339
+ // Agent reads feedback after review
340
+ import { AnnotationFile } from '@henryavila/mdprobe/annotations'
341
+
342
+ const af = await AnnotationFile.load('spec.annotations.yaml')
343
+ for (const ann of af.getOpen()) {
344
+ console.log(`[${ann.tag}] Line ${ann.selectors.position.startLine}: ${ann.comment}`)
345
+ }
346
+ ```
347
+
348
+ ---
349
+
350
+ ## HTTP API
351
+
352
+ All endpoints are available when the server is running.
353
+
354
+ | Method | Endpoint | Description |
355
+ |--------|----------|-------------|
356
+ | `GET` | `/api/files` | List markdown files |
357
+ | `GET` | `/api/file?path=<file>` | Get rendered HTML + TOC + frontmatter |
358
+ | `GET` | `/api/annotations?path=<file>` | Get annotations + sections + drift status |
359
+ | `POST` | `/api/annotations` | Create/update/delete annotations |
360
+ | `POST` | `/api/sections` | Approve/reject/reset sections |
361
+ | `GET` | `/api/export?path=<file>&format=<fmt>` | Export (json, report, inline, sarif) |
362
+ | `GET` | `/api/config` | Get current author |
363
+
364
+ WebSocket at `/ws` provides real-time file change notifications.
365
+
366
+ ---
367
+
368
+ ## Development
369
+
370
+ ```bash
371
+ git clone https://github.com/henryavila/mdprobe.git
372
+ cd mdprobe
373
+ npm install
374
+ npm run build:ui # Build the Preact UI
375
+ npm test # Run test suite (489 tests)
376
+ ```
377
+
378
+ ### Project structure
379
+
380
+ ```
381
+ bin/cli.js CLI entry point
382
+ src/
383
+ server.js HTTP + WebSocket server
384
+ renderer.js Markdown rendering pipeline (remark/rehype)
385
+ annotations.js Annotation CRUD + section approval + cascade
386
+ export.js 4 export formats (report, inline, JSON, SARIF)
387
+ handler.js Library API for embedding
388
+ config.js User configuration (~/.mdprobe.json)
389
+ hash.js SHA-256 drift detection
390
+ anchoring.js Text position matching for highlights
391
+ ui/
392
+ components/ Preact components (App, Content, Popover, Panels...)
393
+ hooks/ Custom hooks (WebSocket, keyboard, theme, annotations)
394
+ state/store.js Preact Signals state management
395
+ styles/themes.css Catppuccin theme system
396
+ schema.json JSON Schema for annotation YAML
397
+ skills/ Claude Code integration skill
398
+ ```
399
+
400
+ ---
401
+
402
+ ## License
403
+
404
+ MIT © [Henry Avila](https://github.com/henryavila)