Time-shaped coordination primitives for swarm-anchor: predict-and-confirm, deadlines, rate limiters, BPM clocks, cron, and DAG-ordered campaigns. Stdlib-only Python.
Project description
swarm-tminus
Time-shaped coordination primitives for swarm-anchor-style multi-agent systems.
swarm-tminus is a Python package that adds the time-shaped coordination primitives developed across the SuperInstance T-Minus ecosystem — t-minus, t-minus-rs, tminus-music, lau-tminus, tick-engine, and terax-fleet-modules — to the file-based shared-state model of swarm-anchor.
Predict-and-confirm, deadline cascades, rate limiters with backpressure, BPM-adaptive heartbeats, CRON scheduling, and DAG-ordered campaigns — all in stdlib Python, all living alongside .swarm/*.json files.
Why
Multi-agent swarms typically coordinate through state: who's here, what's done, who's responsible. swarm-anchor gives you that. But state alone can't tell you when to act, how long to wait, or how fast to send.
tminus-* repositories answered those questions in Rust. swarm-tminus is the Python re-implementation: stdlib-only, file-based, drop-in compatible with the swarm-anchor .swarm/ directory convention.
The unifying idea across the tminus ecosystem:
1. Declare the FUTURE (a countdown event, a predicted beat, a deadline)
2. Subscribe agents confirm readiness → quorum fires
3. Time elapses via a SHARED CLOCK
4. Predictions match → precompiled script EXECUTES
5. Predictions miss → script is discarded, agent re-plans
Installation
pip install swarm-tminus
Or directly from source:
git clone https://github.com/SuperInstance/swarm-tminus.git
cd swarm-tminus
pip install -e .
This installs a swarm-tminus CLI command and the swarm_tminus Python package.
Zero runtime dependencies. Pure stdlib Python 3.10+.
Quick start
from swarm_tminus import (
Predictor, CountdownEvent, EventStore,
DeadlineTree, TokenBucket, LeakyBucket, RatePair,
TickClock, CronParser, Campaign,
)
# 1. Predict-and-confirm
p = Predictor(bpm=120.0)
pid = p.add_prediction("chord_change", beats_ahead=4.0, confidence=0.9)
triggered = p.advance(beats=5.0) # advance the clock
p.confirm(pid)
# 2. Quorum-gated countdown events
store = EventStore(".swarm")
e = CountdownEvent(name="deploy-v1", fire_at_unix=time.time() + 300, quorum_required=3)
e.add_subscriber("alice"); e.confirm("alice")
e.confirm("bob")
store.add_event(e); store.save()
# 3. Hierarchical deadline trees
root = DeadlineNode(name="release", duration_seconds=3600)
root.add_child("build", duration_seconds=600)
root.add_child("test", duration_seconds=900)
tree = DeadlineTree(root=root)
tree.save(".swarm")
# 4. Rate limiters
tb = TokenBucket(capacity=10, refill_per_sec=1.0)
lb = LeakyBucket(capacity=10, drip_per_sec=1.0)
pair = RatePair(token=tb, leaky=lb)
ok, reason = pair.try_send(1.0)
# 5. BPM-adaptive heartbeat
clock = TickClock(bpm=120.0, swing=0.5)
t = clock.next_tick() # Tick(id=0, timestamp=..., delta=...)
clock.adapt(energy=0.7) # adaptive tempo
# 6. Cron scheduling
nxt = CronParser("*/15 * * * *").next_fire()
# 7. DAG-ordered campaigns
camp = Campaign(name="rollout")
camp.add_event(CountdownEvent(name="step1", fire_at_unix=100.0))
camp.add_event(CountdownEvent(name="step2", fire_at_unix=200.0))
camp.add_edge("step1", "step2")
order = camp.topological_order() # ["step1", "step2"]
Modules
| Module | Source | Purpose |
|---|---|---|
predictor |
tminus-music | Predict-and-confirm with named chord progressions |
events |
t-minus | Countdown + quorum-gated events with file-based store |
deadlines |
t-minus-rs | Hierarchical deadline trees with cascade cancel |
rate |
t-minus-rs | Token + leaky bucket rate limiters, in series |
tempo |
tick-engine | BPM-adaptive tick clocks with swing |
cron |
t-minus-rs | 5-field cron parser, no external deps |
campaign |
t-minus | DAG of countdown events with topological order |
matcher |
lau-tminus | Pattern-based event matching with confidence |
casting |
terax-fleet-modules | Casting-call model router (10 curated models, score-based) |
context |
terax-fleet-modules | PLATO tile formatter + fleet fetcher (Promise.allSettled semantics) |
hybrid |
glue | HybridAnchor — unified .swarm/ for swarm-anchor + swarm-tminus |
All modules export a __repr__ and a small, focused surface. All are file-backed where appropriate.
CLI
The swarm-tminus command gives you access to every module from the shell:
# Predict-and-confirm
swarm-tminus predict add --bpm 120 --ahead 4 --confidence 0.9
swarm-tminus predict advance --bpm 120 --beats 8 --ahead 4
swarm-tminus predict savings --predictions 10 --confirmations 3
# Countdown events
swarm-tminus event add --name deploy --in-seconds +5m --quorum 3
swarm-tminus event confirm --name deploy --subscriber alice
swarm-tminus event fire --now-unix 1784154000
swarm-tminus event list
# Deadline trees
swarm-tminus deadline start --name review --duration 60
swarm-tminus deadline cancel --root review --name review
swarm-tminus deadline show --root review
# Rate limiters
swarm-tminus rate token --cap 10 --refill 1 --consume 3
swarm-tminus rate leaky --cap 10 --drip 1 --add 5
swarm-tminus rate pair --cap 10 --refill 1 --drip 1 --consume 3
# Tempo
swarm-tminus tempo tick --bpm 120 --swing 0.5 --count 4
swarm-tminus tempo adapt --bpm 120 --energy 0.7
# Cron
swarm-tminus cron parse --expr "*/5 * * * *"
swarm-tminus cron next --expr "0 9 * * *" --after "+1h"
# Campaigns
swarm-tminus campaign order --edges "a,b|b,c" --nodes "a,b,c"
swarm-tminus campaign add-event --name rollout --event step1 --fire-at 1000
swarm-tminus campaign show --name rollout
# Matcher
swarm-tminus matcher match --name fast \
--pattern '{"speed":{"gt":100}}' \
--actual '{"speed":120}'
Integration with swarm-anchor
swarm-tminus deliberately does not import swarm-anchor. The dependency is by convention: both packages share the .swarm/ directory.
.swarm/
├── *.heartbeat.json ← swarm-anchor (existing)
├── *.prediction.json ← swarm-tminus (predict-and-confirm)
├── *.deadline.json ← swarm-tminus (deadline trees)
├── *.event.json ← swarm-tminus (countdown + quorum)
├── *.campaign.json ← swarm-tminus (DAG campaigns)
└── *.tempo.json ← swarm-tminus (BPM-adaptive)
Example: an agent's heartbeat cadence driven by a TickClock:
from swarm_tminus import TickClock
from swarm_anchor import Anchor, Heartbeat, HeartbeatStatus
anchor = Anchor(root=".swarm")
hb = Heartbeat(animal="alice", task="rolling forecast")
clock = TickClock(bpm=120.0)
while True:
tick = clock.next_tick()
hb.touch()
anchor.heartbeat(hb)
time.sleep(tick.delta)
File-based ground truth
Two modules are explicitly designed for durable shared state:
EventStore
from swarm_tminus import EventStore, CountdownEvent
store = EventStore(".swarm")
store.add_event(CountdownEvent(name="deploy", fire_at_unix=...))
store.save() # writes deploy.event.json
# Reload later:
store2 = EventStore.load(".swarm")
ev = store2.get("deploy")
DeadlineTree
from swarm_tminus import DeadlineTree, DeadlineNode
root = DeadlineNode(name="release", duration_seconds=3600)
root.add_child("build", duration_seconds=600)
tree = DeadlineTree(root=root)
tree.save(".swarm")
loaded = DeadlineTree.load(".swarm", "release")
Campaign
from swarm_tminus import Campaign, CountdownEvent
camp = Campaign(name="rollout")
camp.add_event(CountdownEvent(name="step1", fire_at_unix=100.0))
camp.add_event(CountdownEvent(name="step2", fire_at_unix=200.0))
camp.add_edge("step1", "step2")
camp.save(".swarm")
House style
- stdlib only — zero runtime deps; PyYAML is optional
- Heavy tests — 230 tests across 8 modules
- Dataclasses for value types;
__repr__on everything for debugging - File-based ground truth where applicable
- CLI per module —
swarm-tminus <module> <action> [args] - PyPI-ready —
pyproject.tomlwithconsole_scriptsentry point
Architecture decisions
-
stdlib-only: matches the swarm-anchor convention; no
pip install numpy. Tradeoff: cronnext_firebrute-force-scans up to 5 years of minutes. Acceptable for human timescales. -
File-based vs SQLite: t-minus-rs uses SQLite. swarm-tminus uses JSON files because (a) it slots into swarm-anchor's existing convention, (b) JSON is human-inspectable, (c) zero deps. If you need atomic writes, both
EventStore.save()andDeadlineTree.save()use a.tmp+ rename pattern. -
Token-bucket starts FULL (per t-minus-rs); leaky-bucket starts EMPTY. The asymmetry is intentional: token-bucket allows bursts up to capacity; leaky-bucket smooths them out.
-
Quorum=0 always fires: a 0-quorum event with no confirmations still fires, because
confirmed_count() >= 0is always true. -
Deferred attendee grants grace: an event with any
SubscriberStatus.DEFERREDattendee is held inCOUNTING(notMISSED) regardless of how much time has passed — mirroringsrc/engine.rs:165-189. -
Cycle detection is atomic on
add_edge: the edge is added tentatively, validated via topological sort, and reverted if a cycle would form.
Tests
$ /usr/bin/python3.11 -m unittest discover tests
......................................................................................................................................................................................................................................................................
----------------------------------------------------------------------
Ran 300 tests in 0.037s
OK
Test breakdown:
| Module | Tests | File |
|---|---|---|
| predictor | 41 | tests/test_predictor.py |
| events | 30 | tests/test_events.py |
| deadlines | 28 | tests/test_deadlines.py |
| rate | 35 | tests/test_rate.py |
| tempo | 34 | tests/test_tempo.py |
| cron | 24 | tests/test_cron.py |
| campaign | 20 | tests/test_campaign.py |
| matcher | 22 | tests/test_matcher.py |
| casting | 21 | tests/test_casting.py |
| hybrid | 22 | tests/test_hybrid.py |
| context | 23 | tests/test_context.py |
Source provenance
This package is a clean-room Python re-implementation of primitives from the following SuperInstance T-Minus ecosystem repositories:
- t-minus — countdown + quorum events
- t-minus-rs — cron, deadline cascade, rate limiters, ensemble tempo
- tminus-music — predict-and-confirm + chord progressions
- lau-tminus — typed event matching with confidence + energy cost
- tick-engine — BPM-adaptive scheduler
- terax-fleet-modules — context-and-modeling (now ported in v0.2.0 as
casting.pyandcontext.py)
The patterns map 1:1; only the language and storage substrate change.
License
MIT — see LICENSE.
Contributing
Issues and PRs welcome at https://github.com/SuperInstance/swarm-tminus.
When adding a new module:
- Place it in
swarm_tminus/<name>.py - Re-export from
swarm_tminus/__init__.py - Add a
tests/test_<name>.pywith ≥10 tests - Add CLI subparser in
swarm_tminus/cli.py - Document in this README
The repo targets Python 3.10+ for match/case syntax and modern type hints.
Part of the SuperInstance ecosystem. Built 2026-07-15.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file swarm_tminus-0.2.2.tar.gz.
File metadata
- Download URL: swarm_tminus-0.2.2.tar.gz
- Upload date:
- Size: 63.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c96fe7609b8ab224ffa4c416ba7c34958a5be0266b3a05aa440812ff53de8697
|
|
| MD5 |
540855390df23ba5ec936fd3e227a56c
|
|
| BLAKE2b-256 |
923bb7a540f0cdecd1103b95e2ec99a118324e2d59b154f5f3c5b1f0dd71b248
|
File details
Details for the file swarm_tminus-0.2.2-py3-none-any.whl.
File metadata
- Download URL: swarm_tminus-0.2.2-py3-none-any.whl
- Upload date:
- Size: 46.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ee69084b0cc5088436d71c92dd8a9b6a9990eca59fd3d1a1f2788a18e95508c
|
|
| MD5 |
3ea4206bcd85037e50a8a5140c26b301
|
|
| BLAKE2b-256 |
ff02e00a015edf826d8cc67b074df54573430202bf43aea09a1e3ee08de596b2
|