Forge

Build agents.
Keep control.

An open runtime with identity, tools,
and accountability built in.

A closer lookBuilt to fit together.
FORGE / FIELD NOTES01IDENTITYRUNTIMETOOLS

The runtime takes shape around a common contract.

  1. 01Lay out the parts
  2. 02Fit the contract
  3. 03Check the assembly
  4. 04Ready to build

Six languages. One open contract. Yours to build on.

The SDK

Your language.
Your kind of powerful.

Rust, TypeScript, Go, Python, Swift, and Kotlin.
A common contract, expressed in the language you love.

One idea.
Six ways to build it.

Start with an identity. Add a provider and the tools your agent needs. Keep the same foundations as your project grows.

Meet the SDKs
IdentityGenerationToolsLifecycle
Source quickstartRust
//! Forge SDK Quickstart -- Rust
//!
//! This example demonstrates the complete Forge agent lifecycle:
//!
//! 1. Create a Human Root (HMR) identity
//! 2. Derive an agent identity from the HMR
//! 3. Configure a mock language model provider
//! 4. Register tools in the tool registry
//! 5. Run the agent's tool loop
//! 6. Print the result including the agent's OAS DID
//!
//! No API keys are required. The mock provider returns deterministic
//! responses for demonstration purposes.
…
View the complete example
//! Forge SDK Quickstart -- Rust
//!
//! This example demonstrates the complete Forge agent lifecycle:
//!
//! 1. Create a Human Root (HMR) identity
//! 2. Derive an agent identity from the HMR
//! 3. Configure a mock language model provider
//! 4. Register tools in the tool registry
//! 5. Run the agent's tool loop
//! 6. Print the result including the agent's OAS DID
//!
//! No API keys are required. The mock provider returns deterministic
//! responses for demonstration purposes.

use std::sync::Arc;

use forge_sdk::prelude::*;

// ---------------------------------------------------------------------------
// Step 1: Mock Language Model
// ---------------------------------------------------------------------------
//
// In production, you would use a real provider like "openai:gpt-4o" or
// "anthropic:claude-sonnet-4-5-20250929". For this quickstart, we implement
// a mock that simulates a two-step interaction:
//
//   Turn 1: The model requests the "get_weather" tool.
//   Turn 2: The model produces a final text response using the tool result.

struct MockModel;

#[async_trait]
impl LanguageModel for MockModel {
    fn model_id(&self) -> &str {
        "mock:quickstart-v1"
    }

    fn provider_namespace(&self) -> &str {
        "mock"
    }

    fn supports_tool_calling(&self) -> bool {
        true
    }

    async fn generate(
        &self,
        messages: &[ModelMessage],
        tools: &[ToolDefinition],
        _options: &GenerateOptions,
    ) -> ForgeResult<GenerateResult> {
        // Count assistant messages to determine which turn we are on.
        let assistant_count = messages
            .iter()
            .filter(|m| m.role() == Role::Assistant)
            .count();

        if assistant_count == 0 && !tools.is_empty() {
            // Turn 1: Request the "get_weather" tool.
            let tool_call_msg = ModelMessage::tool_call(
                "call_001",
                "get_weather",
                serde_json::json!({"city": "San Francisco"}),
            );

            Ok(GenerateResult {
                message: tool_call_msg,
                finish_reason: FinishReason::ToolCalls,
                usage: Usage {
                    prompt_tokens: 50,
                    completion_tokens: 20,
                    total_tokens: 70,
                },
            })
        } else {
            // Turn 2: Produce a final text response.
            let response_msg = ModelMessage::text(
                Role::Assistant,
                "Based on the weather data, San Francisco is currently 65 degrees \
                 Fahrenheit with partly cloudy skies. A great day to be outside!",
            );

            Ok(GenerateResult {
                message: response_msg,
                finish_reason: FinishReason::Stop,
                usage: Usage {
                    prompt_tokens: 80,
                    completion_tokens: 30,
                    total_tokens: 110,
                },
            })
        }
    }
}

// ---------------------------------------------------------------------------
// Step 2: Tool Executor
// ---------------------------------------------------------------------------
//
// Tools are the agent's interface to the external world. Each tool has a
// definition (name, description, parameters, tier) and an executor function.

