Introduction
This project connects a computational model of a fruit fly’s nervous system to a small quadrotor. The nervous system model is built directly from the wiring diagram of a real fly. The quadrotor is a Bitcraze Crazyflie 2.1 carrying a forward-facing camera and a downward-facing flow and range sensor. The camera feeds the model’s photoreceptors, the gyroscope feeds the neurons that a fly uses to sense body rotation, and the model’s wing motor neurons are read out and turned into flight commands. A learning procedure tunes the boundaries of the system, the way sensors are encoded and the way motor neurons are decoded, along with a small number of physiological constants, so that the whole thing can keep the drone in the air. The wiring itself is never changed.
The project is named Flatline, after the Dixie Flatline of Gibson’s Neuromancer: a recorded mind, run as a program, to do a job. The recorded wiring that the engine runs is called an imago, the entomological term for the adult insect and the Latin for image. A built imago is a file, and the engine animates it.
This section explains the ideas the design rests on, for readers who know software or robotics but not neuroscience, or the reverse.
Connectomes
A connectome is a map of every neuron in a piece of nervous tissue and every synapse between them, reconstructed from electron microscopy at a resolution fine enough to see individual synaptic contacts. The dataset used here is the Janelia FlyEM male central nervous system (CNS) release, version 1.0. It covers the brain, the optic lobes, and the ventral nerve cord (the fly’s equivalent of a spinal cord) of one adult male Drosophila melanogaster. It contains about 166,000 neurons with assigned cell types and about 25 million significant connections, where each connection records how many synapses link a presynaptic neuron to a postsynaptic one.
Three properties of this dataset make the project possible.
- It is complete from sense organ to muscle. Photoreceptors, the mechanosensory neurons of the halteres (the fly’s gyroscopic organs), the descending neurons that carry commands from the brain to the body, and the motor neurons that drive the wing muscles are all present and labeled.
- Each neuron has a predicted neurotransmitter. In the fly, acetylcholine is the main excitatory transmitter and GABA and glutamate are the main inhibitory ones. Knowing the transmitter tells us the sign of every connection.
- The optic lobe neurons carry coordinates on the hexagonal lattice of the compound eye, which lets us place each photoreceptor in the visual field.
A connectome is a structure, not a program. It says which neurons talk to which and how strongly, but not what any of them are doing at a given moment. To get behavior out of it, the structure has to be animated with a model of how neurons work.
Leaky integrate-and-fire models
The simplest useful model of a neuron treats its membrane voltage as a leaky capacitor. Incoming spikes push the voltage up (excitatory) or down (inhibitory), the voltage relaxes back toward a resting level with a characteristic time constant, and when it crosses a threshold the neuron emits a spike of its own, resets, and stays quiet for a brief refractory period. This is the leaky integrate-and-fire (LIF) model.
In 2024, Shiu and colleagues built a LIF model of an entire fly brain from the FlyWire connectome, with one free parameter, the voltage jump per synapse, and with connection signs taken from neurotransmitter predictions. Despite its simplicity the model reproduced known sensorimotor circuits: stimulating sugar-sensing neurons activated the feeding motor program, and stimulating specific mechanosensory neurons activated grooming. That result is the license for this project. If a signed LIF network built from a connectome recapitulates real circuits, it is worth asking what its flight circuits do when connected to a flying machine.
This project uses the same neuron model and the same initial constants, applied to the male CNS connectome, which unlike FlyWire includes the ventral nerve cord and therefore the wing motor neurons. One caution is owed up front: Shiu et al. drove spiking taste and touch neurons. This project’s main input is the retina, whose photoreceptors release histamine, an inhibitory transmitter, onto lamina cells that in the real fly signal by graded potentials rather than spikes. The design spec, section 8.6, states how this design keeps that pathway alive and how it will be checked.
How a fly flies, briefly
A fly’s flight control loop has four stages that the design mirrors.
- Vision. The compound eyes each have about 800 facets, and each facet samples one direction in the visual field. Downstream circuits in the optic lobes compute local motion, and wide-field neurons in the lobula plate integrate that motion into estimates of self-rotation and self-translation. This is optic flow processing, and it is the fly’s main source of information about drift.
- Halteres. The hindwings of flies have evolved into small club-shaped organs that beat with the wings. When the body rotates, Coriolis forces deflect them, and strain-sensing neurons at their base report the rotation. Halteres are fast gyroscopes and are essential for stable flight.
- Descending neurons. About 1,300 neurons carry commands from the brain down into the ventral nerve cord.
- Wing motor neurons. Two large power muscles drive the wingbeat, and about a dozen small steering muscles per side adjust wing stroke to produce turns, climbs, and corrections. The male CNS contains 67 wing motor neurons and 16 haltere motor neurons.
A quadrotor has none of this anatomy, so the last stage requires a translation: the pattern of activity across the wing motor neurons is mapped to the four things a quadrotor can be told to do, move sideways, move forward, turn, and climb.
The Crazyflie platform
The Crazyflie 2.1 is a 27 gram open-source quadrotor with a well-documented firmware and a Python client library. Two expansion decks are used. The AI deck adds a monochrome 324 by 324 pixel camera with an 87 degree field of view, a small processor, and a WiFi radio that can stream frames to a laptop. The flow deck v2 adds a downward time-of-flight range sensor and an optical-flow sensor, which let the firmware hold height and estimate horizontal velocity.
The firmware’s own stabilizer stays in the loop. The fly brain does not drive motors directly; it issues setpoints that the firmware executes. Two levels of setpoint are used. In hover mode the brain commands velocities and the firmware nulls drift on its own, which is safe but masks the brain’s contribution. In attitude mode the brain commands roll and pitch angles and must correct drift itself from vision and haltere input, which is the real experiment.
Evolution strategies
The parameters that must be learned are few, roughly ten thousand, and the system being tuned is a spiking network that is not differentiable in any convenient way. Evolution strategies fit this case. The optimizer keeps a mean parameter vector, samples a population of perturbed copies, runs each through a simulated flight, scores it, and moves the mean toward the perturbations that scored well. It needs only episode returns, runs identically on any hardware, and parallelizes across a population. The price is sample inefficiency, which is paid for with a batched simulator that advances many brains and many drones at once.
What to expect
It is not known whether a frozen connectome with tuned boundaries can hold a quadrotor in a hover. The literature suggests the visual and haltere circuits are the right ones, and the model will be given every sensible advantage: correct signs, correct sensory placement, a stabilizing firmware underneath, and a training curriculum that starts easy. But the project is an experiment, and the documentation is built as a lab notebook so that negative results are recorded as carefully as positive ones.
Background and related work
This chapter surveys the connectome dataset, the modeling approaches borrowed, and the flight hardware.
The male CNS connectome
The Janelia FlyEM male CNS v1.0 release is a full central nervous system reconstruction of one adult male Drosophila melanogaster: brain, optic lobes, and ventral nerve cord, imaged by electron microscopy and segmented into identified neurons. It contains roughly 166,700 typed neurons and about 25.6 million significant connections, recording how many synapses link a presynaptic neuron to a postsynaptic one. Every neuron carries a predicted neurotransmitter, giving a sign to each synapse, and optic lobe neurons carry column coordinates on the eye’s hexagonal lattice, letting photoreceptors be placed in a visual field.
A separate dataset, FlyWire, reconstructs a female whole brain but lacks a ventral nerve cord, and therefore wing motor neurons: it stops at the brain’s outputs, not muscle. That completeness is why this project uses the male CNS dataset.
Whole-brain spiking models
Shiu et al. 2024 built a leaky integrate-and-fire model of the entire FlyWire brain. Every synapse’s sign came from its presynaptic neuron’s predicted transmitter, and the model had one fitted free parameter, a voltage jump of 0.275 mV per synapse. Despite that simplicity, driving sugar-sensing neurons activated the feeding motor program, and driving mechanosensory neurons activated grooming. That result is this project’s license: a signed network built directly from a connectome can reproduce real circuit behavior without tuning individual connections.
A caution carries over rather than a guarantee. Shiu et al. drove excitatory taste and touch neurons, and their success says nothing about pathways that start differently. This project’s main input is the retina, and photoreceptors are histaminergic, an inhibitory transmitter; inhibition onto a resting spiking neuron does nothing, so vision needs its own answer first.
Connectome-constrained visual models
Lappalainen et al. 2024 took a different approach: a connectome-constrained rate model of the fly visual system, trained by task optimization rather than fit synapse by synapse, that predicted neural responses with good accuracy. The result matters here because fixed connectome structure plus a small set of learned parameters can produce function that matches a real nervous system. This project differs on three axes: spiking rather than rate-based, the whole nervous system rather than one pathway, and closed loop on a physical body rather than scored against recorded activity.
The optic lobe and the eye map
Nern et al. 2025 (Connectome-driven neural inventory of a complete visual system) is the source of the column coordinates used to place photoreceptors in the visual field. Zhao et al. 2025 (Eye structure shapes neuron function in Drosophila motion vision) reports measured facet directions for the compound eye, obtained directly rather than inferred from connectivity. The current design uses a parametric eye model built from the column coordinates; the measured directions are a natural input to a future, more accurate map.
Fly flight control
A fly’s flight loop runs through the stages this design mirrors. Vision starts at the compound eyes, where each facet samples one direction; motion detector neurons T4 and T5 compute local motion, and wide-field lobula plate neurons HS and VS integrate it into estimates of the fly’s own rotation and translation. This optic flow processing is the fly’s primary source of information about drift.
Halteres, the fly’s reduced hindwings, deflect under Coriolis forces when the body rotates; sensory neurons at their base report the deflection, making halteres fast gyroscopes feeding the wing motor system. Descending neurons, about 1,300 of them, carry commands from the brain into the ventral nerve cord, reaching the wing motor neurons: 67 in this dataset, driving the power muscles and the smaller steering muscles per side that produce turns, climbs, and corrections.
The Crazyflie platform
The Crazyflie 2.1 is a 27 gram open-source quadrotor with documented firmware and a Python client library, cflib. Two expansion decks supply the sensors used here: the AI deck adds a monochrome camera with an 87 degree field of view, streaming frames over WiFi to a laptop, and the flow deck v2 adds a downward time-of-flight range sensor and an optical-flow sensor for height and horizontal velocity. The firmware’s own stabilizer stays in the loop; the brain issues setpoints for it to execute rather than driving motors directly, and cflib sends the setpoints and reads telemetry back.
Where this project sits
This project is an early attempt to put a whole-CNS connectome model on a physical body and close the loop in real flight. The wiring itself is never changed; only the boundaries, sensory encoding, motor decoding, and a few global constants, are learned, by evolution strategies rather than by hand. What that framing does and does not claim about the resulting system is the subject of the ethics chapter.
See the References chapter for full citations.
Ethics and philosophical implications
This project sits at the meeting point of three lines of work that each carry their own questions: whole-brain modeling, embodied artificial agents, and autonomous flight. The questions are recorded here so that the project’s claims, and its limits, are stated before any result exists to tempt overstatement.
What is being simulated
The model is built from the wiring of one individual male fly. It keeps the neurons, the synapse counts, and the transmitter signs, and it discards nearly everything else: dendritic computation, graded signaling, electrical synapses, neuromodulation, plasticity, glia, development, and the hormonal and metabolic state of a living animal. It is a connectome-constrained spiking network, a structural echo of a fly, not an emulation of one. The project will describe it that way. Phrases such as “a fly brain flies a drone” are convenient and will be avoided in favor of “a network built from a fly connectome”. The boundary parameters and global constants are tuned by an optimizer, so any behavior the system shows is a joint product of the wiring and the tuning, and the paper must separate the two.
Epistemic commitments
Two commitments follow. First, the wiring stays frozen and the learnable set stays small, so that whatever the optimizer finds is constrained by the connectome rather than replacing it. Second, every claim about the connectome’s contribution is tested against controls with the same learnable set: a connectome whose internal wiring is shuffled within synapse-count classes, preserving every neuron’s synapse totals, sign, and sensory interface, and an untrained network with default constants. If the shuffled control flies as well, the wiring did no work, and that is the result to report. Negative results are recorded in the notebook with the same care as positive ones.
Moral status
Whether insects have experiences that matter morally is an open scientific and philosophical question; recent statements by researchers in animal consciousness treat it as a realistic possibility rather than a settled negative. This project takes the position that the simulation is not the animal. It lacks the biophysics, the body, and the internal states that any current theory of experience relies on, and it is far coarser than the models that would raise the question seriously. That position is stated as an assumption, not a proof, and it is one the field will have to revisit as models become richer. No live animals are used in this project. The dataset derives from a single fly that was sacrificed for the connectome; using that data carefully and crediting it properly is the only way to honor that cost.
Re-embodiment
A fly’s nervous system evolved for a body with wings, halteres, legs, and eyes that span nearly the full sphere. Here it is given a quadrotor with a single 87 degree camera and a gyroscope, and a control interface that is at best an analogy to wing steering. Success would suggest that some of the circuits compute something general enough to survive that transplant, for example an estimate of self-rotation from optic flow that is useful to any flying body. Failure would be harder to interpret, because it could reflect the model, the interface, the sensors, or the optimizer. The design tries to make failure informative through ablations and through the hover-mode curriculum, which isolates the brain’s contribution stage by stage. Closed-loop embodiment is a stronger test than replaying recorded stimuli, because errors feed back into the input, and that is why the project puts the model on a physical machine rather than only in a simulator.
Whole-brain emulation
The fly is the first organism for which a complete central nervous system wiring diagram and a working functional model both exist. Giving such a model a body is the natural next step, and this project is among the early attempts to do so in hardware. That places it on a path that leads, in the long run, toward emulating larger nervous systems, with all the questions about identity, consent, and welfare that path raises. Nothing in this project approaches those questions directly, but a project on the path should say so, and should keep its methods and its language modest enough that others can build on them without inheriting exaggerated claims.
Dual use and physical safety
Autonomous flight controllers derived from neural networks have obvious uses beyond science, and a biologically derived controller is no exception in principle. In practice this controller is a 27 gram research platform that struggles to hover in a workshop, and its scientific value lies in what it reveals about a fly’s circuits, not in its performance as a controller. The repository is private during development and the results will be published as science. Physical safety is a direct obligation: the supervisor, geofence, kill switch, and prop guards exist to protect people in the workshop, and no flight takes place with a person inside the geofence.
Credit and provenance
The connectome is the product of years of work by the Janelia FlyEM project and its collaborators, and the eye-map and visual-system analyses come from the Reiser lab. Their data are used under their published terms and cited in every output. The imago built by this project records the source file hashes so that derived results can be traced to the exact release. No code from those groups is copied into this repository; their conventions are followed and referenced.
Design
This section documents how Flatline Imago is put together: how the raw
connectome files are ingested into a single .imago construct, and how
the brain engine animates that construct as a signed leaky
integrate-and-fire network. It also carries the external review that
shaped the current design.
Connectome ingestion and brain engine
Connectome ingestion
Inputs
From ~/models/fly/model/flat-connectome/:
| File | Used for |
|---|---|
body-annotations-male-cns-v1.0-minconf-0.5.feather | Neuron identity: bodyId, superclass, class, subclass, type, instance, somaSide, rootSide, entryNerve, exitNerve, assignedOlHex1, assignedOlHex2, status |
body-neurotransmitters-male-cns-v1.0.feather | consensus_nt per body |
connectome-weights-male-cns-v1.0-minconf-0.5-significant-only.feather | Edges: body_pre, body_post, weight (synapse count) |
connectome-weights-male-cns-v1.0-minconf-0.5.feather | Full edge list, used only to infer photoreceptor columns |
The synapse-point and synapse-partner files are not used.
Neuron set
Neurons are the bodies with a non-null superclass, about 166,000. Each receives a dense index in a stable order (sorted by bodyId). Region masks (see Region masks) select subsets at load time without rebuilding.
Signs and effective weights
Each synapse’s sign comes from the presynaptic neuron’s consensus neurotransmitter, following Shiu et al.:
| Transmitter | Sign |
|---|---|
| acetylcholine, dopamine, serotonin, octopamine | +1 |
| GABA, glutamate, histamine | −1 |
| unclear (the dataset’s own label, 2,999 neurons) | +1, and the neuron is flagged |
| no row in the transmitter file (178 neurons) | treated as unclear and flagged |
The effective weight of an edge from neuron \(i\) to neuron \(j\) is
\[ w_{ij} = c_{ij} \cdot \mathrm{sign}(nt_i) \cdot s[nt_i] \cdot g[t_i] \cdot W_{\mathrm{syn}} \]
where \(c_{ij}\) is the synapse count, \(nt_i\) and \(t_i\) are the presynaptic neuron’s transmitter and gain group, \(s\) is a learnable per-transmitter scale (eight values in the fixed table order acetylcholine, gaba, glutamate, dopamine, serotonin, octopamine, histamine, unclear; initialized to 1 and constrained non-negative so learning can never flip a sign), \(g\) is a learnable per-gain-group factor (design spec, section 12.1), and \(W_{\mathrm{syn}}\) is 0.275 mV, the Shiu et al. value. Monoamines are excitatory here because Shiu et al. treated them so; that is a recorded decision (design spec, section 4), not a fact about the fly. \(W_{\mathrm{syn}}\) was fitted by Shiu et al. on FlyWire feeding circuits, and its transfer to this dataset is a risk carried in the design spec, section 15. The imago stores counts and signs; scales and gains are applied at load.
Edges whose postsynaptic neuron is an input neuron are dropped at build time and counted in the metadata: input neurons are driven by encoders, never by the network.
A build option produces a shuffled imago for the control condition of the design spec, section 12.5. Edges are grouped by synapse count and, within each group, their destinations are permuted with a seeded generator. Every neuron therefore keeps its exact outgoing edges and their counts, its exact incoming synapse total and incoming count distribution, and its transmitter sign, while its partners are randomized: the synapse totals are preserved exactly, but the number of distinct partners a neuron has may change, because two permuted edges occasionally land on the same pair and are merged. Edges whose presynaptic neuron is an input neuron are never shuffled, so the control shares the real sensory interface and randomizes only the brain’s internal wiring. The sidecar records the seed, the number of edges shuffled, and the number merged.
Imago format
A single safetensors file with the .imago extension plus a JSON
sidecar, about 300 MB:
pre_indptr,pre_indices,pre_counts: edges grouped by presynaptic neuron (int64 pointers, int32 indices, int16 counts). Used by the event propagator.post_indptr,post_indices,post_counts: the same edges grouped by postsynaptic neuron. Used by the batched propagator.- Per-neuron arrays:
body_id(int64),nt(int8 index into the transmitter table),type_id(int32 index into the type table),superclass_id,side(int8: left, right, unknown). - Tables in the sidecar: transmitter names, type names, superclass names, build metadata (source file hashes, date, git describe).
- Named neuron sets:
photoreceptorswith per-neuron eye and column,virtual_photoreceptors,haltere_afferentswith side,wing_motorandhaltere_motorwith side and type,descending.
Photoreceptor placement
Photoreceptor cell bodies lie in the retina, outside the imaged volume, so they carry no hex coordinates and no soma side. Two inferences supply them:
- Eye:
rootSide(3,746 right, 2,345 left). - Column: the hex column receiving the largest summed synapse count from the photoreceptor, over hex-bearing targets, using the full edge list (only 4,038 photoreceptors have any significant-only outgoing edge). The column is chosen by summed weight rather than by the single strongest target because a lamina cartridge, not a cell, is what a photoreceptor innervates; on this dataset the two rules agree on nearly every cell (median fraction of weight on the best column is 1.0). The eye fallback and the recorded target side are the side of that winning column. Hex-bearing targets in v1.0 are exactly the 23,720 optic lobe intrinsic cells of fifteen types: L1, L2, L3, L5, C2, C3, T1, Mi1, Mi4, Mi9, Tm1, Tm2, Tm4, Tm9, Tm20. Placement succeeds for 5,895 of 6,091 photoreceptors, and the target side agrees with the root side in every case.
Coverage of the resulting map:
| Eye | Columns | With any photoreceptor | With R1-R6 | With R7 or R8 |
|---|---|---|---|---|
| Right | 892 | 784 | 526 | 730 |
| Left | 879 | 682 | 300 | 638 |
The reconstructed retina is incomplete and imperfectly placed: a real column has six R1-R6 cells, but placed columns hold between one and eleven (v1.0 build, 826 columns with any R1-R6: 240 hold six, 547 hold fewer, 39 hold seven to eleven, the last being placement errors), and 2,054 of the 6,091 photoreceptors have no outgoing edge at all in the significant graph. The design spec, section 8.3, describes the two corrections that follow from this — a per-lamina-cell factor \(6m/S\), where \(S\) is the R1-R6 synapse count a lamina cell receives and \(m\) the median single-cell count onto its type, and a virtual photoreceptor for every column holding an undriven lamina cell — and the build report that records these counts.
Other named sets
| Set | Count | Selection |
|---|---|---|
| Haltere afferents | 439 (220 right, 219 left) | sensory superclass, entryNerve DMetaN, side from rootSide |
| Wing motor neurons | 67 (33 left, 34 right) | subclass wm; side from somaSide |
| Haltere motor neurons | 16 (8 per side) | subclass hm; side from somaSide |
| Descending neurons | 1,314 | superclass exactly descending_neuron |
Side rule: sensory neurons carry rootSide and a null somaSide; motor
and central neurons carry somaSide and a null rootSide. The imago
records somaSide when present, else rootSide. The haltere afferent
set keeps each cell’s subclass (haltere 205, campaniform sensilla 195,
mechanosensory bristle 39) and type (22 types) as fields, so downstream
encoders can group by type rather than by cell.
Brain engine
Neuron model
Each neuron has a membrane voltage \(v\) and a synaptic variable \(g\), following the Shiu et al. formulation:
\[ \tau_m \frac{dv}{dt} = (v_{\mathrm{rest}} - v) + g + b \qquad \text{(unless refractory)} \]
\[ \tau_s \frac{dg}{dt} = -g \qquad \text{(unless refractory)} \]
\[ g_j \leftarrow g_j + w_{ij} \qquad \text{on presynaptic spike } i \text{ after delay } d \text{, also while refractory} \]
\[ \text{if } v > v_{th}: \quad \text{spike}, \; v = v_{\mathrm{reset}}, \; g = 0, \; \text{refractory for } t_{\mathrm{ref}} \]
These are the Shiu et al. rules as implemented in their released code:
both differential equations are frozen while refractory, incoming
synaptic weight still accumulates into g during that time, the
threshold is strict, and the reset zeroes g. The term b is a
per-neuron bias in mV, zero by default, used by the visual transmission
policy of the design spec, section 8.6.
Initial constants (Shiu et al. 2024):
| Constant | Value |
|---|---|
| τ_m (membrane time constant) | 20 ms |
| τ_s (synaptic time constant) | 5 ms |
| v_rest | −52 mV |
| v_th | −45 mV |
| v_reset | −52 mV |
| t_ref | 2.2 ms |
| d (spike delay) | 1.8 ms, rounded to 2 steps at 1 ms |
| W_syn | 0.275 mV per synapse |
Integration is exponential Euler with step \(dt\), default 1 ms, with 0.1 ms available for fidelity checks. For a non-refractory neuron:
\[ g \leftarrow g \, e^{-dt/\tau_s} + (\text{delayed incoming weights}) \]
\[ v \leftarrow v_{\mathrm{rest}} + g + b + (v - v_{\mathrm{rest}} - g - b) \, e^{-dt/\tau_m} \]
For a refractory neuron \(v\) stays at \(v_{\mathrm{reset}}\) and
\(g\) keeps its value plus any delayed incoming weights (no decay).
Step counts are round(t_ref/dt) for the refractory period (2 at 1 ms)
and max(1, round(d/dt)) for the delay (2 at 1 ms).
Learnable global knobs: the eight transmitter scales (non-negative), \(\tau_m\), \(\tau_s\), an additive threshold offset, the per-group gains and the lamina bias of the design spec, sections 12.1 and 8.6. Gains are regularized toward 1 in the training objective. Optional Gaussian membrane noise is available as a knob but off by default.
Input neurons
Photoreceptors, virtual photoreceptors, and haltere afferents are input
neurons. Their membrane dynamics are bypassed: v and g are held at
rest and no edge targets them (see Signs and effective
weights). Each step they spike with
probability rate_hz × dt_ms / 1000 where the rate is supplied by an
encoder. This is a deliberate simplification of Shiu et al., who added
Poisson input to the membrane of otherwise normal neurons; forcing the
spikes directly makes the encoder’s rate the exact firing rate and costs
nothing in the pathway we care about, since photoreceptor output is the
spike train itself.
Propagation interface
class Propagator(Protocol):
def propagate(self, spikes: Tensor) -> Tensor:
"""spikes: bool [B, N] (B=1 in flight). Returns weight input [B, N]."""
Two implementations:
- Event propagator. Finds spiking indices, gathers their outgoing
segments from the presynaptic CSR, expands with
repeat_interleave, andindex_add_s effective weights into the input vector. Works on Metal, ROCm, and CPU. Used in flight (B = 1). - Batched propagator. Computes the input for all B brains as a
sparse-by-dense product using the postsynaptic CSR on CPU and ROCm.
On Metal, where sparse support is thin, the event propagator handles
all B brains in one packed gather and scatter over the flattened
[B × N]state, never a Python loop over brains.
The event path pays one device-to-host synchronization per step to size the gathered index (the spike count is data dependent); that is inherent to event-driven propagation and is accounted for in the compute budget of the design spec, section 19.
A native (Rust or C++) event kernel may be substituted behind the same interface later. Tests require the two implementations to agree exactly on weights that are exact in float32 (dyadic rationals) and to within a small tolerance on random graphs, because scatter-add order differs between devices and implementations.
Delays
A ring buffer of two spike vectors implements the 2 ms delay. The propagator consumes the vector from two steps ago.
Real-time clock
In flight the engine steps to keep brain time within a configured tolerance of wall time, default 20 ms. Falling behind by more than the tolerance raises a brain-lag fault to the supervisor. Before takeoff the supervisor requires a measured real-time ratio above 1.0 for the configured mask on the current device, taken from the benchmark tool.
Region masks
A mask is a TOML file listing superclasses, classes, or explicit types to include or exclude. Masks are a benchmarking and ablation tool, not a real-time strategy: the optic lobes alone are 89,403 of the 166,700 neurons and cannot be dropped without dropping vision, and excluding everything that is not plausibly involved in flight removes only about 0.2% of neurons. Presets:
full: every neuron in the imago (166,700 real plus 1,250 virtual photoreceptors, 167,950 in all).no-optic-lobe: excludes superclassesol_intrinsic,ol_sensory,visual_projection,visual_projection_tbc, andvisual_centrifugal, and the virtual photoreceptors, leaving 61,433 neurons and 12,165,352 edges. A compute probe and a “blind” ablation; it is never a flight configuration.
Edges to or from excluded neurons are dropped at load. The benchmark tool reports steps per second for each preset on each device, and flight is gated on the measured real-time ratio of the configuration actually flown.
Recording
Named neuron sets can be recorded to a spike ring buffer and flushed to disk as compressed arrays. Flight runs record motor neurons and descending neurons by default; full-brain rasters are available for offline analysis.
Determinism
All randomness is seeded and drawn on the CPU so the random stream is identical across backends. Given the same device, backend, and seed, a run is reproducible up to floating-point scatter order, which is not bitwise stable on GPUs; comparisons across runs use tolerances, and exactness is asserted only on CPU.
Tests
- Three-neuron chains and excitation-inhibition motifs on synthetic graphs with analytically known spike times.
- Event and batched propagators agree exactly on dyadic weights and to tolerance on random graphs.
- Input neurons hold
vandgat rest under a strong incoming edge, and such edges are absent from the built imago. - Delay buffer ordering.
- Refractory handling and reset.
- Mask application drops the right edges.
The benchmark is a tool, not a test.
Implementation notes
Module layout
The engine is implemented across the following modules, per the sub-project plan’s File Structure table:
| Module | Contents |
|---|---|
src/flatline/cli.py | CLI entry point: the three subcommands build-imago, imago-info, and bench |
src/flatline/util/devices.py | Device selection (cuda/ROCm, mps, cpu) |
src/flatline/connectome/sources.py | Reading the feather source files |
src/flatline/connectome/imago.py | The .imago safetensors file and JSON sidecar format |
src/flatline/connectome/ingest.py | Neuron set construction and edge ingestion |
src/flatline/connectome/photoreceptors.py | Photoreceptor eye and column placement |
src/flatline/connectome/sets.py | Named neuron sets (photoreceptors, haltere afferents, wing motor, haltere motor, descending) |
src/flatline/connectome/shuffle.py | Within-synapse-count-class partner shuffle for the control condition |
src/flatline/brain/params.py | LIF parameters and learnable knobs |
src/flatline/brain/weights.py | Effective edge weights, lamina-scoped retina scaling |
src/flatline/brain/mask.py | Region mask loading and application |
src/flatline/brain/propagate.py | Event and batched propagators |
src/flatline/brain/engine.py | The stepped LIF engine |
src/flatline/brain/record.py | Spike recording to disk |
src/flatline/brain/clock.py | Real-time clock and lag detection |
src/flatline/brain/bench.py | The benchmark tool |
Mask presets live at configs/masks/full.toml and
configs/masks/no-optic-lobe.toml.
Build metadata, v1.0 release
Running flatline imago-info against the male CNS v1.0 imago built by
build-imago on this release reports:
| Field | Value |
|---|---|
n_neurons | 167,950 (166,700 real + 1,250 virtual photoreceptors) |
n_edges | 25,530,591 (after dropping edges onto input neurons) |
n_virtual | 1,250 |
n_edges_dropped_onto_inputs | 32,441 |
nt_flagged | 3,177 |
n_gain_groups | 1,296 |
photoreceptors (named set) | 6,091 |
haltere_afferents (named set) | 439 |
wing_motor (named set) | 67 |
haltere_motor (named set) | 16 |
descending (named set) | 1,314 |
The same build writes a retina report into the sidecar:
| Field | Value |
|---|---|
photoreceptors_without_outgoing_edge | 2,054 of 6,091 |
columns_over_six_r16 | 39 |
lamina_cells_zero_drive_before | 3,673 of 5,327 |
lamina_cells_zero_drive_after | 720 |
virtual_photoreceptors_added | 1,250 |
lamina_norm min / median / max | 0.476 / 6.0 / 252.0 |
The 720 lamina cells still without drive all lack a hex column (901 lamina
cells do), so no virtual photoreceptor can reach them. A lamina_norm of 252 is a cell whose whole
reconstructed input is a single small synapse count; the factor is
uncapped by design, and whether it should be is an open question for the
encoder work.
Build time on the Mac M3 Max is about 12 s.
Neuron model fidelity
The neuron model follows the Shiu et al. released code, not just the
published equations: both differential equations are frozen while
refractory, incoming synaptic weight still accumulates into g during
the refractory period, the threshold is strict, and reset zeroes g.
Input neurons (photoreceptors, virtual photoreceptors, and haltere
afferents) are held at rest with no incoming edges; they are driven
entirely by their encoder’s spike probability, never by the network.
Propagator agreement
The event propagator and the batched propagator are required to agree exactly on weights that are exact in float32 (dyadic rationals), and to within a small tolerance on random graphs, since scatter-add order differs across devices and implementations.
External review, 2026-09-15
An external review dated 2026-09-15 examined the spec and the first
implementation plan against the dataset, the Shiu et al. code, and the
cflib source. Its findings and their dispositions follow. The section
numbers in the disposition column refer to the design specification,
docs/superpowers/specs/2026-09-15-flatline-imago-design.md, not to
chapters of this book.
| Finding | Disposition |
|---|---|
| Signed LIF with histaminergic photoreceptors silences the lamina | Accepted; section 8.6 policy and probe |
| LIF differs from Shiu et al. (g reset, refractory freeze, strict threshold) | Accepted after checking the released code; section 7.1 |
| Hover curriculum solvable by a zero decoder | Accepted; section 12.3 |
| No optic-flow diagnostic | Accepted; section 8.6 probe |
| 10 Hz camera far below motion-vision bandwidth | Accepted as risk and measurement; section 8.5 |
| Haltere round-robin discards type structure | Accepted; grouping by type; section 8.4 |
flight-core mask removes 0.2% of neurons | Accepted; replaced by no-optic-lobe, masks are not a real-time strategy; section 7.6 |
| Training compute unbudgeted | Accepted; section 19 |
| Safety envelope inadequate for an open workshop | Accepted; section 10.5 |
| Missing success criteria and open questions | Accepted; section 17 |
| Connectome contract errors (unclear label, eight scales, 1,314 descending, side rule, hex target types) | Accepted; sections 6.3, 6.5, 6.6 |
| Decision log lacks alternatives and reasons | Accepted; section 4 |
| Spec and plan file names diverge | Accepted; section 13.1 |
| Command-axis signs half-specified | Accepted after checking cflib; section 10.4 |
| Clock, threads, determinism underspecified | Accepted; sections 7.8 and 10.1 |
| Shuffle does not preserve in-degree | Accepted; the shuffle permutes partners within synapse-count classes, section 6.3 |
| Retina normalization scaled every photoreceptor edge | Accepted; section 8.3 |
| Photoreceptor column should be the strongest single target | Rejected; strongest column by summed weight retained with the reason in section 4 |
| Input neurons not bypassed and edges onto them kept | Accepted; sections 6.3 and 7.2 |
| Full edge table loaded whole for placement | Accepted; plan filters by photoreceptor before materializing |
| Event propagator loops per brain on Metal | Accepted; packed batch; section 7.3 |
| Config and checkpoint schemas missing | Deferred to the sub-project plans that create them |
The full review is filed at
docs/reviews/2026-09-15-grok-review.md
in the repository.
Execution rulings, sub-project 1
Sub-project 1 (connectome ingestion, brain engine, and this book) was implemented on 2026-09-15 by a controller session dispatching one fresh implementer per plan task with a review after each, followed by a whole-branch review, two independent code reviews, and one consolidated fix wave. Decisions the controller took on the owner’s behalf are listed here in the order they were made, with what each costs if it turns out wrong. The ledger they were copied from lived in the gitignored SDD workspace and was deleted after the merge; this chapter is the record.
Process rulings
- Work proceeded on branch
enginein the main checkout rather than a worktree: the repository was new with nothing onmasterto protect. Cost if wrong: a branch switch. .superpowers/was added to.gitignorebefore the first task so the execution workspace could never be committed. Cost: a one-line merge.- Docstring-only
__init__.pystubs need nofrom __future__ import annotations; the style rule exists for annotated code. Cost: one import per stub. - A commit-message-only amend was verified by the controller instead of a scoped re-review, since the file diff was empty. Cost: none.
- The commit trailer named in the plan binds every subagent regardless of the model that actually ran it. Cost: none.
- Two small changes to finished modules (the
gain_groupfield and thepre_idsfilter) were folded into a later task rather than reopening finished ones. Cost: none. - At the owner’s request the book task ran in parallel with the engine
tasks in a separate worktree on branch
book, with the benchmark notebook entry deferred until the benchmark existed. Cost: a merge, which was clean. - Two defects in the plan’s own test code (a
zip(..., strict=True)over a shifted slice, and a mutable default argument) were fixed by ruling rather than by changing the engine. Cost: none. - After the re-review of the fix wave, the controller edited two
documentation lines and one configuration comment directly, gated by
make all. Cost: none.
Design rulings
- A photoreceptor’s column is the hex column receiving the largest summed synapse count, not its single strongest target, because a lamina cartridge is what a photoreceptor innervates; the side comes from the winning column. On this dataset the two rules agree on nearly every cell. Cost if wrong: a re-placement pass.
- The external review’s findings were accepted and folded into the spec and plan, except the single-strongest-target rule above.
- Config and checkpoint schemas are deferred to the sub-project plans that create them.
- The book keeps a paraphrased lead-in and drops a cross-reference in the data chapter, because the referenced section is not in the book. A reviewer’s objections to the background chapter’s sourcing were overruled: the neuron and edge counts, the FlyWire brain being female, and the characterizations of the cited work are correct. Cost: a sentence edit.
- MathJax stays enabled and genuine equations are rendered as math, at the owner’s instruction.
- The retina correction was redesigned after the whole-branch review measured that the per-photoreceptor rule left the median lamina cell with one sixth of the intended drive and 27% of lamina cells with none. It is now per lamina cell (six cell-equivalents from whatever reaches the cell) with virtual photoreceptors wherever a lamina cell has no drive. Cost: a rebuild, already done; the first benchmark entry records both builds.
- The shuffled control was redesigned after the code review measured that the synapse-stub model quadrupled the edge count and flattened every weight. It now permutes destinations within synapse-count classes, preserving each neuron’s synapse totals, the edge count, and the weight distribution, and it never touches edges from input neurons, so the control shares the real sensory interface. Cost: the control’s definition changed before any training used it.
- The event propagator’s second host synchronization per step, the pandas typing convention, and the duplication between the spec and the book chapters are deferred follow-ups, recorded in the notebook and below.
Parked and deferred
- The shuffle’s int16 merge clamp is latent: the largest merged count in the v1.0 control is 2,601 against a ceiling of 32,767, and no counter reports a clamp. Real, not load-bearing.
- Per-task minor findings, all triaged “can wait” by the whole-branch
review: broader ruff selection than the standard;
pick_device("")auto-selects; sharedtablesandmetabetween derived imagos; the fixture’s repeated photoreceptor loops; mislabeled type-ignore codes and an unused import in one test; pandas cast density; path comments and a rebound local in ingestion; an untyped test helper; no CLI handling of missing paths (must be fixed before the flight supervisor ships); a shared helper for the two edge-orientation functions; no direct test of class-based mask inclusion or of the Metal batched propagator selection; per-step temporaries in the engine step and an untested noise branch; recorder docstrings; two type-ignores in the benchmark test.
Data
This section documents the data artifacts Flatline Imago builds and
consumes: the .imago file that packages the connectome into a form
the brain engine can load directly, its named neuron sets, and how the
photoreceptor and other sensory placements were derived from the source
dataset.
The imago
Format
A single safetensors file with the .imago extension plus a JSON
sidecar, about 300 MB:
pre_indptr,pre_indices,pre_counts: edges grouped by presynaptic neuron (int64 pointers, int32 indices, int16 counts). Used by the event propagator.post_indptr,post_indices,post_counts: the same edges grouped by postsynaptic neuron. Used by the batched propagator.- Per-neuron arrays:
body_id(int64),nt(int8 index into the transmitter table),type_id(int32 index into the type table),superclass_id,side(int8: left, right, unknown). - Tables in the sidecar: transmitter names, type names, superclass names, build metadata (source file hashes, date, git describe).
- Named neuron sets:
photoreceptorswith per-neuron eye and column,virtual_photoreceptors,haltere_afferentswith side,wing_motorandhaltere_motorwith side and type,descending.
Transmitter signs
Each synapse’s sign comes from the presynaptic neuron’s consensus neurotransmitter, following Shiu et al.:
| Transmitter | Sign |
|---|---|
| acetylcholine, dopamine, serotonin, octopamine | +1 |
| GABA, glutamate, histamine | −1 |
| unclear (the dataset’s own label, 2,999 neurons) | +1, and the neuron is flagged |
| no row in the transmitter file (178 neurons) | treated as unclear and flagged |
Photoreceptor coverage
Coverage of the reconstructed retina map, produced by inferring each
photoreceptor’s eye from rootSide and its column from the hex column
receiving the largest summed synapse count over hex-bearing targets:
| Eye | Columns | With any photoreceptor | With R1-R6 | With R7 or R8 |
|---|---|---|---|---|
| Right | 892 | 784 | 526 | 730 |
| Left | 879 | 682 | 300 | 638 |
The reconstructed retina is incomplete and imperfectly placed: a real column has six R1-R6 cells, but placed columns hold between one and eleven (v1.0 build, 826 columns with any R1-R6: 240 hold six, 547 hold fewer, 39 hold seven to eleven, the last being placement errors), and 2,054 of the 6,091 photoreceptors have no outgoing edge at all in the significant graph.
Side rule
Sensory neurons carry rootSide and a null somaSide; motor and
central neurons carry somaSide and a null rootSide. The imago
records somaSide when present, else rootSide. The haltere afferent
set keeps each cell’s subclass (haltere 205, campaniform sensilla 195,
mechanosensory bristle 39) and type (22 types) as fields, so downstream
encoders can group by type rather than by cell.
Lab notebook
Dated entries, newest last. Every entry has the same shape: goal, setup, what happened, results, conclusions, next steps. Setup always records the git describe string, the machine, the device, the imago build metadata, and the exact command.
First benchmark of the whole-CNS imago
Goal
Measure steps per second at batch 1 (the flight gate) for the full imago and for the no-optic-lobe probe on the Mac, on cpu and mps, at a baseline input rate and a high-contrast input rate, to learn whether real time is within reach before any optimization. Masks are a compute probe here, not a strategy: the no-optic-lobe run removes vision and can never fly.
Setup
- git describe:
996072e, then the two mps batch-1 rows re-measured on the fix-wave build (see the note under Results) - machine: Mac M3 Max, 128 GB
- imago:
data/imagos/male-cns-v1.0.imago, meta: n_neurons 167,950 (166,700 real + 1,250 virtual photoreceptors), n_edges 25,530,591, n_virtual 1,250, n_edges_dropped_onto_inputs 32,441, n_gain_groups 1,296, nt_flagged 3,177 - the edge count is arithmetic: 25,560,079 significant edges with both ends in the neuron set, minus 32,441 edges onto input neurons, plus 2,953 edges from the 1,250 virtual photoreceptors, is 25,530,591
- command:
uv run flatline bench --imago data/imagos/male-cns-v1.0.imago --mask configs/masks/<mask>.toml --device <device> --seconds 2 --rate <rate>(batch 1); the batch run used--mask configs/masks/full.toml --device cpu --batch 16 --seconds 0.5 --rate 50.
What happened
All nine runs completed with no crashes, timeouts, or memory problems. Each 2 s run took well under a minute including imago load and a 50-step warm-up.
Results
| mask | device | rate Hz | neurons | edges | steps/s | real-time ratio | mean spikes/step |
|---|---|---|---|---|---|---|---|
| full | cpu | 50 | 167642 | 25529886 | 129.1 | 0.129 | 1926.9 |
| full | cpu | 200 | 167642 | 25529886 | 116.7 | 0.117 | 2070.6 |
| full | mps | 50 | 167950 | 25530591 | 526.9 | 0.527 | 1966.8 |
| full | mps | 200 | 167950 | 25530591 | 510.7 | 0.511 | 2095.6 |
| no-optic-lobe | cpu | 50 | 61435 | 12165384 | 152.9 | 0.153 | 1907.0 |
| no-optic-lobe | cpu | 200 | 61435 | 12165384 | 145.2 | 0.145 | 1994.6 |
| no-optic-lobe | mps | 50 | 61435 | 12165384 | 588.4 | 0.588 | 1907.0 |
| no-optic-lobe | mps | 200 | 61435 | 12165384 | 590.3 | 0.590 | 1994.6 |
Training-shaped run (batch 16, cpu, full, 0.5 s, rate 50): 9.8 steps/s, about 157 brain-steps per second, mean spikes/step 1731.0.
The two mps full-imago rows were re-measured after the fix wave that redesigned the retina correction (the imago now carries 1,250 virtual photoreceptors rather than 942, and 705 more edges). At 50 Hz throughput rose from 494.0 to 526.9 steps per second, 6.7%; at 200 Hz it moved from 507.7 to 510.7, under 1%. The other six rows are the original measurements on the pre-fix build, whose counts were 167,642 neurons and 25,529,886 edges.
Conclusions
The flight gate, a real-time ratio above 1.0 at batch 1, is not met on either device. Metal reaches about half real time on the full imago, and the CPU reaches about an eighth.
Throughput looks bound by per-step overhead rather than edge count.
Dropping the optic lobes removes 63% of neurons and most edges, yet
Metal throughput only rises from about 500 to about 590 steps per
second. Candidates for the bottleneck are the per-step host
synchronization in the event propagator, the number of small kernel
launches per step in the engine (several where operations with fresh
temporaries), and the Bernoulli draw that is currently made on the CPU
each step.
Mean activity sits between about 1,900 and 2,100 spikes per step, around 1.2% of neurons per millisecond (3.1% of the 61,435 neurons in the no-optic-lobe runs), and barely changes between 50 Hz and 200 Hz input. This suggests the network’s activity is dominated by its own recurrent dynamics under this drive rather than by the input rate. This needs a look before any encoder work: spike rasters by superclass, and a check on whether activity is stable or growing over a longer run.
Two structural facts from the final review bear on this. Of the 167,950 neurons, 3,270 have no outgoing edge at all and 2,337 are fully isolated, so about 2% of the graph can never contribute. And the optic lobe is nearly silent under inhibitory photoreceptor drive: that is why removing it barely changes spikes per step, and it is exactly the phenomenon the visual transmission policy of the design spec, section 8.6, is meant to address.
The CPU batched path gives no per-brain speedup at batch 16, about 157 brain-steps per second total, roughly the same as batch 1. CPU training is not viable at this scale. The training gate depends on straylight’s ROCm path or a faster kernel.
Next steps
Profile one step on Metal to attribute time between propagation, the engine’s elementwise updates, and the input draw. The event propagator makes two device-to-host synchronizations per step, one to list the spiking neurons and one to size the gather, at roughly 0.2 ms each on mps; a fixed-capacity padded gather that removes both is the lever to pull first. Fuse the engine’s elementwise updates and keep the Bernoulli draw on the device. Measure a longer run (30 s) to check activity stability and record rasters by superclass. Then measure batch 64 on straylight.
References
- Shiu, P. K. et al. A Drosophila computational brain model reveals sensorimotor processing. Nature 634, 210–219 (2024). https://www.nature.com/articles/s41586-024-07763-9
- Nern, A. et al. Connectome-driven neural inventory of a complete visual system. Nature (2025). https://doi.org/10.1038/s41586-025-08746-0 Code: https://github.com/reiserlab/male-drosophila-visual-system-connectome-code
- Zhao, A. et al. Eye structure shapes neuron function in Drosophila motion vision. Nature (2025). https://www.nature.com/articles/s41586-025-09276-5 Code and eye map: https://github.com/reiserlab/eyemap_T4
- Lappalainen, J. K. et al. Connectome-constrained networks predict neural activity across the fly visual system. Nature 634, 1132–1140 (2024).
- Janelia FlyEM male CNS connectome v1.0 (dataset used here).
- Bitcraze AB. Crazyflie 2.1, AI deck 1.1, and Flow deck v2 documentation (2025). https://www.bitcraze.io/documentation/
- Bitcraze AB. cflib (crazyflie-lib-python) 0.1.30 (2024), commander
API:
send_hover_setpoint,send_zdistance_setpoint,send_stop_setpoint. https://github.com/bitcraze/crazyflie-lib-python
BibTeX entries for these references are in
book/references.bib.