> ## Documentation Index
> Fetch the complete documentation index at: https://docs.silvana.one/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Sample

Now, let's see how we can build an agent.

<Note>
  The same crates the CLI uses are available as Rust libraries. Import them from a path or git and build custom agents, batch tools, or test harnesses.
</Note>

# Example - Buy CC

We take a canonical example – buying CantonCoins.

The agent lives at `examples/buy_cc`.

It buys CC on `CC-USDC`.

`examples/buy_cc/Cargo.toml`:

<CodeGroup>
  ```toml toml theme={null}
  {
    "name": "buy-cc-example",
    "version": "0.1.0",
    "type": "module",
    "dependencies": {
      "cloud-agent": "file:../crates/cloud-agent",
      "agent-logic": "file:../crates/agent-logic",
      "orderbook-proto": "file:../crates/orderbook-proto",
      "dotenv": "^0.15.0",
      "commander": "^4.0.0",
      "pino": "^0.3.0"
    }
  }
  ```
</CodeGroup>

`examples/buy_cc/src/main.rs` (abridged):

<CodeGroup>
  ```ts TypeScript theme={null}
  import "dotenv/config";
  import yargs from "yargs";
  import { hideBin } from "yargs/helpers";

  import { BaseConfig } from "agent-logic/config";
  import { newConfirmLock } from "agent-logic/confirm";
  import { LiquidityManager } from "agent-logic/liquidity";
  import { MulticallSettler } from "cloud-agent/accept-settle";
  import { CloudSettlementBackend } from "cloud-agent/backend";
  import { runFillLoop, FillDirection, type FillParams } from "cloud-agent/fill-loop";
  import { populateInstruments } from "cloud-agent";

  type Args = {
    amount: number;
    maxPrice?: number;
    pollPeriod: number;
    minSettlement: number;
  };

  async function parseArgs(): Promise<Args> {
    const argv = await yargs(hideBin(process.argv))
      .option("amount", {
        type: "number",
        demandOption: true,
        describe: "Amount to buy",
      })
      .option("max_price", {
        type: "number",
        describe: "Maximum acceptable price",
      })
      .option("poll_period", {
        type: "number",
        default: 600,
        describe: "Polling period in seconds",
      })
      .option("min_settlement", {
        type: "number",
        default: 5.0,
        describe: "Minimum settlement amount",
      })
      .strict()
      .parse();

    return {
      amount: argv.amount,
      maxPrice: argv.max_price,
      pollPeriod: argv.poll_period,
      minSettlement: argv.min_settlement,
    };
  }

  async function main(): Promise<void> {
    const args = await parseArgs();

    console.info("Starting buy flow");

    // 1. Load config from .env + agent.toml
    const config = await BaseConfig.loadOrDefaults("agent.toml");

    // 2. Fetch instrument registry from orderbook-rpc
    await populateInstruments(config);

    // 3. Create backend
    const confirmLock = newConfirmLock();
    const lm = new LiquidityManager(
      config.feeReserveCc,
      config.liquidityMargin,
      config.flowEmaWindowHours,
      config.depletionMaxHours,
      config.depletionMinHours
    );

    const backend = new CloudSettlementBackend(
      structuredClone(config),
      false,
      false,
      false,
      false,
      confirmLock,
      lm
    );

    // 4. Create settler for atomic multicall settlement
    const settler = new MulticallSettler({
      config: structuredClone(config),
      amuletCache: backend.amuletCache(),
      verbose: false,
      dryRun: false,
      force: false,
      confirm: false,
      confirmLock,
    });

    // 5. Run the fill loop
    const params: FillParams = {
      direction: FillDirection.Buy,
      marketId: "CC-USDC",
      totalAmount: args.amount,
      priceLimit: args.maxPrice,
      minSettlement: args.minSettlement,
      maxSettlement: args.amount,
      intervalSecs: args.pollPeriod,
    };

    const _backendGuard = backend;

    await runFillLoop(config, settler, params, null, null);
  }

  main().catch((error) => {
    console.error("Fatal error:", error);
    process.exit(1);
  })
  ```

  ```rust Rust theme={null}
  use std::sync::Arc;
  use anyhow::{Context, Result};
  use clap::Parser;

  use agent_logic::config::BaseConfig;
  use agent_logic::confirm::new_confirm_lock;
  use agent_logic::liquidity::LiquidityManager;
  use cloud_agent::accept_settle::MulticallSettler;
  use cloud_agent::backend::CloudSettlementBackend;
  use cloud_agent::fill_loop::{self, FillDirection, FillParams};
  use cloud_agent::populate_instruments;

  #[derive(Parser)]
  struct Args {
      #[arg(long)] amount: f64,
      #[arg(long)] max_price: Option<f64>,
      #[arg(long, default_value = "600")] poll_period: u64,
      #[arg(long, default_value = "5.0")] min_settlement: f64,
  }

  #[tokio::main]
  async fn main() -> Result<()> {
      let _ = dotenvy::dotenv();
      let args = Args::parse();
      tracing_subscriber::fmt().with_env_filter("info").init();

      // 1. Load config from .env + agent.toml
      let mut config = BaseConfig::load_or_defaults("agent.toml")?;

      // 2. Fetch instrument registry (CC/USDC/…) from orderbook-rpc
      populate_instruments(&mut config).await?;

      // 3. Create backend (spawns ACS worker to keep amulet cache fresh)
      let confirm_lock = new_confirm_lock();
      let lm = LiquidityManager::new(
          config.fee_reserve_cc, config.liquidity_margin,
          config.flow_ema_window_hours,
          config.depletion_max_hours, config.depletion_min_hours,
      );
      let backend = CloudSettlementBackend::new(
          config.clone(), false, false, false, false, confirm_lock.clone(), lm,
      );

      // 4. Create settler for atomic multicall settlement
      let settler = Arc::new(MulticallSettler {
          config: config.clone(),
          amulet_cache: backend.amulet_cache().clone(),
          verbose: false, dry_run: false, force: false, confirm: false,
          confirm_lock,
      });

      // 5. Run the fill loop
      let params = FillParams {
          direction: FillDirection::Buy,
          market_id: "CC-USDC".to_string(),
          total_amount: args.amount,
          price_limit: args.max_price,
          min_settlement: args.min_settlement,
          max_settlement: args.amount,
          interval_secs: args.poll_period,
      };
      let _backend_guard = backend;
      fill_loop::run_fill_loop(config, settler, params, None, None).await
  }
  ```
</CodeGroup>

To launch the agent, run this command:

```text theme={null}
cargo run -p buy-cc-example -- --amount 10.0 --max-price 0.16 --poll-period 600
```

<Check>
  CC Buying agent is launched! Great job!
</Check>
