daytona-client

Crates.iodaytona-client
lib.rsdaytona-client
version0.5.0
created_at2025-08-23 16:07:45.401851+00
updated_at2025-09-19 09:40:05.250266+00
descriptionRust client for Daytona — secure sandboxes for AI code execution
homepagehttps://github.com/krzysztofwos/daytona-client
repositoryhttps://github.com/krzysztofwos/daytona-client
max_upload_size
id1807645
size368,601
Krzysztof Woś (krzysztofwos)

documentation

https://docs.rs/daytona-client

README

Daytona Client for Rust

Crates.io Documentation License: MIT/Apache-2.0 Build Status

A Rust client library for the Daytona API, providing secure sandbox environments for code execution and development.

Status

Version 0.5.0 — Complete volume and snapshot management with organization support.

Current Features

  • Sandboxes: Create, list, get, delete, start, stop, archive operations
  • Workspaces: Full workspace lifecycle management
  • Volume Management: Create, attach, detach, delete with async state handling
  • Snapshot Management: Create, list, activate, deactivate, remove snapshots
  • Organization Management: Manage organizations, members, invitations, API keys
  • Process Execution: Execute commands with sessions and timeout support
  • Session Management: Create and manage persistent command sessions
  • File Operations: Upload, download, list, move, copy, delete files and directories
  • Git Operations: Clone, commit, push, pull, branch management, status, history
  • LSP Integration: Language Server Protocol support for code intelligence features
  • Preview URLs: Generate public preview URLs for sandbox ports
  • Type Safety: Strongly typed models with comprehensive error handling

Known API Issues

These are server-side API bugs, not client library issues:

  • ⚠️ Process Execution: cwd parameter exists but doesn't work correctly
  • ⚠️ Sandbox Creation: API incorrectly rejects resource specifications (cpu, memory, disk) claiming a snapshot is used when it isn't

All other features are fully functional and tested.

Installation

Add this to your Cargo.toml:

[dependencies]
daytona-client = "0.5"

Quick Start

use daytona_client::{DaytonaClient, CreateSandboxParams};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create client from environment variables
    let client = DaytonaClient::from_env()?;

    // Create a sandbox
    let sandbox = client.sandboxes()
        .create(CreateSandboxParams {
            class: Some("small".to_string()),
            ..Default::default()
        })
        .await?;

    // Execute a command
    let result = client.process()
        .execute_command(&sandbox.id, "echo 'Hello from Daytona!'")
        .await?;

    println!("Output: {}", result.result);

    // Clean up
    client.sandboxes().delete(&sandbox.id).await?;

    Ok(())
}

Environment Variables

The client can be configured using environment variables:

  • DAYTONA_API_KEY — Daytona API key (required)
  • DAYTONA_BASE_URL — API base URL (default: https://app.daytona.io/api)
  • DAYTONA_ORGANIZATION_ID — Organization ID for multi-org accounts (optional)

Implementation Status

API Endpoints

  • Sandbox Management: Create, list, get, delete, start, stop, archive
  • Workspace Management: Create, list, get, delete, start, stop, archive
  • Volume Management: Create, list, get, delete, attach, detach with state monitoring
  • Snapshot Management: Create, list, get, activate, deactivate, remove, build logs
  • Organization Management: Create, list, update, delete orgs; manage members and API keys
  • Process Execution: Execute commands, session management
  • File Operations: Full file and directory management via upload/download/list/move/copy/delete
  • Git Operations: Clone, commit, push, pull, branch, status, history, stage
  • LSP Integration: Code completions, hover, go-to-definition, diagnostics, formatting
  • Preview URLs: Generate public URLs for sandbox ports
  • WebSocket Connections: Not yet implemented
  • Docker Registry: Not yet implemented
  • Object Storage: Not yet implemented
  • Computer Use/UI Automation: Not yet implemented

Testing Status

70+ integration tests covering all implemented features:

  • Sandbox Integration Tests: Full lifecycle and operation testing
  • Workspace Integration Tests: Complete workspace management testing
  • Volume Integration Tests: Volume lifecycle with async state handling
  • Snapshot Integration Tests: Snapshot creation, activation, and management
  • Organization Integration Tests: Organization and member management
  • Process Integration Tests: Command execution and session management
  • File Integration Tests: Upload, download, and file management operations
  • Git Integration Tests: Repository operations and branch management
  • LSP Integration Tests: Language server operations and code intelligence
  • Preview URL Integration Tests: Public URL generation for sandbox services

Examples

Basic Sandbox Operations

use daytona_client::{DaytonaClient, CreateSandboxParams};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = DaytonaClient::from_env()?;

    // Create a sandbox
    let sandbox = client.sandboxes()
        .create(CreateSandboxParams {
            class: Some("small".to_string()),
            ..Default::default()
        })
        .await?;

    println!("Created sandbox: {}", sandbox.id);

    // Execute a command
    let result = client.process()
        .execute_command(&sandbox.id, "echo 'Hello from Daytona!'")
        .await?;

    println!("Output: {}", result.result);

    // Clean up
    client.sandboxes().delete(&sandbox.id).await?;
    Ok(())
}

