detrix-rs 1.2.0

Detrix client library for debug-on-demand observability in Rust applications
Documentation
# Detrix Rust Client

Debug-on-demand observability library for Rust applications. Enables AI-powered debugging of running Rust processes without code modifications or restarts.

## Features

- **Zero overhead when sleeping**: No debugger loaded until explicitly woken
- **No code changes required**: Add metrics to any line of code at runtime
- **Production-safe**: Non-breaking observation points (logpoints) that don't pause execution
- **Clean lifecycle**: Unlike Python's debugpy, LLDB can be fully stopped on sleep

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
detrix-rs = "1.0.0"
```

## Quick Start

```rust
use detrix_rs::{self as detrix, Config};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize client (starts control plane, stays SLEEPING)
    detrix::init(Config {
        name: Some("my-service".to_string()),
        ..Config::default()
    })?;

    // Your application code runs normally with zero overhead...

    // When debugging is needed (could be months later):
    // POST http://127.0.0.1:{control_port}/detrix/wake
    // → Client spawns lldb-dap and attaches to self
    // → Registers connection with Detrix daemon
    // → AI can now add metrics and observe values

    // Cleanup on shutdown
    detrix::shutdown()?;
    Ok(())
}
```

## Try It

Run the end-to-end example that simulates an AI agent: builds a sample app, wakes it, adds metrics, and captures events.

```bash
# 1. Start the Detrix server
detrix serve --daemon

