Build HyperWrite
A local drafting workspace whose hard problems are chunking sources so a retrieved passage is actually a unit of support, verifying every generated sentence against the passage it cites instead of trusting the model's own citation, and keeping that verification correct as drafts are rewritten and sources removed.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the application and its test suite.
Get it nodejs.org, or your version manager. open ↗
Verify
node --version prints v22 or higher - API keypay per token; measure a real section before choosing the ceiling
Why Generation and the separate verification pass both go through it, and the verification pass roughly doubles the call count per draft.
Get it Create a key with your chosen provider and set a spend limit in their console as well as the ceiling in this app.
Verify
A section drafts and every sentence receives a support state - have readyfree
Why Chunking and verification both behave differently on a research paper, a transcript and a marketing page, and testing on one of them teaches you nothing about the others.
Get it Assemble the documents for something you actually need to write, including at least one long and one badly formatted file.
Verify
All of them import, chunk and show passages in context - decidefree
Why A flagging rule written after the draft exists is written around the draft, which is the opposite of useful.
Get it Write down the claims this document must never make, in the wording the flagger will match on.
Verify
The list is stored on the project and appears in every generation prompt
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- projects(id, title, audience, objective, tone, prohibited_claims_json, created_at) - sources(id, project_id, kind, title, origin, added_at, sha256, text_path) · kind is pasted, uploaded or fetched once - passages(id, source_id, ordinal, text, char_start, char_end) · the only unit anything is ever allowed to cite - outlines(id, project_id, version, approved_at) and sections(id, outline_id, ordinal, heading, brief) - drafts(id, section_id, version, created_at, model_id, prompt_version, cost_minor) · a rewrite is a new version, never an edit - sentences(id, draft_id, ordinal, text, support_state) · support_state is supported, weak or unsupported - citations(sentence_id, passage_id, verifier_score, verified_at) · a row exists only after the id resolved and the check ran - The model's own numbering never becomes a citation row without passing through resolution and verification first.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
MODEL_API_KEYsecret | required | sk-...redacted | Generation and verification. Give it a provider-side spend limit too. |
MODEL_ID | required | a text model identifier | Stored with every draft, because a different model cites differently. |
VERIFIER_MODEL_ID | required | a smaller text model identifier | The support check. A cheaper model is usually enough for this one job. |
DATABASE_PATH | required | ./data/workspace.db | Projects, passages, drafts, sentences and citations. |
SOURCE_TEXT_DIR | required | ./data/sources | Full original text per source, so a passage can be shown in context. |
CHUNK_OVERLAP_CHARS | required | 200 | Overlap between paragraph-aligned chunks. Changing it re-chunks new sources only. |
SUPPORT_THRESHOLD | required | 0.7 | Verifier score below which a sentence is weak, and lower still is unsupported. |
MONTHLY_COST_CEILING | required | 10.00 | Generation stops here; reading, hand editing and export continue. |
The build, in order
Sources in, passages out
Everything the app will ever cite is a passage with a stable id and an offset into the original text.
A passage should be a unit of support, not a unit of tokens.
Files
src/lib/chunk.tstests/chunk.test.tsContext is what lets a human judge a citation in two seconds.
Files
src/lib/sources.tsA reused id turns a stale citation into a wrong one.
Files
src/db/schema.ts
done when · tick each as it passeswatch out- Chunking purely by token count splits a claim from the qualifier that follows it, so the retrieved passage supports half a sentence and your verifier cheerfully passes it. Chunk on paragraph boundaries, overlap by a configured amount, keep the offsets, and show the surrounding text whenever somebody opens a citation.
Retrieval you can see and correct
The passages that will be used are on screen, editable, before anything is generated.
Otherwise you are debugging the prompt for a retrieval bug.
Files
src/app/project/[id]/retrieve/page.tsxSo a strange draft can be explained instead of argued about.
Files
src/lib/drafts.tsAn ungrounded draft is the thing this app exists to avoid.
Files
src/lib/generate.tstests/generate.test.ts
done when · tick each as it passeswatch out- Hiding retrieval behind a generate button makes a bad draft indistinguishable from a bad model, and you end up rewriting prompts to fix a problem that was three irrelevant passages. Put the retrieved set on screen first, let it be corrected, and store the exact set used with the draft.
Outline first, approval before prose
Nothing is drafted until a section structure with a brief per section has been approved.
Structure is cheaper to change than prose.
Files
src/lib/outline.tsA restructure should not delete yesterday's work.
Files
src/db/schema.tsThe rule is useless if it only lives in the settings page.
Files
src/lib/prompt.tstests/prompt.test.ts
done when · tick each as it passeswatch out- Generating three thousand words and then deciding the structure is wrong wastes the generation and, worse, anchors the rewrite to the shape of the thing you were about to throw away. Approve a structure first, and make the approval a stored fact rather than a click that leaves no trace.
Draft, then check every sentence yourself
Each sentence is resolved against the passage it cited and rendered as supported, weak or unsupported.
The model's numbering is a claim until you check it.
Files
src/lib/resolve.tstests/resolve.test.tsA second pass with one job beats a longer first prompt.
Files
src/lib/verify.tsIt is the first thing the writer needs to know.
Files
src/components/SupportSummary.tsx
done when · tick each as it passeswatch out- Rendering the model's citations as the app's citations gives you a document that looks sourced and is not: the published audit of four generative search engines found only about half of generated sentences fully supported by their citations, and about a quarter of citations not supporting the sentence they were attached to. Resolve every number against your own passage store, verify the sentence against the passage text in a separate call, and let the failures show.
- Dropping the citation from a sentence that failed verification leaves a plain, confident sentence sitting in the draft and removes the only signal that it was doubtful. Keep the sentence, mark it unsupported, and make the unsupported count visible before the writer reads a word of the prose.
Rewrites, deletions and getting outproduct builder
Every rewrite is re-verified, deleting a source updates the document, and everything exports with its support state.
Text and its verification have to move together.
Files
src/lib/rewrite.tstests/rewrite.test.tsA citation to a deleted source is a lie with a tick next to it.
Files
src/lib/sources.tsA rented model with no ceiling is a surprise bill.
Files
src/lib/cost.ts
done when · tick each as it passeswatch out- Rewriting a paragraph in place leaves the old sentence rows attached to new text, so the green ticks now belong to sentences nobody verified, which is worse than having no ticks at all. Make every rewrite a new draft version, recompute sentences and citations before rendering, and never show a draft whose verification has not completed.
- Deleting a source while its citations stay green turns the document into a claim about evidence that is no longer there. Cascade the deletion to support state, show the count of sentences affected, and offer to re-verify against remaining sources rather than silently downgrading everything.
That is the whole plan for HyperWrite. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Live web search during drafting.
- Publishing to a content system.
- A browser extension.
- Team approvals and brand governance.
- browser presence, personalization history, and proprietary agent workflows
- proprietary ranking data
- brand-trained models
- team workflows
- large template libraries
- A quotation mode that inserts verbatim passage text with its offsets, which needs no verification at all
- A per-source support report showing which documents actually carried the argument
- A local embedding model for retrieval, so that nothing but the generation call leaves the machine
Need the files? The project pack on the verdict page hands your agent the whole brief · more ai writing.