File Operations

// Upload a file
client.files()
    .upload(&sandbox.id, "/app/main.py", b"print('Hello World!')")
    .await?;

// Download a file
let content = client.files()
    .download(&sandbox.id, "/app/main.py")
    .await?;

// List directory contents
let entries = client.files()
    .list(&sandbox.id, "/app")
    .await?;

Git Operations

use daytona_client::GitCloneRequest;

// Clone a repository
let clone_request = GitCloneRequest {
    url: "https://github.com/user/repo.git".to_string(),
    path: "/workspace".to_string(),
    branch: Some("main".to_string()),
    depth: Some(1),
    auth_token: None,
    ssh_key: None,
};

client.git()
    .clone(&sandbox.id, clone_request)
    .await?;

// Check status
let status = client.git()
    .status(&sandbox.id, "/workspace")
    .await?;

println!("Current branch: {}", status.current_branch);

Session Management

use daytona_client::SessionExecuteRequest;

// Create a persistent session
let session_id = "my-session";
client.process()
    .create_session(&sandbox.id, session_id)
    .await?;

// Execute commands in the session
let response = client.process()
    .execute_session_command(&sandbox.id, session_id, SessionExecuteRequest {
        command: "python -c 'x = 42; print(f\"x = {x}\")'".to_string(),
        run_async: Some(false),
    })
    .await?;

println!("Session output: {:?}", response.output);

Workspace Management

use daytona_client::{CreateWorkspaceParams, WorkspaceState};

// Create a workspace
let workspace = client.workspaces()
    .create(CreateWorkspaceParams {
        name: "my-project".to_string(),
        description: Some("Development environment".to_string()),
        class: Some("small".to_string()),
        ..Default::default()
    })
    .await?;

// Wait for it to start
let workspace = client.workspaces()
    .wait_for_state(&workspace.id, WorkspaceState::Started, 120)
    .await?;

println!("Workspace {} is ready!", workspace.id);

Language Server Protocol (LSP)

use daytona_client::{LspLanguage, SandboxLspExt};

// Initialize LSP for a sandbox
let lsp = sandbox.lsp(&client);
await lsp.start(LspLanguage::TypeScript, "/workspace/project").await?;

// Get code completions
let completions = lsp.get_completions(TextDocumentPosition {
    text_document: TextDocumentIdentifier {
        uri: "file:///workspace/project/src/main.ts".to_string(),
    },
    position: Position { line: 10, character: 15 },
}).await?;

// Get hover information
let hover = lsp.get_hover(position).await?;

// Get diagnostics
let diagnostics = lsp.get_diagnostics("file:///workspace/project/src/main.ts").await?;

Preview URLs

// Get a public preview URL for a web application running on port 3000
let preview_url = client.sandboxes()
    .get_preview_url(&sandbox.id, 3000)
    .await?;

println!("Access the application at: {}", preview_url);

Volume Management

use daytona_client::VolumeState;

