Documentation

A sprout is sandboxed, event-driven trading logic. You write it in Rust, it compiles to WebAssembly, and the engine runs it on your behalf — with no keys, network, or ambient access of its own. Go from zero to a deployed automation in four commands.

Getting started

1

Install the CLI

The sprouts CLI is a Rust crate. You'll need a Rust toolchain and the wasm32-wasip1 target (rustup target add wasm32-wasip1).

2

Sign in

Authenticate in the browser and save a session to ~/.sprouts/config.json.

3

Scaffold a sprout

Generate a standalone crate with a handler, a sprout.toml manifest, and the cotyledon dependency.

4

Deploy it

Build to WebAssembly, upload, and register triggers. Every deploy is a new immutable version you can roll back to.

Anatomy of a sprout

Each pub async fn(ctx: Ctx) -> Result<()> inside a #[sprout::program]module is a handler. An optional second argument is the trigger's deserialized JSON payload.

use cotyledon::prelude::*;
use serde::Deserialize;

#[derive(Deserialize)]
pub struct GreetRequest {
    name: String,
}

#[sprout::program]
pub mod hello_world {
    use super::*;

    // Bound to the `greet` trigger in sprout.toml.
    pub async fn greet(ctx: Ctx, req: GreetRequest) -> Result<()> {
        // Durable, per-sprout state — empty on the first call.
        let mut names: Vec<String> =
            ctx.state().get("names").await?.unwrap_or_default();
        names.push(req.name.clone());
        ctx.state().set("names", &names).await?;

        ctx.log().info(&format!("Hello, {}!", req.name));
        Ok(())
    }
}

The manifest — sprout.toml

Declares the sprout's name, whether it gets a wallet, and its triggers. The engine reads it at deploy to register everything.

name = "hello-world"
wallet = false

# POST { "name": "Ada" } to this trigger's URL to run `greet`.
[triggers.greet]
on      = "webhook"
handler = "greet"

# A scheduled trigger runs a handler on a cron cadence.
[triggers.daily]
on      = "schedule"
cron    = "0 13 * * *"   # daily at 13:00 UTC
handler = "rebalance"

Triggers

Webhook

Each webhook trigger gets a unique, unguessable URL. POST a JSON body to it to invoke the handler with that payload.

Schedule

Run a handler on a cron cadence. cron = "0 13 * * *" fires every day at 13:00 UTC.

Manual

Invoke any handler on demand from the CLI with sprouts run --handler <name>, with an optional input payload.

What a handler can do

Market data

ctx.price("SOL") and other quotes, brokered by the engine.

Wallet & signing

Read balances, sign and submit transactions. The engine holds the keys and enforces the sprout's guardrails — the sandbox never sees them.

Durable state

ctx.state().get / set — a key/value store scoped to the sprout that persists across runs.

Logs & metrics

ctx.log() and ctx.metric() capture per-execution output you can read back with sprouts logs.

CLI reference

sprouts login / logout / whoamiManage your saved session.
sprouts init <name>Scaffold a new sprout in the current directory.
sprouts deployBuild to wasm, upload, and register triggers.
sprouts run --handler <h>Manually run a handler, with an optional payload.
sprouts logs [--exec <id>]List executions, or show one run's captured output.
sprouts rollbackRoll a sprout back to a previous version.

Resources

SDK API reference

The cotyledon crate — Ctx, types, and macros.

CLI on crates.io

cargo install sprouts

Build with AI

Give this URL to an AI assistant (Claude, ChatGPT, Cursor…) so it can write and deploy sprouts for you.