Doom runs as the payload of a spacecraft. An F´ flight computer sends its telemetry and video down through CCSDS frames to Yamcs, and you watch it in Open MCT or a small dashboard. The pilot on the ground is jev (TypeSafe's fast decision model). Every half second it picks where to go and uplinks an intent. Claude reviews each attempt. No part of the pilot ever reads the level file.
On 24 September 2026 jev finished E1M1 in 105 s, with no deaths, through the full stack.
You need about 3 GB of disk, 15 to 20 minutes, and a TypeSafe API key for jev. You don't need a key for Claude: the pilot uses your Claude Code login. Without a TypeSafe key, you can still fly it yourself.
Shortcut: open Claude Code in this folder and say "set DoomSat up on this machine".
CLAUDE.mdgives it the steps.
Windows 10/11 (WSL2)
Everything runs inside WSL2 (Ubuntu). Your Windows browser reaches it on localhost.
- In PowerShell as Administrator:
Restart if Windows asks you to, then open Ubuntu from the Start menu and create your user.
wsl --install -d Ubuntu-24.04
- From here on, work in the Ubuntu terminal and follow the Linux steps below. Clone into your Linux home
(
~/), not/mnt/c/..., because builds on the Windows drive are many times slower. - On Windows 11, WSLg shows the Doom window from
payload/play.py. On Windows 10 use--checkinstead.
Optional, if you'd rather keep the repo on the Windows side and use Git Bash: set
DOOMSAT_WSL_DISTRO (and DOOMSAT_WSL_USER) in .env. scripts/flight.sh then forwards itself into WSL.
Run scripts/setup_ground.sh from Git Bash so the pilot, the dashboard and Open MCT run on Windows.
Linux (Ubuntu 22.04 / 24.04, or inside WSL)
# 1. System packages
sudo apt update
sudo apt install -y git curl build-essential binutils python3 python3-venv python3-pip
# 2. Node.js 24 (for Open MCT)
curl -o- https://github.com/ghraw/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.nvm/nvm.sh && nvm install 24
# 3. Claude Code (for System Two; optional, the pilot runs without it)
curl -fsSL https://claude.ai/install.sh | bash # then run `claude` once to log in
# 4. This repo, your key, and the install
git clone https://github.com/Devonance/DoomSat.git && cd DoomSat
cp .env.example .env && nano .env # set TYPESAFE_API_KEY
scripts/flight.sh setup # ViZDoom, F´ v4.3.0 + DoomSat build, Yamcs, WADs (~10 min)
scripts/setup_ground.sh # pilot venv + Open MCT build (~5 min)
python3 tools/doctor.py --jev # checks every piece and makes one jev callmacOS (Apple Silicon or Intel), not yet tested
The scripts support macOS (the F´ build goes to build-artifacts/Darwin/), but nobody has run them end to end on
a Mac yet. The two likely weak spots are the Java runtime that fprime-yamcs bundles and ViZDoom's wheels. If a
step fails, please open an issue with the output.
# 1. Compiler, Python, git
xcode-select --install
brew install python@3.12 git # `python3 --version` should now say 3.12
# 2. Node.js 24 and Claude Code
curl -o- https://github.com/ghraw/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.nvm/nvm.sh && nvm install 24
curl -fsSL https://claude.ai/install.sh | bash
# 3. This repo, your key, and the install
git clone https://github.com/Devonance/DoomSat.git && cd DoomSat
cp .env.example .env && open -e .env # set TYPESAFE_API_KEY
scripts/flight.sh setup
scripts/setup_ground.sh
python3 tools/doctor.py --jevEach scripts/flight.sh setup step can also run on its own: payload, fprime or wads. The same goes for
scripts/setup_ground.sh python|openmct. Re-running either script skips anything already installed.
Use four terminals, or background the servers:
scripts/flight.sh start # Doom payload + F´ + Yamcs → http://localhost:8090
python3 tools/serve_dashboard.py # mission dashboard → http://localhost:8070
scripts/start_openmct.sh # Open MCT → http://localhost:9000
scripts/start_pilot.sh --duration 600 # jev plays; add --system-two none to leave Claude out
scripts/flight.sh stopLogs go to out/ (the pilot) and ~/doom/run/ (payload, Yamcs). scripts/flight.sh check prints a telemetry
health report.
To try the whole stack without a TypeSafe key, fly it yourself from the dashboard:
scripts/play.sh # you drive; opens http://localhost:8070
scripts/play.sh --autopilot # or watch the code rules fly it (no model)play.sh starts the flight side and the dashboard server if they aren't already running. Click the picture to
take the controls:
| Keys | |
|---|---|
| W S or ↑ ↓ | forward / back |
| A D or ← → | turn left / right |
| Q E | strafe left / right |
| F or mouse button | fire |
| Space | use (doors, switches, the exit) |
| 2 3 | pistol / shotgun |
| Esc | let go |
Your keys go up the same path the pilot's orders do: each change is a CONTROL command issued to Yamcs, which
uplinks it to F´, which passes it to the game. The picture comes back down as telemetry. So what you see is the
real mission loop, round-trip latency included. The commands appear in the dashboard's command panel and in
Yamcs, and the telemetry and video appear in Open MCT (scripts/start_openmct.sh). Manual mode restarts the
level when it starts (--no-reset keeps the game as it is). It logs to out/manual.jsonl, never to the pilot's
out/decisions.jsonl. Ctrl+C stops it, and scripts/flight.sh stop stops the flight
side.
--autopilot flies the pilot with --system-one code, the exact rules jev's questions restate. It is the
same code baseline as research/runner.py --decider code, flown on the full stack.
Doom (ViZDoom): play it, or check it headless
~/doom/payload-venv/bin/python payload/play.py # a window; you play
~/doom/payload-venv/bin/python payload/play.py --check # no window: 100 tics → out/doom_check.png
~/doom/payload-venv/bin/python payload/play.py --wad freedoom1.wadF´: the flight software with the stock F´ GDS
scripts/flight.sh gds # the DoomSat deployment + F´ GDS → http://localhost:5000
scripts/flight.sh payload # (another terminal) add the game, so the Doom channels moveThe component is in flight/Components/Doom/ and the topology in flight/DoomSat/Top/. After an edit, run
scripts/flight.sh build.
Yamcs: mission control, fed by F´
scripts/flight.sh yamcs # F´ + Yamcs, no game → http://localhost:8090 (instance fprime-project)
scripts/flight.sh start # the same, plus the game and the video framesThe Yamcs config is ground/yamcs/. The XTCE database is generated from the F´ dictionary at launch.
Open MCT: the DoomSat displays
Open MCT reads everything from Yamcs, so start Yamcs first. You don't need the game or the pilot:
scripts/flight.sh yamcs # or `start` for live Doom telemetry and video
scripts/start_openmct.sh # → http://localhost:9000The DoomSat configuration is ground/openmct/index.html and index.js. Edit it there:
start_openmct.sh copies it into the plugin's example on every start. In the tree, open
fprime-project → DoomGround → DoomFrame as an imagery view to see the video. Parameters under
DoomSat_DoomSat open as plots.
The dashboard
python3 tools/serve_dashboard.py # → http://localhost:8070 (needs Yamcs on :8090)This is one static page (ground/dashboard/index.html) with a proxy to the Yamcs API, and it needs nothing
installed.
jev (System One): with or without the stack
python3 tools/doctor.py --jev # one real call with your key
# jev (or the code-only baseline) playing Doom in one process, no F´ or Yamcs:
~/doom/payload-venv/bin/python research/runner.py bench --maps E1M1 --seeds 1 --budget 60 \
--decider jev --wad ~/doom/wads/freedoom1.wad --out out/bench --allow-dirtyUse --decider code to run the same bench with no model.
Claude (System Two)
The pilot shells out to the claude CLI, so it uses your Claude Code login and needs no API key. Once a minute
Claude pushes exploration in a direction, and after each attempt it revises the questions jev is asked.
scripts/start_pilot.sh --system-two claude-cli # default
scripts/start_pilot.sh --system-two anthropic # the API instead; set ANTHROPIC_API_KEY in .env
scripts/start_pilot.sh --system-two none # jev + code onlyEverything is in one file, .env at the repo root. Copy it from .env.example:
| Variable | Needed for |
|---|---|
TYPESAFE_API_KEY |
jev (the pilot, the jev bench) |
ANTHROPIC_API_KEY |
only --system-two anthropic |
DOOMSAT_HOME |
where the flight side is installed (default ~/doom) |
DOOMSAT_WSL_DISTRO, DOOMSAT_WSL_USER |
only when you drive WSL from Git Bash |
Common problems
- Start with
python3 tools/doctor.py. It lists what is missing and the command that fixes it. - Yamcs never comes up. Read
~/doom/run/yamcs.log. Port 8090 may already be taken. - Open MCT shows "Missing" rows. That's the plugin's example layout. Browse the tree on the left instead. Yamcs has to be up first.
- The jev call fails. Check the key in
.env. TypeSafe keys can expire. - The pilot can't reach Yamcs. Wait about 30 s after
flight.sh start, then runscripts/flight.sh check. - Scripts fail with
$'\r': command not found. Windows line endings have crept in..gitattributeskeeps*.shas LF, so re-clone, or runsed -i 's/\r$//' scripts/*.sh.
- docs/ARCHITECTURE.md covers what the player may see, the decision graph, who decides what, and the integration findings.
- docs/results/ has the E1M1 finish: the decision log, every attempt and the overnight report.
- docs/CHARTER.md sets out the mission and its rules, and docs/CHARTER-STATUS.md says what is built.
- The full report is docs/doomsat-report.pdf.
- Built on F´ v4.3.0, fprime-yamcs 0.2.1, Yamcs 5.12.8, Open MCT with openmct-yamcs, ViZDoom 1.3.0, TypeSafe jev and Claude Code.


