An open-source operating system framework for physically reconfigurable matter. For full documentation, see tapestry-os.com/docs.
Building a swarm of physical elements — robots, drones, exoskeletons, or whatever comes next — means solving the same coordination problems every time. Gossip protocols, partition tolerance, leader election, shared world state: every project rebuilds this from scratch. There's no agreed-upon line between where the hardware ends and the software begins.
Tapestry draws that line by applying separation of concerns to a domain that has never had it. When the physical substrate is encapsulated below a stable API, developers can write applications that coordinate across many elements — formations, distributed sensing, adaptive structures — without caring whether those elements are drones, microrobots, or something that hasn't been built yet. That's portability, and something more: a new class of collective software, with Tapestry as the platform to write it.
L7 Choreographer High-level intent programming; developer-facing API
L6 Behavior Synthesis Engine Translates intent into collective behavioral plans
L5 Swarm Coordination Runtime Quorum-based coordination, role assignment, lightweight BFT
L4 Collective State Manager Distributed world model; aggregated shared state
L3 Inter-Element Communication Mesh networking, routing, encryption; substrate-agnostic
L2 Element Runtime Per-element OS: scheduling, power, actuation, local sensing
L1 Physical Substrate Interface HAL motor drivers, sensor buses, communication transceivers
L1–L5 execute on each physical element; L6–L7 execute on external compute (developer workstation, edge node, or cloud) or a sufficiently capable element within the collective. The public API (L6–L7) is designed to remain stable as physical scale decreases from centimeters to nanometers.
The current L1–L2 runtime is built on the Zephyr RTOS, used in the same way Android uses Linux. Everything from L3 upward is Tapestry's sole responsibility with no Zephyr dependency.
See CONTRIBUTING.md for prerequisites and workspace setup, then run from the
workspace root (tapestry-workspace/):
# Build the L5 simulation element
west build -b native_sim/native/64 \
--build-dir tapestry/tapestry-scr-sim/build/element \
tapestry/tapestry-scr-sim/zephyr/element
# Run a 5-element swarm through the leader_loss scenario
cd tapestry/tapestry-scr-sim/orchestrator
python main.py --elements 5 --scenario leader_loss --duration 30 --out run.csv
# Plot the results
python plot.py run.csv --out run.pngrun.png shows five panels: fleet-mean quorum state (LOST/DEGRADED/HEALTHY), fraction of
elements agreeing on the same leader, elements with LEADER role, fleet-mean fresh peer count,
and minimum element separation. You should see all elements elect element 0 as leader, then
re-elect element 1 at t≈7.5 s when the partition fires at t=5 s, then recover back to element 0
at t≈16.5 s when the partition heals at t=15 s.
To explore the L4 consistency dial (AP vs. CP tradeoff):
# Build the L4 simulation element
west build -b native_sim/native/64 \
--build-dir tapestry/tapestry-csm-sim/build/element \
tapestry/tapestry-csm-sim/zephyr/element
cd tapestry/tapestry-csm-sim/orchestrator
# AP mode: elements keep moving through the partition (bias=0.0, default)
python main.py --elements 5 --scenario default --duration 60 --out ap.csv
# CP mode: elements freeze on quorum loss (bias=1.0)
CONSISTENCY_BIAS=1.0 python main.py --elements 5 --scenario default --duration 60 --out cp.csv
python plot.py ap.csv cp.csv --labels AP CP --out ap_vs_cp.pngIn AP mode, no element ever sets the degraded flag; the fleet keeps moving and mean position error peaks at 2.4 units during the partition. In CP mode, the minority island freezes in place — 40% of the fleet degrades for ~3.8 s — but position error peaks at only 1.9 units (20% lower). Both modes fully reconverge by t≈20 s.
tapestry/
├── sdk/ L7 Choreographer SDK (stable developer surface)
│ ├── include/tapestry/
│ │ └── choreo.h L7 SDK API header (Goal / lifecycle / directive)
│ ├── python/tapestry/
│ │ ├── choreo.py L7 Python mirror
│ │ ├── bse.py L6 Python stub
│ │ └── script_toml.py Choreo script (TOML) parser/validator
│ ├── tools/
│ │ └── choreoc.py Choreo script compiler: TOML -> C header
│ ├── examples/
│ │ └── hello_swarm.py Minimal worked example (no sim required)
│ └── CHOREO_SCRIPTS.md Script authoring + compilation guide
│
├── tapestry-os/ Tapestry OS framework
│ ├── include/tapestry/
│ │ ├── wire.h L3 on-wire frame format (pure C99, no OS deps)
│ │ ├── csm.h L4 public API boundary (pure C99, no OS deps)
│ │ ├── scr.h L5 public API boundary (includes csm.h)
│ │ ├── bse.h L6 interface contract (intent → directive)
│ │ ├── runtime.h L2 element runtime (full-stack main loop helper)
│ │ ├── substrate.h L1 HAL (motor, power, signal abstractions)
│ │ ├── transport.h L3 transport API (send / drain / telemetry)
│ │ └── transceiver.h L3 transceiver plugin interface
│ ├── boards/
│ │ └── bbc_microbit_v2/ micro:bit V2 board support (Cutebot HAL, BLE overlay)
│ ├── subsys/csm/
│ │ └── world_model.c L4 CSM implementation (pure C99)
│ ├── subsys/scr/
│ │ └── scr.c L5 SCR implementation (pure C99)
│ ├── subsys/bse/
│ │ └── bse.c L6 BSE stub (geometry task decomposition)
│ ├── subsys/choreo/
│ │ └── choreo.c L7 Choreographer stub (lifecycle + goal dispatch)
│ ├── subsys/runtime/
│ │ ├── runtime.c L2 full-stack tick sequencer
│ │ └── power.c/.h L2 power state machine (active/idle/sleep/harvest)
│ └── subsys/transport/
│ ├── transport.c Transceiver registry and multiplexer
│ ├── gossip.c/.h Wire framing, relay, HMAC auth
│ ├── transceiver_ble.c/.h BLE advertising backend (Zephyr bt_* API)
│ ├── transceiver_udp.c/.h UDP broadcast backend (Zephyr zsock_* API)
│ └── net_init.c/.h WiFi / Ethernet bring-up (Zephyr net_mgmt)
│
├── tapestry-csm-sim/ L4 simulation harness
│ ├── sim_protocol.h Sim-only additions: ports, control protocol,
│ │ compat aliases over <tapestry/wire.h>
│ ├── tests/ ztest unit tests for L4
│ ├── zephyr/element/ Zephyr native_sim element application
│ │ └── src/
│ │ ├── main.c Main loop: gossip, tick, movement, metrics
│ │ ├── comms.c/h Sim-specific UDP transport (loopback → orchestrator)
│ │ └── movement.c/h Random walk + peer repulsion
│ └── orchestrator/ Python asyncio gossip broker + telemetry
│ ├── main.py Entry point: launches elements, runs scenario
│ ├── broker.py Routes gossip by partition island, injects ground-truth error
│ ├── protocol.py Python mirror of wire.h + sim_protocol.h structs
│ ├── telemetry.py Per-cycle CSV writer
│ ├── scenarios.py Timed partition/power injection scripts
│ └── plot.py 5-panel matplotlib efficacy visualizer
│
├── tapestry-scr-sim/ L5 simulation harness
│ ├── tests/ ztest unit tests for L5
│ ├── zephyr/element/ Zephyr native_sim element (L4 + L5)
│ │ └── src/
│ │ ├── main.c Main loop: gossip, L4 tick, L5 SCR tick, metrics
│ │ └── comms_scr.c/h SCR metric send (extends csm-sim comms)
│ └── orchestrator/ Python asyncio orchestrator for L5
│ ├── main.py Entry point; --quorum-min, --quorum-target, --bias
│ ├── broker.py Gossip routing + SCR metric dispatch
│ ├── protocol.py Python mirror of wire.h + scr_protocol.h structs
│ ├── telemetry.py Combined L4+L5 CSV writer (one row per element/cycle)
│ ├── scenarios.py L4 scenarios + leader_loss, cascade
│ └── plot.py 5-panel SCR visualizer: quorum, agreement, roles
│
└── tapestry-scr-hw/ Hardware swarm firmware (Phase 1 + Phase 2)
├── README.md Build, flash, and telemetry instructions
├── Kconfig Element configuration (ID, ports, WiFi, ORCH_IP)
├── src/
│ └── main.c Element main loop (L4 + L5); wires OS transport
│ and adaptation layers together
└── telemetry/
├── collect.py UDP metric collector → CSV
├── protocol.py Python mirror of wire.h structs
└── plot.py 5-panel hardware telemetry visualizer
All west build commands run from the workspace root (tapestry-workspace/).
# L4 — gossip, Lamport clocks, staleness, quorum, reconciliation, spatial queries
west build -b native_sim/native/64 \
--build-dir tapestry/tapestry-csm-sim/build/test-csm \
tapestry/tapestry-csm-sim/tests
./tapestry/tapestry-csm-sim/build/test-csm/zephyr/zephyr.exe
# L5 — quorum classification, leader election, partition/heal, re-election on leader loss
west build -b native_sim/native/64 \
--build-dir tapestry/tapestry-scr-sim/build/tests \
tapestry/tapestry-scr-sim/tests
./tapestry/tapestry-scr-sim/build/tests/zephyr/zephyr.exe# L4 element (consumed by the L4 Python orchestrator)
west build -b native_sim/native/64 \
--build-dir tapestry/tapestry-csm-sim/build/element \
tapestry/tapestry-csm-sim/zephyr/element
# L5 element (runs L4 gossip + L5 SCR tick; consumed by the L5 Python orchestrator)
west build -b native_sim/native/64 \
--build-dir tapestry/tapestry-scr-sim/build/element \
tapestry/tapestry-scr-sim/zephyr/elementcd tapestry-csm-sim/orchestrator
python main.py --elements 5 --scenario default --duration 60 --out ap_run.csv
CONSISTENCY_BIAS=1.0 python main.py --elements 5 --scenario default --duration 60 --out cp_run.csv
python plot.py ap_run.csv cp_run.csv --labels AP CP --out ap_vs_cp.pngAvailable scenarios: default, flapping, asymmetric, sleep.
Telemetry columns
| Column | Description |
|---|---|
fresh_ratio |
Fraction of active peers with non-stale world model entries |
degraded |
1 when element is below its quorum threshold |
confidence |
Proximity to quorum threshold [0.0, 1.0] |
mean_age_ms |
Average age of active peer entries (ms) |
mean_position_error |
Mean distance between believed and actual peer positions (broker ground truth) |
min_separation |
Closest peer distance this cycle (safety proxy) |
collision_count |
Peers within MIN_SEPARATION (3.0 units) this cycle |
cd tapestry-scr-sim/orchestrator
python main.py --elements 5 --scenario leader_loss --duration 30 --out leader_loss.csv
python main.py --elements 5 --scenario cascade --duration 30 --out cascade.csv
python plot.py leader_loss.csv cascade.csv --labels "Leader loss" Cascade --out scr_compare.pngAvailable scenarios: leader_loss, cascade, default, flapping, asymmetric, sleep.
--quorum-min and --quorum-target set peer-count thresholds; --bias sets the L4 consistency dial.
Telemetry columns (in addition to all L4 columns above)
| Column | Description |
|---|---|
role |
0=NONE, 1=FOLLOWER, 2=LEADER, 3=RELAY, 4=SENSOR, 5=ACTUATOR |
leader_id |
Elected leader element ID; 255 = no leader (quorum LOST) |
quorum_state |
0=LOST, 1=DEGRADED, 2=HEALTHY |
fresh_count |
Non-self trusted fresh peers visible this cycle |
task_slot |
Ordinal in sorted fresh peer list (0 = leader); valid when quorum ≥ DEGRADED |
election_count |
Cumulative leader changes since element startup |
The L4/L5 stack has been validated on physical hardware in two phases:
- Phase 1 — ztest suites run unchanged on real MCUs, confirming that
world_model.candscr.care pure C99 and compile for any Zephyr-supported target. - Phase 2 — a two-element swarm gossiping via UDP broadcast over a shared LAN, demonstrating partition detection (~1.5 s), autonomous leader election, and recovery with no simulation broker.
See tapestry-scr-hw/README.md for build, flash, and telemetry instructions.
L6/L7 (BSE + Choreographer) is separately under active hardware flight-testing: a two-drone
Crazyflie station-swap script — authored in TOML and compiled via sdk/tools/choreoc.py — driving
real aerial elements through hold/exchange/rest. Iterative flights have found and fixed real bugs
in identity negotiation, gossip delivery, and the exchange/landing interaction; this is a single
script on a single platform, not yet validated as broadly as L4/L5 above. See
examples/cf21bl-formation/README.md for the current state.
The same change-partners script also runs unmodified in simulation:
examples/webots-formation/README.md compiles the real
L3-L7 stack into a Webots controller against simulated physics (no hardware required), with only an L1 substrate and L3 transceiver written
for the sim. That example is a reusable pattern, and new elements can be added here:
controllers/common/.
Useful for iterating on swarm-scale behavior (elections, partitions, larger formations) faster and
more cheaply than re-flying real drones between changes.
Tapestry is released under the Apache 2.0 License.
Copyright 2026 James V Steele.
Tapestry was designed and developed by James V Steele. Claude (Anthropic) was used as a development tool during initial implementation phases.