Skip to content

HORUS v0.2.0

Latest

Choose a tag to compare

@neos-builder neos-builder released this 23 Mar 11:19
· 29 commits to main since this release

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 backend

AudioFrame 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 sync

Shell 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 automatically

Publishing & 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 execution

Bug 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_ready from 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