Repository navigation
How It Works
editwright splits an edit in two. The agent does the judgment: what is wrong, why it matters to a reader, and what kinds of fix exist. ew.py does everything that is counting or bookkeeping, so it can be checked: hashing, cleanup, paragraph numbers, the suggestion file, the ledger and the apply.
SKILL.md states these rules and says they are never relaxed silently.
The agent never writes to your file, your Google Doc or your paste. ew.py intake hashes the file with SHA-256, copies it into the job folder as a read-only snapshot, and works on a cleaned copy, clean.md. ew.py check must pass at the end of every run. A failed check fails the run, and the agent must say so.
Here the story was changed after intake, and check caught it:
$ echo 'A new last line.' >> story.md && python3 ew.py --works works check the-salt-road
FAIL source /tmp/demo/story.md: CHANGED (sha256 0d05478ee6a09c74d51e7303a73fac1eb1efcd402b8d0f86f990f5f4088d3ffb)
OK snapshot source.md: matches
OK clean.md: same words as the source
check: FAILED: the author's source changed; the run fails
$ echo $?
1Cleanup never changes a word. It fixes line endings, invisible characters, odd spaces, hard-wrapped lines, scene-break marks and chapter lines, quote style, double hyphens and spaced ellipses. Then it compares the word sequence before and after, and refuses to write anything if one word differs. Each job's cleanup-log.md lists what changed:
$ cat works/the-salt-road/jobs/*/cleanup-log.md
# Cleanup log
Mechanical cleanup from the source snapshot to clean.md. No word was added, removed or changed: the word sequence check passed (133 words).
Source read as: text (utf-8-sig).
| Rule | Changes | Examples |
|---|---|---|
| hard-wrapped lines joined inside paragraphs | 3 | |
| scene breaks made * * * | 1 | |Quotes follow the source's dominant style by default: a story written with straight quotes keeps them, as this one did. --quotes and --dashes on intake change that.
The output is diagnosis: an editorial letter, notes anchored to quoted passages, and suggestions with an ID, a location, the problem, why it matters and options. A suggestion may carry a change only for the smallest span: a typo, punctuation, a tense slip, agreement, a cut or a reorder, ideally in your own words. Anything that needs new wording is a query. The agent names the problem and the kind of fix, and leaves the sentence to you.
ew.py suggest compares each change with the words it replaces and marks the words you did not write. The provenance ledger totals them. Human-authored mode is the default, with limits of 0 words for fiction, short stories, novels, poetry, scripts and "other", and 1% of the piece (at most 50 words) for nonfiction. How words are counted, and why these numbers, is on Provenance and AI-text rules.
ew.py apply takes the IDs you name, and nothing else. There is no "all":
$ python3 ew.py --works works apply the-salt-road
editwright: name the accepted IDs with --accept (the author's choice; there is no 'all')
$ echo $?
2It refuses unknown IDs, queries you have not written words for, two changes to the same text, and AI-written words over the limit. When it refuses, nothing is applied. When it succeeds, it writes a new file (edited.md, then edited-2.md and so on) beside clean.md, with a changelog that ties each change to its ID. Words you type for a query go in with --author-text ID="..." and count as yours, unless they copy wording the suggestion offered (see Provenance and AI-text rules).
Only when you say something like "rewrite it freely" does the agent turn human-authored mode off, and only for that one job. ew.py override needs your words as its reason, at least three of them, and records them in the job's notes.md:
$ python3 ew.py --works works override the-salt-road --reason "go ahead"
editwright: --reason must quote what the user said (for example "rewrite it freely")
$ echo $?
2$ python3 ew.py --works works override the-salt-road --reason "rewrite it freely, this one is a practice piece"
human-authored mode is off for this job only; recorded in notes.md. The ledger still counts AI-written words.override --off turns the mode back on.
A sixth rule in SKILL.md keeps notes about a work private: manuscripts, style sheets, story bibles and author preferences live in the works store, never in a repository or an issue. See Works store and privacy.
| Step | What happens | Commands |
|---|---|---|
| 0. Freshness | The skill reads its evergreen.json and says so if its research is past due. |
none |
| 1. Intake | Asks only what it cannot infer (genre, level, your name), then snapshots and cleans the text. Over about 20,000 words it splits the text into chunks. |
intake, author, chunk
|
| 2. Read and measure | Reads the whole piece once before judging anything, and runs the counts. Counts are prompts to look, never verdicts. Fills the work's story-bible.md and style-sheet.md. |
show, stats
|
| 3. Passes, big to small | Developmental or assessment: an editorial-letter.md with what works, the two or three biggest issues with quoted evidence, and questions. Then line, copy and proof passes, ranked by severity and kept short. |
suggest, export
|
| 4. Hand over and stop | Runs check, shows you the letter, the top suggestions and the ledger line, and asks which IDs you accept. Nothing is applied in the same turn. |
check |
| 5. Apply | Applies the IDs you named, records what you took and turned down, and checks again. |
apply, feedback, check
|
The genres are fiction, short-story, novel, nonfiction, script, poetry and other. The levels are developmental, assessment, line, copy, proof, fact and full. Scripts and poetry keep single line breaks at intake.
The skill never runs a humanizer or style rewriter on your text. It may run the everwrite checker on its own letter and notes.
- Text, Markdown, Fountain and
.docxdirectly. For a.docx, it reads the body paragraphs, keeps tracked insertions and drops tracked deletions. - EPUB and PDF through extracted text: readwright's
rw.py read FILE --out text.md, thenintake FILE --text text.md. The original file is still the one hashed. - A Google Doc through a read-only export: intake the saved text with
--source-ref gdoc:<id>, and at the end runcheck --againsta fresh export (see Commands).
$ touch book.pdf && python3 ew.py --works works intake book.pdf
editwright: cannot read .pdf files directly; extract the text first (readwright: rw.py read FILE --out text.md) and pass it with --text
$ echo $?
1This wiki describes editwright 0.1.1 (tag v0.1.1, commit 8d9a0d5) and was last updated on 2026-10-09. The plugin is MIT licensed. Report problems in the issues.