Thanks to visit codestin.com
Credit goes to lib.rs

#jam #polkadot #risc-v #pvm

bin+lib cargo-polkajam

A cargo subcommand for generating JAM service projects for Polkadot

2 releases

0.1.1 Dec 29, 2025
0.1.0 Dec 29, 2025

#285 in Cargo plugins

Apache-2.0

120KB
2.5K SLoC

cargo-polkajam

CI

cargo, make me a JAM service

A Rust cargo subcommand for generating and building JAM (Join-Accumulate Machine) services for Polkadot. Follows the cargo-generate project architecture while providing JAM-specific tooling.

Demo

Installation

Install From crates.io

cargo install cargo-polkajam

Install From source

git clone https://github.com/abutlabs/cargo-polkajam
cd cargo-polkajam
cargo install --path .

To reinstall after making changes:

cargo install --path . --force

Prerequisites

Before using cargo-polkajam, you need:

  1. Rust toolchain with nightly support
  2. jam-pvm-build - PVM bytecode compiler
cargo install jam-pvm-build

Quick Start

# 1. Install the JAM toolchain (downloads polkajam binaries)
cargo polkajam setup

# 2. Create a new JAM service
cargo polkajam new my-service

# 3. Build the service
cd my-service
cargo polkajam build

# 4. Start local testnet
cargo polkajam up

# 5. Deploy to testnet (in another terminal)
cargo polkajam deploy my-service.jam

# 6. Stop testnet when done
cargo polkajam down

Commands

cargo polkajam setup

Downloads and installs the JAM/polkajam toolchain from polkajam-releases.

# Install latest nightly
cargo polkajam setup

# List available versions
cargo polkajam setup --list

# Show installed toolchain info
cargo polkajam setup --info

# Install specific version
cargo polkajam setup --version nightly-2025-12-29

# Force reinstall
cargo polkajam setup --force

# Update to latest
cargo polkajam setup --update

Installed binaries (in ~/.cargo-polkajam/toolchain/polkajam-nightly/):

  • polkajam - JAM node
  • jamt - JAM CLI tool for deployment
  • polkajam-testnet - Local testnet runner
  • polkajam-repl - Interactive REPL
  • corevm-builder - CoreVM builder
  • And more...

cargo polkajam new

Creates a new JAM service project from a template.

# Interactive mode
cargo polkajam new my-service

# Skip prompts, use defaults
cargo polkajam new my-service --defaults

# Use custom git template
cargo polkajam new my-service --git https://github.com/user/template

# Specify template values
cargo polkajam new my-service -d author="Your Name" -d license=MIT

Options:

  • -t, --template <name> - Template name (default: basic-service)
  • --git <url> - Git repository URL for custom template
  • --branch <branch> - Git branch (requires --git)
  • --path <path> - Subdirectory in git repo (requires --git)
  • -o, --output <dir> - Output directory
  • --defaults - Skip prompts, use defaults
  • -d, --define <key=value> - Set template variable
  • --no-git - Don't initialize git repository

cargo polkajam build

Builds a JAM service into a .jam blob using jam-pvm-build.

# Build in release mode (default)
cargo polkajam build

# Build specific project
cargo polkajam build --path /path/to/service

# Custom output path
cargo polkajam build --output my-service.jam

# Verbose output
cargo polkajam build --verbose

Options:

  • -p, --path <dir> - Project path (default: current directory)
  • --release - Build in release mode (default: true)
  • -o, --output <path> - Output path for .jam blob
  • -v, --verbose - Verbose output

cargo polkajam up

Starts the local JAM testnet.

# Start in background (default)
cargo polkajam up

# Start in foreground (see logs)
cargo polkajam up --foreground

# Custom RPC endpoint
cargo polkajam up --rpc ws://localhost:9944

