bare-script 0.1.1

The type-safe scripting authority for Rust. A framework for building robust shell commands and automation with 'Parse, don't validate' philosophy.
Documentation
# Architecture


This document explains the architectural decisions in `bare-script`, designed to be understandable by both humans and AI systems.

## Overview


`bare-script` is a **type-safe shell command execution library** built on three pillars:

1. **Zero-cost abstractions**: Type-safe API with minimal runtime overhead
2. **Parse, don't validate**: Validate once at boundaries, trust types thereafter
3. **Explicit over implicit**: Clear contracts, no hidden behavior

## Design Philosophy Deep Dive


### "Parse, Don't Validate"


This concept means:

```
❌ DON'T: Validate everywhere
   CommandBuilder::new("ls")
       .arg(input);  // No validation, could be invalid

✅ DO: Parse once, use types
   let args = Args::new()
       .flag("-v", "--verbose")
       .option("-o", "--output")
       .value("file.txt")
       .validate()?;  // Validation happens here
```

**Why This Matters:**
- **For Humans**: Reduces cognitive load - once validated, you can trust the arguments
- **For AI**: Creates clear boundaries where validation logic belongs

### Builder Pattern


All command building uses the Builder pattern:

```rust
CommandBuilder::new("ls")
    .arg("-l")
    .arg("-h")
    .env("DEBUG", "true")
    .current_dir("/tmp")
    .capture_output()
    .execute()?;
```

**Benefits:**
- Fluency: Chain method calls for readable code
- Immutability: Each method returns a new builder (no mutability)
- Type safety: Compile-time guarantee of valid command structure

## Module Architecture


```
bare-script/
├── lib.rs              # Crate root, public exports
├── args.rs             # Type-safe argument builder
├── config.rs           # Command configuration
├── error.rs            # Error types
├── output.rs           # Command output types
├── logging.rs          # Optional logging (feature = "logging")
├── shell.rs            # Shell integration helpers
├── sync/               # Synchronous execution
│   ├── mod.rs
│   ├── builder.rs     # CommandBuilder for sync
│   └── pipeline.rs    # Pipeline for sync
└── proc/              # Asynchronous execution (feature = "tokio-rt")
    ├── mod.rs
    ├── builder.rs     # CommandBuilder for async
    └── pipeline.rs    # Pipeline for async
```

### Feature-Gated Modules


Modules are conditionally compiled based on features:

```rust
#[cfg(feature = "tokio-rt")]

pub mod proc;

#[cfg(feature = "logging")]

pub mod logging;
```

**Design Decision**: Async support is behind a feature gate to:
- Minimize compile times for users who don't need async
- Reduce binary size for simple sync use cases
- Allow gradual adoption

## Type Hierarchy


### Core Traits


#### `CommandBuilder`


The main entry point for building commands:

```rust
pub struct CommandBuilder {
    cmd: Command,  // std::process::Command or tokio::process::Command
}
```

#### `Args`


Type-safe argument builder:

```rust
pub struct Args {
    args: Vec<Arg>,
    positional: Vec<Arg>,
}

pub enum ArgType {
    Flag,       // e.g., -v, --verbose
    Option,     // e.g., -o file, --output=file
    Positional, // e.g., filename
}
```

#### `Output`


Captured command output:

```rust
pub struct Output {
    stdout: Vec<u8>,
    stderr: Vec<u8>,
    status: ExitStatus,
}
```

### Error Types


All errors use `thiserror` for rich error messages:

```rust
pub enum ScriptError {
    CommandNotFound(String),
    PermissionDenied(String),
    InvalidArgument(String),
    InvalidWorkingDirectory(String),
    ExecutionFailed { code: i32, stderr: String },
    Timeout(Duration),
    IoError(std::io::Error),
    // ... more variants
}
```

## Synchronous vs Asynchronous


### Sync API


Uses `std::process::Command`:

```rust
use bare_script::sync::CommandBuilder;

let output = CommandBuilder::new("ls")
    .arg("-l")
    .execute()?;
```

### Async API


Uses `tokio::process::Command`:

```rust
use bare_script::proc::CommandBuilder;

let output = CommandBuilder::new("ls")
    .arg("-l")
    .execute()
    .await?;
```

## Pipeline Support


Both sync and async APIs support command pipelines:

```rust
use bare_script::sync::Pipeline;

let output = Pipeline::new("echo")
    .arg("hello world")
    .pipe("grep")
    .arg("hello")
    .capture_output()
    .execute()?;
```

## Cross-Platform Design


### Windows


- Default shell: `cmd`
- Shell flag: `/C`
- Uses `creation_flags` for process creation

### Unix


- Default shell: `sh`
- Shell flag: `-c`
- Uses `process_group`, `setsid`, `uid`, `gid` for process control

## Security Considerations


1. **No shell injection**: Arguments are passed directly, not through shell
2. **Environment isolation**: Can clear or remove environment variables
3. **Working directory control**: Explicit control over execution directory
4. **Timeout support**: Prevents hanging processes

## Performance Characteristics


- **Zero-cost abstractions**: After validation, command execution has minimal overhead
- **Process spawn overhead**: Actual command execution includes OS process creation (~5-10ms)
- **Memory**: Small footprint, no internal buffering

## Extension Points


### Custom Arguments


Use the `Args` builder for complex argument patterns:

```rust
let args = Args::new()
    .flag("-v", "--verbose")
    .option("-o", "--output")
    .value("file.txt")
    .positional()
    .validate()?;
```

### Custom Configuration


Use `Config` for reusable configurations:

```rust
let config = Config::new()
    .env("DEBUG", "true")
    .cwd("/tmp");
```