Docs

A complete service

The three files of a working CrabTalk service, a Rust library crate with echo and durable state, and the commands that test, build, deploy and call it.

crab new hello writes these three files. Each compiles and runs as shown; change them from here.

The files

# Cargo.toml
[package]
name = "hello"
version = "0.1.0"
edition = "2024"

# The cdylib is the image `crab build` finishes; the rlib is what `cargo nextest run` links.
[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
berm-lang = { git = "https://github.com/crabtalk/crab", tag = "v0.1.3" }
# crab.toml

[tools.echo]
access = "public"

[tools.remember]
access = "public"
catalog = "memory.put"

[tools.recall]
access = "public"
catalog = "memory.get"

[database]
size = "64MiB"
// src/lib.rs
#![cfg_attr(target_arch = "wasm32", no_std)]

extern crate alloc;

use alloc::string::String;
use berm_lang::{Result, Schema, tool};

/// Answers its argument back.
#[tool]
pub fn echo(
    /// The text to echo back.
    query: String,
) -> Result<Echo> {
    Ok(Echo { query })
}

/// What `echo` answers.
#[derive(Schema)]
pub struct Echo {
    pub query: String,
}

const MESSAGE: &str = "message";

/// Store a message that survives calls and restarts, shared by all callers.
#[tool]
pub fn remember(message: String) -> Result<()> {
    berm_lang::set_json(MESSAGE, &message)?;
    Ok(())
}

/// Read the message saved by remember, or null if none has been saved.
#[tool(query)]
pub fn recall() -> Result<Option<String>> {
    Ok(berm_lang::get_json(MESSAGE)?)
}
  • Cargo.toml says what the package is. The crate is a library with no bin target and no fn main, and berm-lang is its only dependency, pinned to the tag of the crab that wrote it.
  • crab.toml says how it runs: the name it deploys as and who may call each tool. Every key: crab.toml.
  • src/lib.rs is no_std on WebAssembly and an ordinary library off it. Each #[tool] function is a tool; what the macros accept and generate: Macros.

Running it

crab build installs missing Rust tools through the official rustup installer and adds the wasm32-unknown-unknown target before building. It uses the minimal Rust profile, respects CARGO_HOME and RUSTUP_HOME, and makes installed tools available immediately without changing your shell's PATH. An existing rust-toolchain.toml selects the project's toolchain.

$ crab build
$ crab dev -d
$ crab --context default deploy
$ crab --context default call hello echo '{"query":"hi"}'
{"query":"hi"}
$ crab --context default call hello remember '{"message":"kept between calls"}'
$ crab --context default call hello recall '{}'
"kept between calls"
  • crab dev -d starts the local host at 127.0.0.1:7777 in the background. crab --context default deploy builds the crate in its directory and deploys it there; run it again after a change.
  • crab build prints the image's path: berm/hello.wasm under cargo's target directory. A bare cargo build writes an image without the crab.toml declarations, which a host refuses.
  • crab deploy uses the selected context. Run crab login to select your Cloud account, then crab deploy to deploy as {owner}/hello. See Deploying.

remember writes JSON to the service's keyspace; recall reads it in a later call, including after a host restart. The stored message is shared by all callers. Use caller-scoped keys for private per-user data; see Data.

Adding tests

The scaffold does not generate a tool-specific test. Add tests for the tools you keep, updating their export names and arguments when the tools change. For example, create tests/tools.rs for echo:

// tests/tools.rs
use berm_lang::test;

#[test]
fn echo_answers_its_argument() {
    let out = test::call(hello::berm_tool_echo, br#"{"query":"hi"}"#).unwrap();
    assert_eq!(out, br#"{"query":"hi"}"#);
}

For native tests, put $CARGO_HOME/bin (~/.cargo/bin by default) on your PATH and install nextest with cargo install cargo-nextest.

Run cargo nextest run after adding the test. Native tests do not provide storage syscalls; test remember and recall with the real host as described in Testing.

Next

To Read
Write tools, arguments, errors and events Macros
Find a function and its signature API
Keep data, fetch over HTTP, call another service, run on a schedule, take settings The pages under Capabilities