Build WordHero
A local writing workspace whose hard problems are tracking which words came from the model through rounds of editing, keeping reusable instructions versioned so a result can be explained later, and exporting a document with its provenance intact.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the workspace locally.
Get it nodejs.org or your version manager. open ↗
Verify
node --version prints v22 or higher - API keypay per token; a working day of drafting is small change
Why Generation is the only part that leaves your machine and the only part that costs money.
Get it Create a key with the provider you prefer and set a spend limit in their console.
Verify
One generation returns text and records token counts - decidefree
Why The Copyright Office position is one country's, and if you publish commercially the answer where you are is the one that matters.
Get it Read your national copyright office or equivalent on AI-assisted works and write down what it says and when you read it. open ↗
Verify
The README names your jurisdiction's position with a date - decidefree
Why A text box wired to a paid model with no limit is the one way this cheap build becomes expensive.
Get it Pick a figure, set it in the configuration and set a matching limit in the provider console.
Verify
Generation stops at the ceiling and editing continues
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- documents(id, title, created_at, updated_at, current_version) - versions(id, document_id, ordinal, body, created_at, reason) · reason is typed, generated or edited - spans(id, version_id, start_offset, end_offset, origin, generation_id) · origin is human, model or model_edited - generations(id, document_id, instruction_id, instruction_version, model_id, params_json, prompt_tokens, completion_tokens, created_at, cost_minor) - instructions(id, name, body, version, created_at, retired_at) · a reusable instruction, versioned so an old result stays explicable - settings(monthly_cost_ceiling_minor, model_id, redaction_enabled) - There is no column anywhere holding a score for how machine-written a passage looks, and that absence is deliberate.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_PATH | required | ./data/writing.db | Documents, versions, spans, generations and instructions. This is everything. |
MODEL_API_KEYsecret | required | sk-...redacted | The only credential. Give it a provider-side spend limit as well. |
MODEL_ID | required | a model identifier | Stored with every generation, because a different model is a different result. |
MONTHLY_COST_CEILING | required | 10.00 | Generation stops here for the month and the editor keeps working. |
REDACTION_WARNING | required | true | Warns before sending a draft containing what looks like a personal name. |
The build, in order
A draft with a history
Every change to a document produces a version, and nothing is ever overwritten in place.
The history is what makes provenance possible at all.
Files
src/lib/versions.tstests/versions.test.tsLosing a paragraph once ends the user's trust in the tool.
Files
src/components/Editor.tsxRewinding loses whatever came after, which is the usual regret.
Files
src/lib/versions.ts
done when · tick each as it passeswatch out- Autosaving over a single body row means one bad generation replacing a selection destroys the paragraph you spent twenty minutes on, and undo in a browser does not survive the save. Append a version for every change, keep the previous body untouched, and make recovery create a new version rather than rewinding the chain.
Which words were yours
Generated text is marked as generated, and the marking survives being edited.
It is the only moment the boundary is known exactly.
Files
src/lib/spans.tsNever by searching for the text again.
Files
src/lib/spans.tstests/spans.test.tsA gap in coverage is a silent claim of authorship.
Files
tests/spans.test.ts
done when · tick each as it passeswatch out- Recomputing provenance by searching the current document for the text the model returned falls apart the moment a word is changed, and you end up with a document that claims everything is human because nothing matches any more. Maintain spans through the edit offsets as the edits happen, and test it with a sequence that inserts, deletes and retypes across a span boundary.
Instructions you can explain later
A reusable instruction is versioned, and every generation records exactly which version produced it.
Otherwise history rewrites itself every time you improve a prompt.
Files
src/lib/instructions.tstests/instructions.test.tsModel, parameters, instruction version, token counts.
Files
src/lib/generate.tsA half-parsed response in a draft is worse than no response.
Files
src/lib/generate.ts
done when · tick each as it passeswatch out- Editing an instruction in place means every past result now claims to have come from wording that did not exist when it was produced, which quietly destroys the only reason to keep a history in the first place. Version instructions on edit and pin each generation to the version it used.
Out of the app, with the record attachedproduct builder
A document exports as plain Markdown plus a provenance report, and the spend has a ceiling.
A claimed percentage is worth nothing; a computed one is evidence.
Files
src/lib/report.tstests/report.test.tsThe editor should work when the budget does not.
Files
src/lib/cost.tsThe prompt leaves the machine and the draft is often about somebody.
Files
src/lib/redact.ts
done when · tick each as it passeswatch out- Exporting the text without the provenance report throws away the only thing this build produced that a chat window does not, and reconstructing it later from memory is exactly the position the design was meant to avoid. Make the report part of every export, and make the proportions computed rather than claimed.
That is the whole plan for WordHero. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Machine-writing detection or scoring.
- Keyword and ranking features.
- Team workspaces and approvals.
- Bulk article generation.
- team governance and integrations
- vendor-managed prompt and quality tuning
- proprietary models or classifiers
- brand-trained workflows
- A per-document provenance trend, which shows how your use of the model changes as a piece matures
- Local model support, which removes the prompt from the network entirely for sensitive drafts
- An instruction library shared as a file, so a prompt can be reviewed and versioned like code
Need the files? The project pack on the verdict page hands your agent the whole brief · more ai writing.