Skip to content

compozy/arky

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Arky

A Rust SDK for building AI agents with first-class streaming, tool execution, and session management.

License Rust Version Status


Arky treats CLI-backed AI providers (Claude Code, Codex) as first-class streaming runtimes -- not thin text generators. It normalizes provider-specific protocols into a unified event stream, manages session persistence and replay, and gives you composable hooks, tools, and MCP integration out of the box.

Features

  • Streaming-first architecture -- real-time AgentEvent streams with text deltas, tool lifecycle, and extended thinking
  • Multiple providers -- Claude Code CLI, Codex app server, plus Claude-compatible wrappers (Bedrock, Vertex, OpenRouter, Ollama, and more)
  • Tool system with #[tool] macro -- turn any async function into an agent tool with auto-generated JSON schemas
  • MCP integration -- client/server bridge for importing and exposing tools via the Model Context Protocol
  • Session persistence & replay -- in-memory or SQLite-backed session stores with event-sourced replay and resume
  • Lifecycle hooks -- intercept tool calls, session events, stop decisions, and prompt submissions
  • Error classification -- structured error codes with retryability hints, HTTP status mapping, and correction context
  • Cooperative cancellation -- CancellationToken throughout the entire stack for graceful abort
  • HTTP/SSE server -- expose agents over HTTP with Server-Sent Events streaming

Quick Start

Add Arky to your project:

[dependencies]
arky = { version = "0.1", features = ["claude-code"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Build and run an agent:

use arky::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let provider = ClaudeCodeProvider::new();
    let agent = Agent::builder()
        .provider(provider)
        .model("sonnet")
        .build()?;

    let response = agent.prompt("Summarize the repository layout.").await?;
    println!("{:?}", response.message);
    Ok(())
}

Streaming Events

use arky::prelude::*;
use futures::StreamExt;

let mut stream = agent.stream("Plan a release checklist.").await?;
while let Some(event) = stream.next().await {
    match event? {
        AgentEvent::MessageUpdate { delta, .. } => println!("{delta:?}"),
        AgentEvent::ToolExecutionStart { tool_name, .. } => {
            println!("tool: {tool_name}");
        }
        _ => {}
    }
}

Custom Tools

The #[tool] proc macro turns async functions into agent tools with zero boilerplate:

use arky::prelude::*;

#[tool]
async fn search(query: String) -> String {
    /// Search the web for information
    format!("Results for: {query}")
}

let agent = Agent::builder()
    .provider(provider)
    .tool(SearchTool)
    .build()?;

Tools support cancellation tokens, structured ToolResult returns, and JSON input schemas generated automatically via schemars.

Providers

Claude Code

Wraps the Claude CLI with streaming JSON parsing, nested tool tracking, and native session resume.

let provider = ClaudeCodeProvider::with_config(ClaudeCodeProviderConfig {
    binary: "claude".to_owned(),
    ..Default::default()
});

Claude-compatible wrappers are also available: BedrockProvider, VertexProvider, OpenRouterProvider, VercelProvider, OllamaProvider, ZaiProvider, MoonshotProvider, and MinimaxProvider.

Codex

Speaks newline-delimited JSON-RPC with the Codex app server, with thread-aware routing for concurrent sessions.

let provider = CodexProvider::with_config(CodexProviderConfig {
    binary: "codex".to_owned(),
    ..Default::default()
});

Sessions & Replay

Arky persists transcript messages, replay events, and turn checkpoints for safe resume:

// In-memory for development
let store = InMemorySessionStore::new();

// SQLite for production (requires "sqlite" feature)
let store = SqliteSessionStore::new("sessions.db").await?;

let agent = Agent::builder()
    .provider(provider)
    .session_store(store)
    .build()?;

// Resume a previous session
agent.resume(session_id).await?;

Lifecycle Hooks

Intercept and control agent behavior at every stage:

use arky::prelude::*;

struct SafetyHooks;

#[async_trait]
impl Hooks for SafetyHooks {
    async fn before_tool_call(
        &self,
        ctx: &BeforeToolCallContext,
        _cancel: CancellationToken,
    ) -> Result<Verdict, HookError> {
        if ctx.tool_call.name.contains("dangerous") {
            return Ok(Verdict::block("Tool not allowed"));
        }
        Ok(Verdict::Allow)
    }
}

let agent = Agent::builder()
    .provider(provider)
    .hooks(SafetyHooks)
    .build()?;

Hooks support before_tool_call, after_tool_call, session_start, session_end, on_stop, and user_prompt_submit. Compose multiple hooks with HookChain and configure per-hook failure modes (FailOpen / FailClosed).

MCP Integration

Import tools from MCP servers or expose your tools as an MCP server:

// Import tools from an MCP server
let client = McpClient::connect(McpStdioClientConfig {
    command: "my-mcp-server".to_owned(),
    args: vec![],
    env: Default::default(),
}).await?;

// Expose tools as an MCP server
let server = McpServer::builder()
    .tools(tool_registry)
    .transport(McpServerTransport::Http { port: 3000 })
    .build()?;

Tools follow canonical naming: mcp/<server>/<tool_name>.

Architecture

Arky is a Cargo workspace with narrowly-scoped crates that evolve independently:

Layer           Crates                              Responsibility
─────           ──────                              ──────────────
Leaf            arky-error, arky-protocol,          Shared contracts, IDs, protocol
                arky-config, arky-tools-macros       shapes, configuration, proc macros

Foundation      arky-tools, arky-hooks,             Tool registry, lifecycle hooks,
                arky-session, arky-provider          persistence, provider abstractions

Integration     arky-mcp                            MCP client/server bridge

Providers       arky-claude-code, arky-codex        CLI-backed provider implementations

Orchestration   arky-core                           Agent loop, turn runtime, replay,
                                                     event fanout

Exposure        arky-server                         HTTP and SSE runtime

Facade          arky                                Curated public API with
                                                     feature-gated re-exports

Feature Flags

Feature Description Default
claude-code Claude Code CLI provider Yes
codex Codex app server provider Yes
sqlite SQLite session persistence No
server HTTP/SSE server runtime No
full All optional features No

Development

# Format code (uses nightly for unstable rustfmt options)
make fmt

# Run lints (clippy with -D warnings)
make lint

# Run all tests
make test

# Full verification (fmt + lint + test)
make verify

# Build in release mode
make build

# Run live provider examples
cargo run -p arky --example 01_claude_basic
cargo run -p arky --example 09_live_matrix -- all

Requires Rust 1.94.0+. The workspace uses nightly cargo fmt for unstable formatting options.

Documentation

License

Apache-2.0

About

LLM Providers bridge and SDK using Rust

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors