Magic Tools
Hands-OnBy CooconSeptember 26, 20266 views12 min read

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:

  1. Stimulus-driven: given sensory input, does the brain compute a motor signal in the right direction? This tests the connectome's wiring.
  2. 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 GRNs at 200 Hz for 0.3 s: 384 of 139,000 neurons activate. Top: spike raster; bottom: total spikes per 5 ms

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

Visual escape: left, the fly standing in MuJoCo with a black ball approaching from the front-left; top right, the two compound-eye images; right, three traces — flyvis T4/T5 response, FlyWire LPLC2 rate, giant fiber DNp01 spikes (blue left, orange right)

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:

Spontaneous behavior v1, 12 s with no input: left, the fly body; right, the decoded behavior strip, per-group DN z-scores and whole-brain rate

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:

  1. 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).
  2. 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.
  3. 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%

v1 vs v2, 60 s of brain time each: whole-brain inter-burst intervals, forward bout durations, grooming bout durations. Each dot is one burst or bout, the solid line is the median, the dashed line is v1's 0.3 s decoder floor. v1 collapses onto a line; v2 (two seeds pooled) spreads out

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.

Spontaneous behavior v2, 30 s with no input: in the behavior strip at top right, forward (green) and grooming (blue) bouts are clearly longer; bottom panel, grey is whole-brain rate, orange is slow arousal

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.

Related Articles

Claude Code "Error: Reached max turns (1)": when the headless guardrail fires, your file may already be written

Claude Code "Error: Reached max turns (1)": when the headless guardrail fires, your file may already be written

claude -p guardrails stop with Error: Reached max turns (1) or Error: Exceeded USD budget (0.01), exit 1. On 2.1.270 and 2.1.280 they are 28 and 33 bytes on stdout, not stderr, with no newline. In json mode the result key is missing, so jq -r .result prints null with jq exit 0. Failure does not mean nothing happened: --max-turns 2 errors after out.txt is written, and the budget is checked after each call, so a $0.05 cap spent $0.0517, finished the task and still exited 1.

claude-codeautomation+5
hands-onSep 25, 202611 min
55

DeepSeek Says 1M, Claude Code Says 200K: I Measured Both and Neither Number Is the Real Limit

DeepSeek advertises a 1M context window. Point Claude Code at it and Claude Code reports contextWindow 200000 for the same model. I measured what actually happens. DeepSeek's real ceiling is 1,048,576 tokens — literally 2^20, not one million — and it covers input plus your max_tokens budget, proven with a controlled pair. A needle planted at position zero was retrieved correctly at 1,039,744 tokens. Claude Code refuses client-side long before that, in 25ms with zero API calls, and its gate is not on tokens at all: it fires at roughly 480,000 characters. Feed it high-entropy text and 478,000 characters sails through carrying 309,567 real tokens — 55% past the 200K window it just claimed. And in ordinary use you reach none of these, because Bash output over exactly 30,000 characters never enters context at all.

claude-codelong-context+5
hands-onSep 20, 20267 min
112

Running Claude Code on DeepSeek: Everything Works, But the Cost Readout Lies by 38x

DeepSeek ships an Anthropic-format endpoint, so you can point Claude Code at it with three environment variables. I ran the whole thing on a real machine: every local tool (Read / Write / Bash / Glob / Edit / subagents) works and produces real side effects, so the short answer is yes, it works. The long answer is the part nobody measured — Claude Code bills DeepSeek tokens at Claude Sonnet rates. Ten identical turns: Claude Code reported $1.71, DeepSeek's actual balance dropped ¥0.32 (≈$0.045). That is a 38x over-report, measured against the invoice, not a price list. Also inside: the official docs are wrong about unknown model names (they 400, they don't fall back), v4-pro returns thinking blocks by default so a small max_tokens looks like an empty reply, and one failure that looks like DeepSeek's fault but isn't.

claude-codedeepseek+5
hands-onSep 20, 20268 min
98
MiniMax T2A v2 vs Azure Neural TTS, Benchmarked: 6–10× Latency Gap on the Same Text

MiniMax T2A v2 vs Azure Neural TTS, Benchmarked: 6–10× Latency Gap on the Same Text

My video factory wires up both MiniMax and Azure TTS. This benchmark measures them head to head: same Chinese + English text, 5 rounds each, unified 24kHz/mono/16bit output. MiniMax median latency 1.0–2.2s, RTF 0.08–0.18 (5–12× faster than real time); Azure median 6–21s, RTF near 1.0, tail jittering to 27s. Two causes, both with evidence: Azure Neural synthesizes at roughly real-time pace, and its eastasia endpoint is a trans-Pacific hop from mainland China (TLS jitter to 0.8s).

ttsrtf+6
hands-onSep 5, 20269 min
141