Skip to main content

Quickstart - Cargo (Preview)

Preview

The Cargo runtime is in preview. APIs and configuration fields may change before general availability.

Cargo deployments run as native binaries inside a Linux distro image on the processor, isolated via PRoot. Unlike the default Node.js runtime, Cargo gives you full access to the Linux environment: shell scripts, native tooling, and any language you can ship as a Linux binary.

Prerequisites

A 64-bit Android Core processor on Canary

Cargo deployments require a 64-bit (aarch64) Android device running as an Acurast Processor Core on the Canary network. The Lite processor and iOS devices are not supported.

To set one up yourself:

  1. Factory-reset a 64-bit Android phone (Android 12+).
  2. Visit Acurast Hub ↗, switch to the Canary network, and connect your wallet.
  3. Follow the Processor Core setup flow - the device will be locked down as a dedicated compute provider.

Full guide: Become a Compute Provider.

note

After onboarding, there is a warmup period of up to 3 epochs (~4.5 hours) before the device becomes eligible for public assignment matching. If you want to deploy on your freshly onboarded device before the warmup completes, it can be skipped by targeting the device directly with Instant deploy.

Acurast CLI

Install the CLI globally:

npm install -g @acurast/cli

cACU balance

Cargo deployments run on the Canary network. Claim free cACU from the faucet ↗.


Step 1 - Create a project

note

acurast new generates a Node.js project with a file structure that does not apply to Cargo and can be skipped. Create the project directory yourself and run acurast init inside it instead:

mkdir cargo-hello
cd cargo-hello
acurast init

This creates acurast.json (deployment config) and .env (secrets). See the CLI docs for all available commands and options.


Step 2 - Write your Cargo app

info

The PRoot container starts with a minimal environment. Depending on the tooling you use, you may need to set PATH, HOME, or configure DNS resolution before running it.

DNS resolution - Android has no system-level /etc/resolv.conf. Without it, DNS resolution inside the chroot fails silently: apt-get update downloads nothing, package lists stay empty, and subsequent apt-get install calls report packages as not found. Write a nameserver entry before any network calls:

echo "nameserver 8.8.8.8" > /etc/resolv.conf

See PRoot Quirks for more known environment issues, including a getifaddrs() workaround for programs that inspect network interfaces.

Create your app entrypoint file acurast.sh:

acurast.sh
#!/bin/sh

# Set up environment variables
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export HOME=/root

# Set up DNS resolver
echo "nameserver 8.8.8.8" > /etc/resolv.conf

# TODO: Run your code

The bridge socket

The processor injects a BRIDGE_SOCKET environment variable at runtime. This is an abstract Unix domain socket that exposes host services - cryptographic signing, deployment metadata, and browser control - via a JSON-RPC 2.0 API.

Full API reference: Cargo Runtime Environment.


Step 3 - Configure for the Cargo (Shell) runtime

Open acurast.json and configure your project to use the Shell runtime. The Shell runtime is the foundation of Cargo - it boots a Linux distro image on the processor and runs your entrypoint script inside it. Your app files (fileUrl) are extracted into the rootfs before the entrypoint runs. Structure them however you like - the only requirement is that the file named by entrypoint is a shell script and is placed at the root of the fileUrl directory or it's the fileUrl itself.

acurast.json
{
"projects": {
"cargo-hello": {
"projectName": "cargo-hello",
"fileUrl": "acurast.sh",
"entrypoint": "acurast.sh",
"runtime": "Shell",
"image": {
"url": "https://github.com/termux/proot-distro/releases/download/v4.30.1/ubuntu-questing-aarch64-pd-v4.30.1.tar.xz",
"sha256": "5ab35b90cd9a9f180656261ba400a135c4c01c2da4b74522118342f985c2d328"
},
"network": "canary",
...
}
}
}

Key fields for the Cargo runtime:

FieldDescription
runtimeMust be "Shell" to enable the Cargo runtime
imageLinux distro image to boot - url (HTTPS .tar.xz) + sha256 for verification. Must be an aarch64 image
entrypointScript the processor runs after extracting the image
fileUrlPath to the directory (or file) uploaded to the processor alongside the image

For all other fields, see the CLI configuration reference.

Supported distro images are listed in the Termux proot-distro releases ↗.

note

The Linux image is freshly unpacked for every execution - there is no persistent cache between runs. Any dependencies installed during one execution (e.g. via apt-get) will not be available in the next. Make sure your deployment schedule accounts for the setup time required at the start of each execution.

Instant deploy

To deploy directly to a specific device without waiting for the warmup period, use the instantMatch field inside assignmentStrategy. Each entry targets a processor by its SS58 address:

{
"projects": {
"cargo-hello": {
...
"assignmentStrategy": {
"type": "Single",
"instantMatch": [
{
"processor": "<SS58-address>",
"maxAllowedStartDelayInMs": 10000
}
]
},
"numberOfReplicas": 1,
...
}
}
}

Set numberOfReplicas to match the number of entries in instantMatch. You can find the processor address in the Acurast Hub after onboarding.


Step 4 - Deploy

acurast deploy

The CLI uploads your app/ directory to IPFS and registers the deployment on-chain. The processor downloads the distro image and your app, boots the container, and runs start.sh.

Monitor your deployment:

acurast deployments ls --network canary

Example - Hello Cargo

This example uses Python to fetch the processor's public key and POST it to a webhook. It runs four times at 3-minute intervals.

Full source: acurast-example-apps/apps/app-cargo ↗.

Project layout:

app/
start.sh
hello.py
acurast.json
.env

app/start.sh - sets up the environment, installs dependencies, and launches the Python script:

app/start.sh
#!/bin/sh

# Set up PATH, HOME, and DNS
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export HOME=/root

echo "nameserver 8.8.8.8" > /etc/resolv.conf

# Install necessary dependencies and run the main application
apt-get update
apt-get install -y python3-requests
python3 "$(dirname "$0")/hello.py"

app/hello.py - calls the bridge socket to get the signing public key, then POSTs it to a webhook:

app/hello.py
import json
import os
import socket

import requests

BRIDGE_SOCKET = os.environ["BRIDGE_SOCKET"]
WEBHOOK_URL = os.environ["WEBHOOK_URL"]


def get_public_key() -> str:
request = json.dumps({
"jsonrpc": "2.0",
"method": "signer_publicKey",
"params": [{"curve": "p256"}],
"id": "1",
}) + "\n"

with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
sock.connect("\0" + BRIDGE_SOCKET)
sock.sendall(request.encode())
response = b""
while True:
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
if b"\n" in chunk:
break

return json.loads(response)["result"]["publicKey"]


def main():
public_key = get_public_key()
url = WEBHOOK_URL.rstrip("/") + "/hello"
resp = requests.post(url, json={"publicKey": public_key})
print(resp.status_code, resp.text)


if __name__ == "__main__":
main()

Add your webhook URL to .env:

.env
ACURAST_MNEMONIC=abandon abandon about ...
WEBHOOK_URL=https://your-webhook.example.com

Next steps