From lab data to PDF in 1.3 seconds. Change a number: the figure, the fit and the text follow.
Every step above ran for real: the commands, their output and timings, and each page of the PDF. Regenerate it with uv run python tools/make_readme_gif.py.
Status: alpha. The latest release is v0.5.0: tables, five templates, a choice of typeface and engine, Excel files, a lab compound library, references from a DOI, protected raw data and
eject, and most of the modular core of v1.5: a package for any field (labharness new-domain) andlabharness openin VS Code. See Progress for what is done and what is next.
LabHarness is a local-first, open-source (MIT) harness for scientific writing and lab-data automation — Data-to-Paper. Change a data point or a SMILES string, save, and the figure and the PDF update on their own. The pipeline is always short, readable Python you can open and edit, never a black box.
What makes it more than a tool for one lab is its architecture: a small core, and a module for each field. Build one, or ask for one and put a price on it.
The problem we solve
A measurement changes. Today that means opening the graphing program, redrawing the figure, exporting it, pasting it into the manuscript, retyping the number in the text and compiling. Then a co-author asks for one more correction and you do it all again, and by the fourth version nobody is sure which figure goes with which data.
In LabHarness the figure is a script that reads the data file. The figure, the fit and the number in the text all come from that one file, so changing it changes all three.
One core, a module for every field
LabHarness is two things. A core that turns raw data into a document and keeps the PDF in sync, and modules, one per field, that know how to read that field's data and draw it. Chemistry, plots, tables and diagrams are modules. Your field is a module too, and LabHarness never has to change for it: a test guards that the core does not depend on any of them.
| You want | What you do |
|---|---|
| To use one | Chemistry, plots, tables and diagrams come with LabHarness; install only the ones you use |
| To build one | labharness new-domain architecture writes a package ready to fill in, with its tests passing. How it works |
| To ask for one | Open an issue with the module request form: the figure you make today and what the data looks like. If the maintainer finds it worth doing, he does it, free |
| To put a price on it | Anyone can put a bounty on a request, and anyone can claim it: the maintainer or another developer. How bounties work |
The modules that exist today
| Module | For | It draws | Install | Specification |
|---|---|---|---|---|
chem |
Chemistry | Structures from SMILES, offline name resolution (OPSIN), the lab compound library | chem, plus iupac and library |
Usage, the library, source |
plots |
Any experimental science | Regressions and plots with error bars, from CSV or Excel | plots |
Usage, source |
tables |
Any field | Editorial tables from any delimited file or workbook, with values and uncertainties rounded together | (none: it ships with the core) | Usage, source |
diagrams |
Any field | Reaction mechanisms, flowcharts and networks in TikZ and chemfig | (none: it ships with the core) | Usage, source |
They ship inside LabHarness, so there is nothing else to download: install the extras you use. No module by anyone else is listed yet. When one is published, it is added to this table with a pull request, and yours can be the first.
A module brings what the field needs and nothing else: its own kinds of figure for
labharness add, its own rules for AI agents, its own commands and its own tests. It is a
package of its own, so it is published and maintained by whoever wrote it.
How fast is it
From saving a file to seeing the PDF, measured on the author's laptop (Windows 11, MiKTeX) with the watcher running, on a document using the ACS template:
| You change | Figure | LaTeX | Total |
|---|---|---|---|
| A measurement in a CSV | 0.20 s | 1.1 s | 1.3 s |
| A SMILES string | 0.05 s | 1.05 s | 1.1 s |
| A reaction mechanism | 3.1 s | 1.0 s | 4.1 s |
| The text of the manuscript | — | 0.85 s | 0.85 s |
Two things make that possible. Figure scripts run inside the watcher process, so a rebuild never pays again for starting Python and importing RDKit or Matplotlib: the same figure takes 1.8 s from a cold start and 0.2 s once the watcher is up. And when only a figure changed, LaTeX needs a single pass, which is what it gets. A full build runs BibTeX only when the citations or the bibliography changed, and another pass only when LaTeX asks for one.
What is left is LaTeX itself, and mechanisms drawn with chemfig, which are slow to compile.
See what it produces in the gallery: the demo, and every template.
Who it is for and potential consummers
Researchers, PhD students and science students even big lab groups who already write in LaTeX or Overleaf and are comfortable with a terminal and an editor such as VS Code or Zed.
Today it asks a lot of you: a terminal, a few installs, and LaTeX. That is the price of the first
versions, and it is meant to go down. We intend to ship a standalone installer that carries its own
Python, so there is no uv and no environment to set up, and, in v2.0, a desktop application for
people who do not use a terminal. See the roadmap.
And anyone who works in another field and would like LabHarness to speak it: that is what the modules are for.
How it works
data/ scripts/ figures/ tables/ paper.pdf
raw measurements ----> transparent scripts ----> vector figures ---> your manuscript
.csv .xlsx .smi .py and .tex and LaTeX tables
labharness.toml says which script uses which data
labharness watch reacts to every save and rebuilds only what changed
Principles
- Local-first. Everything runs on your machine. The one command that goes online,
labharness cite, does so only when you run it. - Human-in-the-loop. Figures come from scripts you can read, tweak or take over entirely.
- Zero layout friction. One typeface for the whole document, figures included, generated at their final printed size so nothing is ever rescaled.
- Save and see. No manual regeneration step.
- Modular. Install only the domains you use.
Requirements
| What | Why | Notes |
|---|---|---|
| Python ≥ 3.11 | The harness | Developed on 3.12 |
| uv | Environment and lockfile | pip install . also works |
| A LaTeX distribution | Compiling the document and the diagrams | MiKTeX or TeX Live/MacTeX. Perl and latexmk are not needed |
| A PDF viewer that does not lock files | Live reload | SumatraPDF (Windows), Skim (macOS). Adobe Acrobat will not work: it locks the PDF |
| VS Code (optional) | labharness open: the manuscript, the watcher and the PDF in one window |
With the LaTeX Workshop extension. Not needed for watch |
| Java (optional) | IUPAC name resolution with OPSIN | Only for the iupac extra |
Install
1. The requirements
Windows
winget install astral-sh.uv
winget install SumatraPDF.SumatraPDF
winget install MiKTeX.MiKTeX # or TeX Live
winget install Microsoft.VisualStudioCode # optional, only for `labharness open`
winget install EclipseAdoptium.Temurin.21.JDK # optional, only for the iupac extra
macOS
brew install uv
brew install --cask mactex # or basictex for a smaller install
brew install --cask skim
brew install --cask temurin # optional, only for the iupac extra
Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
sudo apt install texlive-full # or a smaller scheme plus achemso, chemfig and standalone
sudo apt install default-jre # optional, only for the iupac extra
Any PDF viewer that reloads on change works: Okular and Zathura both do.
2. LabHarness
git clone https://github.com/AIAYN-creator/Lab-Harness.git
uv tool install --editable "./Lab-Harness[all]"
uv tool update-shell
That puts the labharness command on your PATH, so you can type it in any folder. Run
uv tool update-shell once and open a new terminal; then check the machine:
labharness doctor
labharness doctor checks the requirements above and tells you exactly what is missing and
how to install it. To update LabHarness later, git pull in the clone: it is installed in
editable mode, so nothing else is needed.
pip install labharness will work once the package is on PyPI; until then, the clone is the way.
If you want to work on LabHarness itself, see docs/onboarding.md.
Install only what you need, by replacing all in the command above:
| Extra | Brings | For |
|---|---|---|
| (core) | CLI, watcher, style, TikZ diagrams | Always |
chem |
RDKit, SVG to PDF conversion | Chemical structures |
plots |
NumPy, SciPy, Matplotlib | Regressions and plots |
iupac |
OPSIN (needs Java) | Names to SMILES |
excel |
openpyxl | Reading .xlsx workbooks |
library |
chem and excel |
The lab compound inventory |
all |
Everything above | — |
Quickstart
In a terminal:
labharness init my-paper --journal acs
cd my-paper
labharness add structure catalyst --input data/catalyst.smi --insert
labharness open
labharness open opens VS Code with the manuscript, the watcher running in its terminal and, when
you click the preview icon, the PDF beside it. (It needs VS Code and its LaTeX Workshop extension;
labharness doctor tells you if they are missing. The first time, VS Code asks to allow the
automatic task: say yes.)
Now open data/catalyst.smi, change the SMILES string and save. The structure is redrawn and the
PDF reloads, with the timings printed in the watcher's terminal. Closing VS Code stops everything.
Without VS Code: run labharness watch instead of labharness open, in the same folder, and
use any PDF viewer that reloads on change. Type q and press Enter to stop it.
Commands
All of these work today.
| Command | What it does |
|---|---|
labharness init [PATH] [--journal NAME] [--font NAME] [--field NAME...] |
Create a workspace from a template (acs, elsevier, rsc-draft, article or report), optionally with a typeface, and with the agent rules of each field you work in |
labharness add <kind> <name> [--input FILE...] |
Add a figure or a table: writes the script and the manifest entry, and with --insert the LaTeX |
labharness build [--only NAME] [--no-latex] |
Rebuild figures and compile the PDF once |
labharness new-domain NAME [--path DIR] |
Start a package for a field: modules, figure templates and agent rules, ready to fill in |
labharness open [--pdf left|right] |
Open the workspace in VS Code: the manuscript, the watcher in its terminal and the PDF beside it |
labharness watch [--no-open] [--debounce MS] [--json] |
Watch, rebuild and recompile on every save; with --json, tell it as events for an editor or a script |
labharness preview [--only NAME] [--document] |
Render figures (and the pages of the PDF) as PNG, to review them by eye |
labharness resolve NAME -o FILE |
A compound of the lab library, or an IUPAC name, to SMILES, offline |
labharness library check |
Review the lab compound library: unreadable SMILES, missing stereochemistry, wrong formulas |
labharness accept FILE |
Accept a change to a raw data file, recording who, when and what it replaced |
labharness hook install |
Install the git hook that refuses unaccepted changes to raw data |
labharness eject TARGET |
Copy the workspace into one that rebuilds without LabHarness |
labharness cite DOI |
Add a work to references.bib from its DOI, and print the \cite{...} for it |
labharness doctor |
Check the environment and print the command that fixes each problem |
How to use each command, the manifest and the file formats: docs/usage.md
· Every option of every command: docs/cli.md
The workspace
my-paper/
├── paper.tex # Your manuscript, from the journal template you chose
├── labharness-style.tex # Typography and figure helpers: the only place fonts are set
├── labharness.toml # Manifest: which script builds which figure, from which data
├── labharness.lock # Fingerprints of the raw data: a change is reported until accepted
├── data/ # Raw measurements. Never modified by the tool
├── figures/ tables/ # Generated vector PDFs and LaTeX tables. Never edited by hand
├── scripts/ # Transparent scripts, one per figure or table
├── references.bib
├── AGENTS.md # Rules for AI agents, for every field
├── AGENTS.chemistry.md # ...and those of each field you chose with --field. CLAUDE.md imports them
├── .claude/settings.json # Stops Claude Code from writing to data/ or accepting data changes
└── compile.sh compile.ps1
A script is short enough to read at a glance:
# figures/catalyst.pdf -- structure of the catalyst
from labharness.modules.chem import render_structure
render_structure(smiles_file="data/catalyst.smi", output="figures/catalyst.pdf")
And the manifest says what depends on what:
[[figure]]
output = "figures/catalyst.pdf"
script = "scripts/catalyst.py"
inputs = ["data/catalyst.smi"]
Tables
A table is written in LaTeX exactly as it was given, and changed only when you ask:
# tables/optimisation.tex -- optimisation of the reaction conditions
from labharness.modules.tables import read_table, write_table
table = read_table("data/optimisation.csv") # CSV, TSV, TXT or .xlsx, every cell as written
table = table.with_uncertainty("ee (%)", "ee_err") # 92 ± 1, rounded together
table = table.round(significant=2, columns=["conversion (%)"])
write_table(table, "tables/optimisation.tex")
Numbers go in siunitx columns aligned on the decimal mark, with booktabs rules and notes under the table. Rounding is decimal, so 2.675 to two places is 2.68, not the 2.67 of floating point.
Data and references
- One reader for every file, plots and tables alike. It reads what old instrument software
writes (UTF-16, the Windows encoding,
;and decimal commas, metadata above the header) and Excel workbooks, and never guesses in silence: a bad cell stops with its file, line and column. - Axis labels from the header: a column called
t (min),t [min]ort / mingives its axis the label t (min). A header without a unit is refused, not drawn without one. - The lab's compound library: an inventory exported from Access or Excel, named in the
manifest.
labharness resolve CAT-7Bandrender_structure(compound="CAT-7B", ...)use it, andlabharness library checkflags chiral compounds without stereochemistry and formulas that do not match their SMILES. Nothing in the inventory is ever changed. - References from a DOI:
labharness cite 10.1016/...adds the work toreferences.biband prints the\cite{...}for it.
Typography
One typeface for the entire document — text, axis labels, atom labels, mechanisms — defined once
in labharness-style.tex. Latin Modern by default; TeX Gyre Termes, TeX Gyre Pagella, STIX Two
and Libertinus with font = "..." in the manifest. The LaTeX engine is pdflatex by default,
or xelatex and lualatex with engine = "...". Figures are generated at their final printed
size and included without scaling, so 8 pt in a figure is 8 pt on paper, and each structure is
drawn as large as the column allows.
Progress
v0.1 — released (0.1.0). Chemical structures (RDKit), mechanisms and diagrams (TikZ/chemfig), regressions and plots with error bars (SciPy/Matplotlib), the watcher, the ACS template and offline IUPAC name resolution.
v0.5 — daily use, released (0.5.0). The goal was a chapter of the author's thesis with every figure and table generated by LabHarness. Two items below are still open.
-
addandpreview - Editorial tables from any delimited file, with correct rounding and uncertainties
- Agent rules for every field, and for chemistry
- Raw data protected: fingerprints,
accept, a git hook and Claude Code deny rules -
eject: a copy that rebuilds without LabHarness - Reading instrument exports: encodings, separators, decimal commas, metadata rows, units in the header, and Excel
- A lab compound library, so a figure can use the compound's in-house code
- Tables rebuilt by the watcher, and
labharness add table - Data errors that name the row and column, without stopping the watcher
- Fitted values and uncertainties rounded together, the same way in the text and in tables
- Tested against real exports from the lab's instruments
- Chromatograms and spectra from any instrument's export, with integration windows
- A real document built with it: the checkpoint that closes v0.5
v1.0 — public release, in progress.
- Templates: Elsevier, an RSC working layout, and A4
articleandreportfor lab work - Five typefaces and three LaTeX engines
- A full LaTeX build without Perl
- CI on Linux, Windows and macOS; protected
mainand release tags; security alerts -
doctorprints the exact command that fixes each problem -
init --journal ... --font ... - A test that every journal and typeface combination embeds a single typeface
- Publishing to PyPI, so
pip install labharnessworks (the workflow and the steps indocs/RELEASING.mdare ready; the account is not) - A demo GIF at the top of this README
- A gallery of the demo and every template
-
labharness cite DOI - A full command reference, generated from the command line
v1.5 — modular, in progress. Anyone can build a package for their field without touching the core.
- Domains registered as packages: their modules, the kinds of figure
addoffers and their agent rules, found through entry points, LabHarness's own included -
init --field, repeatable, for work that spans fields -
labharness watch --json: what the watcher does, as events - A domain package tested end to end, and a test that the core imports none: a domain can also add commands
-
labharness new-domain NAME: a package for a field, ready to fill in -
labharness open: VS Code with the manuscript, the watcher and the PDF beside it, on either side, withdata/read-only (VS Code and its LaTeX Workshop extension are needed for it) - A guide to building a module, and bounties for the ones others ask for
- First domains, in the order demand sets: economics, mathematics, construction
- Bar charts and heat maps; PubChem behind
--online
Nothing here is dated: see docs/ROADMAP.md.
v2.0 and beyond — the end goal: a desktop application, for people who do not use a terminal, and the lab library read straight from a SQLite database, without exporting it.
Roadmap
| Version | Focus |
|---|---|
| v0.1 | Demo-ready MVP |
| v0.5 | Daily use: editorial tables, agent rules, protected data, lab compound libraries |
| v1.0 | Public release: more templates, selectable typeface, PyPI |
| v1.5 | Modular: anyone builds a package for their field; a working environment with manuscript, console and PDF |
| v2.0 | The end goal: a desktop application, for people who do not use a terminal |
See docs/ROADMAP.md for the detail.
Contributing
Issues and pull requests are welcome, and so are modules for other fields: build one,
or ask for one. See CONTRIBUTING.md and the
Code of Conduct. If you want to work on LabHarness itself, start with
docs/onboarding.md; the decisions behind the design are in
docs/adr/.
License
MIT © 2026 AIAYN-creator
Metadata
Release files for labharness 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| labharness-0.5.0.tar.gz | 1.7 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| labharness-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.9 MB
Release files / labharness-0.5.0.tar.gz
| Download URL | labharness-0.5.0.tar.gz |
|---|---|
| Size | 1.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
028c2076f5460bbfe95e5427242986a7496ee2ed4fedeafe66a121cb56117ce3
|
|
BLAKE2b-256 checksum How to use checksums |
b3e9cbd9bfac1ae4ebc098d4a55da9d86322fdc0f7b79695671d312bdd2f5f35
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / labharness-0.5.0-py3-none-any.whl
| Download URL | labharness-0.5.0-py3-none-any.whl |
|---|---|
| Size | 136.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a75c3ace663a112e9ea215a584e9a750df4d0d051e8bfcb54848de913f4dc88b
|
|
BLAKE2b-256 checksum How to use checksums |
060c7a4ed417a5eec9f3594fddf4d33691e23af744d38e3023733f667f096199
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|