An Agentic Home Bioreactor
Making a Minimal Automated Home Lab.
This would not be possible without the help of David Jordan, for whom I am grateful to work with. Drop David an email at david [at] livingphysics [dot] org for enquiries / purchasing a bioreactor!
I tested David Jordan’s tabletop bioreactor in my last post. I have a day job so need to be able to run experiments whilst I’m out of the house. I also realised how painful it is to change parameters in re-runs of experiments. So, I wanted to reduce friction in the whole process and make it much easier to interact with the bioreactor.
After all, the less friction there is, the more likely I’ll do stuff.
So, we thought it would be useful to automate the bioreactor so that it can run experiments on its own, in an agentic fashion. And it would be cool if we could tell it what to do in plain English!
So instead of writing an experiment with ad hoc code that looks like this…
import time
import requests
BIOREACTOR = "http://raspberrypi.local:8000"
def set_temperature(celsius: float):
requests.post(f"{BIOREACTOR}/heater", json={"target_c": celsius})
def read_od():
return requests.get(f"{BIOREACTOR}/od").json()["od600"]
def set_stirrer(rpm: int):
requests.post(f"{BIOREACTOR}/stirrer", json={"rpm": rpm})
def pump_media(ml: float):
requests.post(f"{BIOREACTOR}/pump/in", json={"volume_ml": ml})
def drain(ml: float):
requests.post(f"{BIOREACTOR}/pump/out", json={"volume_ml": ml})
# Algae growth experiment: hold at 25C, stir at 200rpm,
# sample OD every 10 minutes, dilute once OD crosses 0.6.
set_temperature(25.0)
set_stirrer(200)
log = []
start = time.time()
while time.time() - start < 24 * 3600:
od = read_od()
log.append((time.time() - start, od))
if od > 0.6:
drain(20)
pump_media(20)
time.sleep(600)
Which is HARD AND ANNOYING, wouldn’t it be cool if you could just ask it something like this?
‘Please loop at different temperatures and measure the photosynthesis rate in increments of 2, making sure that each temperature has enough time to test what you need to test. For each loop flicker the light on for 10 seconds on and off’.
And so I tried to build a rough version. And got it working. Have a look at the first version, which is me telling to change the colours of the LED light in the bioreactor that the organisms are exposed to.
Here’s the architecture.
The bioreactor is controlled by a Raspberry Pi. I enabled ssh on it so that I could access the Pi remotely from my laptop on my local network. I then installed Claude Code on the Pi.
David Jordan then built an API that could control each of the hardware elements, which consist of temperature and gas sensors, a lighting element, a heating element, and an optical sensor.
To get it agentic, I built a model context protocol server on the Raspberry Pi. The model context protocol lets Claude ping the api provided that the server is running.
And to communicate with the bioreactor, the easiest way was to run Claude Code in headless mode. At that point, Claude then converts my plain English commands to api commands that control the bioreactor.
Moving forward, the next step is to create a memory file and data log so that the agent can continually refer to the logs of data as it makes decisions that are in line with the human’s commands. But this should be easy.
I’m excited about this for multiple reasons. It allows people do do experiments much more easily, myself included. It also lets people who are less physically able do science do experiments. And, since I care about biosecurity, it fits as a great minimal model in discovering where we should protect ourselves.

