subako-function-sdk 0.2.3

Write Subako function packages in Rust: typed functions become tools, and the program prints its own manifest.
Documentation
# subako-function-sdk

Write [Subako](https://subako.ai) function packages in Rust. Each `#[function]` becomes a tool an agent can call:

- the function's name is the tool's name;
- its doc comment is the description the model reads;
- its input and output types, which derive `JsonSchema`, become the tool's schemas.

```rust
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use subako_function_sdk::{ToolError, function, package};

#[derive(Deserialize, JsonSchema)]
struct GreetInput {
    /// Who to greet.
    name: String,
}

#[derive(Serialize, JsonSchema)]
struct Greeting {
    message: String,
}

/// Greet someone by name.
#[function]
fn greet(input: GreetInput) -> Result<Greeting, ToolError> {
    Ok(Greeting { message: format!("Hello, {}!", input.name) })
}

package! {
    name: "hello",
    description: "Says hello.",
    functions: [greet],
}
```

<!-- CODESYNC(image-long-edge) -->

To show the model an image, return an `Answer`: the model reads its value as JSON first, then the image. The image travels as an MCP `resource_link` to `volume:///<path beneath /volume>`; Core reads the file from the session volume after the call returns, and downscales it to at most 2000 pixels on its long edge.

```rust
use subako_function_sdk::{Answer, ToolError, function};

#[derive(Serialize, JsonSchema)]
struct Plot {
    path: String,
}

/// Plot a chart and show it.
#[function]
fn plot(input: PlotInput) -> Result<Answer<Plot>, ToolError> {
    let path = "/volume/tmp/chart.png".to_string();
    // ... write the chart to `path` ...
    Ok(Answer::new(Plot { path: path.clone() }).with_image_file(path))
}
```

To call an HTTP API, use `http::request`. The worker sends the request for the function: only https, only to hosts the agent's function grant allows, and with any stored credential the grant names for that origin attached on the way out. An `HttpError` converts into a `ToolError`, so `?` hands the model the reason.

```rust
use subako_function_sdk::http::{self, Request, ResponseBody};

/// Fetch a page's text.
#[function]
fn fetch(input: FetchInput) -> Result<Page, ToolError> {
    let response = http::request(&Request::get(input.url))?;
    match response.body {
        ResponseBody::Inline { text } => Ok(Page { status: response.status, text }),
        ResponseBody::File { .. } => Err(ToolError::new("the body was saved to a file")),
    }
}
```

The body comes back inline as text, up to `http::INLINE_MAX_BYTES`. Set `output` to `ResponseOutput::File { path }` to stream a larger or binary body into the session volume instead, and send a volume file as the body with `RequestBody::File { path }`.

Build the module for `wasm32-wasip1`. The same crate built for your machine prints the package's `subako-package.json` with `cargo run -- --subako-manifest`: its ABI, name, and description. Subako learns the tools from the module itself when the package is uploaded.

## The protocol

The SDK speaks ABI 1, which any language that compiles to WASI preview 1 can speak too. A module is an MCP server over MCP's stdio transport, on the stateless revision `2026-07-28`: one JSON-RPC 2.0 message per line, every request carrying its protocol version and client capabilities in `_meta`.

- On upload, Subako sends `server/discover`, then `tools/list` until its last page. The package serves exactly the tools listed.
- On a call, Subako sends one `tools/call` and closes stdin once it is answered. The module exits 0 when stdin ends.
- A failure the model should read is a result with `isError`. A JSON-RPC error, a request from the module, a result that is not `complete`, or a stdout line that is not a message crashes the call.
- Notifications are ignored, and a block Subako does not show is replaced by a line saying so.

To start a new package, use the template, which also packages the bundle Subako takes:

```sh
cargo generate subako-ai/subako-function-template-rust
```

## License

Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.