neuron-runtime 0.3.0

Production runtime for AI agents — sessions, sub-agents, input/output guardrails, permission policies, and durable execution
Documentation
# neuron-runtime

Production runtime layer for the neuron agent blocks ecosystem. Provides
session management, sub-agent orchestration, input/output guardrails, durable
execution contexts, and tool sandboxing.

## Key Types

- `Session` -- a conversation session with messages, state, and timestamps.
  Created with `Session::new(id, cwd)`.
- `SessionState` -- mutable runtime state within a session (working directory,
  token usage, event count, custom metadata).
- `SessionStorage` trait -- async trait for persisting and loading sessions.
- `InMemorySessionStorage` -- `Arc<RwLock<HashMap>>` storage for testing.
- `FileSessionStorage` -- one JSON file per session on disk.
- `InputGuardrail` / `OutputGuardrail` -- traits for safety checks that run
  before input reaches the LLM or before output reaches the user.
- `GuardrailResult` -- `Pass`, `Tripwire(reason)`, or `Warn(reason)`. A
  tripwire halts execution immediately.
- `GuardrailHook` -- an `ObservabilityHook` that runs input/output guardrails
  during the agent loop. Tripwires terminate; warnings log and continue.
- `SubAgentConfig` -- configuration for spawning sub-agents (system prompt,
  tool filter, max depth, max turns).
- `SubAgentManager` -- registers and spawns sub-agents.
- `LocalDurableContext` -- passthrough `DurableContext` for local development
  (no journaling or replay).
- `Sandbox` trait / `NoOpSandbox` -- tool execution isolation boundary.

## Usage

```rust,no_run
use std::path::PathBuf;
use neuron_runtime::{
    FileSessionStorage, GuardrailResult, InputGuardrail,
    Session, SessionStorage,
};

// Create a session and persist it to disk
async fn create_session() -> Result<(), Box<dyn std::error::Error>> {
    let storage = FileSessionStorage::new(PathBuf::from("/tmp/sessions"));
    let session = Session::new("session-001", PathBuf::from("/home/user"));
    storage.save(&session).await?;

    let loaded = storage.load("session-001").await?;
    assert_eq!(loaded.id, "session-001");
    Ok(())
}

// Define an input guardrail that blocks secrets
struct NoSecrets;
impl InputGuardrail for NoSecrets {
    fn check(
        &self,
        input: &str,
    ) -> impl std::future::Future<Output = GuardrailResult> + Send {
        async move {
            if input.contains("API_KEY") || input.contains("sk-") {
                GuardrailResult::Tripwire(
                    "Input contains a secret".to_string(),
                )
            } else {
                GuardrailResult::Pass
            }
        }
    }
}
```

## GuardrailHook

`GuardrailHook` wraps input and output guardrails as an `ObservabilityHook`,
so they integrate directly into the agent loop via the hook system.

```rust,no_run
use neuron_runtime::{
    GuardrailHook, GuardrailResult, InputGuardrail, OutputGuardrail,
};

struct BlockSecrets;
impl InputGuardrail for BlockSecrets {
    fn check(
        &self,
        input: &str,
    ) -> impl std::future::Future<Output = GuardrailResult> + Send {
        async move {
            if input.contains("API_KEY") {
                GuardrailResult::Tripwire("secret in input".to_string())
            } else {
                GuardrailResult::Pass
            }
        }
    }
}

struct NoLeaks;
impl OutputGuardrail for NoLeaks {
    fn check(
        &self,
        output: &str,
    ) -> impl std::future::Future<Output = GuardrailResult> + Send {
        async move {
            if output.contains("sk-") {
                GuardrailResult::Tripwire("secret in output".to_string())
            } else {
                GuardrailResult::Pass
            }
        }
    }
}

let hook = GuardrailHook::new()
    .input_guardrail(BlockSecrets)
    .output_guardrail(NoLeaks);

// Pass `hook` as the ObservabilityHook when building the agent loop.
```

- On `PreLlmCall`, the hook extracts the last user message text and runs all
  input guardrails. A `Tripwire` returns `HookAction::Terminate`; a `Warn`
  logs via `tracing::warn!` and continues.
- On `PostLlmCall`, the hook extracts the assistant response text and runs all
  output guardrails with the same mapping.

## Part of neuron

This crate is one block in the [neuron](https://github.com/secbear/neuron)
composable agent toolkit. It depends on `neuron-types`, `neuron-tool`, and
`neuron-loop`.

## License

Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
[MIT License](LICENSE-MIT) at your option.