rig-compose 0.2.0

Composable agent kernel: stateless skills, transport-agnostic tools, registry-driven agents, signal-routing coordinator. Companion crate for rig.
Documentation

rig-compose

Composable agent kernel: stateless skills, transport-agnostic tools, registry-driven agents, signal-routing coordinator. Companion crate for rig.

crates.io docs.rs license

Overview

rig-compose is a domain-neutral composition layer for Rig-shaped agent systems. It provides the kernel traits and data structures for stateless skills, side-effectful tools, shared registries, generic agents, deterministic signal routing, workflows, in-process agent delegation, and optional YAML manifest loading.

The crate does not call an LLM itself and does not depend on rig-core; instead it defines the small tool and skill surfaces that companion crates such as rig-mcp and rig-resources plug into.

Why it exists

Rig supplies provider-agnostic model, embedding, vector-store, and tool traits. rig-compose fills a different gap: it organizes domain skills and tools into repeatable agent workflows without forcing those workflows to know whether a tool is local, delegated to another in-process agent, or surfaced through MCP.

This keeps downstream systems from reimplementing the same coordination pieces: Skill, Tool, ToolRegistry, SkillRegistry, GenericAgent, CoordinatorAgent, DelegateTool, and the budget guards used to meter finite work.

Status

  • Crate version: 0.1.2.
  • Rust edition: 2024.
  • MSRV: 1.88.
  • Runtime stance: runtime-agnostic library; tokio is used only as a dev-dependency for tests and examples.
  • Current Unreleased work adds the budget module, drop-safe TokenReservation refunds, and KernelError::ToolNotApplicable for soft tool failures.

Feature flags

Feature Default Enables Checked by just check
none yes Core agent, skill, tool, registry, workflow, delegate, coordinator, context, instruction, and budget APIs. cargo clippy --all-targets, cargo test --all-targets
manifest no YAML-backed portable agent manifest types and materialization helpers from src/manifest.rs. Pulls serde_yaml. cargo clippy --all-targets --features manifest, cargo test --all-targets --features manifest, docs and examples with all features

Key Types

  • src/skill.rs: Skill, SkillId, and SkillOutcome. Skills are stateless and decide whether they apply to an InvestigationContext.
  • src/tool.rs: Tool, ToolSchema, ToolName, and LocalTool. Tools are the side-effectful async boundary.
  • src/registry.rs: ToolRegistry, SkillRegistry, and KernelError. Registries hold shared tools and skills; ToolRegistry::scoped produces per-agent tool views.
  • src/agent.rs: Agent, AgentId, AgentStepResult, GenericAgent, and GenericAgentBuilder. Generic agents run registered skill chains over mutable investigation context.
  • src/context.rs: InvestigationContext, Signal, Evidence, and NextAction. This is the shared state that skills read and enrich.
  • src/delegate.rs: DelegateExecutor, DelegateRegistry, DelegateTool, DelegateName, and InProcessAgentDelegate. This is the model-driven agent-to-agent delegation path.
  • src/coordinator.rs: CoordinatorAgent, CoordinatorBuilder, and RoutingRule. This is deterministic first-match routing for fixed topologies.
  • src/budget.rs: BudgetGuard, TokenBudget, AtomicBudget, AtomicTokenBudget, TokenReservation, TokenRefund, and BudgetError. These meter rows, dispatch slots, and prompt-token reservations.
  • src/workflow.rs: Workflow, the async workflow composition trait.
  • src/instructions.rs: Instructions, a serializable instruction bundle with examples, response schema, and metadata.
  • src/manifest.rs: AgentManifest, ModelSpec, ToolSpec, DelegateSpec, and materialization helpers, gated behind manifest.

The crate-level architecture rule is simple: Skill is pure decision logic, Tool is the side-effect boundary, registries own lookup, and agents compose registered pieces without hard-coding concrete implementations.

Integration With Rig

rig-compose does not pin rig-core in Cargo.toml. It is intentionally Rig-shaped rather than Rig-bound: other crates can adapt Rig tools, MCP tools, local closures, or in-process delegates into the same Tool and Skill flow.

The main companion integration points are:

  • rig-mcp implements remote MCP access by adapting MCP endpoints into rig_compose::Tool values.
  • rig-resources provides reusable skills and tools that implement rig-compose traits.
  • Downstream systems such as Azrael can use BudgetGuard and TokenBudget to enforce compute budgets around agent dispatch and LLM token use.

Usage

