# #\[tool]

An attribute macro that turns an async Rust function into a tool with a typed input and output schema.

`#[nanocode::tool]` replaces the function with a unit struct of the same name that implements `Tool`. The function arguments become the fields of the input schema, and the `Ok` type of the result becomes the output schema. Register the struct with [`Tools`](/docs/api/rust/Tools).

```rust
use nanocode::Tools;

// 1. Declare the tool. The arguments a and b become its JSON input.
#[nanocode::tool(
    description = "Add two signed integers, reporting overflow"
)]
async fn checked_sum(a: i64, b: i64) -> std::io::Result<i64> {
    a.checked_add(b).ok_or_else(|| {
        std::io::Error::other("integer addition overflow")
    })
}

// 2. Register the generated struct
let tools = Tools::builder()
    .without_defaults()
    .tool(checked_sum)
    .build()?;
```

## Signature

```rust
// description is required, and name and parallel are optional
#[nanocode::tool(description = "...", name = "...", parallel = true)]
async fn name(argument: Type, ...) -> Result<Output, Error>
```

## Parameters

### description

* **Type:** string literal

The description that the model reads. The macro fails to compile without it.

```rust
// Describes what the tool does and when it fails
#[nanocode::tool(
    description = "Divide signed integers, reporting zero divisors"
)]
async fn quotient(a: i64, b: i64) -> std::io::Result<i64> {
    a.checked_div(b)
        .ok_or_else(|| std::io::Error::other("division by zero"))
}
```

### name

* **Type:** string literal
* **Default:** the function name

The tool name that the model calls. The Rust struct keeps the function name.

```rust
// The model calls this tool as add_numbers
#[nanocode::tool(
    description = "Add two integers",
    name = "add_numbers"
)]
async fn add(a: i64, b: i64) -> std::io::Result<i64> {
    Ok(a + b)
}
```

### parallel

* **Type:** boolean literal
* **Default:** `false`

Whether the model can call this tool in parallel with other calls.

```rust
// Allows parallel calls for a read-only lookup
#[nanocode::tool(
    description = "Look up the price of a SKU",
    parallel = true
)]
async fn price(sku: String) -> std::io::Result<u64> {
    Ok(if sku == "A-7" { 1200 } else { 0 })
}
```

## Function Shape

The macro accepts a function with these properties. It reports a compile error for any other shape.

* **Async:** The function must be `async fn`.
* **Not generic:** The function cannot have type or lifetime parameters.
* **Plain arguments:** Each argument is a simple identifier with a type, and `self` receivers are not allowed. Each type must implement `serde::Deserialize` and `schemars::JsonSchema`.
* **Result return:** The return type must be a path ending in `Result<T, E>`, such as `std::io::Result<T>` or `anyhow::Result<T>`. `T` must implement `serde::Serialize` and `schemars::JsonSchema`, and `E` must implement `Display`.

```rust
use serde::{Deserialize, Serialize};

// A struct argument and a struct output, both with schemas
#[derive(Deserialize, schemars::JsonSchema)]
struct Range { start: u32, end: u32 }

#[derive(Serialize, schemars::JsonSchema)]
struct Sum { total: u64 }

#[nanocode::tool(description = "Sum the integers in a range")]
async fn sum_range(range: Range) -> std::io::Result<Sum> {
    Ok(Sum { total: (range.start..range.end).map(u64::from).sum() })
}
```

## Behavior

The input decoder rejects fields that the function does not declare. An `Err` value becomes a tool error with the text of `E`, and the model reads that text. Attributes and doc comments on the function stay on the generated struct.

```rust
// The model reads "integer addition overflow" when this call fails
let tools = Tools::builder().tool(checked_sum).build()?;
```
