Jev vs LLM: robot arm control

September 19, 2026 ยท View on GitHub

A simulated Franka arm with a 4-finger Allegro hand (MuJoCo) stacks a blue cube on a red one, driven by two kinds of AI:

  • agent.py: an LLM (Claude Opus 5 by default) with three low-level tools: move_hand_to(x, y, z), set_hand(closed), get_state(). It reasons through every step itself.
  • jev_agent.py: Jev by TypeSafe, a "System One" model that answers typed questions with probabilities in a few hundred ms. Code proposes small moves and simulates each one ahead in a scratch copy of the physics; Jev picks the move, decides when to grasp and release, and decides when the task is done. The design follows jev_fsd: code owns the math, Jev owns the judgment.

One recorded run each:

Claude Opus 5Jev
Resultstackedstacked
Time158.8 s19.1 s
Cost$0.75$0.0006

That Opus run needed one retry; clean first-try Opus runs took about 55 s and $0.19. Times include arm motion at real speed.

Setup (macOS or Linux)

nix develop                                   # Python 3.12 + uv (or bring your own Python 3.12 and uv)
uv venv .venv && uv pip install --python .venv -r requirements.txt

# Robot models from MuJoCo Menagerie (only the two we need)
git clone --depth 1 --filter=blob:none --sparse https://github.com/google-deepmind/mujoco_menagerie.git menagerie
git -C menagerie sparse-checkout set franka_emika_panda wonik_allegro

On macOS, anything that opens the viewer must run with mjpython (installed with mujoco), not python.

Check the sim works (scripted pick-up, no AI):

.venv/bin/mjpython robot.py            # with viewer
.venv/bin/python robot.py --headless   # asserts the cube is lifted

API keys

Keys are read from environment variables only. Set them without echoing them into your shell history:

read -s TYPESAFE_API_KEY && export TYPESAFE_API_KEY      # Jev: request early access at console.typesafe.ai
read -s OPENROUTER_API_KEY && export OPENROUTER_API_KEY  # LLM via OpenRouter...
read -s ANTHROPIC_API_KEY && export ANTHROPIC_API_KEY    # ...or directly via Anthropic (used if no OpenRouter key)

Run

TASK="Put the blue cube on top of the red cube. The stack must stay standing after the hand lets go."

.venv/bin/mjpython jev_agent.py "$TASK"                      # Jev, with viewer
.venv/bin/mjpython agent.py "$TASK"                          # LLM, with viewer
MODEL=z-ai/glm-5.3 .venv/bin/mjpython agent.py "$TASK"       # any OpenRouter model with tool support

Add --headless to run without a window (much faster: arm motion isn't paced to real time). Each run ends by printing a TIME: and COST: line (Jev: $0.042 per million input tokens, output free; Opus 5: $5 / $25 per million input / output tokens, list price).

Making the video

Runs are recorded headless and rendered offscreen, so there are no windows or screen capture involved.

# 1. Record (retry until you like the run)
RECORD=videos/jev.npz  .venv/bin/python jev_agent.py --headless
RECORD=videos/opus.npz .venv/bin/python agent.py --headless "$TASK"

# 2. Render each run to a 720x1440 portrait MP4 (title, live clock and cost, latest log line).
#    Optional third argument: playback speed for the run itself (the 3 s final hold stays at 1x).
nix-shell -p ffmpeg   # or any ffmpeg on PATH
.venv/bin/python replay.py videos/jev.npz  videos/jev.mp4
.venv/bin/python replay.py videos/opus.npz videos/opus_3x.mp4 3

# 3. Side by side as a 1080x1080 square (the shorter clip holds its last frame)
ffmpeg -i videos/opus_3x.mp4 -i videos/jev.mp4 -filter_complex \
  "[1:v]tpad=stop_mode=clone:stop_duration=300[b];[0:v][b]hstack=inputs=2:shortest=1,scale=1080:1080[v]" \
  -map "[v]" -c:v libx264 -pix_fmt yuv420p -crf 20 -movflags +faststart videos/side_by_side.mp4

The replay clock is the live-equivalent time: real wall time while the model was thinking, plus simulated time while the arm moved.

record.py is the older approach: it screen-records the live viewer window (needs Screen Recording permission for your terminal on macOS).

Files

FileWhat it does
scene.pyBuilds the scene from Menagerie: Franka arm, Allegro hand mounted palm-to-flange, two cubes
robot.pySim wrapper: inverse kinematics, hand poses, real-time stepping, viewer overlay, run recording
agent.pyLLM agent (Anthropic SDK tool runner; OpenRouter or Anthropic)
jev_agent.pyJev agent: sense, sample, simulate, ask
replay.pyRenders a recorded run to MP4
record.pyScreen-records a live viewer run (macOS)

License

MIT. The robot models come from MuJoCo Menagerie under their own licenses and are not included in this repo.