The minimal runnable example is examples/basic_agent.rs. It registers one stateless skill, builds a GenericAgent, and runs that agent against an InvestigationContext.

use std::sync::Arc;

use async_trait::async_trait;
use rig_compose::{
    Agent, GenericAgent, InvestigationContext, KernelError, Skill, SkillOutcome, SkillRegistry,
    ToolRegistry,
};

struct KeywordSkill;

#[async_trait]
impl Skill for KeywordSkill {
    fn id(&self) -> &str {
        "example.keyword"
    }

    fn applies(&self, context: &InvestigationContext) -> bool {
        context.has_signal("keyword.match")
    }

    async fn execute(
        &self,
        _context: &mut InvestigationContext,
        _tools: &ToolRegistry,
    ) -> Result<SkillOutcome, KernelError> {
        Ok(SkillOutcome::default().with_delta(0.25))
    }
}

# async fn run() -> Result<(), KernelError> {
let skills = SkillRegistry::new();
skills.register(Arc::new(KeywordSkill));

let tools = ToolRegistry::new();
let agent = GenericAgent::builder("triage")
    .with_skills(["example.keyword"])
    .build(&skills, &tools)?;

let mut context = InvestigationContext::new("entity-1", "default")
    .with_signal("keyword.match");
let result = agent.step(&mut context).await?;

assert_eq!(result.skills_run, vec!["example.keyword".to_string()]);
# Ok(()) }

The budget behavior is covered by the unit tests in src/budget.rs, including reservation reconciliation and drop-time refunds.

Validation

Canonical validation is just check.

That recipe runs formatter checks, clippy and tests for default features and manifest, rustdoc with -D warnings -D rustdoc::broken_intra_doc_links, and cargo build --examples --all-features.

Gotchas

  • DelegateTool and CoordinatorAgent solve different routing problems. Use DelegateTool when the model should decide whether to call another agent; use CoordinatorAgent for fixed host-driven signal routing.
  • KernelError::ToolNotApplicable is a soft failure for tools that cannot apply to the current context. Callers may treat it as a no-op, as rig-resources does for missing graph entities.
  • TokenReservation refunds its estimate on drop unless AtomicTokenBudget::record_usage disarms it. Keep the handle alive until actual usage is recorded.
  • The library is runtime-agnostic. Do not add runtime dependencies to [dependencies]; tests and examples use tokio from [dev-dependencies].

Ecosystem

These companion crates are maintained as separate repositories. Together they form a small stack around the upstream Rig project: rig-compose provides the kernel surface, rig-resources contributes reusable skills and tools, rig-mcp moves tools across MCP, rig-memvid connects Rig agents to persistent .mv2 memory, and rig-ballista reserves the metadata-catalog seam for future query-engine integration.

flowchart TD
    rig["rig / rig-core"]
    compose["rig-compose 0.1.x"]
    resources["rig-resources 0.1.x"]
    mcp["rig-mcp 0.1.x"]
    memvid["rig-memvid 0.1.x"]
    ballista["rig-ballista 0.1.x"]

    compose -. "Rig-shaped kernel; no direct rig-core dep" .-> rig
    resources -- "rig-compose = 0.1; features: security, graph, full" --> compose
    mcp -- "rig-compose = 0.1; rmcp stdio bridge" --> compose
    memvid -- "rig-core = 0.36.0; features: lex, vec, api_embed, temporal, encryption" --> rig
    ballista -. "planned rig-compose catalog integration; no direct dep today" .-> compose

Pinned Rig-facing dependencies from the current manifests:

Crate Direct Rig-facing dependency Notes
rig-compose none Defines a Rig-shaped kernel surface without depending on rig-core.
rig-resources rig-compose = 0.1 Uses a sibling path during local workspace development.
rig-mcp rig-compose = 0.1 Uses a sibling path during local workspace development.
rig-memvid rig-core = 0.36.0 Implements Rig vector-store and prompt-hook flows over Memvid.
rig-ballista none today Ballista/Iceberg/DataFusion dependencies remain planned and commented out.

The concrete multi-crate workflow tested today is the MCP loopback path: a rig_compose::ToolRegistry is exposed through rig_mcp::LoopbackTransport, remote schemas are wrapped as rig_mcp::McpTool, and the wrapped tools are registered back into another ToolRegistry. That proves a local rig-compose tool and an MCP-adapted tool are indistinguishable to callers. The backing test is mcp_tool_indistinguishable_from_local in rig-mcp/src/transport.rs.

License

Licensed under either Apache-2.0 or MIT, at your option.