// Create a volume
let volume = client.volumes()
    .create("my-data-volume".to_string())
    .await?;

// Wait for volume to be ready
let volume = client.volumes()
    .wait_for_state(&volume.id, VolumeState::Ready, 30)
    .await?;

// Attach volume to a sandbox
let sandbox = client.sandboxes()
    .create(CreateSandboxParams {
        volumes: Some(vec![volume.id]),
        ..Default::default()
    })
    .await?;

// List all volumes
let volumes = client.volumes().list(false).await?;
println!("Found {} volumes", volumes.len());

// Delete volume
client.volumes().delete(&volume.id).await?;

Snapshot Management

use daytona_client::{CreateSnapshotRequest, SnapshotState};

// Create a snapshot
let snapshot_request = CreateSnapshotRequest {
    name: "my-snapshot".to_string(),
    image_name: Some("ubuntu:22.04".to_string()),
    cpu: Some(2.0),
    memory: Some(4),
    disk: Some(20),
    entrypoint: Some(vec!["/bin/bash".to_string()]),
    ..Default::default()
};

let snapshot = client.snapshots()
    .create(snapshot_request)
    .await?;

// List snapshots with pagination
let paginated = client.snapshots()
    .list(Some(10), Some(1), None)
    .await?;
println!("Total snapshots: {}", paginated.total);

// Activate a snapshot
client.snapshots().activate(&snapshot.id).await?;

// Get build logs for a snapshot
let logs = client.snapshots()
    .get_build_logs(&snapshot.id, true)
    .await?;

// Remove snapshot
client.snapshots().remove(&snapshot.id).await?;

Organization Management

use daytona_client::{CreateOrganizationRequest, UpdateOrganizationMemberAccess};

// Create an organization
let org = client.organizations()
    .create(CreateOrganizationRequest {
        name: "my-team".to_string(),
        description: Some("My development team".to_string()),
    })
    .await?;

// Invite a member
client.organizations()
    .invite_member(&org.id, "developer@example.com", "developer")
    .await?;

// Update member role
client.organizations()
    .update_member(
        &org.id,
        &member_id,
        UpdateOrganizationMemberAccess {
            role: "admin".to_string(),
        }
    )
    .await?;

// Create API key for organization
let api_key = client.organizations()
    .create_api_key(&org.id, "ci-deployment")
    .await?;
println!("New API key: {}", api_key.key);

Error Handling

The client provides comprehensive error types:

use daytona_client::{DaytonaError, Result};

match client.sandboxes().create(params).await {
    Ok(sandbox) => println!("Created: {}", sandbox.id),
    Err(DaytonaError::QuotaExceeded(msg)) => {
        eprintln!("Quota exceeded: {}", msg);
    }
    Err(DaytonaError::AuthenticationFailed(msg)) => {
        eprintln!("Auth failed: {}", msg);
    }
    Err(e) => eprintln!("Error: {}", e),
}

Testing

Prerequisites

Set the Daytona API key:

export DAYTONA_API_KEY="api-key"

Running Tests

Tests that create sandboxes are automatically run sequentially using the serial_test crate to avoid exceeding Daytona's 30GB quota limit:

# Run all tests (resource-intensive tests run sequentially)
cargo test

# Run specific test suites
cargo test --test sandbox_integration
cargo test --test workspace_integration
cargo test --test process_integration
cargo test --test files_integration
cargo test --test git_integration

Cleanup Utilities

If tests fail or are interrupted, sandboxes may not be cleaned up. Use the provided utilities:

# Check current resource usage
cargo run --bin verify-cleanup

# Clean up test sandboxes only (safer)
cargo run --bin cleanup-test-sandboxes

# Force cleanup all resources (interactive)
cargo run --bin force-cleanup

Contributing

Contributions are welcome. Please feel free to submit a Pull Request.

License

This project is licensed under either of:

at the option of the user.

Acknowledgments

This client is not officially affiliated with Daytona. For official SDKs, visit Daytona's documentation.

Commit count: 72

cargo fmt