Build Jenni AI

YESreplaces $12/mosaves $144/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

Upload your sources, and the assistant drafts sections that quote and cite only those documents, showing which passage supports each sentence, rejecting any output that cites something you did not supply, and exporting to a document with a bibliography built from the sources you actually used.

estimated effort multi-daythe files for this build are in the project pack

RuntimeTypeScript with a desktop shellSourcesPDF and text extraction with page-level positionsRetrievalChunked passages with search over themValidationEvery claim mapped to a passage id, checked before displayExportMarkdown with citations, and a bibliography generated from used sources

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the build and the extraction pipeline.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. decidefree, and it is the first task

    Why Whether assistance of this kind is permitted differs by institution, publisher and assignment, and it is changing. The tool cannot know your rules and the consequence of getting it wrong is yours.

    Get it Read your institution's or publisher's current position on writing assistance, and record what it says and when you read it.

    Verify A policy note is recorded for the project with a date

  3. have readyfree

    Why Extraction, page positions and retrieval are all only meaningful against real papers, which have columns, footnotes and figures that break naive extraction.

    Get it Use the sources for something you are actually writing. Include at least one two column paper and one scanned document.

    Verify At least ten sources import, including a two column paper

  4. API keypay per token; a section is typically a few cents

    Why Phase 3 onward. Import and retrieval work without one, which is deliberate.

    Get it A provider key with a spend limit, or Ollama for a local model where nothing leaves the machine.

    Verify A draft generates and passes validation

  5. decidefree

    Why Styles differ in what fields they require, and discovering a missing field at export is worse than requiring it at import.

    Get it Confirm the required style for your work and which fields it needs.

    Verify The style is configured and its required fields are enforced at source import

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- projects(id, title, style, created_at, policy_note) · policy_note records what you checked about permitted assistance
- sources(id, project_id, path, title, authors, year, doi, added_at, extraction_state)
- passages(id, source_id, page, ordinal, text) · page-level position is what makes a citation checkable
- sections(id, project_id, ordinal, heading, brief)
- drafts(id, section_id, at, model, text, claims_json, validated) · claims_json maps each sentence to passage ids
- revisions(id, draft_id, at, text, author) · your edits, kept separately from generated text
- A sentence with no supporting passage is not written. That is the constraint the whole build enforces.

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.

VariableNeededExampleWhere the value comes from
PROJECT_DIRrequired~/Writing/ThesisSources, drafts and revisions. Your work, in your backup.
MODEL_PROVIDERrequiredlocalWhich adapter. Local means sources never leave the machine.
MODEL_API_KEYsecretoptionalsk-...Only for a hosted provider. Consider whether your sources may be sent to one.
CONTEXT_TOKEN_BUDGETrequired8000Maximum assembled passages per generation.
CITATION_STYLErequiredapaDrives required bibliographic fields and export formatting.
MIN_PASSAGES_TO_GENERATErequired3Below this, generation refuses rather than drafting from thin context.

The build, in order

  1. Sources with checkable positions

    An uploaded document becomes passages that each know their page.

    1. Page number preserved per passage. A citation without a page cannot be checked.

      Files src/extract.ts

    2. Prefilled from metadata as a suggestion, confirmed by you, with unconfirmed fields marked.

      Files src/sources.ts

    3. No text layer means no passages. Say so rather than importing an empty source.

      Files src/extract.ts

    done when · tick each as it passes
    watch out
    • Guessing bibliographic details from a PDF's metadata or its first page is wrong often enough to matter, and a reference list with a wrong year is a real problem in academic work. Ask for the details, prefill from metadata as a suggestion, and mark anything unconfirmed.
  2. Retrieval over your sources only

    The model sees passages from your documents and nothing else.

    1. Search your passages, rank, take until the budget is reached.

      Files src/retrieve.ts

    2. The actual passages. You are about to be responsible for whatever is written from them.

      Files src/ui/ContextPreview.tsx

    3. No relevant passages means no draft. Generating anyway is where fabrication starts.

      Files src/retrieve.ts

    done when · tick each as it passes
    watch out
    • A model asked to write on a topic will draw on its training data whether or not you gave it sources, and the result reads identically. Supplying only your passages narrows what it can say, but the validation in the next phase is what actually enforces it, so build both.
  3. Drafts where every sentence is attributable

    Each generated sentence names the passage that supports it, and one that cannot is not shown.

    1. Structured output with a passage identifier per sentence, so parsing is not a regular expression.

      Files src/generate.ts

    2. A pure function, unit tested with a crafted bad reference rather than waiting for a model to produce one.

      Files src/validate.tssrc/validate.test.ts

    3. One bad sentence rejects the draft. Partial acceptance is how unsupported claims survive.

      Files src/generate.ts

    done when · tick each as it passes
    watch out
    • Stripping an unsupported sentence and showing the rest teaches you to trust the output, and the next unsupported sentence will be one the validator missed. Reject the draft, show why, and regenerate, so trust attaches to the process rather than to individual sentences.
  4. Your writing and its writing, kept apart

    You can always see what was generated and what you wrote.

    1. Generated text is revision one. Your edits are later revisions. The chain answers the question.

      Files src/revisions.ts

    2. Per section. Visible, because hiding it is the same as not tracking it.

      Files src/attribution.ts

    3. To any revision. Editing without a way back makes people cautious rather than productive.

      Files src/revisions.ts

    done when · tick each as it passes
    watch out
    • Once generated text is edited in place, the boundary disappears and you cannot answer what was written by whom, which is exactly the question an institution or a coauthor may ask. Keep the generated text as a revision and your edits as later revisions, so the history answers it.
  5. Bibliography from what was actually cited

    The reference list contains every source you used and nothing you did not.

    1. Walk the citations, collect their sources. Not the upload list and not the model's output.

      Files src/bibliography.ts

    2. Unconfirmed details block the export rather than producing a plausible wrong reference.

      Files src/styles.ts

    3. Useful information rather than an error, and it belongs in the report rather than the bibliography.

      Files src/report.ts

    done when · tick each as it passes
    watch out
    • A reference list built from everything you uploaded includes sources you read and did not use, which is wrong in most styles, and one built from the model's output includes whatever it invented. Build it from the passages actually cited, which is the only list that is both complete and true.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more ai writing.