Six products, and none of them talk.
Every one of these is good at its job. The problem is not any of them — it is that the thread between them only ever existed in your head, and you are going to need it in two years.
Research — a nine-month thesis, a four-year PhD, a postdoc that outlives both — is reading, runs and decisions scattered across six tools that each forget the other five. WeaveForge is the one workspace that keeps the thread, so the paper you read in week three is still attached to the run it inspired and the section it ends up in.
Every one of these is good at its job. The problem is not any of them — it is that the thread between them only ever existed in your head, and you are going to need it in two years.
Papers arrive with their metadata, annotations and tags — and stay attached to everything they touch.
A markdown vault with wikilinks, where an excerpt is a real object pointing back at page four of the PDF.
Milestones that carry dependencies and compute estimates, and know which note they came out of.
Runs land in the same database as the paper they implement, pinned to the branch and commit that produced them.
The outline is the project. Figures and citations are already resolved, so the LaTeX export needs no fixing.
Your collaborators open the object itself — the run, the section, the paper — scoped by the database.
One database, one graph, one export. Not six tools with integrations bolted between them — one workspace where the paper, the note, the run and the section are rows that know about each other.
The writing is the last stretch. The thinking is everything before it — a term or a decade — and almost none of the tools involved were built to keep that part.
“Why did you rule that out?”
You had a good reason early on. It was a margin note in a PDF, or a message to yourself, or nowhere at all. Someone asks two years later — a supervisor, a reviewer, the version of you writing the paper.
excerpts and notes stay attached to the paper
“Which run produced that number?”
The figure is in your draft. The number is in the caption. The code that made it has been rewritten twice and you are no longer certain which commit it was.
runs are pinned to branch and commit
“Hasn’t someone already done this?”
You read it near the start. You remember the shape of the argument and not the title, and it is somewhere in four hundred PDFs.
typed relations and a searchable graph
“Send me an update.”
So you screenshot a chart, paste a paragraph, and describe the rest from memory — every fortnight, for as long as the project runs.
share the objects themselves
Every other research tool holds one link of that chain and loses the rest at its boundary. Here is one paper from a real project, all the way through.
papers
vault
“…a single hyperparameter β that balances latent channel capacity against reconstruction accuracy.”
Does β survive a structured prior? Locatello argues unsupervised disentanglement is impossible without inductive bias — a graph prior is exactly that bias. See [[Variational Graph Auto-Encoders]].
plan
experiments
report
We extend the capacity-constrained objective of [[β-VAE]] with a graph prior over latent factors, reaching val_loss 0.1826 at β=4.
Imported from a DOI in one paste. Metadata, abstract and your Zotero annotations arrive with it, tagged and dropped into a reading list.
The excerpt is an object, not text stranded in a PDF. You quote it in a vault note, disagree with it, and that note stays attached to the paper.
Milestones carry dependencies and compute estimates, so the plan already knows this one cannot start until the baseline lands.
One decorator in the training script. The run lands in the same database as the paper it implements, pinned to the branch and commit that produced it.
The outline is the project. The figure and the citation are already resolved, so the LaTeX export does not need you to fix a single reference.
One library, one graph, and a reference manager that stays in sync instead of being replaced.
graph
A URL, an arXiv ID, a DOI, or your whole Zotero library. Metadata, abstract and annotations arrive together, tagged and dropped into nested reading lists.
Tags are nodes in their own right, so the graph shows how a method you borrowed from one literature reaches the one you are writing in.
cites, extends, contradicts, builds on, uses method. A contradiction you recorded once is still visible the week you write the related work.
Semantic Scholar watches what you track and flags new work citing it — including work that cites you.
A PDF reader inside the workspace, where every highlight carries its page locus, its use in your argument, and the section it is destined for.
reader · Vaswani et al., 2017 · arXiv:1706.03762
Fetching the paper from arXiv…
reader · higgins et al. · annotations
annotation types
report · pinned excerpts
“…balances latent channel capacity against reconstruction accuracy.”
zotero · write-back
The PDF opens in the workspace, beside the library and the graph. Your Zotero annotations are already there, and anything you highlight here is a first-class row rather than a scribble in a viewer’s private store.
Every annotation stores both the rectangles and a text locus. Re-download the PDF, get a different build of it, and the highlight still lands on the sentence it was about.
Direct quote, paraphrase, or summary — the Citavi taxonomy, chosen at reading time. At writing time that one field is the difference between citing it correctly and re-reading the paper.
An excerpt can be placed in a report section the moment you meet it, and it syncs to a vault note as well. When you write that section, the evidence is already sitting in it, with the citation resolved.
Write-back is tracked per annotation — local, synced, pending, conflict. Zotero stays the reference manager it already is for you; nothing is trapped here.
Tracking that lives beside the literature and the plan, instead of in a third place you reconcile later.
train.py
from weaveforge import track_experiment
@track_experiment(
name="β-VAE sweep — seed 42",
paper="higgins-2017-bvae",
config={"beta": 4, "seed": 42},
)
def train(run):
for epoch in range(50):
run.log(epoch=epoch, val_loss=step())experiments · git pin
experiments · live
experiments · compare
report · figures
@track_experiment in your training script, and the run lands in the same database as the paper it implements. There is no separate tracking service to keep in sync.
Branch, commit hash and config travel with the run, so a number in your paper can always be traced back to code that actually existed.
run.log() streams metrics into the workspace, so the curve moves as the job does — in the same screen as the paper the run implements, not in a dashboard on a second monitor.
Overlaid curves and a comparison table, beside the papers the runs came from. Lightning and Keras callbacks ship with it, and TensorBoard or W&B histories import rather than re-run.
Attach a run to a report section and its curve exports with the LaTeX — same numbers, no screenshot round trip.
Sections carry status and word targets. When it is time to submit, the whole thing exports as LaTeX with the bibliography already resolved.
report · outline
Dependencies and compute estimates live on the milestone, so the plan understands that the graph-prior module cannot start until the baseline lands.
Type [[ or @ and pick the paper. It resolves to a real citation on export, not a string you have to go back and fix.
Export the outline as a LaTeX project with \cite{} keys, the .bib and your figures — or keep a linked Overleaf document in sync.
Dated markdown entries with hours and mood. It is the thing you will be grateful for when you write the methods up months after the fact.
Collaboration is a permission on a row, not a second product bolted on the side.
people · vision-group
shared · with dr. m. haddad
postgres · row-level security
-- the access boundary is the database,
-- not a check inside a screen
create policy paper_read on papers
for select using (
user_id = auth.uid()
or exists (select 1 from shares s
where s.object_id = papers.id
and s.grantee = auth.uid())
);standalone
A professor creates the lab and hands out three invite codes — professor, PhD, Master’s. Joining takes one paste. No IT ticket, no admin console to learn.
Share a paper, an experiment, a report section, or a whole type. Your labmate pins it into their own library, comments on it, and co-edits where you granted that.
Postgres row-level security is the access boundary, not application code. Owner-or-shared is enforced where the data lives, so a bug in a screen cannot leak a row.
Standalone is a first-class path: the entire product with the collaboration surface out of the way. Data is encrypted at rest but not end-to-end — the docs say so plainly.
Six commands from a fresh checkout to a running workspace on your own machine.
~/weaveforge
$ git clone https://github.com/Satwik-Miyyapuram/weaveforge.git $ cd weaveforge $ npm install $ npm run build:core $ npm run test:core # 460+ domain tests, no network $ npm run dev # → http://localhost:3000
AGPL-3.0-only, and it stays that way. Anyone who takes it and hosts a better version has to publish their source, so the work flows back rather than away.
No capability is ever hosted-only. Self-hosting is not a stripped tier — it is the same product with your name on the database.
Supabase or a plain self-hosted Postgres. The schema lives in the repo as migrations, and both the web app and the Python SDK talk to it.
A framework-agnostic core with repository contracts and shared test suites, so the domain logic is testable without a browser, a network or a database.
Create a project, import the last thing you read, and see where it goes. Nothing to migrate, nothing to configure, and the export is yours whenever you want it.
Nothing here is a bad tool — most of them are on this page because they are the best at what they do, and WeaveForge syncs with several rather than replacing them. The gap is that research is the whole chain, and the joins between tools are exactly where the reasoning falls out.
| What research needs | WeaveForge | Zotero | Obsidian | Notion | W&B | Overleaf |
|---|---|---|---|---|---|---|
| Reference library & metadataimport by DOI, arXiv, URL or whole Zotero library | yes | yes | partly | no | no | partly |
| PDF reading with durable annotationslocus anchors, quotation types, Zotero write-back | yes | yes | partly | no | no | no |
| Excerpts as objects you can argue withan excerpt links to its paper, its note and its section | yes | partly | partly | no | no | no |
| Markdown vault with wikilinksnested pages, backlinks, images | yes | no | yes | partly | no | no |
| Typed relations between paperscites, extends, contradicts, builds on, uses method | yes | no | no | no | no | no |
| One graph over papers, notes, tags and sectionsnot a graph of files — a graph of the work | yes | no | partly | no | no | no |
| Plan with dependencies and compute estimatesmilestones that know what blocks them | yes | no | partly | yes | no | no |
| Experiment trackingone decorator, Lightning and Keras callbacks | yes | no | no | no | yes | no |
| Live metrics while a run is goingcurves stream in beside the paper the run implements | yes | no | no | no | yes | no |
| Runs pinned to branch and commita number in a paper traces back to code that existed | yes | no | no | no | yes | no |
| Run → figure → section, without a screenshotthe figure exports with the LaTeX | yes | no | no | no | no | partly |
| LaTeX export with the bibliography resolvedoutline, .bib, figures, \cite{} keys | yes | partly | partly | no | no | yes |
| Collaboration: share objects, not screenshotspapers, runs and sections, scoped per person | yes | partly | no | yes | partly | yes |
| Access enforced by the databasePostgres row-level security, not a check in a screen | yes | no | no | no | no | no |
| Self-hostable, all of itAGPL-3.0-only · no hosted-only capability | yes | partly | partly | no | partly | partly |
● covered◐ partly, or via a plugin○ not its job