Note: Limen is in active pre-release development. Contracts and APIs may change without notice before v0.1.0.
- Rust toolchain (stable). See
rust-toolchain.tomlif present. - Cargo (included with Rust).
- No external dependencies required for
no_stdbuilds.
# no_std single-threaded runtime (default features)
cargo test -p limen-examples -- codegen_core_pipeline_runs_with_nostd_runtime --nocapture
# std multi-threaded runtime (concurrent queues, scoped threads)
cargo test -p limen-examples --features std -- codegen_std_pipeline_runs_with_std_runtime --nocaptureBoth tests build a three-node Source → Model → Sink pipeline from a
codegen-generated graph, wire it to a runtime, and step it through several
iterations. --nocapture prints edge occupancies and telemetry to stdout.
# Default: no_std, no heap
cargo build
# With alloc (heap-backed queues, Vec-based batches)
cargo build --features alloc
# With std (concurrent queues, threaded runtimes, I/O sinks)
cargo build --features stdCurrently, std graphs require concurrent edge and memory manager types
(ConcurrentEdge, ConcurrentMemoryManager) which are not available in
no_std builds. A single graph definition does not yet compile across all
feature flags — ADR-013
addresses this.
# Run all tests (default features)
cargo test --workspace
# Run all tests with std features
cargo test --workspace --features std
# Run tests for a specific crate
cargo test -p limen-core
cargo test -p limen-examples
# Run a single test by name
cargo test -p limen-core -- core_pipeline_runs_with_nostd_runtime| Flag | What it enables | Test command |
|---|---|---|
| (default) | no_std path, static queues, static memory managers |
cargo test --workspace |
alloc |
Heap-backed queues, Vec batch paths |
cargo test --workspace --features alloc |
std |
Concurrent queues, scoped-thread runtimes, I/O sinks | cargo test --workspace --features std |
bench |
Test nodes, queues, and runtime impls for integration tests | Enabled automatically by limen-examples |
Before submitting a pull request, run the local CI script to validate the full feature matrix:
./dev_utils/run-local-ci.shThis runs fmt, build, test, and clippy across all feature flag combinations
(no-default-features, alloc, std, spsc_raw). Options:
| Flag | Effect |
|---|---|
--no-clippy-or-fmt |
Skip cargo fmt and cargo clippy checks |
--clean |
Run cargo clean after all checks pass |
--release |
Run cargo build --release after all checks pass |
# Lint
cargo clippy --workspace
# Lint with all features
cargo clippy --workspace --all-features
# Format
cargo fmt --all
# Check formatting (CI gate)
cargo fmt --all -- --check- Line width: 100 columns.
- Field init shorthand:
use_field_init_shorthand = true. no_stdguards: All heap use behind#[cfg(feature = "alloc")]. Allstd-only code behind#[cfg(feature = "std")].- No
println!/eprintln!: Use theTelemetrytrait. - No
unsafe: Except inspsc_raw(gated behind its own feature flag). - No
Box<dyn Trait>in hot paths. - Feature flags are additive:
stdimpliesalloc. Never write#[cfg(any(feature = "alloc", feature = "std"))]where#[cfg(feature = "alloc")]suffices.
Three equivalent approaches:
use limen_build::define_graph;
define_graph! {
pub struct MyGraph;
nodes { ... }
edges { ... }
}// build.rs
use limen_codegen::expand_str_to_file;
expand_str_to_file(DSL_STRING, &out_path)?;
// In source:
include!(concat!(env!("OUT_DIR"), "/my_graph.rs"));// build.rs
use limen_codegen::builder::{GraphBuilder, Node, Edge};
let ast = GraphBuilder::new(vis, name)
.node(Node::new(0).ty::<MySource>().in_ports(0).out_ports(1)
.in_payload::<()>().out_payload::<SensorData>())
.edge(Edge::new(0).ty::<StaticRing<MessageToken, 8>>()
.payload::<SensorData>().from(0, 0).to(1, 0))
.finish();
limen_codegen::expand_ast_to_file(ast, &out_path)?;See Graph Codegen for full details.
-
Implement
process_message. This is the only required method for most nodes:impl Node<1, 1, SensorData, ProcessedData> for MyProcessor { fn process_message<C: PlatformClock>( &mut self, msg: &Message<SensorData>, clock: &C, ) -> Result<ProcessResult<ProcessedData>, NodeError> { let result = self.transform(msg.payload()); Ok(ProcessResult::Output( Message::new(msg.header().clone(), result) )) } // ... capabilities, lifecycle, policy methods }
-
For sources: Implement
Source<OutP, OUT>and wrap withSourceNode. -
For sinks: Implement
Sink<InP, IN>and wrap withSinkNode. -
Wire into a graph using any of the three codegen approaches.
-
Validate with the conformance test suite,
limen-core::node::contract_tests.
-
Implement the
Edgetrait. -
Validate with the conformance test suite:
run_edge_contract_tests!(MyCustomQueue);
The macro tests FIFO ordering, capacity limits, token coherence, occupancy accuracy, and admission correctness.
-
For concurrent use, also implement
ScopedEdge.
limen/
├── limen-core/ # Core contracts (traits, types, policies)
├── limen-node/ # Concrete node implementations
├── limen-runtime/ # Executors and schedulers
├── limen-platform/ # Platform adapters
├── limen-codegen/ # Code generator
├── limen-build/ # Proc-macro wrapper
├── limen-examples/ # Integration tests
├── docs/ # This documentation
└── claude_context_docs/ # Internal development context (not public)