
This summer I got the wonderful opportunity to contribute to Team Olympus, a group of researchers from across the United States designing a food system that could feed fifteen astronauts on Mars for 500 sols.
There’s a renewed interest in longer-term habitation on the Moon and Mars, and one of the many considerations is food. Astronauts on the space station today eat prepackaged meals that cargo ships bring up from Earth, and the station keeps at least six months of food on board.
The problem is that none of this works on Mars. There are no grocery stores, a cargo ship from Earth takes seven months or more, and launch windows open only every 26 months. Packaged space food stays good for one to two years, but food for a Mars mission would have to last about five years. A message to Earth also takes 3 to 22 minutes each way, so the crew can’t count on quick help from home.
So the base has to grow some of its own food. Then the farm becomes part of life support: the plants take in the crew’s CO₂, use the crew’s water, and need light that runs on the base’s power. The question we had to answer was how a small crew could grow, cook, and recycle its own food for 500 sols, without real-time help from the ground.

The challenge
That’s the problem behind NASA’s Deep Space Food Challenge: Mars to Table, run with the Methuselah Foundation. Teams this year had to design how a Mars base feeds its crew, from seed to plate. Our scenario was 15 people for 500 sols. A sol is a Mars day, about 24 hours and 40 minutes, so 500 sols is about 514 Earth days. The rules were:
- No resupply from Earth.
- At most half the crew’s calories from food brought from Earth.
- Nine hours a sol, counting the whole crew’s time together, for all the farming, processing, and cooking.
Out of 113 teams representing 33 different countries, ours placed in the top 40.

Our design
Our design, OLYMPUS, grows the crew’s food, cooks it, and recycles the waste. It’s built as two mirror-image wings, Athena and Ares. Each wing has its own hydroponic crop rooms and its own tanks of algae, fungi, and yeast for protein. Either wing is big enough to feed the whole crew by itself.
The crew starts out eating food brought from Earth. Algae protein from the tanks is ready by sol 5, fungal protein by sol 7, and mushrooms grown on the base’s own waste by sol 15. Grains and other staples take longer. Their first harvest comes at sol 72, and from then on more of the crew’s food comes from Mars than from Earth. Plant scraps and other waste are broken down, and the water and nutrients go back to the crops.
On a normal sol both wings run at 75% of capacity, so together they grow about 150% of what the crew eats. If one wing has a problem, like a contaminated sample or a failed nutrient loop, it’s sealed off for repairs. The other wing ramps up to 100%, so the crew never misses a meal.
The kitchens cook from a 14-sol menu, and the fresh part of each meal changes with whatever was harvested that sol.

Simulating the base with BioSim
I worked on the team’s software: the simulation of the base, and an AI assistant for the crew.
One of the challenge’s six deliverables is a model of the base in BioSim, a life-support simulator developed by TRACLabs with NASA’s Johnson Space Center. It shows whether a design keeps the crew alive for the whole mission. BioSim runs a mission one hour at a time. Each hour, the crew breathes in oxygen and breathes out CO₂, the crops take in CO₂ and water, and the machines draw power. Everything moves through stores, like the oxygen and water tanks, and each store and connection has a limit. Most of my work was in BioSim and the code built around it.
Adding microbes to the simulator
BioSim already modeled crops, but not the microbes our design relies on for fast protein, so I added two modules. The first is a Spirulina tank. Spirulina is a blue-green alga (often sold as a green powder at smoothie shops) that uses CO₂, water, and light to make oxygen and protein-rich biomass. The European Space Agency’s MELiSSA life-support project has grown it for years to make oxygen and food for crews.
The second is a fermenter that does the reverse. It takes in harvested algae and oxygen, gives off CO₂, and grows yeast or mycoprotein, the fungus-based protein in products like Quorn. When the two share the cabin air, each one gives off the gas the other needs.

