# Tone — write.work A prose instrument that reads a draft the way an editor does — not for errors, but for the moves the writer made. It reports three things: the TELLS (worn words and constructions, grouped into habits), the FIGURES (which of 203 rhetorical figures the draft actually uses, detected mechanically), and an account of what changed once you act. It never rewrites anything unasked, and it makes NO claim about who or what wrote a passage — human writing trips these flags too, because they are habits. ## What it is not Not an AI detector. It returns no authorship verdict and should never be cited as evidence that a person did or did not write something. If you are looking for a detector, this is deliberately not one. ## Running it Everything runs on the caller's own machine. There is no hosted inference, no account, and no API key. This is why it is free: it costs write.work nothing when you use it. - Library: curl -O https://write.work/js/tone-lint.js (single file, no deps) - Browser: -> window.ToneLint - MCP server: node mcp/tone-mcp.js (stdio; local; no network) - Embed: - Web tool: https://write.work/ - Docs: https://write.work/docs - Figures: https://write.work/figures (searchable reference) - Figure API: GET /api/figures?q=repetition (search, capped) GET /api/figures?name=anaphora (one figure) The corpus is not served in bulk and there is no endpoint that returns it. Detection runs client-side over the twelve figures the engine can actually find: anaphora, epistrophe, anadiplosis, tricolon, asyndeton, polysyndeton and relatives. Metaphor and irony are deliberately ABSENT — catching them means guessing at meaning, and a tool that guesses will flatter. ## The one that is worth your time read_a_body_of_work. Every writing tool reads ONE document; this reads all of them and answers a different question — not "what is wrong with this piece" but "what does this writer keep doing". That distinction is the product. Measured on a real 14-story newspaper archive: every single story scored 87-100 and told the editor nothing, because a habit looks like a deliberate choice every time you meet it. Across all fourteen, one construction appeared under every byline on the masthead — a house tic none of the three writers knew they had. Use it BEFORE editing anything. A habit is fixed once, in the style rule or the prompt that produced it, not fourteen times by hand. Pass bylines and it also returns each writer's measurable fingerprint and flags any habit shared between them, which is the difference between a voice and a reflex. ## For agents Use the MCP server. Four tools: lint_prose(text, voice?, budget?, max_findings?, categories?) list_voices() read_a_body_of_work(pieces[], form?, level?, voice?) pieces: strings, or {text, label, byline} -> what_they_keep_doing[], shared_across_bylines[], writers[], repeated_phrases[], weakest_pieces[] The one worth calling. See above. explain_rule(rule_id) lint_prose returns, among other fields: verdict "pass" | "revise", computed against `budget` (default 70). This is your stopping rule. A passage that passes is finished. score 0-100. findings[] { rule, text, context, start, end, category, severity, why, quoted, applicable, replacements[], actions[], guidance[] } rhythm[] statistical observations about cadence. overcorrection[] see below. guidance a sentence telling you what to do next. Four rules that matter when acting on this unattended: 1. DO NOT EDIT TOWARD A PERFECT SCORE. Prose stripped of every tell develops its own obvious uniformity — chopped sentences, a conjunction opening every third line, em-dashes swapped for hyphens. When `overcorrection` is non-empty you have already gone too far: stop, or revert. 2. `applicable: false` marks a finding you must not act on automatically. So does anything in `guidance[]` — those are instructions to a human writer, not text to substitute into the document. 3. Findings with `quoted: true` sit inside quotation marks. That is somebody else's phrasing; editing it changes what a source said. Leave it. 4. If you apply edits by offset, apply them BACK TO FRONT (highest `start` first), or every offset after your first edit is wrong. Each finding also carries `context` so you can re-locate it by text instead. ## Programmatic use const Tone = require('./tone-lint.js'); const report = Tone.analyze(text, { voice: 'plain', budget: 70 }); const better = Tone.revise(text, report.findings, { 0: report.findings[0].fix[0] }); `Tone.revise` applies only the choices you pass. It refuses to apply guidance. ## Voices A voice carries a register, the words a writer would never use, and — once calibrated on their published work — the cadence of their own prose, so the lint can measure drift from it rather than from a generic average. Voices are local files. The web tool stores them in browser storage and exports them as JSON; the MCP server reads ~/.tone/voices.json (or $TONE_VOICES). They are never fetched from write.work and are not visible to anyone else. ## Privacy The library, the MCP server and the embed make no network call at all: they read your text, do arithmetic, and return a result. Nothing is sent to write.work. The web tool has exactly two network paths, both explicit and both opt-in: /api/fetch You give it a URL; it returns that page's text so the lint can run on it locally. Your own writing is not involved. Rewrite Sends the passage and the voice profile to the model provider whose API key YOU supplied, directly from your browser. It does not pass through write.work and we never see the key. Nothing happens here unless you press the button. Pages on write.work also load webfonts from Google. That is a request for the page's typography, not for anything you wrote.