Options:

  • --foreground - Run in foreground (see logs, Ctrl+C to stop)
  • --rpc <url> - RPC endpoint (default: ws://localhost:19800)
  • -v, --verbose - Verbose output

cargo polkajam down

Stops the local JAM testnet.

# Stop the testnet gracefully
cargo polkajam down

# Force kill
cargo polkajam down --force

Options:

  • --force - Force kill with SIGKILL instead of SIGTERM
  • -v, --verbose - Verbose output

cargo polkajam deploy

Deploys a JAM service to the network.

# Deploy a service
cargo polkajam deploy my-service.jam

# Deploy with initial balance
cargo polkajam deploy my-service.jam --amount 1000

# Deploy with memo
cargo polkajam deploy my-service.jam --memo "my memo data"

# Deploy to custom RPC endpoint
cargo polkajam deploy my-service.jam --rpc ws://localhost:9944

# Register service with a name
cargo polkajam deploy my-service.jam --register my_service

Options:

  • --amount <value> - Initial balance for the service (default: 0)
  • --memo <data> - Memo data to include
  • -G, --min-item-gas <value> - Minimum gas per work item (default: 1000000)
  • -g, --min-memo-gas <value> - Minimum gas for memo (default: 1000000)
  • -r, --register <name> - Register service with a name
  • --rpc <url> - RPC endpoint (default: ws://localhost:19800)
  • -v, --verbose - Verbose output

cargo polkajam monitor

Monitor the testnet with an interactive TUI (jamtop).

# Start the monitor
cargo polkajam monitor

# Monitor with custom RPC endpoint
cargo polkajam monitor --rpc ws://localhost:9944

Options:

  • --rpc <url> - RPC endpoint (default: ws://localhost:19800)
  • -v, --verbose - Verbose output

cargo polkajam test

Run comprehensive end-to-end tests that verify the entire workflow.

# Run full test suite
cargo polkajam test

# Run tests with verbose output
cargo polkajam test --verbose

# Keep testnet running after tests (for debugging)
cargo polkajam test --keep-running

# Skip testnet startup (use already running testnet)
cargo polkajam test --skip-testnet

# Use custom test directory
cargo polkajam test --dir /tmp/my-test

Options:

  • --keep-running - Keep testnet running after tests complete
  • --skip-testnet - Skip testnet startup (assume already running)
  • --dir <path> - Test directory (default: temp directory)
  • -v, --verbose - Verbose output with command details

Tests performed:

  1. Create new JAM service (cargo polkajam new)
  2. Build JAM service to .jam blob (cargo polkajam build)
  3. Deploy to local testnet (start → deploy → stop)

Local Development

Running from source

# Run commands directly
cargo run -- setup --info
cargo run -- new test-service --defaults
cargo run -- build

# Or build and install locally
cargo build && cargo install --path . --force

Development workflow

# Make changes, rebuild, and test
cargo build && cargo install --path . --force && cargo polkajam setup --info

Uninstall

cargo uninstall cargo-polkajam
rm -rf ~/.cargo-polkajam  # Remove toolchain and config

Testing with Local Testnet

Full end-to-end test

# Terminal 1: Start the testnet
cargo polkajam up --foreground

# Terminal 2: Create and deploy a service
cargo polkajam new test-service --defaults
cd test-service
cargo polkajam build
cargo polkajam deploy test-service.jam

# Stop the testnet when done
cargo polkajam down

Background mode workflow

# Start testnet in background
cargo polkajam up

# Create, build, and deploy
cargo polkajam new test-service --defaults
cd test-service
cargo polkajam build
cargo polkajam deploy test-service.jam

# Stop testnet
cargo polkajam down

Additional testnet tools

# Monitor with jamtop
cargo polkajam monitor

# Interactive REPL
~/.cargo-polkajam/toolchain/polkajam-nightly/polkajam-repl

Project Structure

Generated JAM service structure:

my-service/
├── Cargo.toml          # Dependencies: jam-pvm-common, polkavm-derive
├── src/
│   └── lib.rs          # Service implementation (refine, accumulate)
└── .gitignore

Service Implementation

#![no_std]
#![no_main]

extern crate alloc;

use jam_pvm_common::{declare_service, Service, accumulate::*, jam_types::*};

declare_service!(MyService);

struct MyService;

impl Service for MyService {
    fn refine(
        _core_index: CoreIndex,
        _item_index: usize,
        _service_id: ServiceId,
        payload: WorkPayload,
        _package_hash: WorkPackageHash,
    ) -> WorkOutput {
        // Stateless computation (up to 6 seconds)
        payload.take().into()
    }

    fn accumulate(
        _slot: Slot,
        _service_id: ServiceId,
        item_count: usize,
    ) -> Option<Hash> {
        // Stateful integration (~10ms)
        None
    }
}

Configuration

Configuration is stored in ~/.cargo-polkajam/:

~/.cargo-polkajam/
├── config.toml              # Toolchain configuration
└── toolchain/
    └── polkajam-nightly/    # Installed binaries

config.toml:

installed_version = "nightly-2025-12-29"
toolchain_path = "/Users/you/.cargo-polkajam/toolchain"
installed_at = "1767015039"

Running Tests

The easiest way to test the entire cargo-polkajam workflow:

# Run full end-to-end test suite
cargo polkajam test

# Run with verbose output
cargo polkajam test --verbose

This automatically tests: new → build → up → deploy → down

Unit and integration tests

# Run all Rust tests (excluding ignored tests)
cargo test

# Run with verbose output
cargo test -- --nocapture

Full integration tests (require jam-pvm-build)

# Run ignored tests that require toolchain
cargo test --test integration_tests -- --ignored

Manual testnet deployment tests

These tests require a running local testnet:

# Terminal 1: Start the testnet
cargo polkajam up --foreground

# Terminal 2: Run testnet tests
cargo test --test testnet_tests -- --ignored --nocapture

The testnet tests will:

  1. Create a new JAM service
  2. Build it to a .jam blob
  3. Deploy it to the running testnet using cargo polkajam deploy

Publishing & Releases

This repo has CI/CD that automatically publishes to crates.io when you create a version tag:

One-time setup:

  1. Get your crates.io API token from https://crates.io/settings/tokens
  2. Add it as a GitHub secret: Settings → Secrets → Actions → New secret
    • Name: CARGO_REGISTRY_TOKEN
    • Value: your token

To release a new version:

# Update version in Cargo.toml
# Commit changes
git add . && git commit -m "Release v0.1.0"

# Create and push a version tag
git tag v0.1.0
git push origin main --tags

This triggers the release workflow which:

  1. Runs all tests and lints
  2. Publishes to crates.io
  3. Builds binaries for Linux and macOS
  4. Creates a GitHub Release with downloadable binaries

Manual Publishing

# Login to crates.io
cargo login <your-token>

# Dry run to verify
cargo publish --dry-run

# Publish
cargo publish

Reference JAM Service implementations

Resources

License

MIT OR Apache-2.0

Dependencies

~31–51MB
~858K SLoC