Vibecode WordHero
track this build3 phases, 9 steps, beginner friendly0%WordHero's solo core is compact: build a private AI writing workspace that sends user text to one chosen model, stores versions, applies reusable instructions, and exports Markdown. A competent builder can reach a useful personal version in one sitting, while the paid product mainly wins on model, data, workflow.
You are building a lean indie version of WordHero. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # WordHero · indie build 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. Estimated effort: **one sitting**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Next.js with TypeScript, running on your own machine, one user | the drafts are yours and there is no reason for them to be anywhere else | | Storage | SQLite with documents, versions and provenance spans in one file | the history is the product and it has to survive a crash and a reinstall | | Model access | One provider adapter, the model identifier stored with every generation | two models give two results and a draft nobody can explain is a draft nobody trusts | | Provenance | Character-offset spans updated on every edit, never recomputed by guessing | a guess about who wrote a sentence is worth nothing at all | | Export | Markdown with a provenance report beside it | the report is the thing this build has that a chat window does not | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the workspace locally. - Get it: nodejs.org or your version manager. - Verify: node --version prints v22 or higher - [ ] **A model API key** · pay 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 - [ ] **Your own position on authorship where you live** · free - 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. - Verify: The README names your jurisdiction's position with a date - [ ] **A monthly spend ceiling** · free - 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 ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - 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 If one of those is essential to you, that is the reason to keep paying for WordHero, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · WordHero The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a private writing workspace that keeps a record of which words you wrote and which the model wrote to replace WordHero. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero There is one fact about this category that should shape the schema, and almost no product in it acts on the fact. In the United States, the Copyright Office published Part 2 of its report on copyright and artificial intelligence on 29 January 2025, concluding that outputs of generative AI can be protected only where a human author determined sufficient expressive elements, and that on the technology as it stood, prompts alone do not provide enough human control to make the user of a system the author of its output. Human-authored material that remains perceptible in the output, and creative arrangement or modification of it, are what can carry protection. Other countries answer this differently, so check yours. The design consequence is direct: this workspace records provenance at the level of a passage, not of a document. Every span of text is marked as written by you, generated by the model, or generated and then edited by you, and the marking survives editing and export. That gives you something no chat window can give: a defensible account of what you contributed, produced as a by-product of writing rather than reconstructed afterwards from memory. Two things this app must not do. It must not claim the text is undetectable, original, or safe to pass off, and it must not score text for whether a machine wrote it, because those detectors do not work well enough to accuse anyone with. State the position in the README and leave it alone. ### Stack (fixed, do not substitute) - Runtime: Next.js with TypeScript, running on your own machine, one user · the drafts are yours and there is no reason for them to be anywhere else - Storage: SQLite with documents, versions and provenance spans in one file · the history is the product and it has to survive a crash and a reinstall - Model access: One provider adapter, the model identifier stored with every generation · two models give two results and a draft nobody can explain is a draft nobody trusts - Provenance: Character-offset spans updated on every edit, never recomputed by guessing · a guess about who wrote a sentence is worth nothing at all - Export: Markdown with a provenance report beside it · the report is the thing this build has that a chat window does not ### Data model (create this before Phase 1) - 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. ### Phase 1 · A draft with a history Build: An editor that saves versions rather than mutating a body, with a typed reason for each. Show the version list with a readable difference between any two. Recover an earlier version into a new one rather than by rolling back. Autosave on a timer and on blur, and never lose the in-progress text on a reload. Trap: 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. Done when: Every save appends a version and no existing version body is ever modified, verified in the database after an editing session. A reload mid-edit restores the unsaved text, tested. Restoring an old version creates a new one and leaves the chain intact. The difference view between any two versions is readable and correct on a paragraph that was replaced. Do not build yet: No generation, provenance, instructions or export yet. ### Phase 2 · Which words were yours Build: When a generation is inserted, record a span covering exactly the inserted range with its generation identifier. On every subsequent edit, shift and split spans by the edit's offsets rather than recomputing them from the text. When a user edits inside a model span, mark the touched part as model then edited. Show the provenance as a subtle background in the editor. Trap: 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. Done when: Inserting a generation and then editing one word inside it leaves the edited part marked as model then edited and the rest marked as model, tested with an explicit edit sequence. Deleting across a span boundary leaves both remaining sides correctly marked. Spans always cover the whole document with no gaps and no overlaps, asserted after every version. Typing new text between two model spans produces a human span. Do not build yet: No reusable instructions, cost ceiling or export yet. ### Phase 3 · Instructions you can explain later Build: Named instructions with a body, versioned on edit. A generation stores the instruction identifier and version, the model identifier, the parameters and the token counts. Validate structured output where you ask for it and never insert an unparsed response. Show, next to any generated passage, which instruction version and model produced it. Trap: 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. Done when: Editing an instruction creates a version and past generations still resolve to the wording they used, tested. Every generation stores model identifier, parameters and token counts. A response that fails validation inserts nothing and reports the failure, tested with a fake returning prose. Hovering any generated passage shows the instruction version and model behind it. Do not build yet: No export, cost ceiling or redaction yet. ### Phase 4 · Out of the app, with the record attached Build: Export Markdown, the full version history, and a report listing every passage with its origin, the proportion of the final text that is human, model or model then edited, and the model and instruction versions used. Add a monthly cost ceiling that stops generation and leaves writing working. Offer a redaction pass that warns before a draft containing names is sent. Trap: 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. Done when: Export produces Markdown, the version history and a provenance report whose proportions are computed from spans and sum to the whole document, tested. Reaching the monthly ceiling disables generation with a clear message and leaves editing and export working, tested. The redaction warning fires on a draft containing an obvious name before any request is made. Everything exported reimports into an empty database with spans intact. Do not build yet: Nothing after this. ### Out of scope (and why) - Detecting whether a passage was machine-written, because the available detectors are not accurate enough to accuse a person with and this app would be used to do exactly that. - Search engine ranking features and keyword scoring, which are a different product wearing a writing tool's clothes. - Team workspaces and approval flows, which are what the subscription actually sells and are not a writing problem. - Bulk generation of many articles at once, which produces volume nobody reads and a bill somebody does. ### README must contain - The Copyright Office position on prompts and human authorship with the date and the link, and a note that other countries differ - That provenance is recorded per passage as you write, not reconstructed afterwards, and what the three origins mean - That no claim is made about originality, detectability or ownership of any output - That prompts and drafts leave the machine when you generate, and what the provider's retention policy says - Where the database lives, how to export everything, and how the monthly cost ceiling behaves ===== AGENTS.md ===== # Agent instructions · WordHero indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Next.js with TypeScript, running on your own machine, one user, SQLite with documents, versions and provenance spans in one file, One provider adapter, the model identifier stored with every generation, Character-offset spans updated on every edit, never recomputed by guessing, Markdown with a provenance report beside it. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - 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. - 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. - 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. ===== BUILD_PLAN.md ===== # Build plan · 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. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · A draft with a history Every change to a document produces a version, and nothing is ever overwritten in place. ### Steps 1. Append versions, never mutate a body The history is what makes provenance possible at all. Files: `src/lib/versions.ts`, `tests/versions.test.ts` 2. Autosave without losing in-progress text Losing a paragraph once ends the user's trust in the tool. Files: `src/components/Editor.tsx` 3. Make restore a forward operation Rewinding loses whatever came after, which is the usual regret. Files: `src/lib/versions.ts` ### Done when - [ ] Every save appends a version and mutates nothing - [ ] A reload restores unsaved text - [ ] Restoring creates a new version - [ ] Differences render correctly on replaced paragraphs ### Watch 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. ## Phase 2 · Which words were yours Generated text is marked as generated, and the marking survives being edited. ### Steps 1. Record the inserted range at insertion time It is the only moment the boundary is known exactly. Files: `src/lib/spans.ts` 2. Shift and split spans by edit offsets Never by searching for the text again. Files: `src/lib/spans.ts`, `tests/spans.test.ts` 3. Assert full coverage after every version A gap in coverage is a silent claim of authorship. Files: `tests/spans.test.ts` ### Done when - [ ] Editing inside a model span marks only the edited part - [ ] Deleting across a boundary leaves both sides correct - [ ] Spans cover the document with no gaps or overlaps - [ ] New typing between model spans is marked human ### Watch 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. ## Phase 3 · Instructions you can explain later A reusable instruction is versioned, and every generation records exactly which version produced it. ### Steps 1. Version instructions on edit Otherwise history rewrites itself every time you improve a prompt. Files: `src/lib/instructions.ts`, `tests/instructions.test.ts` 2. Pin every generation to what produced it Model, parameters, instruction version, token counts. Files: `src/lib/generate.ts` 3. Insert nothing on a validation failure A half-parsed response in a draft is worse than no response. Files: `src/lib/generate.ts` ### Done when - [ ] Instruction edits version rather than overwrite - [ ] Past generations resolve to the wording they used - [ ] Failed validation inserts nothing - [ ] Generated passages show their instruction and model ### Watch 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. ## Not in this build - Machine-writing detection or scoring. - Keyword and ranking features. - Team workspaces and approvals. - Bulk article generation. ## After v1, if you want it - 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 ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Documents, versions, spans, generations and instructions. This is everything. DATABASE_PATH=./data/writing.db # Required · secret. The only credential. Give it a provider-side spend limit as well. MODEL_API_KEY=sk-...redacted # Required. Stored with every generation, because a different model is a different result. MODEL_ID=a model identifier # Required. Generation stops here for the month and the editor keeps working. MONTHLY_COST_CEILING=10.00 # Required. Warns before sending a draft containing what looks like a personal name. REDACTION_WARNING=true
You are building a lean indie version of WordHero. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # WordHero · indie build 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. Estimated effort: **one sitting**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Next.js with TypeScript, running on your own machine, one user | the drafts are yours and there is no reason for them to be anywhere else | | Storage | SQLite with documents, versions and provenance spans in one file | the history is the product and it has to survive a crash and a reinstall | | Model access | One provider adapter, the model identifier stored with every generation | two models give two results and a draft nobody can explain is a draft nobody trusts | | Provenance | Character-offset spans updated on every edit, never recomputed by guessing | a guess about who wrote a sentence is worth nothing at all | | Export | Markdown with a provenance report beside it | the report is the thing this build has that a chat window does not | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the workspace locally. - Get it: nodejs.org or your version manager. - Verify: node --version prints v22 or higher - [ ] **A model API key** · pay 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 - [ ] **Your own position on authorship where you live** · free - 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. - Verify: The README names your jurisdiction's position with a date - [ ] **A monthly spend ceiling** · free - 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 ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - 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 If one of those is essential to you, that is the reason to keep paying for WordHero, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · WordHero The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a private writing workspace that keeps a record of which words you wrote and which the model wrote to replace WordHero. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero There is one fact about this category that should shape the schema, and almost no product in it acts on the fact. In the United States, the Copyright Office published Part 2 of its report on copyright and artificial intelligence on 29 January 2025, concluding that outputs of generative AI can be protected only where a human author determined sufficient expressive elements, and that on the technology as it stood, prompts alone do not provide enough human control to make the user of a system the author of its output. Human-authored material that remains perceptible in the output, and creative arrangement or modification of it, are what can carry protection. Other countries answer this differently, so check yours. The design consequence is direct: this workspace records provenance at the level of a passage, not of a document. Every span of text is marked as written by you, generated by the model, or generated and then edited by you, and the marking survives editing and export. That gives you something no chat window can give: a defensible account of what you contributed, produced as a by-product of writing rather than reconstructed afterwards from memory. Two things this app must not do. It must not claim the text is undetectable, original, or safe to pass off, and it must not score text for whether a machine wrote it, because those detectors do not work well enough to accuse anyone with. State the position in the README and leave it alone. ### Stack (fixed, do not substitute) - Runtime: Next.js with TypeScript, running on your own machine, one user · the drafts are yours and there is no reason for them to be anywhere else - Storage: SQLite with documents, versions and provenance spans in one file · the history is the product and it has to survive a crash and a reinstall - Model access: One provider adapter, the model identifier stored with every generation · two models give two results and a draft nobody can explain is a draft nobody trusts - Provenance: Character-offset spans updated on every edit, never recomputed by guessing · a guess about who wrote a sentence is worth nothing at all - Export: Markdown with a provenance report beside it · the report is the thing this build has that a chat window does not ### Data model (create this before Phase 1) - 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. ### Phase 1 · A draft with a history Build: An editor that saves versions rather than mutating a body, with a typed reason for each. Show the version list with a readable difference between any two. Recover an earlier version into a new one rather than by rolling back. Autosave on a timer and on blur, and never lose the in-progress text on a reload. Trap: 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. Done when: Every save appends a version and no existing version body is ever modified, verified in the database after an editing session. A reload mid-edit restores the unsaved text, tested. Restoring an old version creates a new one and leaves the chain intact. The difference view between any two versions is readable and correct on a paragraph that was replaced. Do not build yet: No generation, provenance, instructions or export yet. ### Phase 2 · Which words were yours Build: When a generation is inserted, record a span covering exactly the inserted range with its generation identifier. On every subsequent edit, shift and split spans by the edit's offsets rather than recomputing them from the text. When a user edits inside a model span, mark the touched part as model then edited. Show the provenance as a subtle background in the editor. Trap: 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. Done when: Inserting a generation and then editing one word inside it leaves the edited part marked as model then edited and the rest marked as model, tested with an explicit edit sequence. Deleting across a span boundary leaves both remaining sides correctly marked. Spans always cover the whole document with no gaps and no overlaps, asserted after every version. Typing new text between two model spans produces a human span. Do not build yet: No reusable instructions, cost ceiling or export yet. ### Phase 3 · Instructions you can explain later Build: Named instructions with a body, versioned on edit. A generation stores the instruction identifier and version, the model identifier, the parameters and the token counts. Validate structured output where you ask for it and never insert an unparsed response. Show, next to any generated passage, which instruction version and model produced it. Trap: 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. Done when: Editing an instruction creates a version and past generations still resolve to the wording they used, tested. Every generation stores model identifier, parameters and token counts. A response that fails validation inserts nothing and reports the failure, tested with a fake returning prose. Hovering any generated passage shows the instruction version and model behind it. Do not build yet: No export, cost ceiling or redaction yet. ### Phase 4 · Out of the app, with the record attached Build: Export Markdown, the full version history, and a report listing every passage with its origin, the proportion of the final text that is human, model or model then edited, and the model and instruction versions used. Add a monthly cost ceiling that stops generation and leaves writing working. Offer a redaction pass that warns before a draft containing names is sent. Trap: 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. Done when: Export produces Markdown, the version history and a provenance report whose proportions are computed from spans and sum to the whole document, tested. Reaching the monthly ceiling disables generation with a clear message and leaves editing and export working, tested. The redaction warning fires on a draft containing an obvious name before any request is made. Everything exported reimports into an empty database with spans intact. Do not build yet: Nothing after this. ### Out of scope (and why) - Detecting whether a passage was machine-written, because the available detectors are not accurate enough to accuse a person with and this app would be used to do exactly that. - Search engine ranking features and keyword scoring, which are a different product wearing a writing tool's clothes. - Team workspaces and approval flows, which are what the subscription actually sells and are not a writing problem. - Bulk generation of many articles at once, which produces volume nobody reads and a bill somebody does. ### README must contain - The Copyright Office position on prompts and human authorship with the date and the link, and a note that other countries differ - That provenance is recorded per passage as you write, not reconstructed afterwards, and what the three origins mean - That no claim is made about originality, detectability or ownership of any output - That prompts and drafts leave the machine when you generate, and what the provider's retention policy says - Where the database lives, how to export everything, and how the monthly cost ceiling behaves ===== AGENTS.md ===== # Agent instructions · WordHero indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Next.js with TypeScript, running on your own machine, one user, SQLite with documents, versions and provenance spans in one file, One provider adapter, the model identifier stored with every generation, Character-offset spans updated on every edit, never recomputed by guessing, Markdown with a provenance report beside it. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - 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. - 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. - 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. ===== BUILD_PLAN.md ===== # Build plan · 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. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · A draft with a history Every change to a document produces a version, and nothing is ever overwritten in place. ### Steps 1. Append versions, never mutate a body The history is what makes provenance possible at all. Files: `src/lib/versions.ts`, `tests/versions.test.ts` 2. Autosave without losing in-progress text Losing a paragraph once ends the user's trust in the tool. Files: `src/components/Editor.tsx` 3. Make restore a forward operation Rewinding loses whatever came after, which is the usual regret. Files: `src/lib/versions.ts` ### Done when - [ ] Every save appends a version and mutates nothing - [ ] A reload restores unsaved text - [ ] Restoring creates a new version - [ ] Differences render correctly on replaced paragraphs ### Watch 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. ## Phase 2 · Which words were yours Generated text is marked as generated, and the marking survives being edited. ### Steps 1. Record the inserted range at insertion time It is the only moment the boundary is known exactly. Files: `src/lib/spans.ts` 2. Shift and split spans by edit offsets Never by searching for the text again. Files: `src/lib/spans.ts`, `tests/spans.test.ts` 3. Assert full coverage after every version A gap in coverage is a silent claim of authorship. Files: `tests/spans.test.ts` ### Done when - [ ] Editing inside a model span marks only the edited part - [ ] Deleting across a boundary leaves both sides correct - [ ] Spans cover the document with no gaps or overlaps - [ ] New typing between model spans is marked human ### Watch 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. ## Phase 3 · Instructions you can explain later A reusable instruction is versioned, and every generation records exactly which version produced it. ### Steps 1. Version instructions on edit Otherwise history rewrites itself every time you improve a prompt. Files: `src/lib/instructions.ts`, `tests/instructions.test.ts` 2. Pin every generation to what produced it Model, parameters, instruction version, token counts. Files: `src/lib/generate.ts` 3. Insert nothing on a validation failure A half-parsed response in a draft is worse than no response. Files: `src/lib/generate.ts` ### Done when - [ ] Instruction edits version rather than overwrite - [ ] Past generations resolve to the wording they used - [ ] Failed validation inserts nothing - [ ] Generated passages show their instruction and model ### Watch 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. ## Not in this build - Machine-writing detection or scoring. - Keyword and ranking features. - Team workspaces and approvals. - Bulk article generation. ## After v1, if you want it - 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 ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Documents, versions, spans, generations and instructions. This is everything. DATABASE_PATH=./data/writing.db # Required · secret. The only credential. Give it a provider-side spend limit as well. MODEL_API_KEY=sk-...redacted # Required. Stored with every generation, because a different model is a different result. MODEL_ID=a model identifier # Required. Generation stops here for the month and the editor keeps working. MONTHLY_COST_CEILING=10.00 # Required. Warns before sending a draft containing what looks like a personal name. REDACTION_WARNING=true
You are building a production product version of WordHero. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # WordHero · product brief ## Problem WordHero's solo core is compact: build a private AI writing workspace that sends user text to one chosen model, stores versions, applies reusable instructions, and exports Markdown. A competent builder can reach a useful personal version in one sitting, while the paid product mainly wins on model, data, workflow. ## Product outcome A writing workspace that can tell you, at export time and from records rather than memory, which parts of a finished document you wrote, which the model wrote, and which instruction and model produced each one. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - OpenAI API key in .env - Node.js 22 - SQLite database ## Explicit non-goals for v1 - 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 ## Success criteria - Editing inside a generated passage is confirmed to mark only the edited part - Span coverage is confirmed complete after every version - A failed validation is confirmed to insert nothing - Past generations are confirmed to resolve to the instruction version used - Export is confirmed to include the computed provenance report ===== BRIEF.md ===== # Build brief · WordHero The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a private writing workspace that keeps a record of which words you wrote and which the model wrote to replace WordHero. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero There is one fact about this category that should shape the schema, and almost no product in it acts on the fact. In the United States, the Copyright Office published Part 2 of its report on copyright and artificial intelligence on 29 January 2025, concluding that outputs of generative AI can be protected only where a human author determined sufficient expressive elements, and that on the technology as it stood, prompts alone do not provide enough human control to make the user of a system the author of its output. Human-authored material that remains perceptible in the output, and creative arrangement or modification of it, are what can carry protection. Other countries answer this differently, so check yours. The design consequence is direct: this workspace records provenance at the level of a passage, not of a document. Every span of text is marked as written by you, generated by the model, or generated and then edited by you, and the marking survives editing and export. That gives you something no chat window can give: a defensible account of what you contributed, produced as a by-product of writing rather than reconstructed afterwards from memory. Two things this app must not do. It must not claim the text is undetectable, original, or safe to pass off, and it must not score text for whether a machine wrote it, because those detectors do not work well enough to accuse anyone with. State the position in the README and leave it alone. ### Stack (fixed, do not substitute) - Runtime: Next.js with TypeScript, running on your own machine, one user · the drafts are yours and there is no reason for them to be anywhere else - Storage: SQLite with documents, versions and provenance spans in one file · the history is the product and it has to survive a crash and a reinstall - Model access: One provider adapter, the model identifier stored with every generation · two models give two results and a draft nobody can explain is a draft nobody trusts - Provenance: Character-offset spans updated on every edit, never recomputed by guessing · a guess about who wrote a sentence is worth nothing at all - Export: Markdown with a provenance report beside it · the report is the thing this build has that a chat window does not ### Data model (create this before Phase 1) - 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. ### Phase 1 · A draft with a history Build: An editor that saves versions rather than mutating a body, with a typed reason for each. Show the version list with a readable difference between any two. Recover an earlier version into a new one rather than by rolling back. Autosave on a timer and on blur, and never lose the in-progress text on a reload. Trap: 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. Done when: Every save appends a version and no existing version body is ever modified, verified in the database after an editing session. A reload mid-edit restores the unsaved text, tested. Restoring an old version creates a new one and leaves the chain intact. The difference view between any two versions is readable and correct on a paragraph that was replaced. Do not build yet: No generation, provenance, instructions or export yet. ### Phase 2 · Which words were yours Build: When a generation is inserted, record a span covering exactly the inserted range with its generation identifier. On every subsequent edit, shift and split spans by the edit's offsets rather than recomputing them from the text. When a user edits inside a model span, mark the touched part as model then edited. Show the provenance as a subtle background in the editor. Trap: 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. Done when: Inserting a generation and then editing one word inside it leaves the edited part marked as model then edited and the rest marked as model, tested with an explicit edit sequence. Deleting across a span boundary leaves both remaining sides correctly marked. Spans always cover the whole document with no gaps and no overlaps, asserted after every version. Typing new text between two model spans produces a human span. Do not build yet: No reusable instructions, cost ceiling or export yet. ### Phase 3 · Instructions you can explain later Build: Named instructions with a body, versioned on edit. A generation stores the instruction identifier and version, the model identifier, the parameters and the token counts. Validate structured output where you ask for it and never insert an unparsed response. Show, next to any generated passage, which instruction version and model produced it. Trap: 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. Done when: Editing an instruction creates a version and past generations still resolve to the wording they used, tested. Every generation stores model identifier, parameters and token counts. A response that fails validation inserts nothing and reports the failure, tested with a fake returning prose. Hovering any generated passage shows the instruction version and model behind it. Do not build yet: No export, cost ceiling or redaction yet. ### Phase 4 · Out of the app, with the record attached Build: Export Markdown, the full version history, and a report listing every passage with its origin, the proportion of the final text that is human, model or model then edited, and the model and instruction versions used. Add a monthly cost ceiling that stops generation and leaves writing working. Offer a redaction pass that warns before a draft containing names is sent. Trap: 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. Done when: Export produces Markdown, the version history and a provenance report whose proportions are computed from spans and sum to the whole document, tested. Reaching the monthly ceiling disables generation with a clear message and leaves editing and export working, tested. The redaction warning fires on a draft containing an obvious name before any request is made. Everything exported reimports into an empty database with spans intact. Do not build yet: Nothing after this. ### Out of scope (and why) - Detecting whether a passage was machine-written, because the available detectors are not accurate enough to accuse a person with and this app would be used to do exactly that. - Search engine ranking features and keyword scoring, which are a different product wearing a writing tool's clothes. - Team workspaces and approval flows, which are what the subscription actually sells and are not a writing problem. - Bulk generation of many articles at once, which produces volume nobody reads and a bill somebody does. ### README must contain - The Copyright Office position on prompts and human authorship with the date and the link, and a note that other countries differ - That provenance is recorded per passage as you write, not reconstructed afterwards, and what the three origins mean - That no claim is made about originality, detectability or ownership of any output - That prompts and drafts leave the machine when you generate, and what the provider's retention policy says - Where the database lives, how to export everything, and how the monthly cost ceiling behaves ===== ARCHITECTURE.md ===== # Architecture · WordHero ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Next.js with TypeScript, running on your own machine, one user | the drafts are yours and there is no reason for them to be anywhere else | | Storage | SQLite with documents, versions and provenance spans in one file | the history is the product and it has to survive a crash and a reinstall | | Model access | One provider adapter, the model identifier stored with every generation | two models give two results and a draft nobody can explain is a draft nobody trusts | | Provenance | Character-offset spans updated on every edit, never recomputed by guessing | a guess about who wrote a sentence is worth nothing at all | | Export | Markdown with a provenance report beside it | the report is the thing this build has that a chat window does not | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Documents | Versions and differences. | Any editor, provided saves append rather than mutate. | | Provenance | Spans through every edit. | Not swappable for recomputation by text matching, which does not work. | | Instructions | Named reusable prompts and their versions. | Any store, provided generations pin the version they used. | | Generation | The provider call, validation and token counts. | Any provider, provided a failed response inserts nothing. | | Export | Markdown, history and the provenance report. | Any format, provided the report goes with the text. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DATABASE_PATH` · required · Documents, versions, spans, generations and instructions. This is everything. - `MODEL_API_KEY` · required, secret · The only credential. Give it a provider-side spend limit as well. - `MODEL_ID` · required · Stored with every generation, because a different model is a different result. - `MONTHLY_COST_CEILING` · required · Generation stops here for the month and the editor keeps working. - `REDACTION_WARNING` · required · Warns before sending a draft containing what looks like a personal name. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · WordHero product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Next.js with TypeScript, running on your own machine, one user, SQLite with documents, versions and provenance spans in one file, One provider adapter, the model identifier stored with every generation, Character-offset spans updated on every edit, never recomputed by guessing, Markdown with a provenance report beside it. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - 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. - 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. - 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. - 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. ===== MILESTONES.md ===== # Delivery milestones · WordHero Estimated effort: **one sitting** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · A draft with a history Every change to a document produces a version, and nothing is ever overwritten in place. ### Steps 1. Append versions, never mutate a body The history is what makes provenance possible at all. Files: `src/lib/versions.ts`, `tests/versions.test.ts` 2. Autosave without losing in-progress text Losing a paragraph once ends the user's trust in the tool. Files: `src/components/Editor.tsx` 3. Make restore a forward operation Rewinding loses whatever came after, which is the usual regret. Files: `src/lib/versions.ts` ### Done when - [ ] Every save appends a version and mutates nothing - [ ] A reload restores unsaved text - [ ] Restoring creates a new version - [ ] Differences render correctly on replaced paragraphs ### Watch 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. ## M2 · Which words were yours Generated text is marked as generated, and the marking survives being edited. ### Steps 1. Record the inserted range at insertion time It is the only moment the boundary is known exactly. Files: `src/lib/spans.ts` 2. Shift and split spans by edit offsets Never by searching for the text again. Files: `src/lib/spans.ts`, `tests/spans.test.ts` 3. Assert full coverage after every version A gap in coverage is a silent claim of authorship. Files: `tests/spans.test.ts` ### Done when - [ ] Editing inside a model span marks only the edited part - [ ] Deleting across a boundary leaves both sides correct - [ ] Spans cover the document with no gaps or overlaps - [ ] New typing between model spans is marked human ### Watch 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. ## M3 · Instructions you can explain later A reusable instruction is versioned, and every generation records exactly which version produced it. ### Steps 1. Version instructions on edit Otherwise history rewrites itself every time you improve a prompt. Files: `src/lib/instructions.ts`, `tests/instructions.test.ts` 2. Pin every generation to what produced it Model, parameters, instruction version, token counts. Files: `src/lib/generate.ts` 3. Insert nothing on a validation failure A half-parsed response in a draft is worse than no response. Files: `src/lib/generate.ts` ### Done when - [ ] Instruction edits version rather than overwrite - [ ] Past generations resolve to the wording they used - [ ] Failed validation inserts nothing - [ ] Generated passages show their instruction and model ### Watch 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. ## M4 · Out of the app, with the record attached (production only) A document exports as plain Markdown plus a provenance report, and the spend has a ceiling. ### Steps 1. Compute the proportions from spans A claimed percentage is worth nothing; a computed one is evidence. Files: `src/lib/report.ts`, `tests/report.test.ts` 2. Cap the month and degrade to writing The editor should work when the budget does not. Files: `src/lib/cost.ts` 3. Warn before sending a draft with names in it The prompt leaves the machine and the draft is often about somebody. Files: `src/lib/redact.ts` ### Done when - [ ] Provenance proportions are computed and sum to the whole - [ ] The cost ceiling stops generation, not the editor - [ ] The redaction warning fires before any request - [ ] Exports reimport with spans intact ### Watch 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. ===== OPERATIONS.md ===== # Operations · WordHero ## Backup One database file. Versions and spans are the irreplaceable part: the text can be rewritten, but the record of who wrote which sentence cannot be reconstructed after the fact, which is the entire premise. ## Restore Restore and confirm that span coverage is still complete on the most recent version of every document, and that generations still resolve to their instruction versions. A restore where spans no longer cover the document has lost the provenance even though the text looks fine. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Monthly spend against the ceiling, validation failure rate, and the share of final text marked as model across recent documents. A rising model share is information about how you are working, not a target to move. ## Incident checklist The failure here is a document whose provenance is wrong, which is worse than one with no provenance at all. The coverage assertion after every version is the check that catches it, so keep it in the suite rather than in a script you run sometimes. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Editing inside a generated passage is confirmed to mark only the edited part - [ ] Span coverage is confirmed complete after every version - [ ] A failed validation is confirmed to insert nothing - [ ] Past generations are confirmed to resolve to the instruction version used - [ ] Export is confirmed to include the computed provenance report ## Launch constraint Do not market omitted WordHero capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Documents, versions, spans, generations and instructions. This is everything. DATABASE_PATH=./data/writing.db # Required · secret. The only credential. Give it a provider-side spend limit as well. MODEL_API_KEY=sk-...redacted # Required. Stored with every generation, because a different model is a different result. MODEL_ID=a model identifier # Required. Generation stops here for the month and the editor keeps working. MONTHLY_COST_CEILING=10.00 # Required. Warns before sending a draft containing what looks like a personal name. REDACTION_WARNING=true
# WordHero · indie build 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. Estimated effort: **one sitting**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Next.js with TypeScript, running on your own machine, one user | the drafts are yours and there is no reason for them to be anywhere else | | Storage | SQLite with documents, versions and provenance spans in one file | the history is the product and it has to survive a crash and a reinstall | | Model access | One provider adapter, the model identifier stored with every generation | two models give two results and a draft nobody can explain is a draft nobody trusts | | Provenance | Character-offset spans updated on every edit, never recomputed by guessing | a guess about who wrote a sentence is worth nothing at all | | Export | Markdown with a provenance report beside it | the report is the thing this build has that a chat window does not | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the workspace locally. - Get it: nodejs.org or your version manager. - Verify: node --version prints v22 or higher - [ ] **A model API key** · pay 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 - [ ] **Your own position on authorship where you live** · free - 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. - Verify: The README names your jurisdiction's position with a date - [ ] **A monthly spend ceiling** · free - 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 ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - 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 If one of those is essential to you, that is the reason to keep paying for WordHero, and the README should say so rather than pretend.
# Build brief · WordHero The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a private writing workspace that keeps a record of which words you wrote and which the model wrote to replace WordHero. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero There is one fact about this category that should shape the schema, and almost no product in it acts on the fact. In the United States, the Copyright Office published Part 2 of its report on copyright and artificial intelligence on 29 January 2025, concluding that outputs of generative AI can be protected only where a human author determined sufficient expressive elements, and that on the technology as it stood, prompts alone do not provide enough human control to make the user of a system the author of its output. Human-authored material that remains perceptible in the output, and creative arrangement or modification of it, are what can carry protection. Other countries answer this differently, so check yours. The design consequence is direct: this workspace records provenance at the level of a passage, not of a document. Every span of text is marked as written by you, generated by the model, or generated and then edited by you, and the marking survives editing and export. That gives you something no chat window can give: a defensible account of what you contributed, produced as a by-product of writing rather than reconstructed afterwards from memory. Two things this app must not do. It must not claim the text is undetectable, original, or safe to pass off, and it must not score text for whether a machine wrote it, because those detectors do not work well enough to accuse anyone with. State the position in the README and leave it alone. ### Stack (fixed, do not substitute) - Runtime: Next.js with TypeScript, running on your own machine, one user · the drafts are yours and there is no reason for them to be anywhere else - Storage: SQLite with documents, versions and provenance spans in one file · the history is the product and it has to survive a crash and a reinstall - Model access: One provider adapter, the model identifier stored with every generation · two models give two results and a draft nobody can explain is a draft nobody trusts - Provenance: Character-offset spans updated on every edit, never recomputed by guessing · a guess about who wrote a sentence is worth nothing at all - Export: Markdown with a provenance report beside it · the report is the thing this build has that a chat window does not ### Data model (create this before Phase 1) - 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. ### Phase 1 · A draft with a history Build: An editor that saves versions rather than mutating a body, with a typed reason for each. Show the version list with a readable difference between any two. Recover an earlier version into a new one rather than by rolling back. Autosave on a timer and on blur, and never lose the in-progress text on a reload. Trap: 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. Done when: Every save appends a version and no existing version body is ever modified, verified in the database after an editing session. A reload mid-edit restores the unsaved text, tested. Restoring an old version creates a new one and leaves the chain intact. The difference view between any two versions is readable and correct on a paragraph that was replaced. Do not build yet: No generation, provenance, instructions or export yet. ### Phase 2 · Which words were yours Build: When a generation is inserted, record a span covering exactly the inserted range with its generation identifier. On every subsequent edit, shift and split spans by the edit's offsets rather than recomputing them from the text. When a user edits inside a model span, mark the touched part as model then edited. Show the provenance as a subtle background in the editor. Trap: 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. Done when: Inserting a generation and then editing one word inside it leaves the edited part marked as model then edited and the rest marked as model, tested with an explicit edit sequence. Deleting across a span boundary leaves both remaining sides correctly marked. Spans always cover the whole document with no gaps and no overlaps, asserted after every version. Typing new text between two model spans produces a human span. Do not build yet: No reusable instructions, cost ceiling or export yet. ### Phase 3 · Instructions you can explain later Build: Named instructions with a body, versioned on edit. A generation stores the instruction identifier and version, the model identifier, the parameters and the token counts. Validate structured output where you ask for it and never insert an unparsed response. Show, next to any generated passage, which instruction version and model produced it. Trap: 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. Done when: Editing an instruction creates a version and past generations still resolve to the wording they used, tested. Every generation stores model identifier, parameters and token counts. A response that fails validation inserts nothing and reports the failure, tested with a fake returning prose. Hovering any generated passage shows the instruction version and model behind it. Do not build yet: No export, cost ceiling or redaction yet. ### Phase 4 · Out of the app, with the record attached Build: Export Markdown, the full version history, and a report listing every passage with its origin, the proportion of the final text that is human, model or model then edited, and the model and instruction versions used. Add a monthly cost ceiling that stops generation and leaves writing working. Offer a redaction pass that warns before a draft containing names is sent. Trap: 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. Done when: Export produces Markdown, the version history and a provenance report whose proportions are computed from spans and sum to the whole document, tested. Reaching the monthly ceiling disables generation with a clear message and leaves editing and export working, tested. The redaction warning fires on a draft containing an obvious name before any request is made. Everything exported reimports into an empty database with spans intact. Do not build yet: Nothing after this. ### Out of scope (and why) - Detecting whether a passage was machine-written, because the available detectors are not accurate enough to accuse a person with and this app would be used to do exactly that. - Search engine ranking features and keyword scoring, which are a different product wearing a writing tool's clothes. - Team workspaces and approval flows, which are what the subscription actually sells and are not a writing problem. - Bulk generation of many articles at once, which produces volume nobody reads and a bill somebody does. ### README must contain - The Copyright Office position on prompts and human authorship with the date and the link, and a note that other countries differ - That provenance is recorded per passage as you write, not reconstructed afterwards, and what the three origins mean - That no claim is made about originality, detectability or ownership of any output - That prompts and drafts leave the machine when you generate, and what the provider's retention policy says - Where the database lives, how to export everything, and how the monthly cost ceiling behaves
# Agent instructions · WordHero indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Next.js with TypeScript, running on your own machine, one user, SQLite with documents, versions and provenance spans in one file, One provider adapter, the model identifier stored with every generation, Character-offset spans updated on every edit, never recomputed by guessing, Markdown with a provenance report beside it. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - 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. - 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. - 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.
# Build plan · 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. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · A draft with a history Every change to a document produces a version, and nothing is ever overwritten in place. ### Steps 1. Append versions, never mutate a body The history is what makes provenance possible at all. Files: `src/lib/versions.ts`, `tests/versions.test.ts` 2. Autosave without losing in-progress text Losing a paragraph once ends the user's trust in the tool. Files: `src/components/Editor.tsx` 3. Make restore a forward operation Rewinding loses whatever came after, which is the usual regret. Files: `src/lib/versions.ts` ### Done when - [ ] Every save appends a version and mutates nothing - [ ] A reload restores unsaved text - [ ] Restoring creates a new version - [ ] Differences render correctly on replaced paragraphs ### Watch 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. ## Phase 2 · Which words were yours Generated text is marked as generated, and the marking survives being edited. ### Steps 1. Record the inserted range at insertion time It is the only moment the boundary is known exactly. Files: `src/lib/spans.ts` 2. Shift and split spans by edit offsets Never by searching for the text again. Files: `src/lib/spans.ts`, `tests/spans.test.ts` 3. Assert full coverage after every version A gap in coverage is a silent claim of authorship. Files: `tests/spans.test.ts` ### Done when - [ ] Editing inside a model span marks only the edited part - [ ] Deleting across a boundary leaves both sides correct - [ ] Spans cover the document with no gaps or overlaps - [ ] New typing between model spans is marked human ### Watch 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. ## Phase 3 · Instructions you can explain later A reusable instruction is versioned, and every generation records exactly which version produced it. ### Steps 1. Version instructions on edit Otherwise history rewrites itself every time you improve a prompt. Files: `src/lib/instructions.ts`, `tests/instructions.test.ts` 2. Pin every generation to what produced it Model, parameters, instruction version, token counts. Files: `src/lib/generate.ts` 3. Insert nothing on a validation failure A half-parsed response in a draft is worse than no response. Files: `src/lib/generate.ts` ### Done when - [ ] Instruction edits version rather than overwrite - [ ] Past generations resolve to the wording they used - [ ] Failed validation inserts nothing - [ ] Generated passages show their instruction and model ### Watch 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. ## Not in this build - Machine-writing detection or scoring. - Keyword and ranking features. - Team workspaces and approvals. - Bulk article generation. ## After v1, if you want it - 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
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Documents, versions, spans, generations and instructions. This is everything. DATABASE_PATH=./data/writing.db # Required · secret. The only credential. Give it a provider-side spend limit as well. MODEL_API_KEY=sk-...redacted # Required. Stored with every generation, because a different model is a different result. MODEL_ID=a model identifier # Required. Generation stops here for the month and the editor keeps working. MONTHLY_COST_CEILING=10.00 # Required. Warns before sending a draft containing what looks like a personal name. REDACTION_WARNING=true
# WordHero · product brief ## Problem WordHero's solo core is compact: build a private AI writing workspace that sends user text to one chosen model, stores versions, applies reusable instructions, and exports Markdown. A competent builder can reach a useful personal version in one sitting, while the paid product mainly wins on model, data, workflow. ## Product outcome A writing workspace that can tell you, at export time and from records rather than memory, which parts of a finished document you wrote, which the model wrote, and which instruction and model produced each one. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - OpenAI API key in .env - Node.js 22 - SQLite database ## Explicit non-goals for v1 - 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 ## Success criteria - Editing inside a generated passage is confirmed to mark only the edited part - Span coverage is confirmed complete after every version - A failed validation is confirmed to insert nothing - Past generations are confirmed to resolve to the instruction version used - Export is confirmed to include the computed provenance report
# Build brief · WordHero The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a private writing workspace that keeps a record of which words you wrote and which the model wrote to replace WordHero. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero There is one fact about this category that should shape the schema, and almost no product in it acts on the fact. In the United States, the Copyright Office published Part 2 of its report on copyright and artificial intelligence on 29 January 2025, concluding that outputs of generative AI can be protected only where a human author determined sufficient expressive elements, and that on the technology as it stood, prompts alone do not provide enough human control to make the user of a system the author of its output. Human-authored material that remains perceptible in the output, and creative arrangement or modification of it, are what can carry protection. Other countries answer this differently, so check yours. The design consequence is direct: this workspace records provenance at the level of a passage, not of a document. Every span of text is marked as written by you, generated by the model, or generated and then edited by you, and the marking survives editing and export. That gives you something no chat window can give: a defensible account of what you contributed, produced as a by-product of writing rather than reconstructed afterwards from memory. Two things this app must not do. It must not claim the text is undetectable, original, or safe to pass off, and it must not score text for whether a machine wrote it, because those detectors do not work well enough to accuse anyone with. State the position in the README and leave it alone. ### Stack (fixed, do not substitute) - Runtime: Next.js with TypeScript, running on your own machine, one user · the drafts are yours and there is no reason for them to be anywhere else - Storage: SQLite with documents, versions and provenance spans in one file · the history is the product and it has to survive a crash and a reinstall - Model access: One provider adapter, the model identifier stored with every generation · two models give two results and a draft nobody can explain is a draft nobody trusts - Provenance: Character-offset spans updated on every edit, never recomputed by guessing · a guess about who wrote a sentence is worth nothing at all - Export: Markdown with a provenance report beside it · the report is the thing this build has that a chat window does not ### Data model (create this before Phase 1) - 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. ### Phase 1 · A draft with a history Build: An editor that saves versions rather than mutating a body, with a typed reason for each. Show the version list with a readable difference between any two. Recover an earlier version into a new one rather than by rolling back. Autosave on a timer and on blur, and never lose the in-progress text on a reload. Trap: 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. Done when: Every save appends a version and no existing version body is ever modified, verified in the database after an editing session. A reload mid-edit restores the unsaved text, tested. Restoring an old version creates a new one and leaves the chain intact. The difference view between any two versions is readable and correct on a paragraph that was replaced. Do not build yet: No generation, provenance, instructions or export yet. ### Phase 2 · Which words were yours Build: When a generation is inserted, record a span covering exactly the inserted range with its generation identifier. On every subsequent edit, shift and split spans by the edit's offsets rather than recomputing them from the text. When a user edits inside a model span, mark the touched part as model then edited. Show the provenance as a subtle background in the editor. Trap: 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. Done when: Inserting a generation and then editing one word inside it leaves the edited part marked as model then edited and the rest marked as model, tested with an explicit edit sequence. Deleting across a span boundary leaves both remaining sides correctly marked. Spans always cover the whole document with no gaps and no overlaps, asserted after every version. Typing new text between two model spans produces a human span. Do not build yet: No reusable instructions, cost ceiling or export yet. ### Phase 3 · Instructions you can explain later Build: Named instructions with a body, versioned on edit. A generation stores the instruction identifier and version, the model identifier, the parameters and the token counts. Validate structured output where you ask for it and never insert an unparsed response. Show, next to any generated passage, which instruction version and model produced it. Trap: 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. Done when: Editing an instruction creates a version and past generations still resolve to the wording they used, tested. Every generation stores model identifier, parameters and token counts. A response that fails validation inserts nothing and reports the failure, tested with a fake returning prose. Hovering any generated passage shows the instruction version and model behind it. Do not build yet: No export, cost ceiling or redaction yet. ### Phase 4 · Out of the app, with the record attached Build: Export Markdown, the full version history, and a report listing every passage with its origin, the proportion of the final text that is human, model or model then edited, and the model and instruction versions used. Add a monthly cost ceiling that stops generation and leaves writing working. Offer a redaction pass that warns before a draft containing names is sent. Trap: 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. Done when: Export produces Markdown, the version history and a provenance report whose proportions are computed from spans and sum to the whole document, tested. Reaching the monthly ceiling disables generation with a clear message and leaves editing and export working, tested. The redaction warning fires on a draft containing an obvious name before any request is made. Everything exported reimports into an empty database with spans intact. Do not build yet: Nothing after this. ### Out of scope (and why) - Detecting whether a passage was machine-written, because the available detectors are not accurate enough to accuse a person with and this app would be used to do exactly that. - Search engine ranking features and keyword scoring, which are a different product wearing a writing tool's clothes. - Team workspaces and approval flows, which are what the subscription actually sells and are not a writing problem. - Bulk generation of many articles at once, which produces volume nobody reads and a bill somebody does. ### README must contain - The Copyright Office position on prompts and human authorship with the date and the link, and a note that other countries differ - That provenance is recorded per passage as you write, not reconstructed afterwards, and what the three origins mean - That no claim is made about originality, detectability or ownership of any output - That prompts and drafts leave the machine when you generate, and what the provider's retention policy says - Where the database lives, how to export everything, and how the monthly cost ceiling behaves
# Architecture · WordHero ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Next.js with TypeScript, running on your own machine, one user | the drafts are yours and there is no reason for them to be anywhere else | | Storage | SQLite with documents, versions and provenance spans in one file | the history is the product and it has to survive a crash and a reinstall | | Model access | One provider adapter, the model identifier stored with every generation | two models give two results and a draft nobody can explain is a draft nobody trusts | | Provenance | Character-offset spans updated on every edit, never recomputed by guessing | a guess about who wrote a sentence is worth nothing at all | | Export | Markdown with a provenance report beside it | the report is the thing this build has that a chat window does not | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Documents | Versions and differences. | Any editor, provided saves append rather than mutate. | | Provenance | Spans through every edit. | Not swappable for recomputation by text matching, which does not work. | | Instructions | Named reusable prompts and their versions. | Any store, provided generations pin the version they used. | | Generation | The provider call, validation and token counts. | Any provider, provided a failed response inserts nothing. | | Export | Markdown, history and the provenance report. | Any format, provided the report goes with the text. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DATABASE_PATH` · required · Documents, versions, spans, generations and instructions. This is everything. - `MODEL_API_KEY` · required, secret · The only credential. Give it a provider-side spend limit as well. - `MODEL_ID` · required · Stored with every generation, because a different model is a different result. - `MONTHLY_COST_CEILING` · required · Generation stops here for the month and the editor keeps working. - `REDACTION_WARNING` · required · Warns before sending a draft containing what looks like a personal name. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · WordHero product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Next.js with TypeScript, running on your own machine, one user, SQLite with documents, versions and provenance spans in one file, One provider adapter, the model identifier stored with every generation, Character-offset spans updated on every edit, never recomputed by guessing, Markdown with a provenance report beside it. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - 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. - 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. - 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. - 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.
# Delivery milestones · WordHero Estimated effort: **one sitting** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · A draft with a history Every change to a document produces a version, and nothing is ever overwritten in place. ### Steps 1. Append versions, never mutate a body The history is what makes provenance possible at all. Files: `src/lib/versions.ts`, `tests/versions.test.ts` 2. Autosave without losing in-progress text Losing a paragraph once ends the user's trust in the tool. Files: `src/components/Editor.tsx` 3. Make restore a forward operation Rewinding loses whatever came after, which is the usual regret. Files: `src/lib/versions.ts` ### Done when - [ ] Every save appends a version and mutates nothing - [ ] A reload restores unsaved text - [ ] Restoring creates a new version - [ ] Differences render correctly on replaced paragraphs ### Watch 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. ## M2 · Which words were yours Generated text is marked as generated, and the marking survives being edited. ### Steps 1. Record the inserted range at insertion time It is the only moment the boundary is known exactly. Files: `src/lib/spans.ts` 2. Shift and split spans by edit offsets Never by searching for the text again. Files: `src/lib/spans.ts`, `tests/spans.test.ts` 3. Assert full coverage after every version A gap in coverage is a silent claim of authorship. Files: `tests/spans.test.ts` ### Done when - [ ] Editing inside a model span marks only the edited part - [ ] Deleting across a boundary leaves both sides correct - [ ] Spans cover the document with no gaps or overlaps - [ ] New typing between model spans is marked human ### Watch 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. ## M3 · Instructions you can explain later A reusable instruction is versioned, and every generation records exactly which version produced it. ### Steps 1. Version instructions on edit Otherwise history rewrites itself every time you improve a prompt. Files: `src/lib/instructions.ts`, `tests/instructions.test.ts` 2. Pin every generation to what produced it Model, parameters, instruction version, token counts. Files: `src/lib/generate.ts` 3. Insert nothing on a validation failure A half-parsed response in a draft is worse than no response. Files: `src/lib/generate.ts` ### Done when - [ ] Instruction edits version rather than overwrite - [ ] Past generations resolve to the wording they used - [ ] Failed validation inserts nothing - [ ] Generated passages show their instruction and model ### Watch 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. ## M4 · Out of the app, with the record attached (production only) A document exports as plain Markdown plus a provenance report, and the spend has a ceiling. ### Steps 1. Compute the proportions from spans A claimed percentage is worth nothing; a computed one is evidence. Files: `src/lib/report.ts`, `tests/report.test.ts` 2. Cap the month and degrade to writing The editor should work when the budget does not. Files: `src/lib/cost.ts` 3. Warn before sending a draft with names in it The prompt leaves the machine and the draft is often about somebody. Files: `src/lib/redact.ts` ### Done when - [ ] Provenance proportions are computed and sum to the whole - [ ] The cost ceiling stops generation, not the editor - [ ] The redaction warning fires before any request - [ ] Exports reimport with spans intact ### Watch 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.
# Operations · WordHero ## Backup One database file. Versions and spans are the irreplaceable part: the text can be rewritten, but the record of who wrote which sentence cannot be reconstructed after the fact, which is the entire premise. ## Restore Restore and confirm that span coverage is still complete on the most recent version of every document, and that generations still resolve to their instruction versions. A restore where spans no longer cover the document has lost the provenance even though the text looks fine. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Monthly spend against the ceiling, validation failure rate, and the share of final text marked as model across recent documents. A rising model share is information about how you are working, not a target to move. ## Incident checklist The failure here is a document whose provenance is wrong, which is worse than one with no provenance at all. The coverage assertion after every version is the check that catches it, so keep it in the suite rather than in a script you run sometimes. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Editing inside a generated passage is confirmed to mark only the edited part - [ ] Span coverage is confirmed complete after every version - [ ] A failed validation is confirmed to insert nothing - [ ] Past generations are confirmed to resolve to the instruction version used - [ ] Export is confirmed to include the computed provenance report ## Launch constraint Do not market omitted WordHero capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Documents, versions, spans, generations and instructions. This is everything. DATABASE_PATH=./data/writing.db # Required · secret. The only credential. Give it a provider-side spend limit as well. MODEL_API_KEY=sk-...redacted # Required. Stored with every generation, because a different model is a different result. MODEL_ID=a model identifier # Required. Generation stops here for the month and the editor keeps working. MONTHLY_COST_CEILING=10.00 # Required. Warns before sending a draft containing what looks like a personal name. REDACTION_WARNING=true
$ choose a build depth, inspect the files, then open the complete pack in your agent
WordHero: Customers pay for tuned workflows, predictable quality, governance, and a product team absorbing model churn rather than for the text box alone.
xteam governance and integrations
xvendor-managed prompt and quality tuning
xproprietary models or classifiers
xbrand-trained workflows
Don't feel like building it? These folks already made it free.
all 3 free alternatives to WordHero →· no votes, no pay-to-list · just what's real
WordHero pricing
| plan | monthly | annual (per mo) | what you get |
|---|---|---|---|
| creator | $49 | $29 | 160,000 Enhanced tokens/month; 20 voices; 10 advanced generations/hour; 5 SEO projects; 320 keywords/month; 320 image credits/month. |
| infinity | $99/workspace | $79/workspace | Unlimited Enhanced use subject to fair use; 50 voices; 20 advanced generations/hour; 50 SEO projects; 1,000 keywords/month; 1,000 image credits/month; up to 5 members. |
free tierno free tier; 14-day money-back period
billingmonthly + annual
hidden costsEach image prompt uses 4 image credits. Extra users/credits are add-ons; promotional introductory pricing remains only while the subscription stays active.
verified 2026-08-12 · source ↗
Vibecode WordHero
Yes. A competent AI coding agent (Claude Code, Codex, Cursor) can build a usable personal WordHero replacement in one session with the prompt on this page. It runs on your own machine or server with no subscription.
How much does WordHero cost?
WordHero's pricing is usage-based or varies by plan · The official pricing URL is recorded, but a stable current amount was not safely recoverable in this pass. Do not publish a number until rechecked..
What do I lose by replacing WordHero?
Honestly: team governance and integrations; vendor-managed prompt and quality tuning; proprietary models or classifiers; brand-trained workflows. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to WordHero?
Yes: AnythingLLM (A local-first AI desk with reusable agents, documents, memory, and workflows; less campaign theatre, more settings.) Jan (A desktop local-model writer with reusable assistants and projects; templates are prompts you save yourself.) Open WebUI (A self-hosted AI workbench with saved prompts, knowledge, web search, and multi-model comparison; powerful, not especially house-trained.) All 3 curated free alternatives are at vibecodeit.com/wordhero/alternatives. The prompt is for when you want it exactly your way.