# Golem Add Agent Rust

> 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.

- Skill: `golemcloud/golem-add-agent-rust` (Agent Skill)
- Install (CLI): `npx skillmds@latest add golemcloud/golem-add-agent-rust`
- Raw SKILL.md: https://api.skillmd.com/api/skills/golemcloud/golem-add-agent-rust/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: golemcloud (https://skillmd.com/u/golemcloud)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/golemcloud/golem-add-agent-rust

---


# Adding a New Agent to a Rust Golem Component

## 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

```rust
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`:

```rust
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.

```rust
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

