# SEN: CLI Engine
[](https://www.rust-lang.org/)
[](LICENSE)
A type-safe, macro-powered CLI framework.
## ๐ฏ Philosophy
SEN transforms CLI development from ad-hoc scripts into systematic applications with:
- **Compile-time safety**: Enum-based routing with exhaustiveness checking
- **Zero boilerplate**: Derive macros generate all wiring code
- **Type-driven DI**: Handler parameters injected based on type signature
- **Fixed workflows**: Predictable behavior for humans and AI agents
- **Strict separation**: Prevents the "1000-line main.rs" problem
## ๐ Quick Start
### Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
sen = "0.1"
```
Or use `cargo add`:
```bash
cargo add sen
```
### Example
```rust
use sen::{CliResult, State, SenRouter};
// 1. Define application state
pub struct AppState {
pub config: String,
}
// 2. Define commands with derive macro
#[derive(SenRouter)]
#[sen(state = AppState)]
enum Commands {
#[sen(handler = handlers::status)]
Status,
#[sen(handler = handlers::build)]
Build(BuildArgs),
}
pub struct BuildArgs {
pub release: bool,
}
// 3. Implement handlers as plain functions
mod handlers {
use super::*;
pub fn status(state: State<AppState>) -> CliResult<String> {
Ok(format!("Config: {}", state.get().config))
}
pub fn build(state: State<AppState>, args: BuildArgs) -> CliResult<()> {
let mode = if args.release { "release" } else { "debug" };
println!("Building in {} mode", mode);
Ok(())
}
}
// 4. Wire it up (< 50 lines of main.rs)
fn main() {
let state = State::new(AppState {
config: "production".to_string(),
});
let cmd = Commands::parse(); // Your arg parsing logic
let response = cmd.execute(state); // Macro-generated!
if !response.output.is_empty() {
println!("{}", response.output);
}
std::process::exit(response.exit_code);
}
```
That's it! The `#[derive(SenRouter)]` macro generates the `execute()` method that:
- Routes commands to handlers
- Injects `State<T>` and args automatically
- Converts results into responses with proper exit codes
## ๐ Project Structure
SEN enforces clean file separation from day one:
```
my-cli/
โโโ src/
โ โโโ main.rs # Entry point only (< 50 lines)
โ โโโ handlers/ # One file per command
โ โ โโโ mod.rs
โ โ โโโ status.rs
โ โ โโโ build.rs
โ โ โโโ test.rs
โ โโโ workflows/ # Multi-task operations
โ โ โโโ preflight.rs # fmt โ lint โ test
โ โโโ tasks/ # Atomic operations
โ โ โโโ fmt.rs
โ โ โโโ lint.rs
โ โโโ lib.rs # Re-exports
```
**Why?**
- Each command is independently testable
- No `println!` debugging (handlers return structured data)
- Impossible to create "1000-line main.rs"
- AI agents can understand and modify specific commands easily
## ๐จ Key Features
### 1. Type-Safe Routing
Commands are enums, not strings:
```rust
// โ
Compile-time checked
#[derive(SenRouter)]
#[sen(state = AppState)]
enum Commands {
#[sen(handler = handlers::status)] // Typo? Compile error!
Status,
}
// โ Runtime dispatch (other frameworks)
router.add("/status", handlers::status); // Typo? Runtime panic!
```
### 2. Flexible Handler Signatures (Axum-style)
```rust
// Order doesn't matter!
pub fn handler1(state: State<App>, args: Args) -> CliResult<String>
pub fn handler2(args: Args, state: State<App>) -> CliResult<String>
// State optional
pub fn handler3(args: Args) -> CliResult<()>
```
### 3. Smart Error Handling
```rust
pub enum CliError {
User(UserError), // Exit code 1: user can fix
System(SystemError), // Exit code 101: bug/system failure
}
```
Errors automatically format with helpful hints:
```
Error: Invalid argument '--foo'
The value 'bar' is not supported.
Hint: Use one of: baz, qux
```
### 4. No Println! in Handlers
Handlers return structured data, framework handles output:
```rust
// โ Bad: Can't test, can't redirect
pub fn status() -> CliResult<()> {
println!("Status: OK");
Ok(())
}
// โ
Good: Testable, flexible
pub fn status() -> CliResult<StatusReport> {
Ok(StatusReport { status: "OK" })
}
```
## ๐๏ธ Architecture
SEN follows a three-layer design:
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Router Layer (Compile-time) โ
โ - Enum-based command tree โ
โ - Handler binding via proc macros โ
โ - Type-safe routing โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Handler Layer (Runtime) โ
โ - Dependency injection (State, Args) โ
โ - Business logic execution โ
โ - Result<T, E> return type โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Response Layer (Exit) โ
โ - Exit code mapping (0, 1, 101) โ
โ - Structured output (JSON/Human) โ
โ - Logging & telemetry โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
See [DESIGN.md](./docs/DESIGN.md) for full architecture details.
## ๐ Examples
Check out the [examples/simple-cli](./examples/simple-cli) directory for a working CLI with:
- Status command (no args)
- Build command (with `--release` flag)
- Test command (with optional filter)
- Proper error handling
Run it:
```bash
cd examples/simple-cli
cargo build
./target/debug/admin status
./target/debug/admin build --release
./target/debug/admin test my_test
```
## ๐งช Testing
```bash
# Run all tests
cargo test
# Test specific crate
cargo test -p sen
cargo test -p sen-rs-macros
```
## ๐ Documentation
- [DESIGN.md](./docs/DESIGN.md) - Complete design document
## ๐ฃ๏ธ Roadmap
- [x] Phase 1: Core framework (State, CliResult, IntoResponse)
- [x] Phase 2: Macro system (#[derive(SenRouter)])
- [ ] Phase 3: Advanced features (ReloadableConfig, tracing)
- [ ] Phase 4: Developer experience (CLI generator, templates)
## ๐ค Contributing
Contributions welcome! Please read [DESIGN.md](./docs/DESIGN.md) to understand the architecture first.
## ๐ License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
## ๐ Inspiration
SEN is inspired by:
- [Axum](https://github.com/tokio-rs/axum) - Type-safe handler functions
- [Clap](https://github.com/clap-rs/clap) - CLI argument parsing
- The philosophy of Anti-Fragility and Fixed Workflows
---
**SEN** (็ท/ๅ
): The Line to Success, Leading the Future of CLI Development