akash-deploy-rs
Standalone deployment workflow engine for Akash Network.
Build, authenticate, and deploy applications to Akash using a trait-based state machine. No storage, signing, or transport coupling — bring your own infrastructure.
Features
- SDL → Manifest — Parse SDL YAML to provider-ready JSON with correct serialization
- Canonical JSON — Deterministic hashing that matches Go provider validation
- JWT Authentication — ES256K self-attested tokens for provider communication
- Certificate Generation — TLS certs with encrypted private key storage
- Workflow Engine — State machine for full deployment lifecycle
- Backend Agnostic — Single
AkashBackendtrait, you implement persistence/transport - SDL Templates — Variable substitution for reusable deployment configs (default)
- Default Client — Integrated layer-climb client with file-backed storage (opt-in)
Quick Start
use ;
// 1. Parse SDL to manifest
let manifest_builder = new;
let manifest_groups = manifest_builder.build_from_sdl
// 2. Serialize to canonical JSON (for hash matching)
let canonical_json = to_canonical_json?;
// 3. Compute hash (matches provider validation)
use ;
let hash = digest;
Full Workflow Example
use ;
// Implement the backend trait with your infrastructure
// Run deployment workflow
let backend = new;
let signer = new;
let workflow = new;
let mut state = new
.with_sdl
.with_label;
match workflow.run_to_completion.await?
Architecture
flowchart TB
SDL[SDL YAML] --> MB[ManifestBuilder]
MB --> MG[ManifestGroup]
MG --> CJ[to_canonical_json]
CJ --> Hash[SHA256 Hash]
subgraph akash-deploy-rs
MB
CJ
JB[JwtBuilder]
CG[Certificate Generator]
WF[DeploymentWorkflow]
end
subgraph Consumer Implementation
Backend[AkashBackend Trait]
Storage[(Storage)]
HTTP[HTTP Client]
Signer[Key Signer]
end
WF --> Backend
Backend --> Storage
Backend --> HTTP
WF --> Signer
JB --> Signer
Components
| Component | Purpose | Dependencies |
|---|---|---|
| ManifestBuilder | SDL parsing → JSON manifest | None |
| to_canonical_json | Deterministic JSON serialization | None |
| JwtBuilder | ES256K JWT construction | Consumer provides signing |
| CertificateGenerator | TLS cert generation | None |
| DeploymentWorkflow | State machine orchestration | AkashBackend trait |
Deployment Workflow
sequenceDiagram
participant App as Your App
participant WF as DeploymentWorkflow
participant Backend as AkashBackend
participant Chain as Akash Chain
participant Provider as Akash Provider
App->>WF: run_to_completion(state)
WF->>Backend: query_balance(owner)
Backend->>Chain: Query account
Chain-->>Backend: Balance
Backend-->>WF: Balance OK
WF->>WF: generate_certificate()
WF->>Backend: broadcast_create_deployment(msg)
Backend->>Chain: Broadcast tx
Chain-->>Backend: Tx hash
Backend-->>WF: Deployment created (dseq)
WF->>Backend: query_bids(lease_id)
Backend->>Chain: Query market
Chain-->>Backend: Bid list
Backend-->>WF: Bids available
Note over WF,App: User selects bid
WF->>Backend: broadcast_create_lease(bid)
Backend->>Chain: Broadcast tx
Chain-->>Backend: Tx hash
Backend-->>WF: Lease created
WF->>WF: build_manifest(SDL)
WF->>WF: generate_jwt(owner, keypair)
WF->>Backend: send_manifest(provider, manifest, cert, key)
Backend->>Provider: PUT /deployment/{dseq}/manifest
Provider-->>Backend: 200 OK
Backend-->>WF: Manifest accepted
WF->>Backend: query_provider_status(lease_id)
Backend->>Provider: GET /lease/{...}/status
Provider-->>Backend: Service endpoints
Backend-->>WF: Endpoints available
WF-->>App: Complete (endpoints)
Critical Serialization Details
Provider JSON API has strict requirements. ManifestBuilder handles these correctly:
| Requirement | Implementation |
|---|---|
| CPU units | STRING millicores: "1000" not 1.0 |
| Memory/storage | STRING bytes: "536870912" not int |
| Empty arrays | null not [] for command/args/env |
| Field names | camelCase: externalPort not external_port |
| GPU attributes | Composite keys: vendor/nvidia/model/h100/ram/80Gi |
| Storage attributes | Sorted by key |
| Services | Sorted by name |
Canonical JSON is required — Go's encoding/json sorts keys, we must match for hash validation.
Design Principles
- Single Trait —
AkashBackendis the only interface - Bring Your Own Infrastructure — No storage, HTTP, or signing coupling
- State Machine Focused — Workflow orchestrates, you implement primitives
- Explicit Errors —
DeployErrorcovers all failure modes - Type Safety — Correct manifest serialization enforced at compile time
SDL Templates
SDL templates are enabled by default. To opt out, disable default features:
[]
= { = "0.0.1", = false }
SDL templates allow you to create reusable deployment configurations with variable placeholders using ${VAR} syntax:
version: "2.0"
services:
web:
image: ${IMAGE}:${VERSION}
expose:
- port: ${PORT}
as: ${PORT}
to:
- global: true
profiles:
compute:
web:
resources:
cpu:
units: ${CPU_UNITS}
memory:
size: ${MEMORY_SIZE}
storage:
size: ${STORAGE_SIZE}
placement:
dcloud:
pricing:
web:
denom: uakt
amount: ${PRICE}
deployment:
web:
dcloud:
profile: web
count: ${COUNT}
Usage
use ;
use HashMap;
// Define defaults
let mut defaults = new;
defaults.insert;
defaults.insert;
defaults.insert;
defaults.insert;
defaults.insert;
defaults.insert;
defaults.insert;
defaults.insert;
// User overrides (optional)
let mut variables = new;
variables.insert;
variables.insert;
// Create deployment with template
let state = new
.with_sdl
.with_template
.with_variables;
// Workflow processes template automatically at SendManifest step
workflow.run_to_completion.await?;
Template Features
- Variable Syntax:
${VARIABLE_NAME}— alphanumeric characters and underscores only - Strict Validation: All variables must have defaults (enforced at processing time)
- Priority: User variables override defaults
- YAML-Aware: Preserves document structure during substitution
- Error Handling: Clear error messages for missing defaults, unclosed placeholders, invalid variable names
Direct Template Processing
You can also process templates directly without the workflow:
use ;
let template = new?;
// Validate all variables have defaults
template.validate?;
// Process with overrides
let processed_sdl = template.process?;
// Build manifest from processed SDL
let builder = new;
let manifest = builder.build_from_sdl?;
Default Client & Storage
The library includes a complete, integrated client implementation (NOT enabled by default):
[]
version = "0.0.4", features = ["default-client"]}# Includes default-client feature
Quick Start with Default Client
use ;
# async
Storage System
The default client uses a memory + file persistence strategy:
Storage Layout:
~/.akash-deploy/
sessions/
my-app.json # Deployment state
production.json
certs/
akash1xxx.key # Encrypted private keys
providers.json # Provider cache
certificates.json # Certificate cache
Key Features:
- In-Memory Cache: Fast access to active sessions
- File Persistence: Durable storage survives restarts
- Export/Import: Backup and restore sessions
- Generic Design: Swap storage backends via traits
Session Management
// List all sessions
let sessions = client.storage.list_sessions.await?;
// Load a previous session
let state = client.storage.load_session.await?;
// Export sessions for backup
export_sessions.await?;
// Import sessions from backup
import_sessions.await?;
Custom Storage Implementation
Implement the SessionStorage trait for custom backends:
use SessionStorage;
use async_trait;
// Use custom storage
let client = with_storage;
Opt Out of Default Client
To use only the core workflow engine without the integrated client:
[]
= { = "0.0.3" }
Then implement AkashBackend yourself as shown in the architecture section.
Testing
Unit tests for manifest building and JWT generation:
Integration tests against real Go provider validation:
E2E Testing
The tests/ directory contains a complete integration test suite that validates manifest generation against the actual Akash provider validation code:
provider-validate— Go binary using exact provider logic (ES256K JWT + manifest validation)fixtures/— Known-good JWT/manifest/hash test casestestdata/— SDL YAML files for testingexamples/rust-jwt-gen/— Rust example that generates JWTs usingakash-deploytest.sh— End-to-end test: Rust generates → Go validates
This ensures byte-for-byte compatibility with Akash provider expectations.
Development with Claude Code
This repository includes a specialized Claude skill that provides deep expertise in Akash manifest serialization and provider validation.
Installing the Skill
The akash-manifest-spec skill contains:
- 7 critical serialization rules for manifest generation
- Provider validation procedures using actual Go code
- Debugging decision trees for hash mismatches
- Task-specific implementation checklists
To install:
# Clone the skill to your Claude skills directory
# Or copy it directly
When to use:
The skill activates automatically when you mention:
- "manifest serialization"
- "provider validation"
- "hash mismatch"
- "canonical JSON"
- Akash deployment debugging
It provides structured guidance for:
- Implementing new manifest features while maintaining provider compatibility
- Debugging manifest hash mismatches with actual provider validation code
- Understanding the 7 critical rules (camelCase, null arrays, string numbers, sorting)
- Verifying Rust output matches Go provider expectations byte-for-byte
Manifest Validation Testing
The skill references the integration test suite in tests/:
This validates that your Rust code produces identical output to Go providers, ensuring deployments will succeed.
TODO
- Add more SDL parsing examples
- Implement Storage Write And Load To File For Deployment Instances
- Document AkashBackend trait methods in detail