Both modules keep track of every gram of carbon, so none appears or disappears in the simulation. Their rates come from published measurements. The ×1.35 on the oxygen arrow is one example: Spirulina grown on nitrate gives off about 1.35 molecules of O₂ for every molecule of CO₂ it takes in, not the 1.0 from the textbook photosynthesis equation. Using 1.0 would undercount the crew’s oxygen by about a quarter.
Making runs repeatable
Another issue was that BioSim gave different results for the same setup. In one test the simulated crew died at hour 552 on one run and hour 624 on the next. We couldn’t tell whether a change to the design helped or the run just came out differently.
The cause was six random number generators, each started from the computer’s clock, so no two runs began the same way. Two of them were also shared by every simulation on the server, so a run’s results depended on what had run before it. I changed it so each simulation starts from one fixed number, called a seed, and every part of the base gets its own generator made from it. Now the same setup plays out the same way every time. None of the roughly 120 places in the code that draw random numbers had to change.
Forecasting a few sols ahead
BioSim stands in for the base’s sensors, so I treated its output like real sensor data. Every reading carries its unit, its timestamp, and its source. A missing reading is reported as missing instead of filled in with a guess. Simulated numbers are labelled as simulated, so they can’t be logged as real measurements.
Knowing what’s in stock now isn’t enough, though. The crew needs warning before something runs out, so I built a forecaster, which we called future-sight. It copies the base’s current stock levels into a separate copy of the simulation and runs that copy forward, up to about 80 sols. Then it reports which stores will run low. The live simulation keeps running untouched.
Checking a meal plan before it runs
I also fixed bugs in marsfood, the team’s tool for comparing base designs: how much to grow, how much to ship from Earth, and how well the crew would eat. One example: the ingredient data listed omega-3 in milligrams while the nutrition targets were in grams, so every omega-3 comparison was off by 1,000 times.
Then I built marsops, the program the crew would use to run the pantry and plan meals. It keeps a log of every change to the pantry, which can be added to but never edited. It plans meals from what’s actually in stock, and it has four screens: Today, Inventory, Production, and Risks. It uses only Python’s standard library and no AI, so it keeps working even when wallEat, the AI assistant I describe below, is turned off.
A wrong meal plan could use up food the base needs later or leave the crew short on nutrients. So marsops doesn’t release a plan just because the planner produced it. Right before a plan goes to the kitchen, marsops builds it again and rechecks it. If any check fails, the plan is blocked.
wallEat
The second thing I worked on was wallEat, an AI assistant for the crew. With messages to Earth taking up to 22 minutes each way, the crew can’t wait on mission control for every question. Instead, a crew member can ask wallEat things like “what’s on the meal plan this sol, and why?” or “which crops are ready to harvest?” It runs Gemma, Google’s open model, on the base’s own computers, so it works without a connection to Earth. It answers from the mission documents and the simulator’s live readings. I started from a basic framework for running a local model and rewrote most of it over the summer.
Getting the model to use tools, like looking up the pantry or searching the documents, was the easy part. Most of my time went into the harness, the code around the model that decides what it sees and what it’s allowed to do:
- Six specialists. Instead of one assistant with every tool, wallEat has six roles: a help desk, a crop adviser, a cook, a scheduler, a meal-plan explainer, and future-sight. Each has its own instructions and only the two to seven tools it needs. The 12-billion-parameter model I used did much better this way.
- Permission checks at run time. The model can ask for a tool it was never given, so listing the allowed tools in the prompt isn’t enough. wallEat checks the role’s permissions right before running any tool and logs every refusal.
- Documents are data. Text from documents is fenced off and labelled as data. If a document says “ignore previous instructions,” the model treats that as something the document says and reports it, instead of following it. Sources are also ranked by trust: approved procedures first, then reference material, then past sensor readings, then chat memory. Only an approved procedure can back an instruction to the crew.
- Context budget. The model can only read so much text at once. Once a conversation gets too long, wallEat summarizes it. Passages from documents go in whole or not at all. Tool output that runs over budget is cut off, with a note telling the model it’s only seeing part of it.
- Saying when something is down. If the model, the simulator, or the document index is unavailable, wallEat says which one is down instead of answering anyway. The check that reports whether wallEat is ready also fails whenever a service it needs is missing.
The rule behind all of this is that wallEat can read the pantry, the meal plan, and the simulator, but it can’t change them. Every change is made in marsops by a signed-in crew member who confirms it. I wrote tests that try to break this: the model calling tools it wasn’t given, documents with hidden instructions, file paths that point outside the document folder, and old sensor readings used to answer questions about right now.
What I’m taking away
When I started, I thought of an AI agent as a model plus some tools. Now I think most of the work is in the harness around the model: permissions, which sources to trust, what fits in memory, and what happens when something fails. The model is one part inside it, and not a very reliable one. That’s the biggest thing I learned this summer.
The other thing I learned was to double-check my own tools. At one point an automated code audit proposed deleting about 7,300 lines across two repos. When I checked each claim one by one, twelve of the fifteen proposed deletions turned out to be wrong. I built the same habit into the code: when a nutrition label can’t be converted safely, the simulator sets it aside instead of guessing. I’d rather it tell me it doesn’t know than hand me a wrong number.
Thank you to everyone on Team Olympus. I really appreciate getting to work on this with you all!