# 2. Run the agent simulation (from clients/rust/)
cargo run --example test_wake -- --daemon-port 8090
```

Other examples in `examples/`:

| Example | Description | Run |
|---------|-------------|-----|
| `basic_usage` | Init / wake / sleep cycle | `cargo run --example basic_usage` |
| `trade_bot` | Long-running app with embedded client | `cargo run --example trade_bot` |
| `test_wake` | Agent simulation (builds app, wakes, observes) | `cargo run --example test_wake` |

## Architecture

```
┌─────────────────────────────────────────────────────────────────────┐
│  Rust Application Process                                           │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │ Application Code                                                 ││
│  │   use detrix_rs as detrix;                                       ││
│  │   detrix::init(Config::default())?;                             ││
│  └─────────────────────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │ Control Plane HTTP Server (background thread)                   ││
│  │   - Exposes /detrix/* endpoints                                 ││
│  │   - Manages lldb-dap process lifecycle                          ││
│  └─────────────────────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │ LLDB Manager                                                     ││
│  │   - Spawns: lldb-dap --connection listen://host:port            ││
│  │   - Sends DAP attach request with PID                           ││
│  │   - Monitors process health                                      ││
│  └─────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────┘
        │ ptrace attach (OS-level)
┌─────────────────────────────────────────────────────────────────────┐
│  lldb-dap Process (SEPARATE process)                                │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │ DAP Server                                                       ││
│  │   - Listens on debug_port                                       ││
│  │   - Accepts connections from Detrix daemon                      ││
│  │   - Sets logpoints for metrics                                  ││
│  └─────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────┘
```

## API

### Initialization

```rust
use detrix_rs::{self as detrix, Config};
use std::time::Duration;

// With defaults
detrix::init(Config::default())?;

// With custom configuration
detrix::init(Config {
    name: Some("my-service".to_string()),
    control_host: "127.0.0.1".to_string(),
    control_port: 0,  // 0 = auto-assign
    debug_port: 0,    // 0 = auto-assign
    daemon_url: "http://127.0.0.1:8090".to_string(),
    lldb_dap_path: None,  // searches PATH
    detrix_home: None,
    safe_mode: false,
    health_check_timeout: Duration::from_secs(2),
    register_timeout: Duration::from_secs(5),
    unregister_timeout: Duration::from_secs(2),
    lldb_start_timeout: Duration::from_secs(10),
})?;
```

### Status

```rust
let status = detrix::status();
println!("State: {}", status.state);
println!("Control port: {}", status.control_port);
if let Some(ref conn_id) = status.connection_id {
    println!("Connection ID: {}", conn_id);
}
```

### Wake/Sleep (programmatic)

```rust
// Wake: start debugger and register with daemon
let response = detrix::wake()?;
println!("Debug port: {}", response.debug_port);

// Or wake with daemon URL override
let response = detrix::wake_with_url("http://192.168.1.100:8090")?;

// Sleep: stop debugger and unregister
let response = detrix::sleep()?;
```

### Shutdown

```rust
// Cleanup on application exit
detrix::shutdown()?;
```

## Control Plane Endpoints

| Endpoint | Method | Auth | Description |
|----------|--------|------|-------------|
| `/detrix/health` | GET | No | Health check (always 200 OK) |
| `/detrix/status` | GET | Yes* | Current state, ports, connection info |
| `/detrix/info` | GET | Yes* | App metadata (name, PID, Rust version) |
| `/detrix/wake` | POST | Yes* | Start debugger, register with daemon |
| `/detrix/sleep` | POST | Yes* | Stop debugger, unregister |

*Localhost bypass: 127.0.0.1 and ::1 always authorized

## Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `DETRIX_NAME` | Connection name | `detrix-client-{pid}` |
| `DETRIX_DAEMON_URL` | Daemon URL | `http://127.0.0.1:8090` |
| `DETRIX_CONTROL_HOST` | Control plane bind host | `127.0.0.1` |
| `DETRIX_CONTROL_PORT` | Control plane port | `0` (auto) |
| `DETRIX_DEBUG_PORT` | Debug adapter port | `0` (auto) |
| `DETRIX_TOKEN` | Auth token for remote access | - |
| `DETRIX_LLDB_DAP_PATH` | Path to lldb-dap binary | searches PATH |
| `DETRIX_HOME` | Detrix home directory | `~/detrix` |
| `DETRIX_HEALTH_CHECK_TIMEOUT` | Health check timeout (seconds) | `2.0` |
| `DETRIX_REGISTER_TIMEOUT` | Registration timeout (seconds) | `5.0` |
| `DETRIX_UNREGISTER_TIMEOUT` | Unregistration timeout (seconds) | `2.0` |

## Build Information

The client automatically detects build metadata from:

1. **Explicit parameters** (via `Config::builder().build_commit()/.build_tag()`)
2. **Environment variables at runtime**:
   - `DETRIX_BUILD_COMMIT` / `DETRIX_BUILD_TAG`
   - `GIT_COMMIT`, `CI_COMMIT_SHA`, `GITHUB_SHA`
   - `GIT_TAG`, `CI_COMMIT_TAG`, `GITHUB_REF_NAME`
3. **Compile-time injection** (via environment variables during `cargo build`):
   ```bash
   GIT_COMMIT=$(git rev-parse HEAD) cargo build --release
   ```
4. **Runtime git detection** (local dev only)

### Docker Example

```dockerfile
FROM rust:1.75 AS builder
ARG GIT_COMMIT=unknown
ARG GIT_TAG=unknown

# Set at build time - captured by build.rs
ENV GIT_COMMIT=${GIT_COMMIT}
ENV GIT_TAG=${GIT_TAG}

RUN cargo build --release
```

Build with:
```bash
docker build --build-arg GIT_COMMIT=$(git rev-parse HEAD) \
             --build-arg GIT_TAG=$(git describe --tags) .
```

## Requirements

### lldb-dap

The client requires `lldb-dap` (formerly `lldb-vscode`) to be installed:

**macOS:**
```bash
# Via Homebrew LLVM
brew install llvm
# Binary at: /opt/homebrew/opt/llvm/bin/lldb-dap

# Or via Xcode Command Line Tools
xcode-select --install
# Binary at: xcrun -f lldb-dap
```

**Linux:**
```bash
# Ubuntu/Debian
sudo apt install lldb

# Binary at: /usr/bin/lldb-dap
```

### Debug Symbols

For useful debugging, compile with debug symbols:

```toml
# Cargo.toml
[profile.release]
debug = true
```

## Platform Notes

### macOS
- May need to grant "Developer Tools" access in System Preferences
- lldb-dap paths: `/opt/homebrew/opt/llvm/bin/lldb-dap` or via `xcrun -f lldb-dap`

### Linux
- ptrace_scope=1 works (lldb-dap spawned as child process)
- Check: `cat /proc/sys/kernel/yama/ptrace_scope`

## License

MIT