Build Scholarcy
KINDAback to the verdict
A paper processing tool where extraction is the hard engineering and honesty is the hard design: parsing academic documents whose layout defeats naive extraction, pulling out references and figures correctly, and producing summaries whose every claim can be traced to a sentence.
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 extraction and processing.
Get it python.org or your package manager, then a virtual environment.
Verify
python3 --version prints 3.12 or higher - installfree
Why Reading order across columns is the first problem and a plain text extractor has already lost the information needed to solve it.
Get it A library exposing text with coordinates and block structure.
Verify
A two-column paper extracts with per-block positions - have readyfree for open access
Why Extraction, citation parsing and section detection all break differently across venues, and a single publisher's template proves nothing.
Get it Papers from at least four venues, including one with unusual section headings, one heavy with tables, and one animal study.
Verify
Ten papers from four or more venues are available locally - installfree, needs memory
Why Papers may be licensed or unpublished, and uploading a colleague's preprint to a service is not a decision to make casually.
Get it A local runner with a model that returns structured output reliably for extraction tasks. open ↗
Verify
Ten extractions return valid structured output with quotes - have readyfree
Why Summary honesty cannot be evaluated on papers you have not read, and the failure mode is a summary that sounds right and drops a qualification.
Get it Pick three you could summarise yourself, including one whose main finding is heavily hedged.
Verify
You can state each paper's main finding and its qualifications before running the tool
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- papers(id, path, title, authors_json, year, doi, venue, extracted_at) - sections(id, paper_id, ordinal, kind, heading, text) · kind is abstract, methods, results, discussion or other - claims(id, paper_id, section_id, text, quote, char_start, char_end, claim_kind) · claim_kind is finding, method or limitation - qualifiers(claim_id, sample_size, population, hedging, effect_size, interval) · extracted, not paraphrased - references(id, paper_id, ordinal, raw, parsed_json, doi, resolved) · the bibliography, parsed - figures(id, paper_id, kind, caption, page, bbox_json, image_path) - cards(id, claim_id, front, back, created_at) · study cards, generated only from cited claims - A claim without a quote and a character range cannot be stored, which is enforced by the schema rather than checked afterwards.
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 |
|---|---|---|---|
PAPERS_DIR | required | ./papers | Source documents, read only. |
DB_PATH | required | ./library.db | Extracted structure, claims and citations. |
EXTRACTION_MODEL | required | local | Local, since papers may be licensed or unpublished. |
REQUIRE_QUOTE_PER_CLAIM | required | always | Present as a constant. A claim you cannot quote is one you should not make. |
SHOW_QUALIFIERS_INLINE | required | always | Alongside the claim rather than beneath it. Position is what gets read. |
ALLOW_NETWORK | required | never | Present as a constant. Papers do not need to leave the machine. |
The build, in order
Getting the text out of a paper
A two-column paper with figures parses into ordered sections.
Crossing columns produces plausible nonsense that poisons everything after.
Files
src/extract.pytests/test_reading_order.pyThey interrupt sentences and belong to different objects.
Files
src/structure.pyHeadings vary by venue. Fall back rather than failing.
Files
src/sections.py
done when · tick each as it passeswatch out- Naive extraction reads a two-column paper by crossing both columns on every line, producing text that is grammatically plausible and semantically scrambled, and every downstream step then operates on nonsense. Reconstruct columns first and verify against a paper you can read.
References parsed and resolvable
The bibliography becomes structured entries you can follow.
A parser tuned on one venue mangles another silently.
Files
src/references.pyA bibliography missing a third of itself looks complete.
Files
src/references.pySo a claim's support can be followed.
Files
src/citations.py
done when · tick each as it passeswatch out- Citation styles vary enough that a parser tuned on one venue silently mangles another, and dropping the entries it cannot handle leaves a bibliography that looks complete and is missing a third of itself. Report unparsed entries with their raw text so the gap is visible.
Claims that quote the paper
Every extracted claim carries the sentence it came from.
Not validated afterwards. Unstorable rather than discouraged.
Files
src/schema.sqlIn the suite, against the stored document.
Files
tests/test_quotes_resolve.pyA limitation and a finding are read very differently.
Files
src/claims.py
done when · tick each as it passeswatch out- A summary that paraphrases without quoting cannot be checked, and the paraphrase is exactly where hedging and qualification get lost. Store the quote and its position, and make an unquotable claim impossible to store rather than merely discouraged.
Keeping the hedges and the population
A finding never loses the conditions it was found under.
Paraphrase destroys these first and silently.
Files
src/qualifiers.pyAlongside, not beneath. Position is what gets read.
Files
src/render.pyMissing qualifiers is information, not something to hide.
Files
src/claims.py
done when · tick each as it passeswatch out- Paraphrasing destroys hedging first, so an association observed in forty mice becomes a statement that the thing works, and the reader has no signal that anything was dropped. Extract the qualifiers as fields, show them alongside, and mark a claim whose qualifiers are missing as incompletely characterised rather than presenting it bare.
Summaries and cards that stay honestproduct builder
Every line of output can be traced back to the paper.
Never from the summary. Citations are lost one step at a time.
Files
src/summarise.pyReject the whole output otherwise.
Files
src/validate.pytests/test_mapping.pyA flashcard with no source is what gets believed years later.
Files
src/cards.py
done when · tick each as it passeswatch out- Generating study cards from the summary rather than from the claims loses the citations one step at a time, and a flashcard asserting a finding with no source is exactly the artefact that ends up being believed years later. Generate from claims, and carry the citation onto the card itself.
That is the whole plan for Scholarcy. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Any judgement of study quality.
- Access to papers you do not have.
- Cross-paper synthesis or meta-analysis.
- Replacing reading the paper.
- licensed scholarly metadata
- publisher-specific import reliability
- citation graph scale
- team libraries and institutional access
- Figure and table extraction as data rather than images, which is where a lot of the findings live
- A reading queue ordered by how much a paper's claims bear on your own question
- Following a citation into a paper you also hold, which is where a library starts compounding
Need the files? The project pack on the verdict page hands your agent the whole brief · more read it later.