| Crates.io | nut-shell |
| lib.rs | nut-shell |
| version | 0.1.0 |
| created_at | 2025-12-06 06:29:53.631803+00 |
| updated_at | 2025-12-06 06:29:53.631803+00 |
| description | A lightweight command-line interface library for embedded systems |
| homepage | |
| repository | https://github.com/HybridChild/nut-shell |
| max_upload_size | |
| id | 1969691 |
| size | 397,298 |
Interactive CLI for microcontrollers. No heap, no bloat.
A lightweight command shell library for #![no_std] Rust environments with optional async and authentication support.
nut-shell provides essential CLI primitives for embedded systems with strict memory constraints. Built specifically for microcontrollers, it offers an interactive command-line interface over serial connections (UART/USB), with optional features including async/await support, login authentication, tab completion and command history.
Design Philosophy: Essential primitives only. No shell scripting, no dynamic allocation, no bloat.
system/info, network/status)ls, ?, clearSee docs/PHILOSOPHY.md for rationale.
Bare-Metal Pattern:
// 1. Implement `CharIo` trait for your platform
impl CharIo for MyIo {
type Error = MyError;
fn get_char(&mut self) -> Result<Option<char>, Self::Error> { /* ... */ }
fn put_char(&mut self, c: char) -> Result<(), Self::Error> { /* ... */ }
}
// 2. Define command tree with metadata
const STATUS: CommandMeta<Level> = CommandMeta {
id: "status",
name: "status",
description: "Show system status",
access_level: Level::User,
kind: CommandKind::Sync,
min_args: 0,
max_args: 0,
};
const SYSTEM: Directory<Level> = Directory {
name: "system",
description: "System commands",
access_level: Level::User,
children: &[Node::Command(&STATUS)],
};
const ROOT: Directory<Level> = Directory {
name: "",
description: "Root",
access_level: Level::Guest,
children: &[Node::Directory(&SYSTEM)],
};
// 3. Implement `CommandHandler` trait
impl CommandHandler<MyConfig> for MyHandler {
fn execute_sync(&self, id: &str, args: &[&str]) -> Result<Response<MyConfig>, CliError> {
match id {
"status" => status_fn::<MyConfig>(args),
_ => Err(CliError::CommandNotFound)
}
}
}
// 4. Create shell and run main loop
let handler = MyHandler; // Your `CommandHandler` implementation
let io = MyIo::new(); // Your `CharIo` implementation
let mut shell = Shell::new(&ROOT, handler, io);
shell.activate().ok();
loop {
if let Some(c) = io.get_char()? {
shell.process_char(c)?;
}
}
Async Pattern (Embassy):
// 1. Define async command
const FETCH: CommandMeta<Level> = CommandMeta {
id: "fetch",
name: "fetch",
description: "Fetch data from network",
access_level: Level::User,
kind: CommandKind::Async, // Async command
min_args: 0,
max_args: 0,
};
// 2. Implement async handler
impl CommandHandler<MyConfig> for MyHandler {
async fn execute_async(&self, id: &str, args: &[&str]) -> Result<Response<MyConfig>, CliError> {
match id {
"fetch" => fetch_fn::<MyConfig>(args).await,
_ => Err(CliError::CommandNotFound)
}
}
}
// 3. Run shell in async task
#[embassy_executor::task]
async fn shell_task(usb: CdcAcmClass<'static, Driver<'static, USB>>) {
let handler = MyHandler;
let io = MyIo::new(usb);
let mut shell = Shell::new(&ROOT, handler, io);
shell.activate().ok();
loop {
let c = read_char().await;
shell.process_char_async(c).await?;
io.flush().await?;
}
}
See docs/EXAMPLES.md for further implementation patterns.
Welcome to nut-shell! Type '?' for help.
@/> ?
? - List global commands
ls - List directory contents
clear - Clear screen
ESC ESC - Clear input buffer
@/> ls
system/ - Directory
echo - Echo arguments back
@/> echo hello world!
hello world!
@/> system
@/system> ls
status - Show system status
version - Show version information
@/system> status
System Status:
CPU Usage: 23%
Uptime: 42 hours
@/system> ..
@/>
Built for no_std embedded systems:
Runtime compatibility:
I/O abstraction: Platform-agnostic CharIo trait for UART, USB-CDC, or custom adapters.
See examples/ for complete working implementations on real hardware.
Measured on ARMv6-M (Cortex-M0/M0+) with opt-level = "z" and LTO enabled:
| Feature Set | Flash (.text + .rodata) | RAM (.bss) |
|---|---|---|
| None (minimal) | ~1.5KB | 0B |
| All features | ~1.2KB | 0B |
These measurements use zero-size stubs and minimal command tree to isolate nut-shell's code overhead. Your actual footprint will also include:
Flash costs:
CharIo/CredentialProvider/CommandHandler trait implementationsRAM costs (allocated in Shell instance):
MAX_INPUT bytes (default 128B)HISTORY_SIZE × MAX_INPUT bytes (default 10 × 128 = 1.3KB)Typical total footprint (with default config and features):
For detailed analysis: See size-analysis/README.md for methodology and complete breakdown across all feature combinations.
Optional authentication feature provides:
Welcome to nut-shell! Please login.
Login> admin:********
Logged in. Type '?' for help.
admin@/> ls
system/ - Directory
echo - Echo arguments back
admin@/> system/version
Firmware version 3.4.5
admin@/> logout
Logged out.
Login> admin:*****
Login failed. Try again.
Login> user:*******
Logged in. Type '?' for help.
user@/> ls
echo - Echo arguments back
user@/>
| Document | Description |
|---|---|
| README.md | Quick start and overview (this file) |
| docs/EXAMPLES.md | Implementation patterns, configuration, troubleshooting |
| docs/CHAR_IO.md | CharIo trait design and platform adapters |
| docs/SECURITY.md | Authentication patterns and security considerations |
| docs/PHILOSOPHY.md | Design philosophy and feature criteria |
| docs/DESIGN.md | Architecture decisions and design patterns |
| docs/DEVELOPMENT.md | Build workflows, testing, and CI |
cargo doc --open |
Complete API reference |
Contributions welcome! Review docs/PHILOSOPHY.md for feature criteria and docs/DESIGN.md for architectural patterns before implementing features.
Before submitting: Run ./scripts/ci-local to verify all CI checks pass.
Licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Designed for the Rust embedded ecosystem, with inspiration from:
no_std Rust patternsMaintained by: Esben Dueholm Nørgaard (HybridChild)