Adding a New Agent to a Rust Golem Component

SkillAI & models

Adding a new Rust agent to a Golem component. Use when the user asks to create, add, or define a new agent type, implement an agent trait, or add agent methods in a Rust Golem project.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Adding a New Agent to a Rust Golem Component skill

What this skill tells your AI

The instructions your AI receives, as published by golemcloud/golem in golem-skills/skills/rust/golem-add-agent-rust/SKILL.md and read by ahel’s review.

Overview

An agent is a durable, stateful unit of computation in Golem. Each agent type is defined as a trait annotated with #[agent_definition] and implemented on a struct annotated with #[agent_implementation].

Steps

  1. Create the agent module — add a new file src/<agent_name>.rs
  2. Define the agent trait — annotate with #[agent_definition]
  3. Implement the agent — annotate with #[agent_implementation]
  4. Re-export from lib.rs — add mod <agent_name>; and pub use <agent_name>::*;
  5. Build — run golem build to verify

Agent Definition

use golem_rust::{agent_definition, agent_implementation};

#[agent_definition]
pub trait MyAgent {
    // Constructor parameters form the agent's identity.
    // Two agents with the same parameters are the same agent.
    fn new(name: String) -> Self;

    // Agent methods — can be sync or async
    fn get_count(&self) -> u32;
    fn increment(&mut self) -> u32;
    async fn fetch_data(&self, url: String) -> String;
}

struct MyAgentImpl {
    name: String,
    count: u32,
}

#[agent_implementation]
impl MyAgent for MyAgentImpl {
    fn new(name: String) -> Self {
        Self { name, count: 0 }
    }

    fn get_count(&self) -> u32 {
        self.count
    }

    fn increment(&mut self) -> u32 {
        self.count += 1;
        self.count
    }

    async fn fetch_data(&self, url: String) -> String {
        // Use wstd::http for HTTP requests
        todo!()
    }
}

Custom Types

All parameter and return types must implement the Schema trait. For custom types, derive it along with IntoValue and FromValueAndType:

use golem_rust::Schema;
use serde::{Serialize, Deserialize};

#[derive(Clone, Schema, Serialize, Deserialize)]
pub struct MyData {
    pub field1: String,
    pub field2: u32,
}

Returning Failures

Agent methods should distinguish between domain errors (expected failure outcomes) and uncaught errors:

  • Uncaught errors (panics, unwrapped Err, etc.) are not returned to the caller as a failed invocation. Golem treats them as crashes: the invocation is retried according to the agent's retry policy, and if the retries are exhausted the agent itself becomes failed.
  • Domain errors that the caller should observe as a normal failure result must be expressed in the method's return type using Result<T, E>. The error type E must derive Schema like any other custom type.
use golem_rust::{agent_definition, agent_implementation, Schema};
use serde::{Serialize, Deserialize};

#[derive(Clone, Debug, Schema, Serialize, Deserialize)]
pub enum WithdrawError {
    InsufficientFunds { available: u64 },
    AccountClosed,
}

#[agent_definition]
pub trait Wallet {
    fn new(owner: String) -> Self;

    fn withdraw(&mut self, amount: u64) -> Result<u64, WithdrawError>;
}

struct WalletImpl {
    owner: String,
    balance: u64,
    closed: bool,
}

#[agent_implementation]
impl Wallet for WalletImpl {
    fn new(owner: String) -> Self {
        Self { owner, balance: 0, closed: false }
    }

    fn withdraw(&mut self, amount: u64) -> Result<u64, WithdrawError> {
        if self.closed {
            return Err(WithdrawError::AccountClosed);
        }
        if amount > self.balance {
            return Err(WithdrawError::InsufficientFunds { available: self.balance });
        }
        self.balance -= amount;
        Ok(self.balance)
    }
}

Returning Err(WithdrawError::...) completes the invocation successfully — the caller receives the error as a value. Panicking with unwrap(), expect(), panic!(), or returning from ? on an unrelated error type will instead trigger a retry and eventually fail the whole agent.

Key Constraints

  • All agent method parameters are passed by value (no references)
  • All custom types need Schema derive (plus IntoValue and FromValueAndType, which Schema implies)
  • Constructor parameters form the agent identity — two agents with the same parameters are the same agent
  • Agents are created implicitly on first invocation — no separate creation step
  • Invocations are processed sequentially in a single thread — no concurrency within a single agent
  • Never use block_on — all agent methods run in an async context. Use async methods and .await instead of blocking on futures

Signals

GitHub stars
2k
Forks
212
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
golem-add-agent-rust
Source
github.com/golemcloud/golem