I Ran a 139,000-Neuron Fruit Fly Brain on a Mac mini. With No Input at All, Does It Move on Its Own?
I Ran a 139,000-Neuron Fruit Fly Brain on a Mac mini. With No Input at All, Does It Move on Its Own?
In March 2026, Eon Systems published "uploading a fruit fly": a spiking network built from the FlyWire whole-brain connectome, wired to a physics-simulated fly body that forages, grooms and escapes in a virtual world. The demo is striking, but the key layer — how neuron activity becomes movement — was not open-sourced.
I wanted to answer a plainer question: once this fly brain is replicated, what behavior does it generate by itself? So I assembled the open-source parts they used on a single Mac mini, tested it once with sensory input and once with none.
The short version:
- With input, the connectome alone turns sensation into usable motor signals. Sugar on the legs: the fly turns and starts feeding 0.66 s in. A black ball looming at the compound eyes: the giant fiber fires at 1.89 s and the body backs away.
- With no input, the original model is completely silent. It is a passive responder; it does not move on its own.
- After adding two pieces of basic physiology — membrane noise and spike-frequency adaptation — it does switch spontaneously between resting, walking forward, walking backward, grooming and startle. But version 1 keeps time like a metronome. Version 2 changes three things, and only then does the rhythm turn irregular, with bouts of varied length, closer to a living animal.
- Every one of these "behaviors" passes through a low-dimensional interface I wrote by hand (descending neurons → actions). This is not a motor-neuron-level simulation. Keep that in mind when reading the numbers below.
Background: what exactly got "uploaded"
The stack I used has four parts. The first two are open-source projects Eon's write-up relies on, flybody is a flight body I added, and the last one Eon did not release:
| Component | Role | How I used it |
|---|---|---|
| FlyWire v783 + Shiu 2024 LIF model (Eon fly-brain) | Whole-brain spiking network: 138,639 neurons, ~5 million synapses | Unmodified, Brian2 C++ backend |
| NeuroMechFly v2 (flygym) | Fly body in MuJoCo + CPG gait | Walking, turning, backing up |
| flybody (Janelia / DeepMind) | A second body, flight-oriented | Flight footage; skipped in this article |
| Descending neurons → motor commands | Translate brain output into leg movement | Not released — I wrote my own |
FlyWire covers the brain only, not the ventral nerve cord (the fly's spinal cord), so there is a built-in gap between brain and legs. The last signal the brain produces is the firing of descending neurons (DNs). Everyone replicating this has to fill in the path from DNs to joint torques themselves.
Analysis: "generates behavior by itself" is two questions
What a replicated brain can generate is really two separate things:
- Stimulus-driven: given sensory input, does the brain compute a motor signal in the right direction? This tests the connectome's wiring.
- Spontaneous: given nothing, does it move anyway? A real fly in an empty box still walks, stops and grooms. That is the line between an animal and a reflex machine.
The second question is harder and more interesting. The Shiu 2024 LIF model was designed for "stimulate one population, see what lights up downstream." It has no background activity — no input, not a single spike. To make it move on its own you have to add terms to the equations, and what you add, and how much, directly shapes the conclusion. So I set one rule: add only the minimum physiologically grounded terms, and quantify what each one changes.
Approach and choices
Brain backend: Brian2 C++, GPU ruled out. I benchmarked three backends locally on 0.1 s of brain time:
| Backend | Wall time |
|---|---|
| Brian2 C++ (CPU) | 1.26 s (plus ~8 s compile on first run) |
| PyTorch MPS (Apple GPU) | 9.6 s |
| PyTorch CPU | 36.8 s |
MPS has no CSR sparse kernel, so it falls back to gather + index_add. The result is 7× slower than Brian2, and batching makes it slower linearly. Sparse matrix-vector multiply is memory-bandwidth bound, and a unified-memory GPU gains nothing. The other machine on my LAN has an Intel Arc iGPU with no CUDA and is not expected to beat MPS, so it was ruled out too. Real acceleration means renting an NVIDIA card for Brian2CUDA.
Sensory input: taste and antennal mechanosensation only; smell, temperature and humidity ruled out. I swept the sensory channels. Driving olfactory ORNs, temperature or humidity receptors at even 30 Hz pushes about 8,000 neurons into saturation, and left and right stimulation give identical results (olfactory input projects bilaterally) — useless for steering. Gustatory and antennal JO neurons produce left/right-separated descending responses, so they work.
Descending interface: read only DN groups with well-established roles. Forward DNp09/DNg100, turning via the DNa01/DNa02 left-right difference, backward MDN, grooming DNg11/DNg12, escape DNp01 (the giant fiber). The turning signal subtracts the DN population's intrinsic left bias of about +0.19. That bias comes from calibration; without removing it the fly turns left forever.
Ruled out: no motor-neuron-level simulation (there is no nerve cord data). flybody's trained policies are TF 2.8 SavedModels that won't install on Apple Silicon, so I exported the weights and ran inference in numpy; the walking policy was skipped because it needs a 3 GB reference-trajectory dataset.
Implementation and measurements
1. Stimulus-driven: the connectome's wiring works
Without a body, I stimulated two populations for 0.3 s of brain time each:
| Stimulus | Neurons activated | Total spikes |
|---|---|---|
| Sugar gustatory receptor neurons (GRNs), 200 Hz | 384 | 5,125 |
| P9 forward-walking descending neurons, 100 Hz | 85 | 291 |

Sugar spreads widely (384 neurons lit up), consistent with feeding being a brain-wide decision. Stimulating P9, which already sits at the output end, makes a much smaller ripple.
Then I attached the body and ran two closed loops:
Taste-guided feeding: leg gustatory neurons fire according to the left/right sugar concentration → whole-brain LIF → DN left/right difference → CPG step amplitude per side. Brain and body sync every 15 ms. In 3.48 s of behavior, feeding begins at 0.66 s.
Visual escape: flygym compound-eye images → flyvis (a connectome-constrained visual network) → T4/T5 motion detectors mapped onto FlyWire → LIF brain. A black ball approaches from the front-left, accelerating:
| Time | Event |
|---|---|
| 1.635 s | Left LPLC2 (looming detectors) first spike, peak 6.2 Hz |
| 1.830 s | Right LPLC2 fires, peak 7.8 Hz |
| 1.890 s | Right giant fiber DNp01 fires, peak 66.7 Hz → backward escape |

The LPLC2 → giant fiber → escape pathway emerges entirely from the connectome; I only wrote the last step, "giant fiber fires = back up." The other looming detector class, LC4, and the left giant fiber stayed at zero throughout. My interface only checks whether the giant fiber fires, not which side.
2. Spontaneous behavior v1: add noise, then adaptation
With no input the original model is silent. I added two terms to the membrane equation:
- Membrane noise σ: real neurons have ion-channel noise and fire spontaneously.
- Spike-frequency adaptation a: each spike adds +b to a slow current that decays with τa. This makes activity self-limiting — bursts of activity, then quiet.
I swept nine σ × b combinations (1 s of brain time each). A representative subset:
| σ | b | Mean rate | Active fraction | Population-rate CV | Turning DN left / right |
|---|---|---|---|---|---|
| 2 mV | 0 | 4.03 Hz | 17.9% | 0.04 | 34 / 7 Hz |
| 2 mV | 3 mV | 0.33 Hz | 13.8% | 1.03 | 2 / 4 Hz |
| 3 mV | 0 | 6.12 Hz | 72.2% | 0.04 | 39 / 7 Hz |
| 3 mV | 3 mV | 1.29 Hz | 74.4% | 0.25 | 7 / 9 Hz |
| 4 mV | 0 | 9.46 Hz | 88.9% | 0.04 | 46 / 4 Hz |
The most interesting rows are b = 0. Noise alone, no adaptation: population activity is flat as a line (CV 0.04), yet the turning DNs are locked more than 5× to the left — the fly would spin left in place forever. Noise amplified by the connectome's structure settles into a stable attractor; adaptation breaks it. The left/right bias disappears and bursts appear.
I picked σ = 2.5 mV, b = 3 mV, τa = 400 ms (mean rate about 0.75 Hz, no saturation) and ran the body for 12 s:

30 bouts. Time split: rest 58%, forward 11%, grooming 15%, backward 8%, startle 9%. Forward speed 12.4 mm/s, total path 27.5 mm. With no sensory input at all, it really does walk, stop and groom on its own.
Stretch the brain time to 60 s and compute statistics, though, and the problems show:
- Median inter-burst interval is 1.67 s with a coefficient of variation of just 0.05 — practically a metronome.
- 82% of forward bouts and 84% of grooming bouts are exactly the decoder's minimum duration of 0.3 s. The longest forward bout is 0.42 s.
- Startles occur 7.1 times per minute — absurdly often.
So most of v1's "behavior" is set by what I added: the rhythm comes from a single τa, bout length from a decoder parameter, and startles from one giant-fiber neuron being kicked by noise.
3. Spontaneous behavior v2: more connectome, fewer of my parameters
One change for each problem:
- Heterogeneous adaptation time constants: each neuron's τa is drawn from a log-normal distribution (median 400 ms, 5th–95th percentile about 0.1–1.5 s), plus a slowly drifting whole-brain "arousal" term (an Ornstein-Uhlenbeck process, τ = 4 s).
- Read the DNs' synaptic input, not their spikes: each DN group has only 1–24 neurons, so their spikes are essentially point-process noise. A DN's synaptic input g sums over thousands of upstream neurons and is far smoother. Action selection now uses competing units with mutual inhibition and self-excitation, so bout length emerges from the dynamics.
- Startle requires ≥ 4 giant-fiber spikes within 20 ms (strong synchronous drive); single noise spikes don't count. The giant fiber's own noise is lowered to 0.5 mV — it is a very large neuron, and otherwise fires randomly at about 5 Hz at rest.
Same 60 s of brain time, two random seeds:
| Metric | v1 | v2 seed 0 | v2 seed 1 |
|---|---|---|---|
| Inter-burst interval median / CV | 1.67 s / 0.05 | 2.25 s / 1.19 | 1.16 s / 1.16 |
| Population-rate autocorrelation peak | 0.61 | 0.40 | 0.47 |
| Startles / min | 7.1 | 2.0 | 1.0 |
| Forward bout median / longest | 0.30 / 0.42 s | 0.86 / 4.63 s | 0.60 / 3.48 s |
| Forward bouts stuck at 0.3 s floor | 82% | 0% | 12% |
| Forward bouts > 1 s | 0% | 44% | 29% |
| Grooming bout median / longest | 0.30 / 0.39 s | 0.72 / 1.87 s | 0.65 / 2.23 s |
| Share rest / fwd / back / groom / startle | 57/12/14/13/5% | 27/35/9/28/1% | 33/29/13/24/1% |

The rhythm goes from metronome to irregular (CV 0.05 → 1.2). The fly now walks for 3–4 s at a stretch, grooms for up to 2 s, and startles only 1–2 times per minute. The two seeds differ in their splits but agree in magnitude, so this isn't one lucky run.
Finally, I attached v2 to the body for 30 s (seed 0): 46 bouts — rest 34%, forward 21%, backward 14%, grooming 30%, and no startle in those 30 s. Total path 135 mm, versus 27.5 mm in v1's 12 s.

v2 doesn't fully solve the problem, though. Look at the bottom panel: in the second half, when arousal (orange) is low, whole-brain bursts (grey) fall back into a fairly regular beat. Heterogeneous adaptation loosens the rhythm but can't suppress it alone. The irregularity of a real fly may need other sources, such as neuromodulation or feedback from the body.
Results: what comes from the connectome, and what comes from me
Here is the attribution table for this round. I think it's the most important question to ask of any "digital fly" demo:
| Phenomenon | From the connectome | From what I added |
|---|---|---|
| Sugar → turn and feed | Left/right-separated taste-to-DN pathway | Sugar concentration → firing-rate encoding; DN difference → CPG step amplitude |
| Looming ball → back up | LPLC2 → giant fiber pathway and its timing | Giant fiber spike = back up |
| Activity without input | — (original model is silent) | Membrane noise |
| Activity comes in bursts | How bursts propagate across the brain | Adaptation current and its time-constant distribution |
| Constant left turning under noise alone | Intrinsic left bias of the DN population | — |
| Switching between actions | Fluctuations in each DN group's input | DN grouping, competing-unit parameters |
| The actual walking and grooming motions | — | CPG gait, hand-written grooming/startle trajectories |
So the accurate claim is: the connectome plus two pieces of basic physiology (noise, adaptation) is enough to spontaneously produce a decodable sequence of actions with real temporal structure. It does not show that this virtual fly's behavioral statistics match a real fly's — I haven't compared against recordings of spontaneous behavior in real flies. That's the next step.
On compute: 60 s of brain time takes 18–25 minutes on the M4 (about 20× slower than real time). That's why the web viewer shows pre-rendered videos rather than running the brain live.
Pitfalls
- Noise without adaptation gives you a fly that turns left forever. Turning DNs fire 34 Hz on the left and 7 Hz on the right, and more noise makes it worse. If you only check "is the brain active" and not the left/right split, you'll miss it.
- Spikes from small populations are not a signal. DN groups have 1–24 neurons; in 100 ms bins that's point-process noise. When v1 thresholded against the group mean, the 24-neuron grooming group almost never won, so I switched to within-group z-scores — which in turn artificially evens out the action shares. v2's synaptic-input readout is much smoother, but it still uses within-group z-scores, so the evened-out shares remain unsolved.
- The startup transient gets misread as an escape. A noisy network produces one global synchronous volley in its first 0.5 s, and the giant fiber fires with it. Run 0.5 s of warm-up and discard it.
- Warm up the visual network on the real scene. If flyvis sees a grey screen first and then the scene, the switch produces a strong transient that fires the giant fiber and triggers a false escape.
- The most "natural" input may not be usable. Intuitively flies find food by smell, but in this model olfactory input saturates 8,000 neurons with no left/right difference. Sweep the channels before choosing inputs; don't go by intuition.
- Look at bout-duration distributions, not just the video. v1's 12-second clip looks convincing; over 60 s, about 80% of bouts sit on the decoder floor. A single demo video proves nothing about how realistic the behavior is.