stasis-rs 0.1.0

Durable AI orchestration framework with runtime jobs, lineage, and memory integration
Documentation
# Stasis

Stasis is a Rust framework for AI orchestration with durable runtime jobs, cluster-aware control plane primitives, and memory integration hooks.

Package note: the crates.io package is `stasis-rs` while Rust imports use `stasis`.

## Architecture

- `domain`: Runtime models, policies, events, and error contracts.
- `application`: Use-cases, orchestration pipelines, and runtime handlers.
- `ports`: Stable inbound/outbound interfaces.
- `infrastructure`: Adapters for in-memory, SurrealDB, networking, and providers.
- `sdk`: Consumer-facing facades (`StasisSdk`, `RuntimeSdk`, `ControlPlaneSdk`).

## SDK Surface

- `StasisSdk`: agent registration and prompt invocation flows.
- `RuntimeSdk`: enqueue, process, publish, recurring materialization, runtime stats.
- `ControlPlaneSdk`: endpoint and cluster coordination commands.

## Quick Start

```rust
use stasis::sdk_prelude::{InvokeAgentRequest, InMemoryAgentRepository, RegisterAgentRequest, StasisSdk};
use stasis::sdk_prelude_ext::GenaiLlmGateway;

#[tokio::main]
async fn main() -> stasis::domain::errors::Result<()> {
    let repo = InMemoryAgentRepository::default();
    let llm = GenaiLlmGateway::from_env();
    let sdk = StasisSdk::new(repo, llm);

    sdk.register_agent(RegisterAgentRequest {
        id: "planner".into(),
        name: "Planner".into(),
        system_prompt: "Break tasks into steps".into(),
    })
    .await?;

    let out = sdk
        .invoke_agent(InvokeAgentRequest {
            agent_id: "planner".into(),
            user_prompt: "Plan a sprint kickoff".into(),
        })
        .await?;

    println!("{}", out.completion);
    Ok(())
}
```

For a deterministic local smoke test (no provider dependency), use [examples/simple_agent.rs](examples/simple_agent.rs).

Prelude tiers:

- `stasis::prelude`: minimal, stable default imports.
- `stasis::prelude_ext`: extended runtime/memory/control-plane imports.
- `stasis::sdk_prelude`: minimal SDK-first imports for app code.

To use a real provider via `genai`, set a provider key (for example `OPENAI_API_KEY`) and optionally configure model/provider routing:

```bash
export STASIS_LLM_PROVIDER=openai
export STASIS_LLM_MODEL=gpt-4o-mini
```

You can also set a Stasis-scoped fallback key:

```bash
export STASIS_LLM_API_KEY=...
```

Provider-specific overrides are supported:

- `STASIS_OPENAI_API_KEY`
- `STASIS_ANTHROPIC_API_KEY`
- `STASIS_OLLAMA_API_KEY`

Runtime examples are available in [examples](examples).

### Tool Macro (Signature-Driven)

`StasisTool` can be generated from a typed async function using `#[stasis_tool(...)]`:

```rust
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use stasis::domain::errors::Result;
use stasis::stasis_tool;

#[derive(Debug, Clone, Deserialize, JsonSchema)]
struct SearchInput {
    query: String,
}

#[derive(Debug, Clone, Serialize, JsonSchema)]
struct SearchOutput {
    summary: String,
}

#[stasis_tool(
    name = "search_docs",
    description = "Searches internal docs",
    output_schema = true
)]
async fn search_docs(input: SearchInput) -> Result<SearchOutput> {
    Ok(SearchOutput {
        summary: format!("query={}", input.query),
    })
}

// Generated symbols:
// - struct SearchDocsTool;
// - fn search_docs_tool() -> SearchDocsTool;
```

This avoids repetitive manual trait implementations while preserving strict JSON-schema-based validation.

Macro contract:

- Function must be `async` and take exactly one typed input argument.
- Return type must be `Result<OutputType>`.
- Input type must implement `Deserialize + JsonSchema`.
- Output type must implement `Serialize`.
- When `output_schema = true`, output type must also implement `JsonSchema`.

Production-focused entry points:

- [examples/simple_agent_production.rs]examples/simple_agent_production.rs: minimal real-provider invocation.
- [examples/agentic_workflows_production.rs]examples/agentic_workflows_production.rs: full workflow set with `STASIS_EXAMPLE_TEAM_PROFILE` (`all|sre|product|support`), `STASIS_EXAMPLE_RUNTIME_BACKEND` (`in-memory|surreal-mem|surreal-ws|surreal-kv`), and `STASIS_EXAMPLE_DRY_RUN=1` for provider-safe smoke runs.
- [examples/runtime_backends_profiles.rs]examples/runtime_backends_profiles.rs: backend profile bootstrap for in-memory, Surreal websocket, and Surreal KV modes.
- [examples/team_role_workflows.rs]examples/team_role_workflows.rs: role-specific scenario packs for SRE incident, product planning, and support triage loops.

CI-friendly smoke harness:

- [scripts/smoke-agentic-workflows.sh]scripts/smoke-agentic-workflows.sh

## Embedded Dashboard

You can embed the dashboard into your existing Axum app behind an optional feature flag.

Enable feature:

```bash
cargo add stasis-rs --features dashboard-embedded
```

Mount dashboard routes in your app code:

```rust
use std::sync::Arc;

use axum::Router;
use stasis::dashboard::{DashboardRouterExt, RuntimeDashboardQueryService};

fn app(service: Arc<RuntimeDashboardQueryService>) -> Router {
    Router::new().add_dashboard_with(service, |state| {
        state
            .with_action_auth_bearer_token("replace-me")
            .with_action_required_role("scheduler.admin")
    })
}
```

The standalone `stasis_dashboard` binary remains available for separate operations workflows.

Dashboard runtime backend selection (for `stasis_dashboard`):

- `STASIS_DASHBOARD_RUNTIME_BACKEND=in-memory|surreal-mem|surreal-ws|surreal-kv`
- `STASIS_DASHBOARD_SURREAL_NAMESPACE` (default: `stasis`)
- `STASIS_DASHBOARD_SURREAL_DATABASE` (default: `runtime`)
- `STASIS_DASHBOARD_SURREAL_ENDPOINT` (required for `surreal-ws`)
- `STASIS_DASHBOARD_SURREAL_KV_PATH` (required for `surreal-kv`)

Demo seeding remains opt-in and only applies to in-memory mode:

- `STASIS_DASHBOARD_DEMO_SEED=true`

## Documentation

- Docs index: [docs/README.md]docs/README.md
- V1 draft: [docs/v1-runtime-draft.md]docs/v1-runtime-draft.md
- Runtime design: [docs/design/job-runtime-design.md]docs/design/job-runtime-design.md
- Architecture overview: [docs/architecture/overview.md]docs/architecture/overview.md
- ADR index: [docs/adr/README.md]docs/adr/README.md

## mdBook

- Book root: [docs-book]docs-book
- Table of contents: [docs-book/src/SUMMARY.md]docs-book/src/SUMMARY.md

Build locally:

```bash
mdbook build docs-book
```

Serve locally:

```bash
mdbook serve docs-book --open
```