HORUS 0.2.0 Release Notes
Release Date: March 2026
Highlights
Unified Node API, deterministic replay, cross-process Image pub/sub fix, and a new project manifest system. 179 commits, 662 files changed since v0.1.9.
Breaking Changes
Unified Node API - Single Node Trait
The separate RtNode trait is gone. All nodes use Node. RT behavior is auto-detected from builder methods.
// Before (0.1.9)
scheduler.add_dyn(Box::new(my_node));
// After (0.2.0)
scheduler.add(my_node)
.rate(100_u64.hz()) // RT auto-detected from rate/budget/deadline
.budget(200_u64.us())
.on_miss(Miss::Skip)
.build()?;Removed methods: .done() (use .build()), .rate_hz() (use .rate(100.hz())), .budget_us() (use .budget(200.us())), .deadline_ms() (use .deadline(1.ms()))
Removed presets: Scheduler::deploy(), ::hard_rt(), ::safety_critical() - use composable builders instead:
Scheduler::new()
.deterministic(true)
.tick_rate(100_u64.hz())DurationExt - Ergonomic Durations
use horus::prelude::*;
100_u64.hz() // Frequency
200_u64.us() // Duration (microseconds)
1_u64.ms() // Duration (milliseconds)HFrame -> TransformFrame
All types, topics, and CLI commands renamed:
| Old | New |
|---|---|
HFrame |
TransformFrame |
HFMessage |
TFMessage |
topic hf / hf_static |
topic tf / tf_static |
horus hf |
horus frame (alias: horus tf) |
horus.toml - Single Source of Truth
horus.toml replaces separate Cargo.toml/pyproject.toml in project roots. Native build files are auto-generated into .horus/.
[package]
name = "my_robot"
version = "0.1.0"
language = "rust"
[dependencies]
horus_core = "0.2.0"
numpy = { version = ">=1.24", source = "pypi" }
[scripts]
run = "cargo run --release"New CLI commands: horus add, horus remove, horus run <script>, horus migrate (converts old projects)
Topic Names - Dots Not Slashes
Topic names must use dots for cross-platform compatibility (macOS shm_open limitation):
// Before
Topic::new("camera/rgb")
// After
Topic::new("camera.rgb")New Features
Cross-Process Image Pub/Sub (Issue #37 Fix)
Image, PointCloud, and DepthImage now work reliably across separate processes/schedulers. No workarounds needed.
// Process 1
let topic: Topic<Image> = Topic::new("camera.rgb")?;
topic.send(&image);
// Process 2 (separate binary)
let topic: Topic<Image> = Topic::new("camera.rgb")?;
if let Some(img) = topic.recv() {
// Works - even with 640x480 images, simultaneous startup
}Deterministic Record/Replay
Bit-identical replay of recorded sessions with a new clock abstraction:
let mut scheduler = Scheduler::new()
.deterministic(true)
.tick_rate(100_u64.hz());
// Record
scheduler.record_to("session.horus")?;
// Replay (produces identical outputs)
scheduler.replay_from("session.horus")?;NodeBuilder - Per-Node Configuration
scheduler.add(my_node)
.rate(50_u64.hz())
.budget(500_u64.us())
.deadline(1_u64.ms())
.on_miss(Miss::Skip) // or Warn, SafeMode, Stop
.priority(90)
.core(2) // Pin to CPU core
.watchdog(5_u64.secs())
.order(0) // Execution order
.build()?;RT Executor Thread Pool
RT nodes now run on dedicated threads with independent scheduling chains. Non-RT nodes run on the main thread.
Fan-Out Topics
One publisher, many subscribers - each gets every message:
let topic: Topic<Imu> = Topic::new("imu.data")?;
// Multiple subscribers automatically get FanoutShm backendAudioFrame Message Type
New message type for microphone arrays, speech processing, and acoustic anomaly detection.
Ergonomic PointCloud / DepthImage Constructors
let pc = PointCloud::from_xyz(&points)?;
let depth = DepthImage::meters(640, 480)?;Python Parity
All new builder methods, DurationExt, and time APIs available in Python:
import horus
node = horus.Node("camera", tick=process_frame, rate=30)
scheduler = horus.Scheduler(tick_rate=100, deterministic=True)
scheduler.add(node)
horus.run(node)CLI Changes
New Development Commands
| Command | Description |
|---|---|
horus add <dep> |
Add dependency to horus.toml (--source pypi/crates.io/system/git) |
horus remove <dep> |
Remove dependency |
horus migrate |
Convert old Cargo.toml/pyproject.toml project to horus.toml |
horus bench [FILTER] |
Run benchmarks |
horus lint [--fix] |
Lint code (clippy + ruff/pylint, --types for mypy) |
horus fmt [--check] |
Format code (rustfmt + Python formatters) |
horus doc [--extract] |
Generate docs (--json, --md, --html, --coverage) |
horus doctor [--fix] |
Diagnose environment, install missing toolchains |
horus config |
View/edit horus.toml settings |
horus deps tree/why/outdated/audit |
Dependency insight |
horus scripts [name] |
Run scripts from [scripts] in horus.toml |
horus lock [--check] |
Generate/verify horus.lock |
horus self update |
Update the horus CLI itself |
Native Tool Proxies
Use your existing tools transparently inside horus projects - changes sync back to horus.toml:
horus cargo add serde --features derive # runs cargo, syncs to horus.toml
horus pip install numpy # runs pip, syncs to horus.toml
horus cmake --build . # runs cmake with horus paths
horus conan install . # runs conan with horus sync
horus vcpkg install opencv # runs vcpkg with horus syncShell integration is set up automatically by the installer. After installing, cargo/pip/cmake auto-detect horus projects:
# Inside any horus project - just use your normal tools:
cargo add tokio # automatically syncs to horus.toml
pip install scipy # automatically syncs to horus.toml
cmake --build . # uses horus paths automaticallyPublishing & Registry
| Command | Description |
|---|---|
horus publish [--dry-run] |
Publish package to horus registry |
horus unpublish <pkg@ver> |
Remove a published version |
horus yank <pkg@ver> |
Hide from new installs (existing lockfiles still work) |
horus deprecate <pkg> |
Mark package as deprecated |
horus owner add/remove/list |
Manage package ownership |
horus auth login/logout/status |
Registry authentication |
horus cache info/clean/purge |
Cache management |
Multi-Language Support
horus run auto-detects and runs Rust, Python, and C++ files - even mixed in the same command:
horus new my_robot --rust # Rust project
horus new my_robot --python # Python project
horus new my_robot --cpp # C++ project
horus run controller.rs sensor.py # Mixed-language, concurrent executionBug Fixes
- Cross-process Image crash (Issue #37) - TensorPool initialization race, migration detection delay, and SHM drain memory ordering all fixed
- Topic slot race condition - fixed data corruption during DirectChannel->SHM migration
- Cross-process IPC latency - removed
spin_for_readyfrom recv hot paths - Python binding crashes - fixed AudioFrame dispatch, dead API removal
- Service response_topic - missing field caused silent failures
- flock-based SHM cleanup - stale namespaces from crashed processes now detected and removed on startup
Migration from 0.1.9
// Node API
scheduler.add(node).order(0).done() -> scheduler.add(node).order(0).build()?
scheduler.add(node).rate_hz(100.0) -> scheduler.add(node).rate(100_u64.hz())
// Scheduler presets
Scheduler::deploy() -> Scheduler::new().tick_rate(100.hz())
Scheduler::safety_critical() -> Scheduler::new().deterministic(true)
// TransformFrame
use horus::prelude::HFrame -> use horus::prelude::TransformFrame
Topic::new("hf") -> Topic::new("tf")
// Topic names
Topic::new("camera/rgb") -> Topic::new("camera.rgb")
// Project manifest
Cargo.toml (in project root) -> horus.toml (Cargo.toml generated in .horus/)For questions or issues: https://github.com/softmata/horus/issues