Skip to main content

LabHarness

From lab data to PDF in 1.3 seconds. Change a number: the figure, the fit and the text follow.

From a CSV to a figure in the PDF with labharness add and watch; then a changed measurement moves its point and the rate constant quoted in the text

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) and labharness open in 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] or t / min gives 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-7B and render_structure(compound="CAT-7B", ...) use it, and labharness library check flags 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 to references.bib and 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.

  • add and preview
  • 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 article and report for lab work
  • Five typefaces and three LaTeX engines
  • A full LaTeX build without Perl
  • CI on Linux, Windows and macOS; protected main and release tags; security alerts
  • doctor prints 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 labharness works (the workflow and the steps in docs/RELEASING.md are 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 add offers 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, with data/ 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)

Source distribution for labharness 0.5.0
File Size Uploaded
labharness-0.5.0.tar.gz 1.7 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for labharness 0.5.0
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page