async fn handle_get_weather(args: serde_json::Value) -> Result<String, String> {
    let city = args
        .get("city")
        .and_then(|v| v.as_str())
        .unwrap_or("unknown");

    // In production, this would call a real weather API.
    Ok(format!(
        "Weather in {city}: 65F, partly cloudy, humidity 72%, wind 8 mph SW"
    ))
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

#[tokio::main]
async fn main() {
    println!("=== Forge SDK Quickstart (Rust) ===\n");

    // -----------------------------------------------------------------------
    // Step 3: Create the identity hierarchy
    // -----------------------------------------------------------------------
    //
    // Every Forge agent carries an OAS DID (Decentralized Identifier) from
    // birth. The identity hierarchy starts with a Human Root (HMR) and agents
    // are derived from it via HKDF key derivation.

    let hmr = create_hmr_identity("l1fe", "alice")
        .expect("HMR identity creation should succeed");

    println!("HMR identity created:");
    println!("  DID:            {}", hmr.did());
    println!("  Lineage depth:  {}", hmr.lineage_depth());
    println!();

    let agent_identity = derive_agent_identity(&hmr, "weather-assistant", "l1fe")
        .expect("Agent identity derivation should succeed");

    println!("Agent identity derived:");
    println!("  DID:            {}", agent_identity.did());
    println!("  Lineage depth:  {}", agent_identity.lineage_depth());
    println!();

    // -----------------------------------------------------------------------
    // Step 4: Build the tool registry
    // -----------------------------------------------------------------------
    //
    // Tools are classified into three immutable tiers per the ANVIL spec:
    //   Tier 1 (Platform): Always available inside the sandbox.
    //   Tier 2 (Host):     Outside the sandbox; requires Arsenal ACT authorization.
    //   Tier 3 (Embedded): Custom logic compiled into the agent's WASM module.

    let weather_tool = ToolDefinition::builder("get_weather")
        .description("Get the current weather for a city")
        .tier(ToolTier::Host)
        .build();

    let mut registry = ToolRegistry::new();
    registry.register(
        weather_tool,
        FnToolExecutor::new(|call| {
            Box::pin(async move { handle_get_weather(call.arguments().clone()).await })
        }),
    );

    println!("Tool registry: {} tool(s) registered", registry.len());
    println!();

    // -----------------------------------------------------------------------
    // Step 5: Configure and run the agent
    // -----------------------------------------------------------------------

    let model: Arc<dyn LanguageModel> = Arc::new(MockModel);
    let approval: Arc<dyn ApprovalHandler> = Arc::new(AutoApprove);

    let config = AgentConfig::new("weather-assistant", "mock:quickstart-v1")
        .with_system_prompt("You are a helpful weather assistant. Use the get_weather tool to answer questions.")
        .with_identity(agent_identity)
        .with_max_steps(5);

    let agent = ToolLoopAgent::new(config, model, registry, approval);

    println!("Running agent tool loop...\n");

    match agent.run("What is the weather in San Francisco?").await {
        Ok(output) => {
            // ---------------------------------------------------------------
            // Step 6: Print the results
            // ---------------------------------------------------------------

            println!("--- Agent Output ---");
            println!("Final text:    {}", output.final_text);
            println!("Steps taken:   {}", output.steps_taken);
            println!("Total tokens:  {}", output.usage.total_tokens);
            println!("Messages:      {}", output.messages.len());
            println!();

            // Print the agent's DID from the config
            println!("--- Agent Identity ---");
            println!("Agent DID:     {}", agent.config().agent_did().unwrap_or("(none)"));
            println!("Lifecycle:     {:?}", agent.lifecycle());
            println!();

            // Print health profile
            let health = agent.health();
            println!("--- Health Profile ---");
            println!("Tool calls:    {}", health.tool_invocations);
            println!("Inferences:    {}", health.inference_tokens);
        }
        Err(e) => {
            eprintln!("Agent execution failed: {e}");
            std::process::exit(1);
        }
    }

    println!("\n=== Quickstart complete ===");
}

Snapshot of examples/rust/quickstart/src/main.rs. These examples use a mock provider. Follow the language guide for setup; the website does not execute them.

Rust source quickstart
$cd examples/rust/quickstart
Rust guide

Different languages. Shared foundations. ANVIL defines eight contracts: identity, capability, tools, health, communication, collaboration, lifecycle, and telemetry.

Explore ANVIL

Identity at the foundation

Power begins
with trust.

An agent should be able to show where it came from. And exactly what it has permission to do.

Forge brings OAS identities, signed lineage, and Arsenal capabilities into the runtime. Delegation carries its history. Authority has a boundary.

Discover agent identity

Stay in control

A lot can happen.
Keep a clear view.

Choose the intelligence. Understand the state.
Follow the work, from action to evidence.

Provider choice

Great agents.
Your choice of model.

A provider interface keeps model configuration separate from your agent. Connect a service, use a local model, or implement your own provider.

Explore providers

Explicit lifecycle

Know where things stand.

Initialization, ready, running, paused, error, and terminated. Defined transitions give the work a structure you can inspect.

Explore the lifecycle

Telemetry and audit

Every action has a story.

OpenTelemetry-compatible spans and signed audit-trail primitives make execution inspectable.

Follow the evidence

Architecture illustrations. No models, lifecycle transitions, or audit events are running on this page.

The developer experience

From first idea.
To finer details.

A place to build. A way to inspect.
Tools for the work around the agent.

Conceptual tool illustrations. Explore each guide for implementation and usage details.

Made to move

Your next environment.
Within reach.

Explore WASM and WASI deployment, from local execution to hosted runtimes. Carry the contract with you, and check the requirements of each destination.

Find your deployment path

Open by design

The next great agent
starts with you.

Read the contracts. Explore the implementation.
Build something the rest of us can build on.

Part of Open Software