Skip to main content

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.

Tests Python Deps License

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 moduleswarm-tminus <module> <action> [args]
  • PyPI-readypyproject.toml with console_scripts entry point

Architecture decisions

  1. stdlib-only: matches the swarm-anchor convention; no pip install numpy. Tradeoff: cron next_fire brute-force-scans up to 5 years of minutes. Acceptable for human timescales.

  2. 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() and DeadlineTree.save() use a .tmp + rename pattern.

  3. 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.

  4. Quorum=0 always fires: a 0-quorum event with no confirmations still fires, because confirmed_count() >= 0 is always true.

  5. Deferred attendee grants grace: an event with any SubscriberStatus.DEFERRED attendee is held in COUNTING (not MISSED) regardless of how much time has passed — mirroring src/engine.rs:165-189.

  6. 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-modulescontext-and-modeling (now ported in v0.2.0 as casting.py and context.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:

  1. Place it in swarm_tminus/<name>.py
  2. Re-export from swarm_tminus/__init__.py
  3. Add a tests/test_<name>.py with ≥10 tests
  4. Add CLI subparser in swarm_tminus/cli.py
  5. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

swarm_tminus-0.2.2.tar.gz (63.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

swarm_tminus-0.2.2-py3-none-any.whl (46.8 kB view details)

Uploaded Python 3

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

Hashes for swarm_tminus-0.2.2.tar.gz
Algorithm Hash digest
SHA256 c96fe7609b8ab224ffa4c416ba7c34958a5be0266b3a05aa440812ff53de8697
MD5 540855390df23ba5ec936fd3e227a56c
BLAKE2b-256 923bb7a540f0cdecd1103b95e2ec99a118324e2d59b154f5f3c5b1f0dd71b248

See more details on using hashes here.

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

Hashes for swarm_tminus-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3ee69084b0cc5088436d71c92dd8a9b6a9990eca59fd3d1a1f2788a18e95508c
MD5 3ea4206bcd85037e50a8a5140c26b301
BLAKE2b-256 ff02e00a015edf826d8cc67b074df54573430202bf43aea09a1e3ee08de596b2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page