# Daytona Documentation v0.0.0-dev # Generated on: 2026-03-19 Daytona API keys authenticate requests to the [Daytona API](https://www.daytona.io/docs/en/tools/api.md). They are used by the Daytona [SDKs](https://www.daytona.io/docs/en/getting-started.md#sdks) and [CLI](https://www.daytona.io/docs/en/getting-started.md#cli) to access and manage resources in your organization. ## Create an API key Daytona provides options to create API keys in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/keys) or programmatically using the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys). 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard/keys) 2. Click the **Create Key** button 3. Enter the name of the API key, set the expiration date, and [select permissions](#permissions--scopes) 4. Click **Create** to create the API key 5. Copy the API key to your clipboard To use the API key in your application, set the `DAYTONA_API_KEY` environment variable. Daytona supports multiple options to configure your environment: [in code](https://www.daytona.io/docs/en/configuration.md#configuration-in-code), [environment variables](https://www.daytona.io/docs/en/configuration.md#environment-variables), [.env file](https://www.daytona.io/docs/en/configuration.md#env-file), and [default values](https://www.daytona.io/docs/en/configuration.md#default-values). API keys support optional expiration and can be revoked at any time. After creation, you can only retrieve a masked key value when listing keys. ```bash curl 'https://app.daytona.io/api/api-keys' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data '{ "name": "My API Key", "permissions": ["write:sandboxes", "delete:sandboxes"], "expiresAt": "2030-01-01T00:00:00.000Z" }' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys) reference: > [**Create API key (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/POST/api-keys) ## Permissions & Scopes | **Resource** | **Scope** | **Description** | | ------------ | ----------------------- | ------------------------ | | Sandboxes | **`write:sandboxes`** | Create/modify sandboxes | | | **`delete:sandboxes`** | Delete sandboxes | | Snapshots | **`write:snapshots`** | Create/modify snapshots | | | **`delete:snapshots`** | Delete snapshots | | Registries | **`write:registries`** | Create/modify registries | | | **`delete:registries`** | Delete registries | | Volumes | **`read:volumes`** | View volumes | | | **`write:volumes`** | Create/modify volumes | | | **`delete:volumes`** | Delete volumes | | Audit | **`read:audit_logs`** | View audit logs | | Regions | **`write:regions`** | Create/modify regions | | | **`delete:regions`** | Delete regions | | Runners | **`read:runners`** | View runners | | | **`write:runners`** | Create/modify runners | | | **`delete:runners`** | Delete runners | ## List API keys Daytona provides methods to list all API keys for the current user or organization. ```bash curl 'https://app.daytona.io/api/api-keys' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys) reference: > [**list (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/GET/api-keys) ## Get current API key Daytona provides methods to get details of the API key used to authenticate the current request. ```bash curl 'https://app.daytona.io/api/api-keys/current' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys) reference: > [**get current (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/GET/api-keys/current) ## Get API key Daytona provides methods to get a single API key by name. ```bash curl 'https://app.daytona.io/api/api-keys/my-api-key' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys) reference: > [**get (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/GET/api-keys/{name}) ## Delete API key Daytona provides options to delete an API key in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/keys) or programmatically using the API. The key is revoked immediately and cannot be recovered. 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard/keys) 2. Click **Revoke** next to the API key you want to delete 3. Confirm the revocation ```bash curl 'https://app.daytona.io/api/api-keys/my-api-key' \ --request DELETE \ --header 'Authorization: Bearer YOUR_API_KEY' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys) reference: > [**delete (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/DELETE/api-keys/{name}) ## Delete API key for user Daytona provides options for organization admins to delete an API key for a specific user. ```bash curl 'https://app.daytona.io/api/api-keys/{userId}/my-api-key' \ --request DELETE \ --header 'Authorization: Bearer YOUR_API_KEY' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys) reference: > [**delete for user (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/DELETE/api-keys/{userId}/{name}) Daytona provides **full composable computers** — [sandboxes](https://www.daytona.io/docs/en/sandboxes.md) — for AI agents. Daytona platform is organized into multiple plane components, each serving a specific purpose: - [Interface plane](#interface-plane) provides client interfaces for interacting with Daytona - [Control plane](#control-plane) orchestrates all sandbox operations - [Compute plane](#compute-plane) runs and manages sandbox instances ### Interface plane The interface plane provides client interfaces for users and agents to interact with Daytona. The following components are part of the interface plane and available to all users and agents: - **SDK**: [Python](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go](https://www.daytona.io/docs/en/go-sdk.md) for programmatic sandbox management - [CLI](https://www.daytona.io/docs/en/tools/cli.md): command-line interface for direct sandbox operations - [Dashboard](https://app.daytona.io/dashboard/): web interface for visual sandbox management and monitoring - [MCP](https://www.daytona.io/docs/en/mcp.md): Model Context Protocol server for AI tool integration - [SSH](https://www.daytona.io/docs/en/ssh-access.md): secure shell access to running sandboxes ### Control plane The control plane is the central coordination layer of the Daytona platform. It receives all client requests, manages the full sandbox lifecycle, schedules sandboxes onto runners, and continuously reconciles states across the infrastructure. The control plane includes the following components: - [API](#api) handles authentication, sandbox lifecycle management, and resource allocation - [Proxy](#proxy) routes external traffic to sandboxes, enabling direct access to services - [Snapshot builder](#snapshot-builder) builds and manages sandbox [snapshots](https://www.daytona.io/docs/en/snapshots.md) - [Sandbox manager](#sandbox-manager) handles sandbox lifecycle management and state reconciliation #### API The API is a NestJS-based RESTful service that serves as the primary entry point for all platform operations, managing authentication, sandbox lifecycle, snapshots, volumes, and resource allocation. The [snapshot builder](#snapshot-builder) and [sandbox manager](#sandbox-manager) run as internal processes within the API. The API integrates the following internal services and components: - **Redis** provides caching, session management, and distributed locking - **PostgreSQL** serves as the primary persistent store for metadata and configuration - **Auth0/OIDC provider** authenticates users and services via OpenID Connect. The API enforces organization-level multi-tenancy, where each sandbox, snapshot, and volume belongs to an organization, and access control is applied at the organization boundary - **SMTP server** handles email delivery for organization invitations, account notifications, and alert messages - [Sandbox manager](#sandbox-manager) schedules sandboxes onto runners, reconciles states, and enforces sandbox lifecycle management policies - **PostHog** collects platform analytics and usage metrics for monitoring and improvement To interact with sandboxes from the API, see the [API](https://www.daytona.io/docs/en/tools/api.md) and [Toolbox API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references. #### Proxy The proxy is a dedicated HTTP proxy that routes external traffic to the correct sandbox using host-based routing. Each sandbox is reachable at `{port}-{sandboxId}.{proxy-domain}`, where the port maps to a service running inside the sandbox. The proxy resolves the target runner for a given sandbox, injects authentication headers, and forwards the request. It supports both HTTP and WebSocket protocols. #### Snapshot builder The snapshot builder is part of the API process and orchestrates the creation of sandbox [snapshots](https://www.daytona.io/docs/en/snapshots.md) from a Dockerfile or a pre-built image from a [container registry](#container-registry). It coordinates with runners to build or pull images, which are then pushed to an internal snapshot registry that implements the OCI distribution specification. #### Sandbox manager The sandbox manager is part of the API process and schedules sandboxes onto runners, reconciles states, and enforces [sandbox lifecycle management](https://www.daytona.io/docs/en/sandboxes.md#sandbox-lifecycle) policies. ### Compute plane The compute plane is the infrastructure layer where sandboxes run. Sandboxes run on [runners](#sandbox-runners), compute nodes that host multiple sandboxes with dedicated resources and scale horizontally across shared or dedicated [regions](https://www.daytona.io/docs/en/regions.md). The compute plane consists of the following components: - [Sandbox runners](#sandbox-runners) host sandboxes with dedicated resources - [Sandbox daemon](#sandbox-daemon) provides code execution and environment access inside each sandbox - [Snapshot store](#snapshot-store) stores sandbox snapshot images - [Volumes](#volumes) provides persistent storage shared across sandboxes #### Sandbox runners Runners are compute nodes that power Daytona's compute plane, providing the underlying infrastructure for running sandbox workloads. Each runner polls the control plane API for jobs and executes sandbox operations: creating, starting, stopping, destroying, resizing, and backing up sandboxes. Runners interact with S3-compatible object storage for snapshot and volume data, and with the internal snapshot registry. Each sandbox runs as an isolated instance with its own Linux namespaces for processes, network, filesystem mounts, and inter-process communication. Each runner allocates dedicated vCPU, RAM, and disk resources per sandbox. #### Sandbox daemon The sandbox daemon is a code execution agent that runs inside each sandbox. It exposes the [Toolbox API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox), providing direct access to the sandbox environment: file system and Git operations, process and code execution, computer use, log streaming, and terminal sessions. #### Snapshot store The snapshot store is an internal OCI-compliant registry that stores sandbox snapshot images using the OCI distribution specification. Runners pull snapshot images from this store when creating new sandboxes. The store uses S3-compatible object storage as its backend. #### Volumes [Volumes](https://www.daytona.io/docs/en/volumes.md) provide persistent storage that can be shared across sandboxes. Each volume is backed by S3-compatible object storage and mounted into sandboxes as a read-write directory. Multiple sandboxes can mount the same volume simultaneously, allowing data to be shared across sandboxes and persist independently of the sandbox lifecycle. ### Container registry Container registries serve as the source for sandbox base images. When creating a [snapshot](https://www.daytona.io/docs/en/snapshots.md), the snapshot builder pulls the specified image from an external registry, and pushes it to the internal snapshot registry for use by runners. For Dockerfile-based snapshots, parent images referenced in `FROM` directives are also pulled from the configured source registries during the build. Daytona supports any OCI-compatible registry: - [Docker Hub](https://www.daytona.io/docs/en/snapshots.md#docker-hub) - [Google Artifact Registry](https://www.daytona.io/docs/en/snapshots.md#google-artifact-registry) - [GitHub Container Registry (GHCR)](https://www.daytona.io/docs/en/snapshots.md#github-container-registry-ghcr) - [Private registries](https://www.daytona.io/docs/en/snapshots.md#using-images-from-private-registries): any registry that implements the OCI distribution specification Daytona audit logs provide a detailed record of user and system activity across your organization. Use this feature to track sandbox lifecycle events, user access, system changes, and more. - **Security audits**: monitor for unauthorized access or sandbox misuse - **Debugging**: understand sandbox lifecycle issues (e.g. failed starts) - **Compliance Export**: export logs for internal or external audits (coming soon) Audit logs are available to [admins](https://www.daytona.io/docs/en/organizations.md#organization-roles) with full access and [members](https://www.daytona.io/docs/en/organizations.md#organization-roles) with audit log permissions. Contact your organization administrator if you cannot access audit logs. ## Access from Dashboard Access the audit logs page directly from [Daytona Dashboard ↗](https://app.daytona.io/dashboard/audit-logs). The audit logs page displays a list of all audit logs for your organization, including the following columns: - **Time**: the timestamp of the action - **User**: the user who performed the action - [Actions](#actions): the action performed - [Targets](#targets): the resource affected by the action - [Outcomes](#outcomes): the result of the action To filter audit logs by time, use the date range picker in the top-left corner of the page. ## Real-time updates Daytona provides real-time updates of audit logs. Enable the **Auto Refresh** toggle in the top-right corner of the [Daytona Audit Logs ↗](https://app.daytona.io/dashboard/audit-logs) page to automatically refresh logs as new events occur. ## Programmatic management Daytona provides API endpoints for programmatic access to audit logs. ### Get all audit logs To get all audit logs, use the following API endpoint: ```bash curl https://app.daytona.io/api/audit \ --header 'Authorization: Bearer YOUR_API_KEY' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/audit) reference: > [**Get all audit logs (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/audit/GET/audit-logs) ### Get audit logs for organization To get audit logs for a specific organization, use the following API endpoint: ```bash curl https://app.daytona.io/api/audit/organizations/{organizationId} \ --header 'Authorization: Bearer YOUR_API_KEY' ``` For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/audit) reference: > [**Get audit logs for organization (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/audit/GET/audit/organizations/{organizationId}) ## Log Structure Each audit log entry contains the following fields: | Field | Type | Description | | -------------------- | ------ | ---------------------------------------------------- | | **`id`** | string | Unique log entry identifier | | **`actorId`** | string | ID of the user who performed the action | | **`actorEmail`** | string | Email of the user who performed the action | | **`organizationId`** | string | Organization ID | | **`action`** | string | Operation executed (e.g., `create`, `start`, `stop`) | | **`targetType`** | string | Resource type affected (e.g., `sandbox`, `snapshot`) | | **`targetId`** | string | ID of the affected resource | | **`statusCode`** | number | HTTP status code of the result | | **`errorMessage`** | string | Error message if the action failed | | **`ipAddress`** | string | IP address of the request origin | | **`userAgent`** | string | User agent of the request origin | | **`source`** | string | Source of the action | | **`metadata`** | object | Additional context about the action | | **`createdAt`** | string | ISO 8601 timestamp of when the action occurred | ## Actions Below is the complete list of actions logged by Daytona: ```text create, read, update, delete, login, set_default, update_access, update_quota, update_region_quota, suspend, unsuspend, accept, decline, link_account, unlink_account, leave_organization, regenerate_key_pair, update_scheduling, start, stop, replace_labels, create_backup, update_public_status, set_auto_stop_interval, set_auto_archive_interval, set_auto_delete_interval, archive, get_port_preview_url, set_general_status, activate, deactivate, update_network_settings, send_webhook_message, initialize_webhooks, update_sandbox_default_limited_network_egress, create_ssh_access, revoke_ssh_access, regenerate_proxy_api_key,regenerate_ssh_gateway_api_key,regenerate_snapshot_manager_credentials, toolbox_delete_file, toolbox_download_file, toolbox_create_folder, toolbox_move_file, toolbox_set_file_permissions, toolbox_replace_in_files, toolbox_upload_file, toolbox_bulk_upload_files, toolbox_git_add_files, toolbox_git_create_branch, toolbox_git_delete_branch, toolbox_git_clone_repository, toolbox_git_commit_changes, toolbox_git_pull_changes, toolbox_git_push_changes, toolbox_git_checkout_branch, toolbox_execute_command, toolbox_create_session, toolbox_session_execute_command, toolbox_delete_session, toolbox_computer_use_start, toolbox_computer_use_stop, toolbox_computer_use_restart_process ``` ## Targets Each action targets a specific resource type. Possible targets include: ```text api_key, organization, organization_invitation, organization_role, organization_user, docker_registry, runner, sandbox, snapshot, user, volume ``` ## Outcomes The outcome field indicates the result of the action. Statuses follow standard HTTP semantics: | **Outcome** | **Description** | | ----------- | ----------------------------- | | Info | Informational (1xx codes) | | Success | Action succeeded (2xx codes) | | Redirect | Redirects (3xx codes) | | Error | Client/server error (4xx/5xx) | [Daytona Billing ↗](https://app.daytona.io/dashboard/billing/spending) provides an overview of your organization's billing, wallet, and usage details. Daytona displays a cost breakdown chart that shows a breakdown of costs per resource. You can choose between area and bar charts and filter by RAM, CPU, and storage. You can also filter by date range (last 12, 6, or 3 months). ## Wallet [Daytona Wallet ↗](https://app.daytona.io/dashboard/billing/wallet) shows the current balance of the organization's wallet and the amount of credits spent this month. ### Add payment method Daytona provides a payment method to add to your wallet. You can connect your credit card to your wallet to top up your balance. 1. Navigate to [Daytona Wallet ↗](https://app.daytona.io/dashboard/billing/wallet) 2. Click the **Connect** button next to the **Payment method** section 3. Follow the prompts to connect your credit card to your wallet. Organizations can set automatic top-up rules for their wallets. - **Threshold** — When the wallet balance drops to this amount, a top-up is triggered. - **Target** — The wallet balance is topped up to this amount. Set both **Threshold** and **Target** to `0` to disable automatic top-up. ### Redeem coupon Daytona provides coupon codes to redeem credits on your wallet. 1. Navigate to [Daytona Wallet ↗](https://app.daytona.io/dashboard/billing/wallet) 2. Enter the coupon code in the **Redeem coupon** input field 3. Click the **Redeem** button to redeem the coupon code. ### Billing emails Daytona provides billing emails to receive important billing notifications such as invoices and credit depletion notices. 1. Navigate to [Daytona Wallet ↗](https://app.daytona.io/dashboard/billing/wallet) 2. Click the **Add Email** button to add a new email address. 3. Enter the email address and click the **Add Email** button. A verification email will be sent to the email address to verify it. Once verified, the email address will be added to the list of billing emails. Computer Use enables programmatic control of desktop environments within sandboxes. It provides mouse, keyboard, screenshot, screen recording, and display operations for automating GUI interactions and testing desktop applications. Computer Use and [VNC](https://www.daytona.io/docs/en/vnc-access.md) work together to enable both manual and automated desktop interactions. VNC provides the visual interface for users to manually interact with the desktop, while Computer Use provides the programmatic API for AI agents to automate operations. Computer Use is available for **Linux**. **Windows** and **macOS** support is currently in private alpha. :::caution[Private Alpha] Computer Use for macOS and Windows is currently in private alpha and requires access. To request access, fill out the [Windows](https://docs.google.com/forms/d/e/1FAIpQLSfoK-77-VpfsMubw8F4f1opCxIL1AyJUgnM0ONYup5hZ0RTvQ/viewform?usp=dialog) or [macOS](https://docs.google.com/forms/d/e/1FAIpQLSc9xlGZ49OjWNkyzDPC9Ip3InMRR0ZXY3tcoD-PFQj3ck6gzQ/viewform?usp=sharing&ouid=103304973264148733944) access request form. Our team will review your request and reach out with setup instructions. ::: - **GUI application testing**: automate interactions with native applications, click buttons, fill forms, and validate UI behavior - **Visual testing & screenshots**: capture screenshots of applications, compare UI states, and perform visual regression testing - **Desktop automation**: automate repetitive desktop tasks, file management through GUI, and complex workflows ## Start Computer Use Start all computer use processes (Xvfb, xfce4, x11vnc, novnc) in the Sandbox. ```python result = sandbox.computer_use.start() print("Computer use processes started:", result.message) ``` ```typescript const result = await sandbox.computerUse.start(); console.log('Computer use processes started:', result.message); ``` ```ruby result = sandbox.computer_use.start puts "Computer use processes started: #{result.message}" ``` ```go err := sandbox.ComputerUse.Start(ctx) if err != nil { log.Fatal(err) } defer sandbox.ComputerUse.Stop(ctx) fmt.Println("Computer use processes started") ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/start' \ --request POST ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**start (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computerusestart) > > [**start (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#start) > > [**start (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#start) > > [**Start Computer Use Processes (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/start) ## Stop Computer Use Stop all computer use processes in the Sandbox. ```python result = sandbox.computer_use.stop() print("Computer use processes stopped:", result.message) ``` ```typescript const result = await sandbox.computerUse.stop(); console.log('Computer use processes stopped:', result.message); ``` ```ruby result = sandbox.computer_use.stop puts "Computer use processes stopped: #{result.message}" ``` ```go err := sandbox.ComputerUse.Stop(ctx) if err != nil { log.Fatal(err) } fmt.Println("Computer use processes stopped") ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/stop' \ --request POST ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**stop (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computerusestop) > > [**stop (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#stop) > > [**stop (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#stop) > > [**Stop Computer Use Processes (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/stop) ## Get status Get the status of all computer use processes. ```python response = sandbox.computer_use.get_status() print("Computer use status:", response.status) ``` ```typescript const status = await sandbox.computerUse.getStatus(); console.log('Computer use status:', status.status); ``` ```ruby response = sandbox.computer_use.status puts "Computer use status: #{response.status}" ``` ```go status, err := sandbox.ComputerUse.GetStatus(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Computer use status: %v\n", status["status"]) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/status' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get_status (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computeruseget_status) > > [**getStatus (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getstatus) > > [**status (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#status) > > [**Get Computer Use status (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/status) ## Get process status Get the status of a specific VNC process. ```python xvfb_status = sandbox.computer_use.get_process_status("xvfb") novnc_status = sandbox.computer_use.get_process_status("novnc") ``` ```typescript const xvfbStatus = await sandbox.computerUse.getProcessStatus('xvfb'); const noVncStatus = await sandbox.computerUse.getProcessStatus('novnc'); ``` ```ruby xvfb_status = sandbox.computer_use.get_process_status("xvfb") no_vnc_status = sandbox.computer_use.get_process_status("novnc") ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/status' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get_process_status (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computeruseget_process_status) > > [**getProcessStatus (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getprocessstatus) > > [**get_process_status (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#get_process_status) > > [**Get Process Status (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/process/{processName}/status) ## Restart process Restart a specific VNC process. ```python result = sandbox.computer_use.restart_process("xfce4") print("XFCE4 process restarted:", result.message) ``` ```typescript const result = await sandbox.computerUse.restartProcess('xfce4'); console.log('XFCE4 process restarted:', result.message); ``` ```ruby result = sandbox.computer_use.restart_process("xfce4") puts "XFCE4 process restarted: #{result.message}" ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/restart' \ --request POST ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**restart_process (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computeruserestart_process) > > [**restartProcess (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#restartprocess) > > [**restart_process (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#restart_process) > > [**Restart process (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/process/{processName}/restart) ## Get process logs Get logs for a specific VNC process. ```python logs = sandbox.computer_use.get_process_logs("novnc") print("NoVNC logs:", logs) ``` ```typescript const logsResp = await sandbox.computerUse.getProcessLogs('novnc'); console.log('NoVNC logs:', logsResp.logs); ``` ```ruby logs = sandbox.computer_use.get_process_logs("novnc") puts "NoVNC logs: #{logs}" ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/logs' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get_process_logs (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computeruseget_process_logs) > > [**getProcessLogs (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getprocesslogs) > > [**get_process_logs (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#get_process_logs) > > [**Get process logs (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/process/{processName}/logs) ## Get process errors Get error logs for a specific VNC process. ```python errors = sandbox.computer_use.get_process_errors("x11vnc") print("X11VNC errors:", errors) ``` ```typescript const errorsResp = await sandbox.computerUse.getProcessErrors('x11vnc'); console.log('X11VNC errors:', errorsResp.errors); ``` ```ruby errors = sandbox.computer_use.get_process_errors("x11vnc") puts "X11VNC errors: #{errors}" ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/errors' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get_process_errors (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computeruseget_process_errors) > > [**getProcessErrors (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getprocesserrors) > > [**get_process_errors (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#get_process_errors) > > [**Get process errors (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/process/{processName}/errors) ## Mouse operations ### Click Click the mouse at the specified coordinates. ```python # Single left click result = sandbox.computer_use.mouse.click(100, 200) # Double click double_click = sandbox.computer_use.mouse.click(100, 200, "left", True) # Right click right_click = sandbox.computer_use.mouse.click(100, 200, "right") ``` ```typescript // Single left click const result = await sandbox.computerUse.mouse.click(100, 200); // Double click const doubleClick = await sandbox.computerUse.mouse.click(100, 200, 'left', true); // Right click const rightClick = await sandbox.computerUse.mouse.click(100, 200, 'right'); ``` ```ruby # Single left click result = sandbox.computer_use.mouse.click(x: 100, y: 200) # Double click double_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'left', double: true) # Right click right_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'right') ``` ```go // Single left click result, err := sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, nil, nil) if err != nil { log.Fatal(err) } // Double click doubleClick := true result, err = sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, nil, &doubleClick) // Right click rightButton := "right" result, err = sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, &rightButton, nil) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/click' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "button": "", "double": true, "x": 1, "y": 1 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**click (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#mouseclick) > > [**click (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#click) > > [**Click (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#MouseService.Click) > > [**Mouse click (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/mouse/click) ### Move Move the mouse cursor to the specified coordinates. ```python result = sandbox.computer_use.mouse.move(100, 200) print(f"Mouse moved to: {result.x}, {result.y}") ``` ```typescript const result = await sandbox.computerUse.mouse.move(100, 200); console.log(`Mouse moved to: ${result.x}, ${result.y}`); ``` ```ruby result = sandbox.computer_use.mouse.move(x: 100, y: 200) puts "Mouse moved to: #{result.x}, #{result.y}" ``` ```go result, err := sandbox.ComputerUse.Mouse().Move(ctx, 100, 200) if err != nil { log.Fatal(err) } fmt.Printf("Mouse moved to: %v, %v\n", result["x"], result["y"]) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/move' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "x": 1, "y": 1 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**move (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#mousemove) > > [**move (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#move) > > [**Move (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#MouseService.Move) > > [**Mouse move (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/mouse/move) ### Drag Drag the mouse from start coordinates to end coordinates. ```python result = sandbox.computer_use.mouse.drag(50, 50, 150, 150) print(f"Dragged from {result.from_x},{result.from_y} to {result.to_x},{result.to_y}") ``` ```typescript const result = await sandbox.computerUse.mouse.drag(50, 50, 150, 150); console.log(`Dragged from ${result.from.x},${result.from.y} to ${result.to.x},${result.to.y}`); ``` ```ruby result = sandbox.computer_use.mouse.drag(start_x: 50, start_y: 50, end_x: 150, end_y: 150) puts "Dragged from #{result.from_x},#{result.from_y} to #{result.to_x},#{result.to_y}" ``` ```go result, err := sandbox.ComputerUse.Mouse().Drag(ctx, 50, 50, 150, 150, nil) if err != nil { log.Fatal(err) } fmt.Printf("Dragged to %v, %v\n", result["x"], result["y"]) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/drag' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "button": "", "endX": 1, "endY": 1, "startX": 1, "startY": 1 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**drag (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#mousedrag) > > [**drag (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#drag) > > [**Drag (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#MouseService.Drag) > > [**Mouse drag (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/mouse/drag) ### Scroll Scroll the mouse wheel at the specified coordinates. ```python # Scroll up scroll_up = sandbox.computer_use.mouse.scroll(100, 200, "up", 3) # Scroll down scroll_down = sandbox.computer_use.mouse.scroll(100, 200, "down", 5) ``` ```typescript // Scroll up const scrollUp = await sandbox.computerUse.mouse.scroll(100, 200, 'up', 3); // Scroll down const scrollDown = await sandbox.computerUse.mouse.scroll(100, 200, 'down', 5); ``` ```ruby # Scroll up scroll_up = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'up', amount: 3) # Scroll down scroll_down = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'down', amount: 5) ``` ```go // Scroll up amount := 3 success, err := sandbox.ComputerUse.Mouse().Scroll(ctx, 100, 200, "up", &amount) if err != nil { log.Fatal(err) } // Scroll down amount = 5 success, err = sandbox.ComputerUse.Mouse().Scroll(ctx, 100, 200, "down", &amount) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/scroll' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "amount": 1, "direction": "", "x": 1, "y": 1 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**scroll (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#mousescroll) > > [**scroll (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#scroll) > > [**Scroll (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#MouseService.Scroll) > > [**Mouse scroll (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/mouse/scroll) ### Get position Get the current mouse cursor position. ```python position = sandbox.computer_use.mouse.get_position() print(f"Mouse is at: {position.x}, {position.y}") ``` ```typescript const position = await sandbox.computerUse.mouse.getPosition(); console.log(`Mouse is at: ${position.x}, ${position.y}`); ``` ```ruby position = sandbox.computer_use.mouse.position puts "Mouse is at: #{position.x}, #{position.y}" ``` ```go position, err := sandbox.ComputerUse.Mouse().GetPosition(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Mouse is at: %v, %v\n", position["x"], position["y"]) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/position' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get_position (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#mouseget_position) > > [**getPosition (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getposition) > > [**GetPosition (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#MouseService.GetPosition) > > [**Get mouse position (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/mouse/position) ## Keyboard operations ### Type Type the specified text. ```python sandbox.computer_use.keyboard.type("Hello, World!") # With delay between characters sandbox.computer_use.keyboard.type("Slow typing", 100) ``` ```typescript await sandbox.computerUse.keyboard.type('Hello, World!'); // With delay between characters await sandbox.computerUse.keyboard.type('Slow typing', 100); ``` ```ruby sandbox.computer_use.keyboard.type(text: "Hello, World!") # With delay between characters sandbox.computer_use.keyboard.type(text: "Slow typing", delay: 100) ``` ```go err := sandbox.ComputerUse.Keyboard().Type(ctx, "Hello, World!", nil) if err != nil { log.Fatal(err) } // With delay between characters delay := 100 err = sandbox.ComputerUse.Keyboard().Type(ctx, "Slow typing", &delay) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/type' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "delay": 1, "text": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**type (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#keyboardtype) > > [**type (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#type) > > [**Type (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#KeyboardService.Type) > > [**Keyboard type (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/keyboard/type) ### Press Press a key with optional modifiers. ```python # Press Enter sandbox.computer_use.keyboard.press("Return") # Press Ctrl+C sandbox.computer_use.keyboard.press("c", ["ctrl"]) # Press Ctrl+Shift+T sandbox.computer_use.keyboard.press("t", ["ctrl", "shift"]) ``` ```typescript // Press Enter await sandbox.computerUse.keyboard.press('Return'); // Press Ctrl+C await sandbox.computerUse.keyboard.press('c', ['ctrl']); // Press Ctrl+Shift+T await sandbox.computerUse.keyboard.press('t', ['ctrl', 'shift']); ``` ```ruby # Press Enter sandbox.computer_use.keyboard.press(key: "Return") # Press Ctrl+C sandbox.computer_use.keyboard.press(key: "c", modifiers: ["ctrl"]) # Press Ctrl+Shift+T sandbox.computer_use.keyboard.press(key: "t", modifiers: ["ctrl", "shift"]) ``` ```go // Press Enter err := sandbox.ComputerUse.Keyboard().Press(ctx, "Return", nil) if err != nil { log.Fatal(err) } // Press Ctrl+C err = sandbox.ComputerUse.Keyboard().Press(ctx, "c", []string{"ctrl"}) // Press Ctrl+Shift+T err = sandbox.ComputerUse.Keyboard().Press(ctx, "t", []string{"ctrl", "shift"}) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/key' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "key": "", "modifiers": [ "" ] }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**press (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#keyboardpress) > > [**press (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#press) > > [**Press (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#KeyboardService.Press) > > [**Keyboard press (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/keyboard/press) ### Hotkey Press a hotkey combination. ```python # Copy sandbox.computer_use.keyboard.hotkey("ctrl+c") # Paste sandbox.computer_use.keyboard.hotkey("ctrl+v") # Alt+Tab sandbox.computer_use.keyboard.hotkey("alt+tab") ``` ```typescript // Copy await sandbox.computerUse.keyboard.hotkey('ctrl+c'); // Paste await sandbox.computerUse.keyboard.hotkey('ctrl+v'); // Alt+Tab await sandbox.computerUse.keyboard.hotkey('alt+tab'); ``` ```ruby # Copy sandbox.computer_use.keyboard.hotkey(keys: "ctrl+c") # Paste sandbox.computer_use.keyboard.hotkey(keys: "ctrl+v") # Alt+Tab sandbox.computer_use.keyboard.hotkey(keys: "alt+tab") ``` ```go // Copy err := sandbox.ComputerUse.Keyboard().Hotkey(ctx, "ctrl+c") if err != nil { log.Fatal(err) } // Paste err = sandbox.ComputerUse.Keyboard().Hotkey(ctx, "ctrl+v") // Alt+Tab err = sandbox.ComputerUse.Keyboard().Hotkey(ctx, "alt+tab") ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/hotkey' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "keys": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**hotkey (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#keyboardhotkey) > > [**hotkey (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#hotkey) > > [**Hotkey (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#KeyboardService.Hotkey) > > [**Keyboard hotkey (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/keyboard/hotkey) ## Screenshot operations ### Take full screen Take a screenshot of the entire screen. ```python screenshot = sandbox.computer_use.screenshot.take_full_screen() print(f"Screenshot size: {screenshot.width}x{screenshot.height}") # With cursor visible with_cursor = sandbox.computer_use.screenshot.take_full_screen(True) ``` ```typescript const screenshot = await sandbox.computerUse.screenshot.takeFullScreen(); console.log(`Screenshot size: ${screenshot.width}x${screenshot.height}`); // With cursor visible const withCursor = await sandbox.computerUse.screenshot.takeFullScreen(true); ``` ```ruby screenshot = sandbox.computer_use.screenshot.take_full_screen puts "Screenshot size: #{screenshot.width}x#{screenshot.height}" # With cursor visible with_cursor = sandbox.computer_use.screenshot.take_full_screen(show_cursor: true) ``` ```go screenshot, err := sandbox.ComputerUse.Screenshot().TakeFullScreen(ctx, nil) if err != nil { log.Fatal(err) } fmt.Printf("Screenshot captured, size: %d bytes\n", *screenshot.SizeBytes) // With cursor visible showCursor := true withCursor, err := sandbox.ComputerUse.Screenshot().TakeFullScreen(ctx, &showCursor) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**take_full_screen (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#screenshottake_full_screen) > > [**takeFullScreen (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#takefullscreen) > > [**TakeFullScreen (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ScreenshotService.TakeFullScreen) > > [**Take screenshot (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/screenshot) ### Take region Take a screenshot of a specific region. ```python from daytona import ScreenshotRegion region = ScreenshotRegion(x=100, y=100, width=300, height=200) screenshot = sandbox.computer_use.screenshot.take_region(region) print(f"Captured region: {screenshot.region.width}x{screenshot.region.height}") ``` ```typescript const region = { x: 100, y: 100, width: 300, height: 200 }; const screenshot = await sandbox.computerUse.screenshot.takeRegion(region); console.log(`Captured region: ${screenshot.region.width}x${screenshot.region.height}`); ``` ```ruby region = Daytona::ComputerUse::ScreenshotRegion.new(x: 100, y: 100, width: 300, height: 200) screenshot = sandbox.computer_use.screenshot.take_region(region: region) puts "Captured region: #{screenshot.region.width}x#{screenshot.region.height}" ``` ```go region := types.ScreenshotRegion{X: 100, Y: 100, Width: 300, Height: 200} screenshot, err := sandbox.ComputerUse.Screenshot().TakeRegion(ctx, region, nil) if err != nil { log.Fatal(err) } fmt.Printf("Captured region: %dx%d\n", screenshot.Width, screenshot.Height) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region?x=1&y=1&width=1&height=1' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**take_region (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#screenshottake_region) > > [**takeRegion (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#takeregion) > > [**TakeRegion (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ScreenshotService.TakeRegion) > > [**Take Screenshot Region (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/screenshot/region) ### Take compressed Take a compressed screenshot of the entire screen. ```python from daytona import ScreenshotOptions # Default compression screenshot = sandbox.computer_use.screenshot.take_compressed() # High quality JPEG jpeg = sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="jpeg", quality=95, show_cursor=True) ) # Scaled down PNG scaled = sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="png", scale=0.5) ) ``` ```typescript // Default compression const screenshot = await sandbox.computerUse.screenshot.takeCompressed(); // High quality JPEG const jpeg = await sandbox.computerUse.screenshot.takeCompressed({ format: 'jpeg', quality: 95, showCursor: true }); // Scaled down PNG const scaled = await sandbox.computerUse.screenshot.takeCompressed({ format: 'png', scale: 0.5 }); ``` ```ruby # Default compression screenshot = sandbox.computer_use.screenshot.take_compressed # High quality JPEG jpeg = sandbox.computer_use.screenshot.take_compressed( options: Daytona::ComputerUse::ScreenshotOptions.new(format: "jpeg", quality: 95, show_cursor: true) ) # Scaled down PNG scaled = sandbox.computer_use.screenshot.take_compressed( options: Daytona::ComputerUse::ScreenshotOptions.new(format: "png", scale: 0.5) ) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/compressed' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**take_compressed (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#screenshottake_compressed) > > [**takeCompressed (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#takecompressed) > > [**Take compressed screenshot (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/screenshot/compressed) ### Take compressed region Take a compressed screenshot of a specific region. ```python from daytona import ScreenshotRegion, ScreenshotOptions region = ScreenshotRegion(x=0, y=0, width=800, height=600) screenshot = sandbox.computer_use.screenshot.take_compressed_region( region, ScreenshotOptions(format="webp", quality=80, show_cursor=True) ) print(f"Compressed size: {screenshot.size_bytes} bytes") ``` ```typescript const region = { x: 0, y: 0, width: 800, height: 600 }; const screenshot = await sandbox.computerUse.screenshot.takeCompressedRegion(region, { format: 'webp', quality: 80, showCursor: true }); console.log(`Compressed size: ${screenshot.size_bytes} bytes`); ``` ```ruby region = Daytona::ComputerUse::ScreenshotRegion.new(x: 0, y: 0, width: 800, height: 600) screenshot = sandbox.computer_use.screenshot.take_compressed_region( region: region, options: Daytona::ComputerUse::ScreenshotOptions.new(format: "webp", quality: 80, show_cursor: true) ) puts "Compressed size: #{screenshot.size_bytes} bytes" ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region/compressed?x=1&y=1&width=1&height=1' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**take_compressed_region (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#screenshottake_compressed_region) > > [**takeCompressedRegion (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#takecompressedregion) > > [**Take compressed screenshot region (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/screenshot/region/compressed) ## Screen Recording Computer Use supports screen recording capabilities, allowing you to capture desktop sessions for debugging, documentation, or automation workflows. ### Configure Recording Directory By default, recordings are saved to `~/.daytona/recordings`. You can specify a custom directory by passing the `DAYTONA_RECORDINGS_DIR` environment variable when creating a sandbox: ```python from daytona import Daytona, CreateSandboxFromSnapshotParams daytona = Daytona() sandbox = daytona.create( CreateSandboxFromSnapshotParams( snapshot="daytonaio/sandbox:0.6.0", name="my-sandbox", env_vars={"DAYTONA_RECORDINGS_DIR": "/home/daytona/my-recordings"} ) ) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create({ snapshot: 'daytonaio/sandbox:0.6.0', name: 'my-sandbox', envVars: { DAYTONA_RECORDINGS_DIR: '/home/daytona/my-recordings' } }); ``` ```ruby require 'daytona' daytona = Daytona::Client.new sandbox = daytona.create( snapshot: 'daytonaio/sandbox:0.6.0', name: 'my-sandbox', env_vars: { DAYTONA_RECORDINGS_DIR: '/home/daytona/my-recordings' } ) ``` ```go import ( "github.com/daytonaio/daytona/pkg/client" "github.com/daytonaio/daytona/pkg/types" ) daytona := client.New() envVars := map[string]string{ "DAYTONA_RECORDINGS_DIR": "/home/daytona/my-recordings", } sandbox, err := daytona.Create(ctx, &types.CreateSandboxParams{ Snapshot: "daytonaio/sandbox:0.6.0", Name: "my-sandbox", EnvVars: envVars, }) if err != nil { log.Fatal(err) } ``` ### Start Recording Start a new screen recording session with an optional name identifier: ```python # Start recording with a custom name recording = sandbox.computer_use.recording.start("test-1") print(f"Recording started: {recording.id}") print(f"File path: {recording.file_path}") ``` ```typescript // Start recording with a custom name const recording = await sandbox.computerUse.recording.start('test-1'); console.log(`Recording started: ${recording.id}`); console.log(`File path: ${recording.file_path}`); ``` ```ruby # Start recording with a custom label recording = sandbox.computer_use.recording.start(label: 'test-1') puts "Recording started: #{recording.id}" puts "File path: #{recording.file_path}" ``` ```go // Start recording with a custom name name := "test-1" recording, err := sandbox.ComputerUse.Recording().Start(ctx, &name) if err != nil { log.Fatal(err) } fmt.Printf("Recording started: %s\n", *recording.Id) fmt.Printf("File path: %s\n", *recording.FilePath) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/start' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "name": "test-1" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**start (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#recordingstart) > > [**start (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#start-1) > > [**start (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md) > > [**Start (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#RecordingService.Start) > > [**Start Recording (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/recordings/start) ### Stop Recording Stop an active recording session by providing the recording ID: ```python # Stop the recording stopped_recording = sandbox.computer_use.recording.stop(recording.id) print(f"Recording stopped: {stopped_recording.duration_seconds} seconds") print(f"Saved to: {stopped_recording.file_path}") ``` ```typescript // Stop the recording const stoppedRecording = await sandbox.computerUse.recording.stop(recording.id); console.log(`Recording stopped: ${stoppedRecording.duration_seconds} seconds`); console.log(`Saved to: ${stoppedRecording.file_path}`); ``` ```ruby # Stop the recording stopped_recording = sandbox.computer_use.recording.stop(id: recording.id) puts "Recording stopped: #{stopped_recording.duration_seconds} seconds" puts "Saved to: #{stopped_recording.file_path}" ``` ```go // Stop the recording stoppedRecording, err := sandbox.ComputerUse.Recording().Stop(ctx, *recording.Id) if err != nil { log.Fatal(err) } fmt.Printf("Recording stopped: %f seconds\n", *stoppedRecording.DurationSeconds) fmt.Printf("Saved to: %s\n", *stoppedRecording.FilePath) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/stop' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "id": "recording-id" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**stop (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#recordingstop) > > [**stop (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#stop-1) > > [**stop (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md) > > [**Stop (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#RecordingService.Stop) > > [**Stop Recording (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/recordings/stop) ### List Recordings Get a list of all recordings in the sandbox: ```python recordings_list = sandbox.computer_use.recording.list() print(f"Total recordings: {len(recordings_list.recordings)}") for rec in recordings_list.recordings: print(f"- {rec.name}: {rec.duration_seconds}s ({rec.file_size_bytes} bytes)") ``` ```typescript const recordingsList = await sandbox.computerUse.recording.list(); console.log(`Total recordings: ${recordingsList.recordings.length}`); recordingsList.recordings.forEach(rec => { console.log(`- ${rec.name}: ${rec.duration_seconds}s (${rec.file_size_bytes} bytes)`); }); ``` ```ruby recordings_list = sandbox.computer_use.recording.list puts "Total recordings: #{recordings_list.recordings.length}" recordings_list.recordings.each do |rec| puts "- #{rec.name}: #{rec.duration_seconds}s (#{rec.file_size_bytes} bytes)" end ``` ```go recordingsList, err := sandbox.ComputerUse.Recording().List(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Total recordings: %d\n", len(recordingsList.Recordings)) for _, rec := range recordingsList.Recordings { fmt.Printf("- %s: %.2fs (%d bytes)\n", *rec.Name, *rec.DurationSeconds, *rec.FileSizeBytes) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**list (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#recordinglist) > > [**list (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#list) > > [**list (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md) > > [**List (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#RecordingService.List) > > [**List Recordings (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/recordings) ### Get Recording Get details about a specific recording: ```python recording_detail = sandbox.computer_use.recording.get("recording-id") print(f"Recording: {recording_detail.name}") print(f"Status: {recording_detail.status}") print(f"Duration: {recording_detail.duration_seconds}s") ``` ```typescript const recordingDetail = await sandbox.computerUse.recording.get('recording-id'); console.log(`Recording: ${recordingDetail.name}`); console.log(`Status: ${recordingDetail.status}`); console.log(`Duration: ${recordingDetail.duration_seconds}s`); ``` ```ruby recording_detail = sandbox.computer_use.recording.get(id: 'recording-id') puts "Recording: #{recording_detail.name}" puts "Status: #{recording_detail.status}" puts "Duration: #{recording_detail.duration_seconds}s" ``` ```go recordingDetail, err := sandbox.ComputerUse.Recording().Get(ctx, "recording-id") if err != nil { log.Fatal(err) } fmt.Printf("Recording: %s\n", *recordingDetail.Name) fmt.Printf("Status: %s\n", *recordingDetail.Status) fmt.Printf("Duration: %.2fs\n", *recordingDetail.DurationSeconds) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#recordingget) > > [**get (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#get) > > [**get (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md) > > [**Get (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#RecordingService.Get) > > [**Get Recording (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/recordings/{id}) ### Delete Recording Delete a recording by ID: ```python sandbox.computer_use.recording.delete("recording-id") print("Recording deleted successfully") ``` ```typescript await sandbox.computerUse.recording.delete('recording-id'); console.log('Recording deleted successfully'); ``` ```ruby sandbox.computer_use.recording.delete(id: 'recording-id') puts 'Recording deleted successfully' ``` ```go err := sandbox.ComputerUse.Recording().Delete(ctx, "recording-id") if err != nil { log.Fatal(err) } fmt.Println("Recording deleted successfully") ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}' \ --request DELETE ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**delete (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#recordingdelete) > > [**delete (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#delete) > > [**delete (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md) > > [**Delete (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#RecordingService.Delete) > > [**Delete Recording (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/DELETE/computeruse/recordings/{id}) ### Download Recording Download a recording file from the sandbox to your local machine. The file is streamed efficiently without loading the entire content into memory, making it suitable for large recordings. ```python # Download recording to local file sandbox.computer_use.recording.download(recording.id, "local_recording.mp4") print("Recording downloaded successfully") # Or with custom path import os download_path = os.path.join("recordings", f"recording_{recording.id}.mp4") sandbox.computer_use.recording.download(recording.id, download_path) ``` ```typescript // Download recording to local file await sandbox.computerUse.recording.download(recording.id, 'local_recording.mp4'); console.log('Recording downloaded successfully'); // Or with custom path const downloadPath = `recordings/recording_${recording.id}.mp4`; await sandbox.computerUse.recording.download(recording.id, downloadPath); ``` ```ruby # Download recording to local file sandbox.computer_use.recording.download(id: recording.id, local_path: 'local_recording.mp4') puts 'Recording downloaded successfully' # Or with custom path download_path = "recordings/recording_#{recording.id}.mp4" sandbox.computer_use.recording.download(id: recording.id, local_path: download_path) ``` ```go // Download recording to local file err := sandbox.ComputerUse.Recording().Download(ctx, recording.GetId(), "local_recording.mp4") if err != nil { log.Fatal(err) } fmt.Println("Recording downloaded successfully") // Or with custom path downloadPath := fmt.Sprintf("recordings/recording_%s.mp4", recording.GetId()) err = sandbox.ComputerUse.Recording().Download(ctx, recording.GetId(), downloadPath) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}/download' \ --output local_recording.mp4 ``` :::tip[Streaming Downloads] All SDK implementations stream the recording file directly to disk without loading the entire content into memory. This allows you to download large recordings (hundreds of MB or even GB) efficiently without running out of memory. - **Python**: Streams in 64KB chunks using `httpx` - **TypeScript**: Uses Node.js `pipeline()` with backpressure handling - **Ruby**: Uses Typhoeus streaming with `on_body` callbacks - **Go**: Uses `io.Copy()` with 32KB internal buffer ::: For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**download (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#recordingdownload) > > [**download (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#download) > > [**download (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md) > > [**Download (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#RecordingService.Download) > > [**Download Recording (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/recordings/{id}/download) ### Recording Dashboard Every sandbox includes a built-in recording dashboard for managing screen recordings through a web interface. The dashboard allows you to view, download, and delete recordings without writing code. To access the recording dashboard: 1. Navigate to your sandboxes in the Daytona Dashboard 2. Click the action menu (three dots) for your sandbox 3. Select **Screen Recordings** from the dropdown menu The recording dashboard provides: - List of all recordings with metadata (name, duration, file size, creation time) - Playback controls for reviewing recordings - Download functionality to save recordings locally - Delete options for managing storage :::tip The recording dashboard runs on a private port and is automatically secured. No additional authentication is required once you access it through the Daytona Dashboard. ::: ## Display operations ### Get info Get information about the displays. ```python info = sandbox.computer_use.display.get_info() print(f"Primary display: {info.primary_display.width}x{info.primary_display.height}") print(f"Total displays: {info.total_displays}") for i, display in enumerate(info.displays): print(f"Display {i}: {display.width}x{display.height} at {display.x},{display.y}") ``` ```typescript const info = await sandbox.computerUse.display.getInfo(); console.log(`Primary display: ${info.primary_display.width}x${info.primary_display.height}`); console.log(`Total displays: ${info.total_displays}`); info.displays.forEach((display, index) => { console.log(`Display ${index}: ${display.width}x${display.height} at ${display.x},${display.y}`); }); ``` ```ruby info = sandbox.computer_use.display.info puts "Primary display: #{info.primary_display.width}x#{info.primary_display.height}" puts "Total displays: #{info.total_displays}" info.displays.each_with_index do |display, i| puts "Display #{i}: #{display.width}x#{display.height} at #{display.x},#{display.y}" end ``` ```go info, err := sandbox.ComputerUse.Display().GetInfo(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Displays: %v\n", info["displays"]) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/info' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get_info (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#displayget_info) > > [**getInfo (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getinfo) > > [**GetInfo (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#DisplayService.GetInfo) > > [**Get display info (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/display/info) ### Get windows Get the list of open windows. ```python windows = sandbox.computer_use.display.get_windows() print(f"Found {windows.count} open windows:") for window in windows.windows: print(f"- {window.title} (ID: {window.id})") ``` ```typescript const windows = await sandbox.computerUse.display.getWindows(); console.log(`Found ${windows.count} open windows:`); windows.windows.forEach(window => { console.log(`- ${window.title} (ID: ${window.id})`); }); ``` ```ruby windows = sandbox.computer_use.display.windows puts "Found #{windows.count} open windows:" windows.windows.each do |window| puts "- #{window.title} (ID: #{window.id})" end ``` ```go result, err := sandbox.ComputerUse.Display().GetWindows(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Open windows: %v\n", result["windows"]) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/windows' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use) references: > [**get_windows (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#displayget_windows) > > [**getWindows (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getwindows) > > [**GetWindows (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#DisplayService.GetWindows) > > [**Get Windows (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/display/windows) Daytona supports multiple methods to configure your environment, in order of precedence: 1. [Configuration in code](#configuration-in-code) 2. [Environment variables](#environment-variables) 3. [.env file](#env-file) 4. [Default values](#default-values) ## Configuration in code To configure your environment in code, use the `DaytonaConfig` class. The `DaytonaConfig` class accepts the following parameters: - `api_key`: Your Daytona [API Key](https://www.daytona.io/docs/api-keys.md) - `api_url`: URL of your [Daytona API](https://www.daytona.io/docs/en/tools/api.md) - `target`: Target region to create the Sandboxes on (`us` / `eu`) ```python from daytona import DaytonaConfig config = DaytonaConfig( api_key="your-api-key", api_url="your-api-url", target="us" ) ``` ```typescript import { DaytonaConfig } from '@daytonaio/sdk' const config: DaytonaConfig = { apiKey: 'your-api-key', apiUrl: 'your-api-url', target: 'us', } ``` ```ruby require 'daytona' config = Daytona::Config.new( api_key: 'your-api-key', api_url: 'your-api-url', target: 'us' ) ``` ```go package main import ( "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) func main() { config := daytona.Config{ APIKey: "your-api-key", APIURL: "your-api-url", Target: "us", } client := daytona.NewClient(&config) _ = client } ``` ```bash curl https://app.daytona.io/api/api-keys \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "name": "", "permissions": [ "write:registries" ], "expiresAt": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/daytona.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/daytona.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/daytona.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys) references: > [**DaytonaConfig (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/daytona.md#daytonaconfig) > > [**DaytonaConfig (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#daytonaconfig) > > [**Config (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/config.md#config) > > [**DaytonaConfig (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/types.md#DaytonaConfig) > > [**Config (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/POST/api-keys) ## Environment variables Daytona supports environment variables for configuration. The SDK automatically looks for these environment variables: | Variable | Description | Required | | --------------------- | ------------------------------------------ | -------- | | **`DAYTONA_API_KEY`** | Your Daytona API key. | Yes | | **`DAYTONA_API_URL`** | URL of your Daytona API. | No | | **`DAYTONA_TARGET`** | Daytona Target to create the sandboxes on. | No | ### Shell Set environment variables in your shell using the following methods: ```bash export DAYTONA_API_KEY=your-api-key export DAYTONA_API_URL=https://your-api-url export DAYTONA_TARGET=us ``` ```bash $env:DAYTONA_API_KEY="your-api-key" $env:DAYTONA_API_URL="https://your-api-url" $env:DAYTONA_TARGET="us" ``` ### .env file Set the environment variables in a `.env` file using the following format: ```bash DAYTONA_API_KEY=YOUR_API_KEY DAYTONA_API_URL=https://your_api_url DAYTONA_TARGET=us ``` ## Default values If no configuration is provided, Daytona will use its built-in default values: | **Option** | **Value** | | ---------- | ----------------------------------- | | API URL | https://app.daytona.io/api | | Target | Default region for the organization | Daytona provides a preview proxy service that can be used to handle [preview URLs](https://www.daytona.io/docs/en/preview.md) for sandboxes. This gives you full control over the preview experience, including custom domains, authentication, error handling, and styling. - **Custom domain**: host your proxy under your own domain (e.g., `preview.yourcompany.com`) - **User authentication**: implement custom authentication logic for private previews - **Sandbox management**: automatically start stopped sandboxes before forwarding users - **Custom error pages**: style error pages to match your brand - **Preview warning control**: disable Daytona's preview warning - **CORS management**: override Daytona's default CORS settings ## How it works When a user visits a preview URL, your custom proxy receives the request and can: 1. Authenticate the user using custom logic 2. Check sandbox status and start it if needed 3. Forward the request to the actual sandbox 4. Handle responses with custom styling and error pages 5. Send custom headers to control Daytona's behavior Your proxy should forward the `X-Forwarded-Host` header with the original request host when proxying requests to Daytona. ## WebSocket support The preview proxy fully supports WebSocket connections. WebSocket upgrade requests (`Upgrade: websocket`) are automatically detected and proxied. WebSocket connections skip the preview warning page. ## Reserved ports The following ports are reserved for internal services and always require authentication, even on public sandboxes: | Port | Service | | ----------- | ----------------------------------------- | | **`22222`** | [**Web** terminal](https://www.daytona.io/docs/en/web-terminal.md) | | **`2280`** | Toolbox (IDE/development interface) | | **`33333`** | Recording dashboard | Your custom proxy should avoid exposing these ports unless you explicitly need access to these services. ## Proxy headers Your proxy can send special headers to control Daytona's behavior. ### Disable preview warning To disable Daytona's preview warning page, send: ``` X-Daytona-Skip-Preview-Warning: true ``` The warning page is only shown to browser requests. It sets a `daytona-preview-page-accepted` cookie that persists for 24 hours after acceptance. ### Disable CORS Daytona's default CORS policy allows all origins with credentials. To override this and use your own CORS settings, send: ``` X-Daytona-Disable-CORS: true ``` ### Disable last activity update To prevent sandbox last activity updates when previewing, set the `X-Daytona-Skip-Last-Activity-Update` header to `true`. This prevents Daytona from keeping sandboxes that have [auto-stop enabled](https://www.daytona.io/docs/en/sandboxes.md#auto-stop-interval) in a started state: ```bash curl -H "X-Daytona-Skip-Last-Activity-Update: true" \ https://3000-sandbox-123456.proxy.daytona.work ``` ### Authentication For private preview links, send: ``` X-Daytona-Preview-Token: {sandboxToken} ``` The `sandboxToken` can be fetched through the Daytona SDK or API using the [standard preview URL](https://www.daytona.io/docs/en/preview.md#standard-preview-url) methods. ## Examples Examples of custom preview proxies are available on [GitHub](https://github.com/daytonaio/daytona-proxy-samples). Declarative Builder provides a powerful, code-first approach to defining dependencies for Daytona Sandboxes. Instead of importing images from a container registry, you can programmatically define them using the Daytona SDK. The declarative builder system supports two primary workflows: 1. [**Declarative images**](#declarative-image-building): build images with varying dependencies _on demand_ when creating sandboxes 2. [**Pre-built Snapshots**](#creating-pre-built-snapshots): create and register _ready-to-use_ [Snapshots](https://www.daytona.io/docs/snapshots.md) that can be shared across multiple sandboxes ## Build declarative images Daytona provides an option to create declarative images on-the-fly when creating sandboxes. This is ideal for iterating quickly without creating separate snapshots. Declarative images are cached for 24 hours, and are automatically reused when running the same script. Thus, subsequent runs on the same runner will be almost instantaneous. ```python # Define a declarative image with python packages declarative_image = ( Image.debian_slim("3.12") .pip_install(["requests", "pytest"]) .workdir("/home/daytona") ) # Create a new sandbox with the declarative image and stream the build logs sandbox = daytona.create( CreateSandboxFromImageParams(image=declarative_image), timeout=0, on_snapshot_create_logs=print, ) ``` ```typescript // Define a declarative image with python packages const declarativeImage = Image.debianSlim('3.12') .pipInstall(['requests', 'pytest']) .workdir('/home/daytona') // Create a new sandbox with the declarative image and stream the build logs const sandbox = await daytona.create( { image: declarativeImage, }, { timeout: 0, onSnapshotCreateLogs: console.log, } ) ``` ```ruby # Define a simple declarative image with Python packages declarative_image = Daytona::Image .debian_slim('3.12') .pip_install(['requests', 'pytest']) .workdir('/home/daytona') # Create a new Sandbox with the declarative image and stream the build logs sandbox = daytona.create( Daytona::CreateSandboxFromImageParams.new(image: declarative_image), on_snapshot_create_logs: proc { |chunk| puts chunk } ) ``` ```go // Define a declarative image with python packages version := "3.12" declarativeImage := daytona.DebianSlim(&version). PipInstall([]string{"requests", "pytest"}). Workdir("/home/daytona") // Create a new sandbox with the declarative image and stream the build logs logChan := make(chan string) go func() { for log := range logChan { fmt.Print(log) } }() sandbox, err := client.Create(ctx, types.ImageParams{ Image: declarativeImage, }, options.WithTimeout(0), options.WithLogChannel(logChan)) if err != nil { // handle error } ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**CreateSandboxFromImageParams (Python SDK)**](https://www.daytona.io/docs/python-sdk/sync/daytona.md#createsandboxfromimageparams) > > [**CreateSandboxFromImageParams (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/daytona.md#createsandboxfromimageparams) > > [**CreateSandboxFromImageParams (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/daytona.md#createsandboxfromimageparams) > > [**Create (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#Client.Create) :::note Use the following best practices when working with the declarative builder: - **Layer Optimization**: Group related operations to minimize Docker layers - **Cache Utilization**: Identical build commands and context will be cached and subsequent builds will be almost instant - **Security**: Create non-root users for application workloads - **Resource Efficiency**: Use slim base images when appropriate - **Context Minimization**: Only include necessary files in the build context ::: ## Create pre-built Snapshots Daytona provides an option to [create pre-built snapshots](https://www.daytona.io/docs/snapshots.md#create-snapshots) that can be reused across multiple sandboxes. The snapshot remains visible in the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/snapshots) and is permanently cached, ensuring instant availability without rebuilding. ```python # Create a python data science image snapshot_name = "data-science-snapshot" image = ( Image.debian_slim("3.12") .pip_install(["pandas", "numpy"]) .workdir("/home/daytona") ) # Create the snapshot and stream the build logs daytona.snapshot.create( CreateSnapshotParams( name=snapshot_name, image=image, ), on_logs=print, ) # Create a new sandbox using the pre-built snapshot sandbox = daytona.create( CreateSandboxFromSnapshotParams(snapshot=snapshot_name) ) ``` ```typescript // Create a python data science image const snapshotName = 'data-science-snapshot' const image = Image.debianSlim('3.12') .pipInstall(['pandas', 'numpy']) .workdir('/home/daytona') // Create the snapshot and stream the build logs await daytona.snapshot.create( { name: snapshotName, image, }, { onLogs: console.log, } ) // Create a new sandbox using the pre-built snapshot const sandbox = await daytona.create({ snapshot: snapshotName, }) ``` ```ruby # Create a simple Python data science image snapshot_name = 'data-science-snapshot' image = Daytona::Image .debian_slim('3.12') .pip_install(['pandas', 'numpy']) .workdir('/home/daytona') # Create the Snapshot and stream the build logs daytona.snapshot.create( Daytona::CreateSnapshotParams.new( name: snapshot_name, image: image ), on_logs: proc { |chunk| puts chunk } ) # Create a new Sandbox using the pre-built Snapshot sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new(snapshot: snapshot_name) ) ``` ```go // Create a python data science image snapshotName := "data-science-snapshot" version := "3.12" image := daytona.DebianSlim(&version). PipInstall([]string{"pandas", "numpy"}). Workdir("/home/daytona") // Create the snapshot and stream the build logs _, logChan, err := client.Snapshot.Create(ctx, &types.CreateSnapshotParams{ Name: snapshotName, Image: image, }) if err != nil { // handle error } for log := range logChan { fmt.Print(log) } // Create a new sandbox using the pre-built snapshot sandbox, err := client.Create(ctx, types.SnapshotParams{ Snapshot: snapshotName, }) if err != nil { // handle error } ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**CreateSnapshotParams (Python SDK)**](https://www.daytona.io/docs/python-sdk/sync/snapshot.md#createsnapshotparams) > > [**CreateSnapshotParams (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/snapshot.md#createsnapshotparams) > > [**CreateSnapshotParams (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/snapshot.md#createsnapshotparams) > > [**Create (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#SnapshotService.Create) ## Image configuration Daytona provides an option to define images programmatically using the Daytona SDK. You can specify base images, install packages, add files, set environment variables, and more. For a complete API reference and method signatures, see the [Python](https://www.daytona.io/docs/python-sdk/common/image.md), [TypeScript](https://www.daytona.io/docs/typescript-sdk/image.md), [Ruby](https://www.daytona.io/docs/ruby-sdk/image.md), and [Go](https://www.daytona.io/docs/go-sdk/daytona.md#type-DockerImage) SDK references. ### Base image selection Daytona provides an option to select base images. The following snippets demonstrate how to select and configure base images: ```python # Create an image from a base image = Image.base("python:3.12-slim-bookworm") # Use a Debian slim image with Python 3.12 image = Image.debian_slim("3.12") ``` ```typescript // Create an image from a base const image = Image.base('python:3.12-slim-bookworm') // Use a Debian slim image with Python 3.12 const image = Image.debianSlim('3.12') ``` ```ruby # Create an image from a base image = Daytona::Image.base('python:3.12-slim-bookworm') # Use a Debian slim image with Python 3.12 image = Daytona::Image.debian_slim('3.12') ``` ```go // Create an image from a base image := daytona.Base("python:3.12-slim-bookworm") // Use a Debian slim image with Python 3.12 version := "3.12" image := daytona.DebianSlim(&version) ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**base (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagebase) > > [**base (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#base) > > [**Base (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#Base) > > [**debian_slim (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagedebian_slim) > > [**debianSlim (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#debianslim) > > [**DebianSlim (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DebianSlim) ### Package management Daytona provides an option to install packages and dependencies to your image. The following snippets demonstrate how to install packages and dependencies to your image: ```python # Add pip packages image = Image.debian_slim("3.12").pip_install(["requests", "pandas"]) # Install from requirements.txt image = Image.debian_slim("3.12").pip_install_from_requirements("requirements.txt") # Install from pyproject.toml (with optional dependencies) image = Image.debian_slim("3.12").pip_install_from_pyproject("pyproject.toml", optional_dependencies=["dev"]) ``` ```typescript // Add pip packages const image = Image.debianSlim('3.12').pipInstall(['requests', 'pandas']) // Install from requirements.txt const image = Image.debianSlim('3.12').pipInstallFromRequirements('requirements.txt') // Install from pyproject.toml (with optional dependencies) const image = Image.debianSlim('3.12').pipInstallFromPyproject('pyproject.toml', { optionalDependencies: ['dev'] }) ``` ```ruby # Add pip packages image = Daytona::Image.debian_slim('3.12').pip_install(['requests', 'pandas']) # Install from requirements.txt image = Daytona::Image.debian_slim('3.12').pip_install_from_requirements('requirements.txt') # Install from pyproject.toml (with optional dependencies) image = Daytona::Image.debian_slim('3.12').pip_install_from_pyproject('pyproject.toml', optional_dependencies: ['dev'] ) ``` ```go // Add pip packages version := "3.12" image := daytona.DebianSlim(&version).PipInstall([]string{"requests", "pandas"}) // Install from requirements.txt image := daytona.DebianSlim(&version). AddLocalFile("requirements.txt", "/tmp/requirements.txt"). Run("pip install -r /tmp/requirements.txt") // Install from pyproject.toml (with optional dependencies) image := daytona.DebianSlim(&version). AddLocalFile("pyproject.toml", "/tmp/pyproject.toml"). Run("pip install /tmp[dev]") ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**pip_install (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagepip_install) > > [**pipInstall (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#pipinstall) > > [**pip_install (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#pip_install) > > [**PipInstall (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.PipInstall) > > [**pip_install_from_requirements (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagepip_install_from_requirements) > > [**pipInstallFromRequirements (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#pipinstallfromrequirements) > > [**pip_install_from_requirements (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#pip_install_from_requirements) > > [**pip_install_from_pyproject (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagepip_install_from_pyproject) > > [**pipInstallFromPyproject (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#pipinstallfrompyproject) > > [**pip_install_from_pyproject (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#pip_install_from_pyproject) ### File system operations Daytona provides an option to add files and directories to your image. The following snippets demonstrate how to add files and directories to your image: ```python # Add a local file image = Image.debian_slim("3.12").add_local_file("package.json", "/home/daytona/package.json") # Add a local directory image = Image.debian_slim("3.12").add_local_dir("src", "/home/daytona/src") ``` ```typescript // Add a local file const image = Image.debianSlim('3.12').addLocalFile('package.json', '/home/daytona/package.json') // Add a local directory const image = Image.debianSlim('3.12').addLocalDir('src', '/home/daytona/src') ``` ```ruby # Add a local file image = Daytona::Image.debian_slim('3.12').add_local_file('package.json', '/home/daytona/package.json') # Add a local directory image = Daytona::Image.debian_slim('3.12').add_local_dir('src', '/home/daytona/src') ``` ```go // Add a local file version := "3.12" image := daytona.DebianSlim(&version).AddLocalFile("package.json", "/home/daytona/package.json") // Add a local directory image := daytona.DebianSlim(&version).AddLocalDir("src", "/home/daytona/src") ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**add_local_file (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imageadd_local_file) > > [**add_local_dir (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imageadd_local_dir) > > [**addLocalFile (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#addlocalfile) > > [**addLocalDir (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#addlocaldir) > > [**add_local_file (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#add_local_file) > > [**add_local_dir (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#add_local_dir) > > [**AddLocalFile (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.AddLocalFile) > > [**AddLocalDir (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.AddLocalDir) ### Environment configuration Daytona provides an option to configure environment variables and working directories. The following snippets demonstrate how to configure environment variables and working directories: ```python # Set environment variables image = Image.debian_slim("3.12").env({"PROJECT_ROOT": "/home/daytona"}) # Set working directory image = Image.debian_slim("3.12").workdir("/home/daytona") ``` ```typescript // Set environment variables const image = Image.debianSlim('3.12').env({ PROJECT_ROOT: '/home/daytona' }) // Set working directory const image = Image.debianSlim('3.12').workdir('/home/daytona') ``` ```ruby # Set environment variables image = Daytona::Image.debian_slim('3.12').env({ 'PROJECT_ROOT' => '/home/daytona' }) # Set working directory image = Daytona::Image.debian_slim('3.12').workdir('/home/daytona') ``` ```go // Set environment variables version := "3.12" image := daytona.DebianSlim(&version).Env("PROJECT_ROOT", "/home/daytona") // Set working directory image := daytona.DebianSlim(&version).Workdir("/home/daytona") ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**env (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imageenv) > > [**workdir (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imageworkdir) > > [**env (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#env) > > [**workdir (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#workdir) > > [**env (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#env) > > [**workdir (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#workdir) > > [**Env (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.Env) > > [**Workdir (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.Workdir) ### Commands and entrypoints Daytona provides an option to execute commands during build and configure container startup behavior. The following snippets demonstrate how to execute commands during build and configure container startup behavior: ```python # Run shell commands during build image = Image.debian_slim("3.12").run_commands( 'apt-get update && apt-get install -y git', 'groupadd -r daytona && useradd -r -g daytona -m daytona', 'mkdir -p /home/daytona/workspace' ) # Set entrypoint image = Image.debian_slim("3.12").entrypoint(["/bin/bash"]) # Set default command image = Image.debian_slim("3.12").cmd(["/bin/bash"]) ``` ```typescript // Run shell commands during build const image = Image.debianSlim('3.12').runCommands( 'apt-get update && apt-get install -y git', 'groupadd -r daytona && useradd -r -g daytona -m daytona', 'mkdir -p /home/daytona/workspace' ) // Set entrypoint const image = Image.debianSlim('3.12').entrypoint(['/bin/bash']) // Set default command const image = Image.debianSlim('3.12').cmd(['/bin/bash']) ``` ```ruby # Run shell commands during build image = Daytona::Image.debian_slim('3.12').run_commands( 'apt-get update && apt-get install -y git', 'groupadd -r daytona && useradd -r -g daytona -m daytona', 'mkdir -p /home/daytona/workspace' ) # Set entrypoint image = Daytona::Image.debian_slim('3.12').entrypoint(['/bin/bash']) # Set default command image = Daytona::Image.debian_slim('3.12').cmd(['/bin/bash']) ``` ```go // Run shell commands during build version := "3.12" image := daytona.DebianSlim(&version). Run("apt-get update && apt-get install -y git"). Run("groupadd -r daytona && useradd -r -g daytona -m daytona"). Run("mkdir -p /home/daytona/workspace") // Set entrypoint image := daytona.DebianSlim(&version).Entrypoint([]string{"/bin/bash"}) // Set default command image := daytona.DebianSlim(&version).Cmd([]string{"/bin/bash"}) ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**run_commands (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagerun_commands) > > [**entrypoint (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imageentrypoint) > > [**cmd (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagecmd) > > [**runCommands (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#runcommands) > > [**entrypoint (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#entrypoint) > > [**cmd (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#cmd) > > [**run_commands (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#run_commands) > > [**entrypoint (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#entrypoint) > > [**cmd (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#cmd) > > [**Run (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.Run) > > [**Entrypoint (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.Entrypoint) > > [**Cmd (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#DockerImage.Cmd) ### Dockerfile integration Daytona provides an option to integrate existing Dockerfiles or add custom Dockerfile commands. The following snippets demonstrate how to integrate existing Dockerfiles or add custom Dockerfile commands: ```python # Add custom Dockerfile commands image = Image.debian_slim("3.12").dockerfile_commands(["RUN echo 'Hello, world!'"]) # Use an existing Dockerfile image = Image.from_dockerfile("Dockerfile") # Extend an existing Dockerfile image = Image.from_dockerfile("app/Dockerfile").pip_install(["numpy"]) ``` ```typescript // Add custom Dockerfile commands const image = Image.debianSlim('3.12').dockerfileCommands(['RUN echo "Hello, world!"']) // Use an existing Dockerfile const image = Image.fromDockerfile('Dockerfile') // Extend an existing Dockerfile const image = Image.fromDockerfile("app/Dockerfile").pipInstall(['numpy']) ``` ```ruby # Add custom Dockerfile commands image = Daytona::Image.debian_slim('3.12').dockerfile_commands(['RUN echo "Hello, world!"']) # Use an existing Dockerfile image = Daytona::Image.from_dockerfile('Dockerfile') # Extend an existing Dockerfile image = Daytona::Image.from_dockerfile('app/Dockerfile').pip_install(['numpy']) ``` ```go // Note: In Go, FromDockerfile takes the Dockerfile content as a string content, err := os.ReadFile("Dockerfile") if err != nil { // handle error } image := daytona.FromDockerfile(string(content)) // Extend an existing Dockerfile with additional commands content, err = os.ReadFile("app/Dockerfile") if err != nil { // handle error } image := daytona.FromDockerfile(string(content)). PipInstall([]string{"numpy"}) ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**dockerfile_commands (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagedockerfile_commands) > > [**from_dockerfile (Python SDK)**](https://www.daytona.io/docs/python-sdk/common/image.md#imagefrom_dockerfile) > > [**dockerfileCommands (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#dockerfilecommands) > > [**fromDockerfile (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/image.md#fromdockerfile) > > [**dockerfile_commands (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/image.md#dockerfile_commands) > > [**FromDockerfile (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#FromDockerfile) OpenTelemetry (OTEL) tracing allows you to monitor and debug your Daytona SDK operations by collecting distributed traces. This is particularly useful for understanding performance bottlenecks, debugging issues, and gaining visibility into your sandbox operations. :::caution OpenTelemetry collection is currently an experimental feature and may change in future releases. To request access to this feature, please contact [support@daytona.io](mailto:support@daytona.io). ::: --- ## Sandbox Telemetry Collection Daytona can collect traces, logs, and metrics directly from your sandboxes. This provides complete observability across your entire Daytona environment, from [SDK calls](#sdk-tracing-configuration) to sandbox runtime behavior. ### What Gets Collected from Sandboxes When sandbox telemetry is enabled, the following data is collected: **Metrics:** - `daytona.sandbox.cpu.utilization` - CPU usage percentage (0-100%) - `daytona.sandbox.cpu.limit` - CPU cores limit - `daytona.sandbox.memory.utilization` - Memory usage percentage (0-100%) - `daytona.sandbox.memory.usage` - Memory used in bytes - `daytona.sandbox.memory.limit` - Memory limit in bytes - `daytona.sandbox.filesystem.utilization` - Disk usage percentage (0-100%) - `daytona.sandbox.filesystem.usage` - Disk space used in bytes - `daytona.sandbox.filesystem.available` - Disk space available in bytes - `daytona.sandbox.filesystem.total` - Total disk space in bytes **Traces:** - HTTP requests and responses - Custom spans from your application code **Logs:** - Application logs (stdout/stderr) - System logs - Runtime errors and warnings ### Viewing Telemetry in the Dashboard Logs, traces, and metrics collected from sandboxes can be viewed directly in the Daytona Dashboard. Open the **Sandbox Details** sheet for any sandbox and use the **Logs**, **Traces**, and **Metrics** tabs to inspect the collected telemetry data. :::note Daytona retains sandbox telemetry data for **3 days**. If you need to keep the data for longer, it is recommended that you connect your own OTLP-compatible collector using the [sandbox collection configuration](#configure-sandbox-collection). ::: :::tip Sandbox telemetry collection works independently from SDK tracing. You can enable one or both depending on your observability needs: - **SDK tracing only**: Monitor Daytona API operations and SDK calls - **Sandbox telemetry only**: Monitor application behavior inside sandboxes - **Both**: Get complete end-to-end observability across your entire stack ::: ### Configure Sandbox Collection To enable telemetry collection from sandboxes: 1. Navigate to the [Daytona Dashboard](https://app.daytona.io) 2. Go to **Settings** → **Experimental** 3. Configure the following fields: - **OTLP Endpoint**: Your OpenTelemetry collector endpoint (e.g., `https://otlp.nr-data.net`) - **OTLP Headers**: Authentication headers in `key=value` format (e.g., `api-key=YOUR_API_KEY`) Once configured, all sandboxes will automatically export their telemetry data to your specified OTLP endpoint. --- ## SDK Tracing Configuration When enabled, the Daytona SDK automatically instruments all SDK operations including: - Sandbox creation, starting, stopping, and deletion - File system operations - Code execution - Process management - HTTP requests to the Daytona API Traces are exported using the OTLP (OpenTelemetry Protocol) format and can be sent to any OTLP-compatible backend such as New Relic, Jaeger, or Zipkin. ### 1. Enable OTEL in SDK To enable OpenTelemetry tracing, pass the `otelEnabled` experimental flag when initializing the Daytona client: Alternatively, you can set the `DAYTONA_EXPERIMENTAL_OTEL_ENABLED` environment variable to `true` instead of passing the configuration option: ```bash export DAYTONA_EXPERIMENTAL_OTEL_ENABLED=true ``` ```python from daytona import Daytona, DaytonaConfig # Using async context manager (recommended) async with Daytona(DaytonaConfig( _experimental={"otelEnabled": True} )) as daytona: sandbox = await daytona.create() # All operations will be traced # OpenTelemetry traces are flushed on close ``` Or without context manager: ```python daytona = Daytona(DaytonaConfig( _experimental={"otelEnabled": True} )) try: sandbox = await daytona.create() # All operations will be traced finally: await daytona.close() # Flushes traces ``` ```typescript import { Daytona } from '@daytonaio/sdk' // Using async dispose (recommended) await using daytona = new Daytona({ _experimental: { otelEnabled: true } }) const sandbox = await daytona.create() // All operations will be traced // Traces are automatically flushed on dispose ``` Or with explicit disposal: ```typescript const daytona = new Daytona({ _experimental: { otelEnabled: true } }) try { const sandbox = await daytona.create() // All operations will be traced } finally { await daytona[Symbol.asyncDispose]() // Flushes traces } ``` ```go import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) client, err := daytona.NewClientWithConfig(&types.DaytonaConfig{ Experimental: &types.ExperimentalConfig{ OtelEnabled: true, }, }) if err != nil { log.Fatal(err) } defer client.Close(context.Background()) // Flushes traces sandbox, err := client.Create(context.Background(), nil) // All operations will be traced ``` ```ruby require 'daytona' config = Daytona::Config.new( _experimental: { 'otel_enabled' => true } ) daytona = Daytona::Daytona.new(config) sandbox = daytona.create # All operations will be traced daytona.close # Flushes traces ``` Or with `ensure` block: ```ruby daytona = Daytona::Daytona.new( Daytona::Config.new(_experimental: { 'otel_enabled' => true }) ) begin sandbox = daytona.create # All operations will be traced ensure daytona.close # Flushes traces end ``` ### 2. Configure OTLP Exporter The SDK uses standard OpenTelemetry environment variables for configuration. Set these before running your application: #### Required Environment Variables ```bash # OTLP endpoint (without the /v1/traces path) OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net:4317 # Authentication headers (format: key1=value1,key2=value2) OTEL_EXPORTER_OTLP_HEADERS="api-key=your-api-key-here" ``` --- ## Provider-Specific Examples ### New Relic ```bash OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net:4317 OTEL_EXPORTER_OTLP_HEADERS="api-key=YOUR_NEW_RELIC_LICENSE_KEY" ``` ### Jaeger (Local) ```bash OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 ``` ### Grafana Cloud ```bash OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp-gateway-prod-.grafana.net/otlp OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic " ``` Setup: Go to [Grafana Cloud Portal](https://grafana.com) → **Connections** → **Add new connection** → Search for **OpenTelemetry (OTLP)** → Follow the wizard to create an access token. The endpoint and headers will be provided in the instrumentation instructions. See the [Grafana dashboard example](https://github.com/daytonaio/daytona/tree/main/examples/otel-dashboards/grafana) for detailed setup steps. --- ## Complete Example Here's a complete example showing how to use OpenTelemetry tracing with the Daytona SDK: ```python import asyncio import os from daytona import Daytona, DaytonaConfig # Set OTEL configuration os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://otlp.nr-data.net:4317" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = "api-key=YOUR_API_KEY" async def main(): # Initialize Daytona with OTEL enabled async with Daytona(DaytonaConfig( _experimental={"otelEnabled": True} )) as daytona: # Create a sandbox - this operation will be traced sandbox = await daytona.create() print(f"Created sandbox: {sandbox.id}") # Execute code - this operation will be traced result = await sandbox.process.code_run("" import numpy as np print(f"NumPy version: {np.__version__}") "") print(f"Execution result: {result.result}") # Upload a file - this operation will be traced await sandbox.fs.upload_file("local.txt", "/home/daytona/remote.txt") # Delete sandbox - this operation will be traced await daytona.delete(sandbox) # Traces are automatically flushed when exiting the context manager if __name__ == "__main__": asyncio.run(main()) ``` ```typescript // Set OTEL configuration process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://otlp.nr-data.net:4317" process.env.OTEL_EXPORTER_OTLP_HEADERS = "api-key=YOUR_API_KEY" import { Daytona } from '@daytonaio/sdk' async function main() { // Initialize Daytona with OTEL enabled await using daytona = new Daytona({ _experimental: { otelEnabled: true } }) // Create a sandbox - this operation will be traced const sandbox = await daytona.create() console.log(`Created sandbox: ${sandbox.id}`) // Execute code - this operation will be traced const result = await sandbox.process.codeRun(` import numpy as np print(f"NumPy version: {np.__version__}") `) console.log(`Execution result: ${result.result}`) // Upload a file - this operation will be traced await sandbox.fs.uploadFile('local.txt', '/home/daytona/remote.txt') // Delete sandbox - this operation will be traced await daytona.delete(sandbox) // Traces are automatically flushed when the daytona instance is disposed } main().catch(console.error) ``` ```go package main import ( "context" "fmt" "log" "os" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { // Set OTEL configuration os.Setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "https://otlp.nr-data.net:4317") os.Setenv("OTEL_EXPORTER_OTLP_HEADERS", "api-key=YOUR_API_KEY") ctx := context.Background() // Initialize Daytona with OTEL enabled client, err := daytona.NewClientWithConfig(&types.DaytonaConfig{ Experimental: &types.ExperimentalConfig{ OtelEnabled: true, }, }) if err != nil { log.Fatal(err) } defer client.Close(ctx) // Flushes traces on exit // Create a sandbox - this operation will be traced sandbox, err := client.Create(ctx, nil) if err != nil { log.Fatal(err) } fmt.Printf("Created sandbox: %s\n", sandbox.ID) // Execute code - this operation will be traced result, err := sandbox.Process.CodeRun(ctx, &types.CodeRunParams{ Code: ` import numpy as np print(f"NumPy version: {np.__version__}") `, }) if err != nil { log.Fatal(err) } fmt.Printf("Execution result: %s\n", result.Result) // Upload a file - this operation will be traced err = sandbox.Fs.UploadFile(ctx, "local.txt", "/home/daytona/remote.txt") if err != nil { log.Fatal(err) } // Delete sandbox - this operation will be traced err = client.Delete(ctx, sandbox, nil) if err != nil { log.Fatal(err) } // Traces are flushed when client.Close is called via defer } ``` ```ruby require 'daytona' # Set OTEL configuration ENV["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://otlp.nr-data.net:4317" ENV["OTEL_EXPORTER_OTLP_HEADERS"] = "api-key=YOUR_API_KEY" # Initialize Daytona with OTEL enabled config = Daytona::Config.new( _experimental: { 'otel_enabled' => true } ) daytona = Daytona::Daytona.new(config) begin # Create a sandbox - this operation will be traced sandbox = daytona.create puts "Created sandbox: #{sandbox.id}" # Execute code - this operation will be traced result = sandbox.process.code_run(" import numpy as np print(f'NumPy version: {np.__version__}') ") puts "Execution result: #{result.result}" # Upload a file - this operation will be traced sandbox.fs.upload_file("local.txt", "/home/daytona/remote.txt") # Delete sandbox - this operation will be traced daytona.delete(sandbox) ensure daytona.close # Flushes traces end ``` --- ## What Gets Traced The Daytona SDK automatically instruments the following operations: ### SDK-Level Operations - `create()` - Sandbox creation and initialization - `get()` - Retrieving sandbox instances - `list()` - Listing sandboxes - `start()` - Starting sandboxes - `stop()` - Stopping sandboxes - `delete()` - Deleting sandboxes - All sandbox, snapshot and volume operations (file system, code execution, process management, etc.) ### HTTP Requests - All API calls to the Daytona backend - Request duration and response status codes - Error information for failed requests ### Trace Attributes Each trace includes valuable metadata such as: - Service name and version - HTTP method, URL, and status code - Request and response duration - Error details (if applicable) - Custom SDK operation metadata --- ## Dashboard Examples - [New Relic](https://github.com/daytonaio/daytona/tree/main/examples/otel-dashboards/new-relic) - [Grafana](https://github.com/daytonaio/daytona/tree/main/examples/otel-dashboards/grafana) ## Troubleshooting ### Verify Traces Are Being Sent 1. Check that environment variables are set correctly 2. Verify your OTLP endpoint is reachable 3. Confirm API keys/headers are valid 4. Check your observability platform for incoming traces 5. Look for connection errors in application logs ### Common Issues **Traces not appearing:** - Ensure `otelEnabled: true` is set in the configuration - Verify OTLP endpoint and headers are correct - Check that you're properly closing/disposing the Daytona instance to flush traces **Connection refused:** - Verify the OTLP endpoint URL is correct - Ensure the endpoint is accessible from your application - Check firewall rules if running in a restricted environment **Authentication errors:** - Verify API key format matches your provider's requirements - Check that the `OTEL_EXPORTER_OTLP_HEADERS` format is correct (key=value pairs) --- ## Best Practices 1. **Always close the client**: Use `async with` (Python), `await using` (TypeScript), `defer client.Close()` (Go), or `ensure daytona.close` (Ruby) to ensure traces are properly flushed 1. **Monitor trace volume**: Be aware that enabling tracing will increase network traffic and storage in your observability platform 1. **Use in development first**: Test OTEL configuration in development before enabling in production 1. **Configure sampling**: For high-volume applications, consider configuring trace sampling to reduce costs --- ## Additional Resources - [OpenTelemetry Documentation](https://opentelemetry.io/docs/) - [OTLP Specification](https://opentelemetry.io/docs/specs/otlp/) - [Daytona SDK Documentation](https://www.daytona.io/docs/en/introduction.md) Daytona provides comprehensive file system operations through the `fs` module in sandboxes. ## Basic operations Daytona provides methods to interact with the file system in sandboxes. You can perform various operations like listing files, creating directories, reading and writing files, and more. File operations assume you are operating in the sandbox user's home directory (e.g. `workspace` implies `/home/[username]/workspace`). Use a leading `/` when providing absolute paths. ### List files and directories Daytona provides methods to list files and directories in a sandbox by providing the path to the directory. If the path is not provided, the method will list the files and directories in the sandbox working directory. ```python # List files in a directory files = sandbox.fs.list_files("workspace") for file in files: print(f"Name: {file.name}") print(f"Is directory: {file.is_dir}") print(f"Size: {file.size}") print(f"Modified: {file.mod_time}") ``` ```typescript // List files in a directory const files = await sandbox.fs.listFiles('workspace') files.forEach(file => { console.log(`Name: ${file.name}`) console.log(`Is directory: ${file.isDir}`) console.log(`Size: ${file.size}`) console.log(`Modified: ${file.modTime}`) }) ``` ```ruby # List directory contents files = sandbox.fs.list_files("workspace/data") # Print files and their sizes files.each do |file| puts "#{file.name}: #{file.size} bytes" unless file.is_dir end # List only directories dirs = files.select(&:is_dir) puts "Subdirectories: #{dirs.map(&:name).join(', ')}" ``` ```go // List files in a directory files, err := sandbox.FileSystem.ListFiles(ctx, "workspace") if err != nil { log.Fatal(err) } for _, file := range files { fmt.Printf("Name: %s\n", file.Name) fmt.Printf("Is directory: %t\n", file.IsDirectory) fmt.Printf("Size: %d\n", file.Size) fmt.Printf("Modified: %s\n", file.ModifiedTime) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**list_files (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemlist_files) > > [**listFiles (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#listfiles) > > [**list_files (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#list_files) > > [**ListFiles (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.ListFiles) > > [**list files and directories (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/GET/files) ### Get directory or file information Daytona provides methods to get directory or file information such as group, directory, modified time, mode, name, owner, permissions, and size by providing the path to the directory or file. ```python # Get file metadata info = sandbox.fs.get_file_info("workspace/data/file.txt") print(f"Size: {info.size} bytes") print(f"Modified: {info.mod_time}") print(f"Mode: {info.mode}") # Check if path is a directory info = sandbox.fs.get_file_info("workspace/data") if info.is_dir: print("Path is a directory") ``` ```typescript // Get file details const info = await fs.getFileDetails('app/config.json') console.log(`Size: ${info.size}, Modified: ${info.modTime}`) ``` ```ruby # Get file metadata info = sandbox.fs.get_file_info("workspace/data/file.txt") puts "Size: #{info.size} bytes" puts "Modified: #{info.mod_time}" puts "Mode: #{info.mode}" # Check if path is a directory info = sandbox.fs.get_file_info("workspace/data") puts "Path is a directory" if info.is_dir ``` ```go // Get file metadata info, err := sandbox.FileSystem.GetFileInfo(ctx, "workspace/data/file.txt") if err != nil { log.Fatal(err) } fmt.Printf("Size: %d bytes\n", info.Size) fmt.Printf("Modified: %s\n", info.ModifiedTime) fmt.Printf("Mode: %s\n", info.Mode) // Check if path is a directory info, err = sandbox.FileSystem.GetFileInfo(ctx, "workspace/data") if err != nil { log.Fatal(err) } if info.IsDirectory { fmt.Println("Path is a directory") } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/info?path=' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**get_file_info (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemget_file_info) > > [**getFileDetails (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#getfiledetails) > > [**get_file_info (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#get_file_info) > > [**GetFileInfo (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.GetFileInfo) > > [**get file information (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/GET/files/info) ### Create directories Daytona provides methods to create directories by providing the path to the directory and the permissions to set on the directory. ```python # Create with specific permissions sandbox.fs.create_folder("workspace/new-dir", "755") ``` ```typescript // Create with specific permissions await sandbox.fs.createFolder('workspace/new-dir', '755') ``` ```ruby # Create a directory with standard permissions sandbox.fs.create_folder("workspace/data", "755") # Create a private directory sandbox.fs.create_folder("workspace/secrets", "700") ``` ```go // Create with specific permissions err := sandbox.FileSystem.CreateFolder(ctx, "workspace/new-dir", options.WithMode("755"), ) if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/folder?path=&mode=' \ --request POST ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**create_folder (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemcreate_folder) > > [**createFolder (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#createfolder) > > [**create_folder (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#create_folder) > > [**CreateFolder (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.CreateFolder) > > [**create folder (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/POST/files/folder) ### Upload files Daytona provides methods to upload a single or multiple files in sandboxes. #### Upload a single file Daytona provides methods to upload a single file in sandboxes by providing the content to upload and the path to the file to upload it to. ```python # Upload a single file with open("local_file.txt", "rb") as f: content = f.read() sandbox.fs.upload_file(content, "remote_file.txt") ``` ```typescript // Upload a single file const fileContent = Buffer.from('Hello, World!') await sandbox.fs.uploadFile(fileContent, 'data.txt') ``` ```ruby # Upload a text file from string content content = "Hello, World!" sandbox.fs.upload_file(content, "tmp/hello.txt") # Upload a local file sandbox.fs.upload_file("local_file.txt", "tmp/file.txt") # Upload binary data data = { key: "value" }.to_json sandbox.fs.upload_file(data, "tmp/config.json") ``` ```go // Upload from a local file path err := sandbox.FileSystem.UploadFile(ctx, "local_file.txt", "remote_file.txt") if err != nil { log.Fatal(err) } // Or upload from byte content content := []byte("Hello, World!") err = sandbox.FileSystem.UploadFile(ctx, content, "hello.txt") if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/upload?path=' \ --request POST \ --header 'Content-Type: multipart/form-data' \ --form 'file=' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**upload_file (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemupload_file) > > [**uploadFile (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#uploadfile) > > [**upload_file (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#upload_file) > > [**UploadFile (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.UploadFile) > > [**upload file (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/POST/files/upload) #### Upload multiple files Daytona provides methods to upload multiple files in sandboxes by providing the content to upload and their destination paths. ```python # Upload multiple files at once files_to_upload = [] with open("file1.txt", "rb") as f1: files_to_upload.append(FileUpload( source=f1.read(), destination="data/file1.txt", )) with open("file2.txt", "rb") as f2: files_to_upload.append(FileUpload( source=f2.read(), destination="data/file2.txt", )) with open("settings.json", "rb") as f3: files_to_upload.append(FileUpload( source=f3.read(), destination="config/settings.json", )) sandbox.fs.upload_files(files_to_upload) ``` ```typescript // Upload multiple files at once const files = [ { source: Buffer.from('Content of file 1'), destination: 'data/file1.txt', }, { source: Buffer.from('Content of file 2'), destination: 'data/file2.txt', }, { source: Buffer.from('{"key": "value"}'), destination: 'config/settings.json', }, ] await sandbox.fs.uploadFiles(files) ``` ```ruby # Upload multiple files files = [ FileUpload.new("Content of file 1", "/tmp/file1.txt"), FileUpload.new("workspace/data/file2.txt", "/tmp/file2.txt"), FileUpload.new('{"key": "value"}', "/tmp/config.json") ] sandbox.fs.upload_files(files) ``` ```go // Upload multiple files by calling UploadFile for each filesToUpload := []struct { source string destination string }{ {"file1.txt", "data/file1.txt"}, {"file2.txt", "data/file2.txt"}, {"settings.json", "config/settings.json"}, } for _, f := range filesToUpload { err := sandbox.FileSystem.UploadFile(ctx, f.source, f.destination) if err != nil { log.Fatal(err) } } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/bulk-upload' \ --request POST ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**upload_files (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemupload_files) > > [**uploadFiles (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#uploadfiles) > > [**upload_files (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#upload_files) > > [**upload multiple files (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/POST/files/bulk-upload) ### Download files Daytona provides methods to download files from sandboxes. #### Download a single file Daytona provides methods to download a single file from sandboxes by providing the path to the file to download. ```python content = sandbox.fs.download_file("file1.txt") with open("local_file.txt", "wb") as f: f.write(content) print(content.decode('utf-8')) ``` ```typescript const downloadedFile = await sandbox.fs.downloadFile('file1.txt') console.log('File content:', downloadedFile.toString()) ``` ```ruby # Download and get file content content = sandbox.fs.download_file("workspace/data/file.txt") puts content # Download and save a file locally sandbox.fs.download_file("workspace/data/file.txt", "local_copy.txt") size_mb = File.size("local_copy.txt") / 1024.0 / 1024.0 puts "Size of the downloaded file: #{size_mb} MB" ``` ```go // Download and get contents in memory content, err := sandbox.FileSystem.DownloadFile(ctx, "file1.txt", nil) if err != nil { log.Fatal(err) } fmt.Println(string(content)) // Download and save to a local file localPath := "local_file.txt" content, err = sandbox.FileSystem.DownloadFile(ctx, "file1.txt", &localPath) if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/download?path=' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**download_file (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemdownload_file) > > [**downloadFile (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#downloadfile) > > [**download_file (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#download_file) > > [**DownloadFile (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.DownloadFile) > > [**download file (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/GET/files/download) #### Download multiple files Daytona provides methods to download multiple files from sandboxes by providing the paths to the files to download. ```python # Download multiple files at once files_to_download = [ FileDownloadRequest(source="data/file1.txt"), # No destination - download to memory FileDownloadRequest(source="data/file2.txt", destination="local_file2.txt"), # Download to local file ] results = sandbox.fs.download_files(files_to_download) for result in results: if result.error: print(f"Error downloading {result.source}: {result.error}") elif result.result: print(f"Downloaded {result.source} to {result.result}") ``` ```typescript // Download multiple files at once const files = [ { source: 'data/file1.txt' }, // No destination - download to memory { source: 'data/file2.txt', destination: 'local_file2.txt' }, // Download to local file ] const results = await sandbox.fs.downloadFiles(files) results.forEach(result => { if (result.error) { console.error(`Error downloading ${result.source}: ${result.error}`) } else if (result.result) { console.log(`Downloaded ${result.source} to ${result.result}`) } }) ``` ```ruby # Download multiple files by calling download_file for each files_to_download = [ { remote: "data/file1.txt", local: nil }, # Download to memory { remote: "data/file2.txt", local: "local_file2.txt" } # Download to local file ] files_to_download.each do |f| if f[:local] sandbox.fs.download_file(f[:remote], f[:local]) puts "Downloaded #{f[:remote]} to #{f[:local]}" else content = sandbox.fs.download_file(f[:remote]) puts "Downloaded #{f[:remote]} to memory (#{content.size} bytes)" end end ``` ```go // Download multiple files by calling DownloadFile for each filesToDownload := []struct { remotePath string localPath *string }{ {"data/file1.txt", nil}, // Download to memory {"data/file2.txt", ptrString("local_file2.txt")}, // Download to local file } for _, f := range filesToDownload { content, err := sandbox.FileSystem.DownloadFile(ctx, f.remotePath, f.localPath) if err != nil { fmt.Printf("Error downloading %s: %v\n", f.remotePath, err) continue } if f.localPath == nil { fmt.Printf("Downloaded %s to memory (%d bytes)\n", f.remotePath, len(content)) } else { fmt.Printf("Downloaded %s to %s\n", f.remotePath, *f.localPath) } } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/bulk-download' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "paths": [ "" ] }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**download_files (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemdownload_files) > > [**downloadFiles (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#downloadfiles) > > [**download_file (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#download_file) > > [**download multiple files (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/POST/files/bulk-download) ### Delete files Daytona provides methods to delete files or directories from sandboxes by providing the path to the file or directory to delete. ```python sandbox.fs.delete_file("workspace/file.txt") ``` ```typescript await sandbox.fs.deleteFile('workspace/file.txt') ``` ```ruby # Delete a file sandbox.fs.delete_file("workspace/data/old_file.txt") # Delete a directory recursively sandbox.fs.delete_file("workspace/old_dir", recursive: true) ``` ```go // Delete a file err := sandbox.FileSystem.DeleteFile(ctx, "workspace/file.txt", false) if err != nil { log.Fatal(err) } // Delete a directory recursively err = sandbox.FileSystem.DeleteFile(ctx, "workspace/old_dir", true) if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files?path=' \ --request DELETE ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**delete_file (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemdelete_file) > > [**deleteFile (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#deletefile) > > [**delete_file (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#delete_file) > > [**DeleteFile (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.DeleteFile) > > [**delete file or directory (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/DELETE/files) ## Advanced operations Daytona provides advanced file system operations such as file permissions, search and replace, and move files. ### File permissions Daytona provides methods to set file permissions, ownership, and group for a file or directory by providing the path to the file or directory and the permissions to set. ```python # Set file permissions sandbox.fs.set_file_permissions("workspace/file.txt", "644") # Get file permissions file_info = sandbox.fs.get_file_info("workspace/file.txt") print(f"Permissions: {file_info.permissions}") ``` ```typescript // Set file permissions await sandbox.fs.setFilePermissions('workspace/file.txt', { mode: '644' }) // Get file permissions const fileInfo = await sandbox.fs.getFileDetails('workspace/file.txt') console.log(`Permissions: ${fileInfo.permissions}`) ``` ```ruby # Make a file executable sandbox.fs.set_file_permissions( path: "workspace/scripts/run.sh", mode: "755" # rwxr-xr-x ) # Change file owner sandbox.fs.set_file_permissions( path: "workspace/data/file.txt", owner: "daytona", group: "daytona" ) ``` ```go // Set file permissions err := sandbox.FileSystem.SetFilePermissions(ctx, "workspace/file.txt", options.WithPermissionMode("644"), ) if err != nil { log.Fatal(err) } // Set owner and group err = sandbox.FileSystem.SetFilePermissions(ctx, "workspace/file.txt", options.WithOwner("daytona"), options.WithGroup("daytona"), ) if err != nil { log.Fatal(err) } // Get file info to check permissions fileInfo, err := sandbox.FileSystem.GetFileInfo(ctx, "workspace/file.txt") if err != nil { log.Fatal(err) } fmt.Printf("Mode: %s\n", fileInfo.Mode) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/permissions?path=' \ --request POST ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**set_file_permissions (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemset_file_permissions) > > [**setFilePermissions (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#setfilepermissions) > > [**set_file_permissions (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#set_file_permissions) > > [**SetFilePermissions (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.SetFilePermissions) > > [**set file permissions (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/POST/files/permissions) ### Find and replace text in files Daytona provides methods to find and replace text in files by providing the path to the directory to search in and the pattern to search for. ```python # Search for text in files by providing the path to the directory to search in and the pattern to search for results = sandbox.fs.find_files( path="workspace/src", pattern="text-of-interest" ) for match in results: print(f"Absolute file path: {match.file}") print(f"Line number: {match.line}") print(f"Line content: {match.content}") print("\n") # Replace text in files sandbox.fs.replace_in_files( files=["workspace/file1.txt", "workspace/file2.txt"], pattern="old_text", new_value="new_text" ) ``` ```typescript // Search for text in files; if a folder is specified, the search is recursive const results = await sandbox.fs.findFiles({ path="workspace/src", pattern: "text-of-interest" }) results.forEach(match => { console.log('Absolute file path:', match.file) console.log('Line number:', match.line) console.log('Line content:', match.content) }) // Replace text in files await sandbox.fs.replaceInFiles( ["workspace/file1.txt", "workspace/file2.txt"], "old_text", "new_text" ) ``` ```ruby # Search for TODOs in Ruby files matches = sandbox.fs.find_files("workspace/src", "TODO:") matches.each do |match| puts "#{match.file}:#{match.line}: #{match.content.strip}" end # Replace in specific files results = sandbox.fs.replace_in_files( files: ["workspace/src/file1.rb", "workspace/src/file2.rb"], pattern: "old_function", new_value: "new_function" ) # Print results results.each do |result| if result.success puts "#{result.file}: #{result.success}" else puts "#{result.file}: #{result.error}" end end ``` ```go // Search for text in files result, err := sandbox.FileSystem.FindFiles(ctx, "workspace/src", "text-of-interest") if err != nil { log.Fatal(err) } matches := result.([]map[string]any) for _, match := range matches { fmt.Printf("Absolute file path: %s\n", match["file"]) fmt.Printf("Line number: %v\n", match["line"]) fmt.Printf("Line content: %s\n\n", match["content"]) } // Replace text in files _, err = sandbox.FileSystem.ReplaceInFiles(ctx, []string{"workspace/file1.txt", "workspace/file2.txt"}, "old_text", "new_text", ) if err != nil { log.Fatal(err) } ``` Find text in files: ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/find?path=&pattern=' ``` Replace text in files: ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/replace' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "files": [ "" ], "newValue": "", "pattern": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**find_files (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemfind_files) > > [**replace_in_files (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemreplace_in_files) > > [**findFiles (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#findfiles) > > [**replaceInFiles (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#replaceinfiles) > > [**find_files (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#find_files) > > [**replace_in_files (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#replace_in_files) > > [**FindFiles (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.FindFiles) > > [**ReplaceInFiles (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.ReplaceInFiles) > > [**find text in files (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/GET/files/find) > > [**replace text in files (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/POST/files/replace) ### Move or rename directory or file Daytona provides methods to move or rename a directory or file in sandboxes by providing the path to the file or directory (source) and the new path to the file or directory (destination). ```python # Rename a file sandbox.fs.move_files( "workspace/data/old_name.txt", "workspace/data/new_name.txt" ) # Move a file to a different directory sandbox.fs.move_files( "workspace/data/file.txt", "workspace/archive/file.txt" ) # Move a directory sandbox.fs.move_files( "workspace/old_dir", "workspace/new_dir" ) ``` ```typescript // Move a file to a new location await fs.moveFiles('app/temp/data.json', 'app/data/data.json') ``` ```ruby # Rename a file sandbox.fs.move_files( "workspace/data/old_name.txt", "workspace/data/new_name.txt" ) # Move a file to a different directory sandbox.fs.move_files( "workspace/data/file.txt", "workspace/archive/file.txt" ) # Move a directory sandbox.fs.move_files( "workspace/old_dir", "workspace/new_dir" ) ``` ```go // Rename a file err := sandbox.FileSystem.MoveFiles(ctx, "workspace/data/old_name.txt", "workspace/data/new_name.txt") if err != nil { log.Fatal(err) } // Move a file to a different directory err = sandbox.FileSystem.MoveFiles(ctx, "workspace/data/file.txt", "workspace/archive/file.txt") if err != nil { log.Fatal(err) } // Move a directory err = sandbox.FileSystem.MoveFiles(ctx, "workspace/old_dir", "workspace/new_dir") if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/files/move?source=&destination=' \ --request POST ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**move_files (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/file-system.md#filesystemmove_files) > > [**moveFiles (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/file-system.md#movefiles) > > [**move_files (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/file-system.md#move_files) > > [**MoveFiles (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#FileSystemService.MoveFiles) > > [**move or rename file or directory (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/file-system/POST/files/move) This section introduces core concepts, common workflows, and next steps for using Daytona. ## Dashboard [Daytona Dashboard ↗](https://app.daytona.io/) is a visual user interface where you can manage sandboxes, access API keys, view usage, and more. It serves as the primary point of control for managing your Daytona resources. ## SDKs Daytona provides [Python](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go](https://www.daytona.io/docs/en/go-sdk.md) SDKs to programmatically interact with sandboxes. They support sandbox lifecycle management, code execution, resource access, and more. ## CLI Daytona provides command-line access to core features for interacting with Daytona Sandboxes, including managing their lifecycle, snapshots, and more. To interact with Daytona Sandboxes from the command line, install the Daytona CLI: ```bash brew install daytonaio/cli/daytona ``` ```bash powershell -Command "irm https://get.daytona.io/windows | iex" ``` After installing the Daytona CLI, use the `daytona` command to interact with Daytona Sandboxes from the command line. To upgrade the Daytona CLI to the latest version: ```bash brew upgrade daytonaio/cli/daytona ``` ```bash powershell -Command "irm https://get.daytona.io/windows | iex" ``` To view all available commands and flags, see the [CLI reference](https://www.daytona.io/docs/en/tools/cli.md). ## API Daytona provides a RESTful API for interacting with Daytona Sandboxes, including managing their lifecycle, snapshots, and more. It serves as a flexible and powerful way to interact with Daytona from your own applications. To interact with Daytona Sandboxes from the API, see the [API reference](https://www.daytona.io/docs/en/tools/api.md). ## MCP server Daytona provides a Model Context Protocol (MCP) server that enables AI agents to interact with Daytona Sandboxes programmatically. The MCP server integrates with popular AI agents including Claude, Cursor, and Windsurf. To set up the MCP server with your AI agent: ```bash daytona mcp init [claude/cursor/windsurf] ``` For more information, see the [MCP server documentation](https://www.daytona.io/docs/en/mcp.md). ## Multiple runtime support Daytona supports multiple programming language runtimes for direct code execution inside the sandbox. [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md) works across multiple **JavaScript runtimes** including **Node.js**, **browsers**, and **serverless platforms**: Cloudflare Workers, AWS Lambda, Azure Functions, etc. Using the Daytona SDK in browser-based environments or frameworks like [**Vite**](https://www.daytona.io/docs/en/getting-started.md#daytona-in-vite-projects) and [**Next.js**](https://www.daytona.io/docs/en/getting-started.md#daytona-in-nextjs-projects) requires configuring node polyfills. ### Daytona in Vite projects When using Daytona SDK in a Vite-based project, configure node polyfills to ensure compatibility. Add the following configuration to your `vite.config.ts` file in the `plugins` array: ```typescript import { nodePolyfills } from 'vite-plugin-node-polyfills' plugins: [ // ... other plugins nodePolyfills({ globals: { global: true, process: true, Buffer: true }, overrides: { path: 'path-browserify-win32', }, }), ], // ... rest of your config }) ``` ### Daytona in Next.js projects When using Daytona SDK in a Next.js project, configure node polyfills to ensure compatibility with Webpack and Turbopack bundlers. Add the following configuration to your `next.config.ts` file: ```typescript import type { NextConfig } from 'next' import NodePolyfillPlugin from 'node-polyfill-webpack-plugin' import { env, nodeless } from 'unenv' const { alias: turbopackAlias } = env(nodeless, {}) const nextConfig: NextConfig = { // Turbopack experimental: { turbo: { resolveAlias: { ...turbopackAlias, }, }, }, // Webpack webpack: (config, { isServer }) => { if (!isServer) { config.plugins.push(new NodePolyfillPlugin()) } return config }, } ``` ## Guides Daytona provides a comprehensive set of guides to help you get started. The guides cover a wide range of topics, from basic usage to advanced topics, and showcase various types of integrations between Daytona and other tools. For more information, see [guides](https://www.daytona.io/docs/en/guides.md). ## Examples Daytona provides quick examples for common sandbox operations and best practices.
The examples are based on the Daytona [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/process.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/process.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references. More examples are available in the [GitHub repository ↗](https://github.com/daytonaio/daytona/tree/main/examples). ### Create a sandbox Create a [sandbox](https://www.daytona.io/docs/en/sandboxes.md) with default settings. ```python from daytona import Daytona daytona = Daytona() sandbox = daytona.create() print(f"Sandbox ID: {sandbox.id}") ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create(); console.log(`Sandbox ID: ${sandbox.id}`); ``` ```go package main import ( "context" "fmt" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } sandbox, err := client.Create(context.Background(), nil) if err != nil { log.Fatal(err) } fmt.Printf("Sandbox ID: %s\n", sandbox.ID) } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create puts "Sandbox ID: #{sandbox.id}" ``` ```shell daytona create ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{}' ``` ### Create and run code in a sandbox Create a [sandbox](https://www.daytona.io/docs/en/sandboxes.md) and run code securely in it. ```python from daytona import Daytona daytona = Daytona() sandbox = daytona.create() response = sandbox.process.exec("echo 'Hello, World!'") print(response.result) sandbox.delete() ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create(); const response = await sandbox.process.executeCommand('echo "Hello, World!"'); console.log(response.result); await sandbox.delete(); ``` ```go package main import ( "context" "fmt" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } sandbox, err := client.Create(context.Background(), nil) if err != nil { log.Fatal(err) } response, err := sandbox.Process.ExecuteCommand(context.Background(), "echo 'Hello, World!'") if err != nil { log.Fatal(err) } fmt.Println(response.Result) sandbox.Delete(context.Background()) } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create response = sandbox.process.exec(command: "echo 'Hello, World!'") puts response.result daytona.delete(sandbox) ``` ```shell daytona create --name my-sandbox daytona exec my-sandbox -- echo 'Hello, World!' daytona delete my-sandbox ``` ```bash # Create a sandbox curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{}' # Execute a command in the sandbox curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/execute' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "command": "echo '\''Hello, World!'\''" }' # Delete the sandbox curl 'https://app.daytona.io/api/sandbox/{sandboxId}' \ --request DELETE \ --header 'Authorization: Bearer ' ``` ### Create a sandbox with custom resources Create a sandbox with [custom resources](https://www.daytona.io/docs/en/sandboxes.md#resources) (CPU, memory, disk). ```python from daytona import Daytona, CreateSandboxFromImageParams, Image, Resources daytona = Daytona() sandbox = daytona.create( CreateSandboxFromImageParams( image=Image.debian_slim("3.12"), resources=Resources(cpu=2, memory=4, disk=8) ) ) ``` ```typescript import { Daytona, Image } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create({ image: Image.debianSlim('3.12'), resources: { cpu: 2, memory: 4, disk: 8 } }); ``` ```go package main import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } sandbox, err := client.Create(context.Background(), types.ImageParams{ Image: daytona.DebianSlim(nil), Resources: &types.Resources{ CPU: 2, Memory: 4, Disk: 8, }, }) if err != nil { log.Fatal(err) } } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create( Daytona::CreateSandboxFromImageParams.new( image: Daytona::Image.debian_slim('3.12'), resources: Daytona::Resources.new(cpu: 2, memory: 4, disk: 8) ) ) ``` ```shell daytona create --class small ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "cpu": 2, "memory": 4, "disk": 8 }' ``` ### Create an ephemeral sandbox Create an [ephemeral sandbox](https://www.daytona.io/docs/en/sandboxes.md#ephemeral-sandboxes) that is automatically deleted when stopped. ```python from daytona import Daytona, CreateSandboxFromSnapshotParams daytona = Daytona() sandbox = daytona.create( CreateSandboxFromSnapshotParams(ephemeral=True, auto_stop_interval=5) ) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create({ ephemeral: true, autoStopInterval: 5 }); ``` ```go package main import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } autoStop := 5 sandbox, err := client.Create(context.Background(), types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ Ephemeral: true, AutoStopInterval: &autoStop, }, }) if err != nil { log.Fatal(err) } } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new(ephemeral: true, auto_stop_interval: 5) ) ``` ```shell daytona create --auto-stop 5 --auto-delete 0 ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "autoStopInterval": 5, "autoDeleteInterval": 0 }' ``` ### Create a sandbox from a snapshot Create a sandbox from a pre-built [snapshot](https://www.daytona.io/docs/en/snapshots.md) for faster sandbox creation with pre-installed dependencies. ```python from daytona import Daytona, CreateSandboxFromSnapshotParams daytona = Daytona() sandbox = daytona.create( CreateSandboxFromSnapshotParams( snapshot="my-snapshot-name", language="python" ) ) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create({ snapshot: 'my-snapshot-name', language: 'typescript' }); ``` ```go package main import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } sandbox, err := client.Create(context.Background(), types.SnapshotParams{ Snapshot: "my-snapshot-name", SandboxBaseParams: types.SandboxBaseParams{ Language: types.CodeLanguagePython, }, }) if err != nil { log.Fatal(err) } } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( snapshot: 'my-snapshot-name', language: Daytona::CodeLanguage::PYTHON ) ) ``` ```shell daytona create --snapshot my-snapshot-name ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "snapshot": "my-snapshot-name" }' ``` ### Create a sandbox with a declarative image Create a sandbox with a [declarative image](https://www.daytona.io/docs/en/declarative-builder.md) that defines dependencies programmatically. ```python from daytona import Daytona, CreateSandboxFromImageParams, Image daytona = Daytona() image = ( Image.debian_slim("3.12") .pip_install(["requests", "pandas", "numpy"]) .workdir("/home/daytona") ) sandbox = daytona.create( CreateSandboxFromImageParams(image=image), on_snapshot_create_logs=print ) ``` ```typescript import { Daytona, Image } from '@daytonaio/sdk'; const daytona = new Daytona(); const image = Image.debianSlim('3.12') .pipInstall(['requests', 'pandas', 'numpy']) .workdir('/home/daytona'); const sandbox = await daytona.create( { image }, { onSnapshotCreateLogs: console.log } ); ``` ```go package main import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } image := daytona.DebianSlim(nil). PipInstall([]string{"requests", "pandas", "numpy"}). Workdir("/home/daytona") sandbox, err := client.Create(context.Background(), types.ImageParams{ Image: image, }) if err != nil { log.Fatal(err) } } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new image = Daytona::Image .debian_slim('3.12') .pip_install(['requests', 'pandas', 'numpy']) .workdir('/home/daytona') sandbox = daytona.create( Daytona::CreateSandboxFromImageParams.new(image: image), on_snapshot_create_logs: proc { |chunk| puts chunk } ) ``` ```shell daytona create --dockerfile ./Dockerfile ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "buildInfo": { "dockerfileContent": "FROM python:3.12-slim\nRUN pip install requests pandas numpy\nWORKDIR /home/daytona" } }' ``` ### Create a sandbox with volumes Create a sandbox with a [volume](https://www.daytona.io/docs/en/volumes.md) mounted to share data across sandboxes. ```python from daytona import Daytona, CreateSandboxFromSnapshotParams, VolumeMount daytona = Daytona() volume = daytona.volume.get("my-volume", create=True) sandbox = daytona.create( CreateSandboxFromSnapshotParams( volumes=[VolumeMount(volume_id=volume.id, mount_path="/home/daytona/data")] ) ) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const volume = await daytona.volume.get('my-volume', true); const sandbox = await daytona.create({ volumes: [{ volumeId: volume.id, mountPath: '/home/daytona/data' }] }); ``` ```go package main import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } volume, err := client.Volume.Get(context.Background(), "my-volume") if err != nil { volume, err = client.Volume.Create(context.Background(), "my-volume") if err != nil { log.Fatal(err) } } sandbox, err := client.Create(context.Background(), types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ Volumes: []types.VolumeMount{{ VolumeID: volume.ID, MountPath: "/home/daytona/data", }}, }, }) if err != nil { log.Fatal(err) } } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new volume = daytona.volume.get('my-volume', create: true) sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( volumes: [DaytonaApiClient::SandboxVolume.new( volume_id: volume.id, mount_path: '/home/daytona/data' )] ) ) ``` ```shell daytona volume create my-volume daytona create --volume my-volume:/home/daytona/data ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "volumes": [ { "volumeId": "", "mountPath": "/home/daytona/data" } ] }' ``` ### Create a sandbox with a Git repository cloned Create a sandbox with a [Git repository](https://www.daytona.io/docs/en/typescript-sdk/git.md) cloned to manage version control. ```python from daytona import Daytona daytona = Daytona() sandbox = daytona.create() sandbox.git.clone("https://github.com/daytonaio/daytona.git", "/home/daytona/daytona") status = sandbox.git.status("/home/daytona/daytona") print(f"Branch: {status.current_branch}") ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create(); await sandbox.git.clone('https://github.com/daytonaio/daytona.git', '/home/daytona/daytona'); const status = await sandbox.git.status('/home/daytona/daytona'); console.log(`Branch: ${status.currentBranch}`); ``` ```go package main import ( "context" "fmt" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } sandbox, err := client.Create(context.Background(), nil) if err != nil { log.Fatal(err) } sandbox.Git.Clone(context.Background(), "https://github.com/daytonaio/daytona.git", "/home/daytona/daytona") status, err := sandbox.Git.Status(context.Background(), "/home/daytona/daytona") if err != nil { log.Fatal(err) } fmt.Printf("Branch: %s\n", status.CurrentBranch) } ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create sandbox.git.clone(url: "https://github.com/daytonaio/daytona.git", path: "/home/daytona/daytona") status = sandbox.git.status("/home/daytona/daytona") puts "Branch: #{status.current_branch}" ``` ```bash # Create a sandbox curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{}' # Clone a Git repository in the sandbox curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/clone' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "url": "https://github.com/daytonaio/daytona.git", "path": "/home/daytona/daytona" }' # Get repository status curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/status?path=/home/daytona/daytona' \ --header 'Authorization: Bearer ' ``` Daytona provides built-in Git support through the `git` module in sandboxes. ## Basic operations Daytona provides methods to clone, check status, and manage Git repositories in sandboxes. Similar to [file system operations](https://www.daytona.io/docs/en/file-system-operations.md), the starting cloning directory is the current sandbox working directory. It uses the WORKDIR specified in the Dockerfile if present, or falls back to the user's home directory if not - e.g. `workspace/repo` implies `/my-work-dir/workspace/repo`, but you are free to provide an absolute `workDir` path as well (by starting the path with `/`). ### Clone repositories Daytona provides methods to clone Git repositories into sandboxes. You can clone public or private repositories, specific branches, and authenticate using personal access tokens. ```python # Basic clone sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo" ) # Clone with authentication sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo", username="git", password="personal_access_token" ) # Clone specific branch sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo", branch="develop" ) ``` ```typescript // Basic clone await sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo" ); // Clone with authentication await sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo", undefined, undefined, "git", "personal_access_token" ); // Clone specific branch await sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo", "develop" ); ``` ```ruby # Basic clone sandbox.git.clone( url: 'https://github.com/user/repo.git', path: 'workspace/repo' ) # Clone with authentication sandbox.git.clone( url: 'https://github.com/user/repo.git', path: 'workspace/repo', username: 'git', password: 'personal_access_token' ) # Clone specific branch sandbox.git.clone( url: 'https://github.com/user/repo.git', path: 'workspace/repo', branch: 'develop' ) ``` ```go // Basic clone err := sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "workspace/repo") if err != nil { log.Fatal(err) } // Clone with authentication err = sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "workspace/repo", options.WithUsername("git"), options.WithPassword("personal_access_token"), ) if err != nil { log.Fatal(err) } // Clone specific branch err = sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "workspace/repo", options.WithBranch("develop"), ) if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/clone' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "branch": "", "commit_id": "", "password": "", "path": "", "url": "", "username": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**clone (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitclone) > > [**clone (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#clone) > > [**clone (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#clone) > > [**Clone (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.Clone) > > [**clone repository (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/POST/git/clone) ### Get repository status Daytona provides methods to check the status of Git repositories in sandboxes. You can get the current branch, modified files, number of commits ahead and behind main branch. ```python # Get repository status status = sandbox.git.status("workspace/repo") print(f"Current branch: {status.current_branch}") print(f"Commits ahead: {status.ahead}") print(f"Commits behind: {status.behind}") for file in status.file_status: print(f"File: {file.name}") # List branches response = sandbox.git.branches("workspace/repo") for branch in response.branches: print(f"Branch: {branch}") ``` ```typescript // Get repository status const status = await sandbox.git.status("workspace/repo"); console.log(`Current branch: ${status.currentBranch}`); console.log(`Commits ahead: ${status.ahead}`); console.log(`Commits behind: ${status.behind}`); status.fileStatus.forEach(file => { console.log(`File: ${file.name}`); }); // List branches const response = await sandbox.git.branches("workspace/repo"); response.branches.forEach(branch => { console.log(`Branch: ${branch}`); }); ``` ```ruby # Get repository status status = sandbox.git.status('workspace/repo') puts "Current branch: #{status.current_branch}" puts "Commits ahead: #{status.ahead}" puts "Commits behind: #{status.behind}" status.file_status.each do |file| puts "File: #{file.name}" end # List branches response = sandbox.git.branches('workspace/repo') response.branches.each do |branch| puts "Branch: #{branch}" end ``` ```go // Get repository status status, err := sandbox.Git.Status(ctx, "workspace/repo") if err != nil { log.Fatal(err) } fmt.Printf("Current branch: %s\n", status.CurrentBranch) fmt.Printf("Commits ahead: %d\n", status.Ahead) fmt.Printf("Commits behind: %d\n", status.Behind) for _, file := range status.FileStatus { fmt.Printf("File: %s\n", file.Path) } // List branches branches, err := sandbox.Git.Branches(ctx, "workspace/repo") if err != nil { log.Fatal(err) } for _, branch := range branches { fmt.Printf("Branch: %s\n", branch) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/status?path=' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**status (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitstatus) > > [**status (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#status) > > [**status (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#status) > > [**Status (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.Status) > > [**get Git repository status (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/GET/git/status) ## Branch operations Daytona provides methods to manage branches in Git repositories. You can create, switch, and delete branches. ### Create branches Daytona provides methods to create branches in Git repositories. The following snippet creates a new branch called `new-feature`. ```python # Create a new branch sandbox.git.create_branch("workspace/repo", "new-feature") ``` ```typescript // Create new branch await git.createBranch('workspace/repo', 'new-feature'); ``` ```ruby # Create a new branch sandbox.git.create_branch('workspace/repo', 'new-feature') ``` ```go // Create a new branch err := sandbox.Git.CreateBranch(ctx, "workspace/repo", "new-feature") if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/branches' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "name": "", "path": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**create_branch (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitcreate_branch) > > [**createBranch (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#createbranch) > > [**create_branch (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#create_branch) > > [**CreateBranch (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.CreateBranch) > > [**create branch (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/POST/git/branches) ### Checkout branches Daytona provides methods to checkout branches in Git repositories. The following snippet checks out the branch called `feature-branch`. ```python # Checkout a branch sandbox.git.checkout_branch("workspace/repo", "feature-branch") ``` ```typescript // Checkout a branch await git.checkoutBranch('workspace/repo', 'feature-branch'); ``` ```ruby # Checkout a branch sandbox.git.checkout_branch('workspace/repo', 'feature-branch') ``` ```go // Checkout a branch err := sandbox.Git.Checkout(ctx, "workspace/repo", "feature-branch") if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/checkout' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "branch": "", "path": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**checkout_branch (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitcheckout_branch) > > [**checkoutBranch (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#checkoutbranch) > > [**checkout_branch (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#checkout_branch) > > [**Checkout (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.Checkout) > > [**checkout branch (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/POST/git/checkout) ### Delete branches Daytona provides methods to delete branches in Git repositories. The following snippet deletes the branch called `old-feature`. ```python # Delete a branch sandbox.git.delete_branch("workspace/repo", "old-feature") ``` ```typescript // Delete a branch await git.deleteBranch('workspace/repo', 'old-feature'); ``` ```ruby # Delete a branch sandbox.git.delete_branch('workspace/repo', 'old-feature') ``` ```go // Delete a branch err := sandbox.Git.DeleteBranch(ctx, "workspace/repo", "old-feature") if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/branches' \ --request DELETE \ --header 'Content-Type: application/json' \ --data '{ "name": "", "path": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**delete_branch (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitdelete_branch) > > [**deleteBranch (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#deletebranch) > > [**delete_branch (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#delete_branch) > > [**DeleteBranch (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.DeleteBranch) > > [**delete branch (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/DELETE/git/branches) ## Stage changes Daytona provides methods to stage changes in Git repositories. You can stage specific files, all changes, and commit with a message. The following snippet stages the file `file.txt` and the `src` directory. ```python # Stage a single file sandbox.git.add("workspace/repo", ["file.txt"]) # Stage multiple files sandbox.git.add("workspace/repo", [ "src/main.py", "tests/test_main.py", "README.md" ]) ``` ```typescript // Stage a single file await git.add('workspace/repo', ['file.txt']); // Stage whole repository await git.add('workspace/repo', ['.']); ``` ```ruby # Stage a single file sandbox.git.add('workspace/repo', ['file.txt']) ``` ```go // Stage a single file err := sandbox.Git.Add(ctx, "workspace/repo", []string{"file.txt"}) if err != nil { log.Fatal(err) } // Stage multiple files err = sandbox.Git.Add(ctx, "workspace/repo", []string{ "src/main.py", "tests/test_main.py", "README.md", }) if err != nil { log.Fatal(err) } // Stage whole repository err = sandbox.Git.Add(ctx, "workspace/repo", []string{"."}) if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/add' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "files": [ "" ], "path": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**add (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitadd) > > [**add (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#add) > > [**add (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#add) > > [**Add (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.Add) > > [**add (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/POST/git/add) ## Commit changes Daytona provides methods to commit changes in Git repositories. You can commit with a message, author, and email. The following snippet commits the changes with the message `Update documentation` and the author `John Doe` and email `john@example.com`. ```python # Stage and commit changes sandbox.git.add("workspace/repo", ["README.md"]) sandbox.git.commit( path="workspace/repo", message="Update documentation", author="John Doe", email="john@example.com", allow_empty=True ) ``` ```typescript // Stage and commit changes await git.add('workspace/repo', ['README.md']); await git.commit( 'workspace/repo', 'Update documentation', 'John Doe', 'john@example.com', true ); ``` ```ruby # Stage and commit changes sandbox.git.add('workspace/repo', ['README.md']) sandbox.git.commit('workspace/repo', 'Update documentation', 'John Doe', 'john@example.com', true) ``` ```go // Stage and commit changes err := sandbox.Git.Add(ctx, "workspace/repo", []string{"README.md"}) if err != nil { log.Fatal(err) } response, err := sandbox.Git.Commit(ctx, "workspace/repo", "Update documentation", "John Doe", "john@example.com", options.WithAllowEmpty(true), ) if err != nil { log.Fatal(err) } fmt.Printf("Commit SHA: %s\n", response.SHA) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/commit' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "allow_empty": true, "author": "", "email": "", "message": "", "path": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**commit (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitcommit) > > [**commit (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#commit) > > [**commit (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#commit) > > [**Commit (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.Commit) > > [**commit (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/POST/git/commit) ## Remote operations Daytona provides methods to work with remote repositories in Git. You can push and pull changes from remote repositories. ### Push changes Daytona provides methods to push changes to remote repositories. The following snippet pushes the changes to a public repository. ```python # Push without authentication (for public repos or SSH) sandbox.git.push("workspace/repo") # Push with authentication sandbox.git.push( path="workspace/repo", username="user", password="github_token" ) ``` ```typescript // Push to a public repository await git.push('workspace/repo'); // Push to a private repository await git.push( 'workspace/repo', 'user', 'token' ); ``` ```ruby # Push changes sandbox.git.push('workspace/repo') ``` ```go // Push without authentication (for public repos or SSH) err := sandbox.Git.Push(ctx, "workspace/repo") if err != nil { log.Fatal(err) } // Push with authentication err = sandbox.Git.Push(ctx, "workspace/repo", options.WithPushUsername("user"), options.WithPushPassword("github_token"), ) if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/push' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "password": "", "path": "", "username": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**push (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitpush) > > [**push (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#push) > > [**push (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#push) > > [**Push (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.Push) > > [**push (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/POST/git/push) ### Pull changes Daytona provides methods to pull changes from remote repositories. The following snippet pulls the changes from a public repository. ```python # Pull without authentication sandbox.git.pull("workspace/repo") # Pull with authentication sandbox.git.pull( path="workspace/repo", username="user", password="github_token" ) ``` ```typescript // Pull from a public repository await git.pull('workspace/repo'); // Pull from a private repository await git.pull( 'workspace/repo', 'user', 'token' ); ``` ```ruby # Pull changes sandbox.git.pull('workspace/repo') ``` ```go // Pull without authentication err := sandbox.Git.Pull(ctx, "workspace/repo") if err != nil { log.Fatal(err) } // Pull with authentication err = sandbox.Git.Pull(ctx, "workspace/repo", options.WithPullUsername("user"), options.WithPullPassword("github_token"), ) if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/pull' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "password": "", "path": "", "username": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/git.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/git.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/git.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) references: > [**pull (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/git.md#gitpull) > > [**pull (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/git.md#pull) > > [**pull (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/git.md#pull) > > [**Pull (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#GitService.Pull) > > [**pull (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/git/POST/git/pull) {/* Code generated by gomarkdoc. DO NOT EDIT */} # daytona ```go import "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ``` Package daytona provides a Go SDK for interacting with the Daytona platform. The Daytona SDK enables developers to programmatically create, manage, and interact with sandboxes \- isolated development environments that can run code, execute commands, and manage files. ### Getting Started Create a client using your API key or JWT token: ``` client, err := daytona.NewClient() if err != nil { log.Fatal(err) } ``` The client reads configuration from environment variables: - DAYTONA\_API\_KEY: API key for authentication - DAYTONA\_JWT\_TOKEN: JWT token for authentication \(alternative to API key\) - DAYTONA\_ORGANIZATION\_ID: Organization ID \(required when using JWT token\) - DAYTONA\_API\_URL: API URL \(defaults to https://app.daytona.io/api\) - DAYTONA\_TARGET: Target environment Or provide configuration explicitly: ``` client, err := daytona.NewClientWithConfig(&types.DaytonaConfig{ APIKey: "your-api-key", APIUrl: "https://your-instance.daytona.io/api", }) ``` ### Creating Sandboxes Create a sandbox from a snapshot: ``` sandbox, err := client.Create(ctx, types.SnapshotParams{ Snapshot: "my-snapshot", }) ``` Create a sandbox from a Docker image: ``` sandbox, err := client.Create(ctx, types.ImageParams{ Image: "python:3.11", }) ``` ### Working with Sandboxes Execute code in a sandbox: ``` result, err := sandbox.Process.CodeRun(ctx, "print('Hello, World!')") ``` Run shell commands: ``` result, err := sandbox.Process.ExecuteCommand(ctx, "ls -la") ``` ## Index - [Variables](https://www.daytona.io/docs/%3C.md#variables%3E) - [type Client](https://www.daytona.io/docs/%3C.md#Client%3E) - [func NewClient\(\) \(\*Client, error\)](https://www.daytona.io/docs/%3C.md#NewClient%3E) - [func NewClientWithConfig\(config \*types.DaytonaConfig\) \(\*Client, error\)](https://www.daytona.io/docs/%3C.md#NewClientWithConfig%3E) - [func \(c \*Client\) Close\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#Client.Close%3E) - [func \(c \*Client\) Create\(ctx context.Context, params any, opts ...func\(\*options.CreateSandbox\)\) \(\*Sandbox, error\)](https://www.daytona.io/docs/%3C.md#Client.Create%3E) - [func \(c \*Client\) Get\(ctx context.Context, sandboxIDOrName string\) \(\*Sandbox, error\)](https://www.daytona.io/docs/%3C.md#Client.Get%3E) - [func \(c \*Client\) List\(ctx context.Context, labels map\[string\]string, page \*int, limit \*int\) \(\*PaginatedSandboxes, error\)](<#Client.List>) - [type CodeInterpreterService](https://www.daytona.io/docs/%3C.md#CodeInterpreterService%3E) - [func NewCodeInterpreterService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*CodeInterpreterService](https://www.daytona.io/docs/%3C.md#NewCodeInterpreterService%3E) - [func \(c \*CodeInterpreterService\) CreateContext\(ctx context.Context, cwd \*string\) \(map\[string\]any, error\)](<#CodeInterpreterService.CreateContext>) - [func \(c \*CodeInterpreterService\) DeleteContext\(ctx context.Context, contextID string\) error](https://www.daytona.io/docs/%3C.md#CodeInterpreterService.DeleteContext%3E) - [func \(c \*CodeInterpreterService\) ListContexts\(ctx context.Context\) \(\[\]map\[string\]any, error\)](<#CodeInterpreterService.ListContexts>) - [func \(c \*CodeInterpreterService\) RunCode\(ctx context.Context, code string, opts ...func\(\*options.RunCode\)\) \(\*OutputChannels, error\)](https://www.daytona.io/docs/%3C.md#CodeInterpreterService.RunCode%3E) - [type ComputerUseService](https://www.daytona.io/docs/%3C.md#ComputerUseService%3E) - [func NewComputerUseService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*ComputerUseService](https://www.daytona.io/docs/%3C.md#NewComputerUseService%3E) - [func \(c \*ComputerUseService\) Display\(\) \*DisplayService](https://www.daytona.io/docs/%3C.md#ComputerUseService.Display%3E) - [func \(c \*ComputerUseService\) GetStatus\(ctx context.Context\) \(map\[string\]any, error\)](<#ComputerUseService.GetStatus>) - [func \(c \*ComputerUseService\) Keyboard\(\) \*KeyboardService](https://www.daytona.io/docs/%3C.md#ComputerUseService.Keyboard%3E) - [func \(c \*ComputerUseService\) Mouse\(\) \*MouseService](https://www.daytona.io/docs/%3C.md#ComputerUseService.Mouse%3E) - [func \(c \*ComputerUseService\) Recording\(\) \*RecordingService](https://www.daytona.io/docs/%3C.md#ComputerUseService.Recording%3E) - [func \(c \*ComputerUseService\) Screenshot\(\) \*ScreenshotService](https://www.daytona.io/docs/%3C.md#ComputerUseService.Screenshot%3E) - [func \(c \*ComputerUseService\) Start\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#ComputerUseService.Start%3E) - [func \(c \*ComputerUseService\) Stop\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#ComputerUseService.Stop%3E) - [type DisplayService](https://www.daytona.io/docs/%3C.md#DisplayService%3E) - [func NewDisplayService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*DisplayService](https://www.daytona.io/docs/%3C.md#NewDisplayService%3E) - [func \(d \*DisplayService\) GetInfo\(ctx context.Context\) \(map\[string\]any, error\)](<#DisplayService.GetInfo>) - [func \(d \*DisplayService\) GetWindows\(ctx context.Context\) \(map\[string\]any, error\)](<#DisplayService.GetWindows>) - [type DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage%3E) - [func Base\(baseImage string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#Base%3E) - [func DebianSlim\(pythonVersion \*string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DebianSlim%3E) - [func FromDockerfile\(dockerfile string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#FromDockerfile%3E) - [func \(img \*DockerImage\) Add\(source, destination string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.Add%3E) - [func \(img \*DockerImage\) AddLocalDir\(localPath, remotePath string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.AddLocalDir%3E) - [func \(img \*DockerImage\) AddLocalFile\(localPath, remotePath string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.AddLocalFile%3E) - [func \(img \*DockerImage\) AptGet\(packages \[\]string\) \*DockerImage](<#DockerImage.AptGet>) - [func \(img \*DockerImage\) Cmd\(cmd \[\]string\) \*DockerImage](<#DockerImage.Cmd>) - [func \(img \*DockerImage\) Contexts\(\) \[\]DockerImageContext](<#DockerImage.Contexts>) - [func \(img \*DockerImage\) Copy\(source, destination string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.Copy%3E) - [func \(img \*DockerImage\) Dockerfile\(\) string](https://www.daytona.io/docs/%3C.md#DockerImage.Dockerfile%3E) - [func \(img \*DockerImage\) Entrypoint\(cmd \[\]string\) \*DockerImage](<#DockerImage.Entrypoint>) - [func \(img \*DockerImage\) Env\(key, value string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.Env%3E) - [func \(img \*DockerImage\) Expose\(ports \[\]int\) \*DockerImage](<#DockerImage.Expose>) - [func \(img \*DockerImage\) Label\(key, value string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.Label%3E) - [func \(img \*DockerImage\) PipInstall\(packages \[\]string, opts ...func\(\*options.PipInstall\)\) \*DockerImage](<#DockerImage.PipInstall>) - [func \(img \*DockerImage\) Run\(command string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.Run%3E) - [func \(img \*DockerImage\) User\(username string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.User%3E) - [func \(img \*DockerImage\) Volume\(paths \[\]string\) \*DockerImage](<#DockerImage.Volume>) - [func \(img \*DockerImage\) Workdir\(path string\) \*DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage.Workdir%3E) - [type DockerImageContext](https://www.daytona.io/docs/%3C.md#DockerImageContext%3E) - [type FileSystemService](https://www.daytona.io/docs/%3C.md#FileSystemService%3E) - [func NewFileSystemService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*FileSystemService](https://www.daytona.io/docs/%3C.md#NewFileSystemService%3E) - [func \(f \*FileSystemService\) CreateFolder\(ctx context.Context, path string, opts ...func\(\*options.CreateFolder\)\) error](https://www.daytona.io/docs/%3C.md#FileSystemService.CreateFolder%3E) - [func \(f \*FileSystemService\) DeleteFile\(ctx context.Context, path string, recursive bool\) error](https://www.daytona.io/docs/%3C.md#FileSystemService.DeleteFile%3E) - [func \(f \*FileSystemService\) DownloadFile\(ctx context.Context, remotePath string, localPath \*string\) \(\[\]byte, error\)](<#FileSystemService.DownloadFile>) - [func \(f \*FileSystemService\) FindFiles\(ctx context.Context, path, pattern string\) \(any, error\)](https://www.daytona.io/docs/%3C.md#FileSystemService.FindFiles%3E) - [func \(f \*FileSystemService\) GetFileInfo\(ctx context.Context, path string\) \(\*types.FileInfo, error\)](https://www.daytona.io/docs/%3C.md#FileSystemService.GetFileInfo%3E) - [func \(f \*FileSystemService\) ListFiles\(ctx context.Context, path string\) \(\[\]\*types.FileInfo, error\)](<#FileSystemService.ListFiles>) - [func \(f \*FileSystemService\) MoveFiles\(ctx context.Context, source, destination string\) error](https://www.daytona.io/docs/%3C.md#FileSystemService.MoveFiles%3E) - [func \(f \*FileSystemService\) ReplaceInFiles\(ctx context.Context, files \[\]string, pattern, newValue string\) \(any, error\)](<#FileSystemService.ReplaceInFiles>) - [func \(f \*FileSystemService\) SearchFiles\(ctx context.Context, path, pattern string\) \(any, error\)](https://www.daytona.io/docs/%3C.md#FileSystemService.SearchFiles%3E) - [func \(f \*FileSystemService\) SetFilePermissions\(ctx context.Context, path string, opts ...func\(\*options.SetFilePermissions\)\) error](https://www.daytona.io/docs/%3C.md#FileSystemService.SetFilePermissions%3E) - [func \(f \*FileSystemService\) UploadFile\(ctx context.Context, source any, destination string\) error](https://www.daytona.io/docs/%3C.md#FileSystemService.UploadFile%3E) - [type GitService](https://www.daytona.io/docs/%3C.md#GitService%3E) - [func NewGitService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*GitService](https://www.daytona.io/docs/%3C.md#NewGitService%3E) - [func \(g \*GitService\) Add\(ctx context.Context, path string, files \[\]string\) error](<#GitService.Add>) - [func \(g \*GitService\) Branches\(ctx context.Context, path string\) \(\[\]string, error\)](<#GitService.Branches>) - [func \(g \*GitService\) Checkout\(ctx context.Context, path, name string\) error](https://www.daytona.io/docs/%3C.md#GitService.Checkout%3E) - [func \(g \*GitService\) Clone\(ctx context.Context, url, path string, opts ...func\(\*options.GitClone\)\) error](https://www.daytona.io/docs/%3C.md#GitService.Clone%3E) - [func \(g \*GitService\) Commit\(ctx context.Context, path, message, author, email string, opts ...func\(\*options.GitCommit\)\) \(\*types.GitCommitResponse, error\)](https://www.daytona.io/docs/%3C.md#GitService.Commit%3E) - [func \(g \*GitService\) CreateBranch\(ctx context.Context, path, name string\) error](https://www.daytona.io/docs/%3C.md#GitService.CreateBranch%3E) - [func \(g \*GitService\) DeleteBranch\(ctx context.Context, path, name string, opts ...func\(\*options.GitDeleteBranch\)\) error](https://www.daytona.io/docs/%3C.md#GitService.DeleteBranch%3E) - [func \(g \*GitService\) Pull\(ctx context.Context, path string, opts ...func\(\*options.GitPull\)\) error](https://www.daytona.io/docs/%3C.md#GitService.Pull%3E) - [func \(g \*GitService\) Push\(ctx context.Context, path string, opts ...func\(\*options.GitPush\)\) error](https://www.daytona.io/docs/%3C.md#GitService.Push%3E) - [func \(g \*GitService\) Status\(ctx context.Context, path string\) \(\*types.GitStatus, error\)](https://www.daytona.io/docs/%3C.md#GitService.Status%3E) - [type KeyboardService](https://www.daytona.io/docs/%3C.md#KeyboardService%3E) - [func NewKeyboardService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*KeyboardService](https://www.daytona.io/docs/%3C.md#NewKeyboardService%3E) - [func \(k \*KeyboardService\) Hotkey\(ctx context.Context, keys string\) error](https://www.daytona.io/docs/%3C.md#KeyboardService.Hotkey%3E) - [func \(k \*KeyboardService\) Press\(ctx context.Context, key string, modifiers \[\]string\) error](<#KeyboardService.Press>) - [func \(k \*KeyboardService\) Type\(ctx context.Context, text string, delay \*int\) error](https://www.daytona.io/docs/%3C.md#KeyboardService.Type%3E) - [type LspServerService](https://www.daytona.io/docs/%3C.md#LspServerService%3E) - [func NewLspServerService\(toolboxClient \*toolbox.APIClient, languageID types.LspLanguageID, projectPath string, otel \*otelState\) \*LspServerService](https://www.daytona.io/docs/%3C.md#NewLspServerService%3E) - [func \(l \*LspServerService\) Completions\(ctx context.Context, path string, position types.Position\) \(any, error\)](https://www.daytona.io/docs/%3C.md#LspServerService.Completions%3E) - [func \(l \*LspServerService\) DidClose\(ctx context.Context, path string\) error](https://www.daytona.io/docs/%3C.md#LspServerService.DidClose%3E) - [func \(l \*LspServerService\) DidOpen\(ctx context.Context, path string\) error](https://www.daytona.io/docs/%3C.md#LspServerService.DidOpen%3E) - [func \(l \*LspServerService\) DocumentSymbols\(ctx context.Context, path string\) \(\[\]any, error\)](<#LspServerService.DocumentSymbols>) - [func \(l \*LspServerService\) SandboxSymbols\(ctx context.Context, query string\) \(\[\]any, error\)](<#LspServerService.SandboxSymbols>) - [func \(l \*LspServerService\) Start\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#LspServerService.Start%3E) - [func \(l \*LspServerService\) Stop\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#LspServerService.Stop%3E) - [type MouseService](https://www.daytona.io/docs/%3C.md#MouseService%3E) - [func NewMouseService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*MouseService](https://www.daytona.io/docs/%3C.md#NewMouseService%3E) - [func \(m \*MouseService\) Click\(ctx context.Context, x, y int, button \*string, double \*bool\) \(map\[string\]any, error\)](<#MouseService.Click>) - [func \(m \*MouseService\) Drag\(ctx context.Context, startX, startY, endX, endY int, button \*string\) \(map\[string\]any, error\)](<#MouseService.Drag>) - [func \(m \*MouseService\) GetPosition\(ctx context.Context\) \(map\[string\]any, error\)](<#MouseService.GetPosition>) - [func \(m \*MouseService\) Move\(ctx context.Context, x, y int\) \(map\[string\]any, error\)](<#MouseService.Move>) - [func \(m \*MouseService\) Scroll\(ctx context.Context, x, y int, direction string, amount \*int\) \(bool, error\)](https://www.daytona.io/docs/%3C.md#MouseService.Scroll%3E) - [type OutputChannels](https://www.daytona.io/docs/%3C.md#OutputChannels%3E) - [type PaginatedSandboxes](https://www.daytona.io/docs/%3C.md#PaginatedSandboxes%3E) - [type ProcessService](https://www.daytona.io/docs/%3C.md#ProcessService%3E) - [func NewProcessService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*ProcessService](https://www.daytona.io/docs/%3C.md#NewProcessService%3E) - [func \(p \*ProcessService\) CodeRun\(ctx context.Context, code string, opts ...func\(\*options.CodeRun\)\) \(\*types.ExecuteResponse, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.CodeRun%3E) - [func \(p \*ProcessService\) ConnectPty\(ctx context.Context, sessionID string\) \(\*PtyHandle, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.ConnectPty%3E) - [func \(p \*ProcessService\) CreatePty\(ctx context.Context, id string, opts ...func\(\*options.CreatePty\)\) \(\*PtyHandle, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.CreatePty%3E) - [func \(p \*ProcessService\) CreatePtySession\(ctx context.Context, id string, opts ...func\(\*options.PtySession\)\) \(\*types.PtySessionInfo, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.CreatePtySession%3E) - [func \(p \*ProcessService\) CreateSession\(ctx context.Context, sessionID string\) error](https://www.daytona.io/docs/%3C.md#ProcessService.CreateSession%3E) - [func \(p \*ProcessService\) DeleteSession\(ctx context.Context, sessionID string\) error](https://www.daytona.io/docs/%3C.md#ProcessService.DeleteSession%3E) - [func \(p \*ProcessService\) ExecuteCommand\(ctx context.Context, command string, opts ...func\(\*options.ExecuteCommand\)\) \(\*types.ExecuteResponse, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.ExecuteCommand%3E) - [func \(p \*ProcessService\) ExecuteSessionCommand\(ctx context.Context, sessionID, command string, runAsync bool, suppressInputEcho bool\) \(map\[string\]any, error\)](<#ProcessService.ExecuteSessionCommand>) - [func \(p \*ProcessService\) GetEntrypointLogs\(ctx context.Context\) \(string, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.GetEntrypointLogs%3E) - [func \(p \*ProcessService\) GetEntrypointLogsStream\(ctx context.Context, stdout, stderr chan\<\- string\) error](https://www.daytona.io/docs/%3C.md#ProcessService.GetEntrypointLogsStream%3E) - [func \(p \*ProcessService\) GetEntrypointSession\(ctx context.Context\) \(\*toolbox.Session, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.GetEntrypointSession%3E) - [func \(p \*ProcessService\) GetPtySessionInfo\(ctx context.Context, sessionID string\) \(\*types.PtySessionInfo, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.GetPtySessionInfo%3E) - [func \(p \*ProcessService\) GetSession\(ctx context.Context, sessionID string\) \(map\[string\]any, error\)](<#ProcessService.GetSession>) - [func \(p \*ProcessService\) GetSessionCommand\(ctx context.Context, sessionID, commandID string\) \(map\[string\]any, error\)](<#ProcessService.GetSessionCommand>) - [func \(p \*ProcessService\) GetSessionCommandLogs\(ctx context.Context, sessionID, commandID string\) \(map\[string\]any, error\)](<#ProcessService.GetSessionCommandLogs>) - [func \(p \*ProcessService\) GetSessionCommandLogsStream\(ctx context.Context, sessionID, commandID string, stdout, stderr chan\<\- string\) error](https://www.daytona.io/docs/%3C.md#ProcessService.GetSessionCommandLogsStream%3E) - [func \(p \*ProcessService\) KillPtySession\(ctx context.Context, sessionID string\) error](https://www.daytona.io/docs/%3C.md#ProcessService.KillPtySession%3E) - [func \(p \*ProcessService\) ListPtySessions\(ctx context.Context\) \(\[\]\*types.PtySessionInfo, error\)](<#ProcessService.ListPtySessions>) - [func \(p \*ProcessService\) ListSessions\(ctx context.Context\) \(\[\]map\[string\]any, error\)](<#ProcessService.ListSessions>) - [func \(p \*ProcessService\) ResizePtySession\(ctx context.Context, sessionID string, ptySize types.PtySize\) \(\*types.PtySessionInfo, error\)](https://www.daytona.io/docs/%3C.md#ProcessService.ResizePtySession%3E) - [type PtyHandle](https://www.daytona.io/docs/%3C.md#PtyHandle%3E) - [func \(h \*PtyHandle\) DataChan\(\) \<\-chan \[\]byte](<#PtyHandle.DataChan>) - [func \(h \*PtyHandle\) Disconnect\(\) error](https://www.daytona.io/docs/%3C.md#PtyHandle.Disconnect%3E) - [func \(h \*PtyHandle\) Error\(\) \*string](https://www.daytona.io/docs/%3C.md#PtyHandle.Error%3E) - [func \(h \*PtyHandle\) ExitCode\(\) \*int](https://www.daytona.io/docs/%3C.md#PtyHandle.ExitCode%3E) - [func \(h \*PtyHandle\) IsConnected\(\) bool](https://www.daytona.io/docs/%3C.md#PtyHandle.IsConnected%3E) - [func \(h \*PtyHandle\) Kill\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#PtyHandle.Kill%3E) - [func \(h \*PtyHandle\) Read\(p \[\]byte\) \(n int, err error\)](<#PtyHandle.Read>) - [func \(h \*PtyHandle\) Resize\(ctx context.Context, cols, rows int\) \(\*types.PtySessionInfo, error\)](https://www.daytona.io/docs/%3C.md#PtyHandle.Resize%3E) - [func \(h \*PtyHandle\) SendInput\(data \[\]byte\) error](<#PtyHandle.SendInput>) - [func \(h \*PtyHandle\) SessionID\(\) string](https://www.daytona.io/docs/%3C.md#PtyHandle.SessionID%3E) - [func \(h \*PtyHandle\) Wait\(ctx context.Context\) \(\*types.PtyResult, error\)](https://www.daytona.io/docs/%3C.md#PtyHandle.Wait%3E) - [func \(h \*PtyHandle\) WaitForConnection\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#PtyHandle.WaitForConnection%3E) - [func \(h \*PtyHandle\) Write\(p \[\]byte\) \(n int, err error\)](<#PtyHandle.Write>) - [type PushAccessCredentials](https://www.daytona.io/docs/%3C.md#PushAccessCredentials%3E) - [type RecordingService](https://www.daytona.io/docs/%3C.md#RecordingService%3E) - [func NewRecordingService\(toolboxClient \*toolbox.APIClient\) \*RecordingService](https://www.daytona.io/docs/%3C.md#NewRecordingService%3E) - [func \(r \*RecordingService\) Delete\(ctx context.Context, id string\) error](https://www.daytona.io/docs/%3C.md#RecordingService.Delete%3E) - [func \(r \*RecordingService\) Download\(ctx context.Context, id string, localPath string\) error](https://www.daytona.io/docs/%3C.md#RecordingService.Download%3E) - [func \(r \*RecordingService\) Get\(ctx context.Context, id string\) \(\*toolbox.Recording, error\)](https://www.daytona.io/docs/%3C.md#RecordingService.Get%3E) - [func \(r \*RecordingService\) List\(ctx context.Context\) \(\*toolbox.ListRecordingsResponse, error\)](https://www.daytona.io/docs/%3C.md#RecordingService.List%3E) - [func \(r \*RecordingService\) Start\(ctx context.Context, label \*string\) \(\*toolbox.Recording, error\)](https://www.daytona.io/docs/%3C.md#RecordingService.Start%3E) - [func \(r \*RecordingService\) Stop\(ctx context.Context, id string\) \(\*toolbox.Recording, error\)](https://www.daytona.io/docs/%3C.md#RecordingService.Stop%3E) - [type Sandbox](https://www.daytona.io/docs/%3C.md#Sandbox%3E) - [func NewSandbox\(client \*Client, toolboxClient \*toolbox.APIClient, id string, name string, state apiclient.SandboxState, target string, autoArchiveInterval int, autoDeleteInterval int, networkBlockAll bool, networkAllowList \*string\) \*Sandbox](https://www.daytona.io/docs/%3C.md#NewSandbox%3E) - [func \(s \*Sandbox\) Archive\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#Sandbox.Archive%3E) - [func \(s \*Sandbox\) Delete\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#Sandbox.Delete%3E) - [func \(s \*Sandbox\) DeleteWithTimeout\(ctx context.Context, timeout time.Duration\) error](https://www.daytona.io/docs/%3C.md#Sandbox.DeleteWithTimeout%3E) - [func \(s \*Sandbox\) GetPreviewLink\(ctx context.Context, port int\) \(\*types.PreviewLink, error\)](https://www.daytona.io/docs/%3C.md#Sandbox.GetPreviewLink%3E) - [func \(s \*Sandbox\) GetUserHomeDir\(ctx context.Context\) \(string, error\)](https://www.daytona.io/docs/%3C.md#Sandbox.GetUserHomeDir%3E) - [func \(s \*Sandbox\) GetWorkingDir\(ctx context.Context\) \(string, error\)](https://www.daytona.io/docs/%3C.md#Sandbox.GetWorkingDir%3E) - [func \(s \*Sandbox\) RefreshData\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#Sandbox.RefreshData%3E) - [func \(s \*Sandbox\) Resize\(ctx context.Context, resources \*types.Resources\) error](https://www.daytona.io/docs/%3C.md#Sandbox.Resize%3E) - [func \(s \*Sandbox\) ResizeWithTimeout\(ctx context.Context, resources \*types.Resources, timeout time.Duration\) error](https://www.daytona.io/docs/%3C.md#Sandbox.ResizeWithTimeout%3E) - [func \(s \*Sandbox\) SetAutoArchiveInterval\(ctx context.Context, intervalMinutes \*int\) error](https://www.daytona.io/docs/%3C.md#Sandbox.SetAutoArchiveInterval%3E) - [func \(s \*Sandbox\) SetAutoDeleteInterval\(ctx context.Context, intervalMinutes \*int\) error](https://www.daytona.io/docs/%3C.md#Sandbox.SetAutoDeleteInterval%3E) - [func \(s \*Sandbox\) SetLabels\(ctx context.Context, labels map\[string\]string\) error](<#Sandbox.SetLabels>) - [func \(s \*Sandbox\) Start\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#Sandbox.Start%3E) - [func \(s \*Sandbox\) StartWithTimeout\(ctx context.Context, timeout time.Duration\) error](https://www.daytona.io/docs/%3C.md#Sandbox.StartWithTimeout%3E) - [func \(s \*Sandbox\) Stop\(ctx context.Context\) error](https://www.daytona.io/docs/%3C.md#Sandbox.Stop%3E) - [func \(s \*Sandbox\) StopWithTimeout\(ctx context.Context, timeout time.Duration\) error](https://www.daytona.io/docs/%3C.md#Sandbox.StopWithTimeout%3E) - [func \(s \*Sandbox\) WaitForResize\(ctx context.Context, timeout time.Duration\) error](https://www.daytona.io/docs/%3C.md#Sandbox.WaitForResize%3E) - [func \(s \*Sandbox\) WaitForStart\(ctx context.Context, timeout time.Duration\) error](https://www.daytona.io/docs/%3C.md#Sandbox.WaitForStart%3E) - [func \(s \*Sandbox\) WaitForStop\(ctx context.Context, timeout time.Duration\) error](https://www.daytona.io/docs/%3C.md#Sandbox.WaitForStop%3E) - [type ScreenshotService](https://www.daytona.io/docs/%3C.md#ScreenshotService%3E) - [func NewScreenshotService\(toolboxClient \*toolbox.APIClient, otel \*otelState\) \*ScreenshotService](https://www.daytona.io/docs/%3C.md#NewScreenshotService%3E) - [func \(s \*ScreenshotService\) TakeFullScreen\(ctx context.Context, showCursor \*bool\) \(\*types.ScreenshotResponse, error\)](https://www.daytona.io/docs/%3C.md#ScreenshotService.TakeFullScreen%3E) - [func \(s \*ScreenshotService\) TakeRegion\(ctx context.Context, region types.ScreenshotRegion, showCursor \*bool\) \(\*types.ScreenshotResponse, error\)](https://www.daytona.io/docs/%3C.md#ScreenshotService.TakeRegion%3E) - [type SnapshotService](https://www.daytona.io/docs/%3C.md#SnapshotService%3E) - [func NewSnapshotService\(client \*Client\) \*SnapshotService](https://www.daytona.io/docs/%3C.md#NewSnapshotService%3E) - [func \(s \*SnapshotService\) Create\(ctx context.Context, params \*types.CreateSnapshotParams\) \(\*types.Snapshot, \<\-chan string, error\)](https://www.daytona.io/docs/%3C.md#SnapshotService.Create%3E) - [func \(s \*SnapshotService\) Delete\(ctx context.Context, snapshot \*types.Snapshot\) error](https://www.daytona.io/docs/%3C.md#SnapshotService.Delete%3E) - [func \(s \*SnapshotService\) Get\(ctx context.Context, nameOrID string\) \(\*types.Snapshot, error\)](https://www.daytona.io/docs/%3C.md#SnapshotService.Get%3E) - [func \(s \*SnapshotService\) List\(ctx context.Context, page \*int, limit \*int\) \(\*types.PaginatedSnapshots, error\)](https://www.daytona.io/docs/%3C.md#SnapshotService.List%3E) - [type VolumeService](https://www.daytona.io/docs/%3C.md#VolumeService%3E) - [func NewVolumeService\(client \*Client\) \*VolumeService](https://www.daytona.io/docs/%3C.md#NewVolumeService%3E) - [func \(v \*VolumeService\) Create\(ctx context.Context, name string\) \(\*types.Volume, error\)](https://www.daytona.io/docs/%3C.md#VolumeService.Create%3E) - [func \(v \*VolumeService\) Delete\(ctx context.Context, volume \*types.Volume\) error](https://www.daytona.io/docs/%3C.md#VolumeService.Delete%3E) - [func \(v \*VolumeService\) Get\(ctx context.Context, name string\) \(\*types.Volume, error\)](https://www.daytona.io/docs/%3C.md#VolumeService.Get%3E) - [func \(v \*VolumeService\) List\(ctx context.Context\) \(\[\]\*types.Volume, error\)](<#VolumeService.List>) - [func \(v \*VolumeService\) WaitForReady\(ctx context.Context, volume \*types.Volume, timeout time.Duration\) \(\*types.Volume, error\)](https://www.daytona.io/docs/%3C.md#VolumeService.WaitForReady%3E) ## Variables Version is the semantic version of the Daytona SDK. This value is embedded at build time from the VERSION file. Example: ``` fmt.Printf("Daytona SDK version: %s\n", daytona.Version) ``` ```go var Version = strings.TrimSpace(version) ``` ## type Client Client is the main entry point for interacting with the Daytona platform. Client provides methods to create, retrieve, list, and manage sandboxes. It handles authentication, API communication, and provides access to services like Volume and Snapshot management. Create a Client using [NewClient](https://www.daytona.io/docs/%3C.md#NewClient%3E) or [NewClientWithConfig](https://www.daytona.io/docs/%3C.md#NewClientWithConfig%3E): ``` client, err := daytona.NewClient() if err != nil { log.Fatal(err) } ``` The Client is safe for concurrent use by multiple goroutines. ```go type Client struct { // Otel holds OpenTelemetry state; nil when OTel is disabled. Otel *otelState // Volume provides methods for managing persistent volumes. Volume *VolumeService // Snapshot provides methods for managing sandbox snapshots. Snapshot *SnapshotService // contains filtered or unexported fields } ``` ### func NewClient ```go func NewClient() (*Client, error) ``` NewClient creates a new Daytona client with default configuration. NewClient reads configuration from environment variables: - DAYTONA\_API\_KEY or DAYTONA\_JWT\_TOKEN for authentication \(one is required\) - DAYTONA\_ORGANIZATION\_ID \(required when using JWT token\) - DAYTONA\_API\_URL for custom API endpoint - DAYTONA\_TARGET for target environment For explicit configuration, use [NewClientWithConfig](https://www.daytona.io/docs/%3C.md#NewClientWithConfig%3E) instead. ### func NewClientWithConfig ```go func NewClientWithConfig(config *types.DaytonaConfig) (*Client, error) ``` NewClientWithConfig creates a new Daytona client with a custom configuration. Configuration values provided in config take precedence over environment variables. Any configuration field left empty will fall back to the corresponding environment variable \(see [NewClient](https://www.daytona.io/docs/%3C.md#NewClient%3E) for the list of supported variables\). Example: ``` client, err := daytona.NewClientWithConfig(&types.DaytonaConfig{ APIKey: "your-api-key", APIUrl: "https://custom.daytona.io/api", OrganizationID: "org-123", }) if err != nil { log.Fatal(err) } ``` Returns an error if neither API key nor JWT token is provided, or if JWT token is provided without an organization ID. ### func \(\*Client\) Close ```go func (c *Client) Close(ctx context.Context) error ``` Close shuts down the client and releases resources. When OpenTelemetry is enabled, Close flushes and shuts down the OTel providers. It is safe to call Close even when OTel is not enabled. ### func \(\*Client\) Create ```go func (c *Client) Create(ctx context.Context, params any, opts ...func(*options.CreateSandbox)) (*Sandbox, error) ``` Create creates a new sandbox with the specified parameters. The params argument accepts either \[types.SnapshotParams\] to create from a snapshot, or \[types.ImageParams\] to create from a Docker image: ``` // Create from a snapshot sandbox, err := client.Create(ctx, types.SnapshotParams{ Snapshot: "my-snapshot", SandboxBaseParams: types.SandboxBaseParams{ Name: "my-sandbox", }, }) // Create from a Docker image sandbox, err := client.Create(ctx, types.ImageParams{ Image: "python:3.11", Resources: &types.Resources{ CPU: 2, Memory: 4096, }, }) ``` By default, Create waits for the sandbox to reach the started state before returning. Use \[options.WithWaitForStart\]\(false\) to return immediately after creation. Optional parameters can be configured using functional options: - \[options.WithTimeout\]: Set maximum wait time for creation - \[options.WithWaitForStart\]: Control whether to wait for started state - \[options.WithLogChannel\]: Receive build logs during image builds Returns the created [Sandbox](https://www.daytona.io/docs/%3C.md#Sandbox%3E) or an error if creation fails. ### func \(\*Client\) Get ```go func (c *Client) Get(ctx context.Context, sandboxIDOrName string) (*Sandbox, error) ``` Get retrieves an existing sandbox by its ID or name. The sandboxIDOrName parameter accepts either the sandbox's unique ID or its human\-readable name. If a sandbox with the given identifier is not found, a [errors.DaytonaNotFoundError](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/errors.md#DaytonaNotFoundError%3E) is returned. Example: ``` sandbox, err := client.Get(ctx, "my-sandbox") if err != nil { var notFound *errors.DaytonaNotFoundError if errors.As(err, ¬Found) { log.Println("Sandbox not found") } return err } ``` ### func \(\*Client\) List ```go func (c *Client) List(ctx context.Context, labels map[string]string, page *int, limit *int) (*PaginatedSandboxes, error) ``` List retrieves sandboxes with optional label filtering and pagination. Parameters: - labels: Optional map of labels to filter sandboxes. Pass nil for no filtering. - page: Optional page number \(1\-indexed\). Pass nil for the first page. - limit: Optional number of results per page. Pass nil for the default limit. Example: ``` // List all sandboxes result, err := client.List(ctx, nil, nil, nil) // List sandboxes with pagination page, limit := 1, 10 result, err := client.List(ctx, nil, &page, &limit) // Filter by labels result, err := client.List(ctx, map[string]string{"env": "dev"}, nil, nil) // Iterate through results for _, sandbox := range result.Items { fmt.Printf("Sandbox: %s (state: %s)\n", sandbox.Name, sandbox.State) } ``` Returns a [PaginatedSandboxes](https://www.daytona.io/docs/%3C.md#PaginatedSandboxes%3E) containing the matching sandboxes and pagination metadata. ## type CodeInterpreterService CodeInterpreterService provides Python code execution capabilities for a sandbox. CodeInterpreterService enables running Python code in isolated execution contexts with support for streaming output, persistent state, and environment variables. It uses WebSockets for real\-time output streaming. Access through \[Sandbox.CodeInterpreter\]. Example: ``` // Simple code execution channels, err := sandbox.CodeInterpreter.RunCode(ctx, "print('Hello, World!')") if err != nil { return err } // Wait for completion and get result result := <-channels.Done fmt.Println(result.Stdout) // With persistent context ctxInfo, _ := sandbox.CodeInterpreter.CreateContext(ctx, nil) contextID := ctxInfo["id"].(string) channels, _ = sandbox.CodeInterpreter.RunCode(ctx, "x = 42", options.WithCustomContext(contextID), ) <-channels.Done channels, _ = sandbox.CodeInterpreter.RunCode(ctx, "print(x)", options.WithCustomContext(contextID), ) ``` ```go type CodeInterpreterService struct { // contains filtered or unexported fields } ``` ### func NewCodeInterpreterService ```go func NewCodeInterpreterService(toolboxClient *toolbox.APIClient, otel *otelState) *CodeInterpreterService ``` NewCodeInterpreterService creates a new CodeInterpreterService. This is typically called internally by the SDK when creating a [Sandbox](https://www.daytona.io/docs/%3C.md#Sandbox%3E). Users should access CodeInterpreterService through \[Sandbox.CodeInterpreter\] rather than creating it directly. ### func \(\*CodeInterpreterService\) CreateContext ```go func (c *CodeInterpreterService) CreateContext(ctx context.Context, cwd *string) (map[string]any, error) ``` CreateContext creates an isolated execution context for persistent state. Contexts allow you to maintain state \(variables, imports, etc.\) across multiple code executions. Without a context, each RunCode call starts fresh. Parameters: - cwd: Optional working directory for the context Example: ``` // Create a context ctxInfo, err := sandbox.CodeInterpreter.CreateContext(ctx, nil) if err != nil { return err } contextID := ctxInfo["id"].(string) // Use the context to maintain state sandbox.CodeInterpreter.RunCode(ctx, "x = 42", options.WithCustomContext(contextID)) sandbox.CodeInterpreter.RunCode(ctx, "print(x)", options.WithCustomContext(contextID)) // prints 42 // Clean up when done sandbox.CodeInterpreter.DeleteContext(ctx, contextID) ``` Returns context information including "id", "cwd", "language", "active", and "createdAt". ### func \(\*CodeInterpreterService\) DeleteContext ```go func (c *CodeInterpreterService) DeleteContext(ctx context.Context, contextID string) error ``` DeleteContext removes an execution context and releases its resources. Parameters: - contextID: The context identifier to delete Example: ``` err := sandbox.CodeInterpreter.DeleteContext(ctx, contextID) ``` Returns an error if the context doesn't exist or deletion fails. ### func \(\*CodeInterpreterService\) ListContexts ```go func (c *CodeInterpreterService) ListContexts(ctx context.Context) ([]map[string]any, error) ``` ListContexts returns all active execution contexts. Example: ``` contexts, err := sandbox.CodeInterpreter.ListContexts(ctx) if err != nil { return err } for _, ctx := range contexts { fmt.Printf("Context %s (language: %s)\n", ctx["id"], ctx["language"]) } ``` Returns a slice of context information maps. ### func \(\*CodeInterpreterService\) RunCode ```go func (c *CodeInterpreterService) RunCode(ctx context.Context, code string, opts ...func(*options.RunCode)) (*OutputChannels, error) ``` RunCode executes Python code and returns channels for streaming output. This method establishes a WebSocket connection to execute code asynchronously, streaming stdout and stderr as they become available. Optional parameters can be configured using functional options: - \[options.WithCustomContext\]: Use a persistent context for state - \[options.WithEnv\]: Set environment variables - \[options.WithInterpreterTimeout\]: Set execution timeout Example: ``` // Basic execution channels, err := sandbox.CodeInterpreter.RunCode(ctx, ` for i in range(5): print(f"Count: {i}") `) if err != nil { return err } // Stream output for msg := range channels.Stdout { fmt.Print(msg.Text) } // Get final result result := <-channels.Done if result.Error != nil { fmt.Printf("Error: %s\n", result.Error.Value) } // With options channels, err := sandbox.CodeInterpreter.RunCode(ctx, "import os; print(os.environ['API_KEY'])", options.WithEnv(map[string]string{"API_KEY": "secret"}), options.WithInterpreterTimeout(30*time.Second), ) ``` Returns [OutputChannels](https://www.daytona.io/docs/%3C.md#OutputChannels%3E) for receiving streamed output, or an error if connection fails. ## type ComputerUseService ComputerUseService provides desktop automation operations for a sandbox. ComputerUseService enables GUI automation including mouse control, keyboard input, screenshots, display management, and screen recording. The desktop environment must be started before using these features. Access through \[Sandbox.ComputerUse\]. Example: ``` cu := sandbox.ComputerUse // Start the desktop environment if err := cu.Start(ctx); err != nil { return err } defer cu.Stop(ctx) // Take a screenshot screenshot, err := cu.Screenshot().TakeFullScreen(ctx, nil) if err != nil { return err } // Click at coordinates cu.Mouse().Click(ctx, 100, 200, nil, nil) // Type text cu.Keyboard().Type(ctx, "Hello, World!", nil) ``` ```go type ComputerUseService struct { // contains filtered or unexported fields } ``` ### func NewComputerUseService ```go func NewComputerUseService(toolboxClient *toolbox.APIClient, otel *otelState) *ComputerUseService ``` NewComputerUseService creates a new ComputerUseService. This is typically called internally by the SDK when creating a [Sandbox](https://www.daytona.io/docs/%3C.md#Sandbox%3E). Users should access ComputerUseService through \[Sandbox.ComputerUse\] rather than creating it directly. ### func \(\*ComputerUseService\) Display ```go func (c *ComputerUseService) Display() *DisplayService ``` Display returns the [DisplayService](https://www.daytona.io/docs/%3C.md#DisplayService%3E) for display information. The service is lazily initialized on first access. ### func \(\*ComputerUseService\) GetStatus ```go func (c *ComputerUseService) GetStatus(ctx context.Context) (map[string]any, error) ``` GetStatus returns the current status of the desktop environment. Example: ``` status, err := cu.GetStatus(ctx) if err != nil { return err } fmt.Printf("Desktop status: %v\n", status["status"]) ``` Returns a map containing status information. ### func \(\*ComputerUseService\) Keyboard ```go func (c *ComputerUseService) Keyboard() *KeyboardService ``` Keyboard returns the [KeyboardService](https://www.daytona.io/docs/%3C.md#KeyboardService%3E) for keyboard operations. The service is lazily initialized on first access. ### func \(\*ComputerUseService\) Mouse ```go func (c *ComputerUseService) Mouse() *MouseService ``` Mouse returns the [MouseService](https://www.daytona.io/docs/%3C.md#MouseService%3E) for mouse operations. The service is lazily initialized on first access. ### func \(\*ComputerUseService\) Recording ```go func (c *ComputerUseService) Recording() *RecordingService ``` Recording returns the [RecordingService](https://www.daytona.io/docs/%3C.md#RecordingService%3E) for screen recording operations. The service is lazily initialized on first access. ### func \(\*ComputerUseService\) Screenshot ```go func (c *ComputerUseService) Screenshot() *ScreenshotService ``` Screenshot returns the [ScreenshotService](https://www.daytona.io/docs/%3C.md#ScreenshotService%3E) for capturing screen images. The service is lazily initialized on first access. ### func \(\*ComputerUseService\) Start ```go func (c *ComputerUseService) Start(ctx context.Context) error ``` Start initializes and starts the desktop environment. The desktop environment must be started before using mouse, keyboard, or screenshot operations. Call [ComputerUseService.Stop](https://www.daytona.io/docs/%3C.md#ComputerUseService.Stop%3E) when finished. Example: ``` if err := cu.Start(ctx); err != nil { return err } defer cu.Stop(ctx) ``` Returns an error if the desktop fails to start. ### func \(\*ComputerUseService\) Stop ```go func (c *ComputerUseService) Stop(ctx context.Context) error ``` Stop shuts down the desktop environment and releases resources. Example: ``` err := cu.Stop(ctx) ``` Returns an error if the desktop fails to stop gracefully. ## type DisplayService DisplayService provides display information and window management operations. DisplayService enables querying display configuration and window information. Access through [ComputerUseService.Display](https://www.daytona.io/docs/%3C.md#ComputerUseService.Display%3E). ```go type DisplayService struct { // contains filtered or unexported fields } ``` ### func NewDisplayService ```go func NewDisplayService(toolboxClient *toolbox.APIClient, otel *otelState) *DisplayService ``` NewDisplayService creates a new DisplayService. ### func \(\*DisplayService\) GetInfo ```go func (d *DisplayService) GetInfo(ctx context.Context) (map[string]any, error) ``` GetInfo returns information about connected displays. Example: ``` info, err := display.GetInfo(ctx) if err != nil { return err } displays := info["displays"] fmt.Printf("Connected displays: %v\n", displays) ``` Returns a map containing display information. ### func \(\*DisplayService\) GetWindows ```go func (d *DisplayService) GetWindows(ctx context.Context) (map[string]any, error) ``` GetWindows returns information about open windows. Example: ``` result, err := display.GetWindows(ctx) if err != nil { return err } windows := result["windows"] fmt.Printf("Open windows: %v\n", windows) ``` Returns a map containing window information. ## type DockerImage DockerImage provides a fluent interface for building Docker images declaratively. DockerImage allows you to define Docker images using Go code instead of Dockerfiles. Methods can be chained to build up the image definition, which is then converted to a Dockerfile when used with [SnapshotService.Create](https://www.daytona.io/docs/%3C.md#SnapshotService.Create%3E). Example: ``` // Create a Python image with dependencies image := daytona.Base("python:3.11-slim"). AptGet([]string{"git", "curl"}). PipInstall([]string{"numpy", "pandas"}). Workdir("/app"). Env("PYTHONUNBUFFERED", "1") // Use with snapshot creation snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "my-python-env", DockerImage: image, }) ``` ```go type DockerImage struct { // contains filtered or unexported fields } ``` ### func Base ```go func Base(baseImage string) *DockerImage ``` Base creates a new Image from a base Docker image. This is typically the starting point for building an image definition. The baseImage parameter is any valid Docker image reference. Example: ``` image := daytona.Base("ubuntu:22.04") image := daytona.Base("python:3.11-slim") image := daytona.Base("node:18-alpine") ``` ### func DebianSlim ```go func DebianSlim(pythonVersion *string) *DockerImage ``` DebianSlim creates a Python image based on Debian slim. This is a convenience function for creating Python environments. If pythonVersion is nil, defaults to Python 3.12. Example: ``` // Use default Python 3.12 image := daytona.DebianSlim(nil) // Use specific version version := "3.10" image := daytona.DebianSlim(&version) ``` ### func FromDockerfile ```go func FromDockerfile(dockerfile string) *DockerImage ``` FromDockerfile creates an Image from an existing Dockerfile string. Use this when you have an existing Dockerfile you want to use. Example: ``` dockerfile := `FROM python:3.11 RUN pip install numpy WORKDIR /app` image := daytona.FromDockerfile(dockerfile) ``` ### func \(\*DockerImage\) Add ```go func (img *DockerImage) Add(source, destination string) *DockerImage ``` Add adds an ADD instruction to the image. ADD supports URLs and automatic tar extraction. For simple file copying, prefer [DockerImage.Copy](https://www.daytona.io/docs/%3C.md#DockerImage.Copy%3E). Example: ``` image := daytona.Base("ubuntu:22.04"). Add("https://example.com/app.tar.gz", "/app/") ``` ### func \(\*DockerImage\) AddLocalDir ```go func (img *DockerImage) AddLocalDir(localPath, remotePath string) *DockerImage ``` AddLocalDir adds a local directory to the build context and copies it to the image. The directory is uploaded to object storage and included in the Docker build context. Example: ``` image := daytona.Base("python:3.11"). AddLocalDir("./src", "/app/src") ``` ### func \(\*DockerImage\) AddLocalFile ```go func (img *DockerImage) AddLocalFile(localPath, remotePath string) *DockerImage ``` AddLocalFile adds a local file to the build context and copies it to the image. The file is uploaded to object storage and included in the Docker build context. Example: ``` image := daytona.Base("python:3.11"). AddLocalFile("./requirements.txt", "/app/requirements.txt"). Run("pip install -r /app/requirements.txt") ``` ### func \(\*DockerImage\) AptGet ```go func (img *DockerImage) AptGet(packages []string) *DockerImage ``` AptGet adds an apt\-get install instruction for system packages. This automatically handles updating the package list and cleaning up afterward to minimize image size. Example: ``` image := daytona.Base("ubuntu:22.04").AptGet([]string{"git", "curl", "build-essential"}) ``` ### func \(\*DockerImage\) Cmd ```go func (img *DockerImage) Cmd(cmd []string) *DockerImage ``` Cmd sets the default command for the image. If an entrypoint is set, the cmd provides default arguments to it. Example: ``` image := daytona.Base("python:3.11"). Cmd([]string{"python", "app.py"}) ``` ### func \(\*DockerImage\) Contexts ```go func (img *DockerImage) Contexts() []DockerImageContext ``` Contexts returns the build contexts for local files/directories. This is called internally when creating snapshots to upload local files. ### func \(\*DockerImage\) Copy ```go func (img *DockerImage) Copy(source, destination string) *DockerImage ``` Copy adds a COPY instruction to copy files into the image. For local files, use [DockerImage.AddLocalFile](https://www.daytona.io/docs/%3C.md#DockerImage.AddLocalFile%3E) instead, which handles uploading to the build context. Example: ``` image := daytona.Base("python:3.11"). Copy("requirements.txt", "/app/requirements.txt") ``` ### func \(\*DockerImage\) Dockerfile ```go func (img *DockerImage) Dockerfile() string ``` Dockerfile returns the generated Dockerfile content. This is called internally when creating snapshots. Example: ``` image := daytona.Base("python:3.11").PipInstall([]string{"numpy"}) fmt.Println(image.Dockerfile()) // Output: // FROM python:3.11 // RUN pip install numpy ``` ### func \(\*DockerImage\) Entrypoint ```go func (img *DockerImage) Entrypoint(cmd []string) *DockerImage ``` Entrypoint sets the entrypoint for the image. The cmd parameter is the command and arguments as a slice. Example: ``` image := daytona.Base("python:3.11"). Entrypoint([]string{"python", "-m", "myapp"}) ``` ### func \(\*DockerImage\) Env ```go func (img *DockerImage) Env(key, value string) *DockerImage ``` Env sets an environment variable in the image. Example: ``` image := daytona.Base("python:3.11"). Env("PYTHONUNBUFFERED", "1"). Env("APP_ENV", "production") ``` ### func \(\*DockerImage\) Expose ```go func (img *DockerImage) Expose(ports []int) *DockerImage ``` Expose declares ports that the container listens on. This is documentation for users and tools; it doesn't actually publish ports. Example: ``` image := daytona.Base("python:3.11"). Expose([]int{8080, 8443}) ``` ### func \(\*DockerImage\) Label ```go func (img *DockerImage) Label(key, value string) *DockerImage ``` Label adds metadata to the image. Example: ``` image := daytona.Base("python:3.11"). Label("maintainer", "team@example.com"). Label("version", "1.0.0") ``` ### func \(\*DockerImage\) PipInstall ```go func (img *DockerImage) PipInstall(packages []string, opts ...func(*options.PipInstall)) *DockerImage ``` PipInstall adds a pip install instruction for Python packages. Optional parameters can be configured using functional options: - \[options.WithFindLinks\]: Add find\-links URLs - \[options.WithIndexURL\]: Set custom PyPI index - \[options.WithExtraIndexURLs\]: Add extra index URLs - \[options.WithPre\]: Allow pre\-release versions - \[options.WithExtraOptions\]: Add additional pip options Example: ``` // Basic installation image := daytona.Base("python:3.11").PipInstall([]string{"numpy", "pandas"}) // With options image := daytona.Base("python:3.11").PipInstall( []string{"torch"}, options.WithIndexURL("https://download.pytorch.org/whl/cpu"), options.WithExtraOptions("--no-cache-dir"), ) ``` ### func \(\*DockerImage\) Run ```go func (img *DockerImage) Run(command string) *DockerImage ``` Run adds a RUN instruction to execute a shell command. Example: ``` image := daytona.Base("ubuntu:22.04"). Run("mkdir -p /app/data"). Run("chmod 755 /app") ``` ### func \(\*DockerImage\) User ```go func (img *DockerImage) User(username string) *DockerImage ``` User sets the user for subsequent instructions and container runtime. Example: ``` image := daytona.Base("python:3.11"). Run("useradd -m appuser"). User("appuser"). Workdir("/home/appuser") ``` ### func \(\*DockerImage\) Volume ```go func (img *DockerImage) Volume(paths []string) *DockerImage ``` Volume declares mount points for the container. Example: ``` image := daytona.Base("python:3.11"). Volume([]string{"/data", "/logs"}) ``` ### func \(\*DockerImage\) Workdir ```go func (img *DockerImage) Workdir(path string) *DockerImage ``` Workdir sets the working directory for subsequent instructions. Example: ``` image := daytona.Base("python:3.11"). Workdir("/app"). Run("pip install -r requirements.txt") ``` ## type DockerImageContext DockerImageContext represents a local file or directory to include in the build context. When using [DockerImage.AddLocalFile](https://www.daytona.io/docs/%3C.md#DockerImage.AddLocalFile%3E) or [DockerImage.AddLocalDir](https://www.daytona.io/docs/%3C.md#DockerImage.AddLocalDir%3E), the file/directory is uploaded to object storage and included in the Docker build context. ```go type DockerImageContext struct { SourcePath string // Local path to the file or directory ArchivePath string // Path within the build context archive } ``` ## type FileSystemService FileSystemService provides file system operations for a sandbox. FileSystemService enables file and directory management including creating, reading, writing, moving, and deleting files. It also supports file searching and permission management. Access through \[Sandbox.FileSystem\]. Example: ``` // List files in a directory files, err := sandbox.FileSystem.ListFiles(ctx, "/home/user") // Create a directory err = sandbox.FileSystem.CreateFolder(ctx, "/home/user/mydir") // Upload a file err = sandbox.FileSystem.UploadFile(ctx, "/local/path/file.txt", "/home/user/file.txt") // Download a file data, err := sandbox.FileSystem.DownloadFile(ctx, "/home/user/file.txt", nil) ``` ```go type FileSystemService struct { // contains filtered or unexported fields } ``` ### func NewFileSystemService ```go func NewFileSystemService(toolboxClient *toolbox.APIClient, otel *otelState) *FileSystemService ``` NewFileSystemService creates a new FileSystemService with the provided toolbox client. This is typically called internally by the SDK when creating a [Sandbox](https://www.daytona.io/docs/%3C.md#Sandbox%3E). Users should access FileSystemService through \[Sandbox.FileSystem\] rather than creating it directly. ### func \(\*FileSystemService\) CreateFolder ```go func (f *FileSystemService) CreateFolder(ctx context.Context, path string, opts ...func(*options.CreateFolder)) error ``` CreateFolder creates a directory at the specified path. The path parameter specifies the absolute path for the new directory. Parent directories are created automatically if they don't exist. Optional parameters can be configured using functional options: - \[options.WithMode\]: Set Unix file permissions \(defaults to "0755"\) Example: ``` // Create with default permissions err := sandbox.FileSystem.CreateFolder(ctx, "/home/user/mydir") // Create with custom permissions err := sandbox.FileSystem.CreateFolder(ctx, "/home/user/private", options.WithMode("0700"), ) ``` Returns an error if the directory creation fails. ### func \(\*FileSystemService\) DeleteFile ```go func (f *FileSystemService) DeleteFile(ctx context.Context, path string, recursive bool) error ``` DeleteFile deletes a file or directory. Parameters: - path: The file or directory path to delete - recursive: If true, delete directories and their contents recursively Example: ``` // Delete a file err := sandbox.FileSystem.DeleteFile(ctx, "/home/user/file.txt", false) // Delete a directory recursively err := sandbox.FileSystem.DeleteFile(ctx, "/home/user/mydir", true) ``` Returns an error if the deletion fails \(e.g., path doesn't exist, permission denied, or attempting to delete a non\-empty directory without recursive=true\). ### func \(\*FileSystemService\) DownloadFile ```go func (f *FileSystemService) DownloadFile(ctx context.Context, remotePath string, localPath *string) ([]byte, error) ``` DownloadFile downloads a file from the sandbox. Parameters: - remotePath: The path to the file in the sandbox - localPath: Optional local path to save the file. If nil, only returns the data. Returns the file contents as a byte slice. If localPath is provided, also writes the contents to that local file. Example: ``` // Download and get contents data, err := sandbox.FileSystem.DownloadFile(ctx, "/home/user/file.txt", nil) fmt.Println(string(data)) // Download and save to local file localPath := "/tmp/downloaded.txt" data, err := sandbox.FileSystem.DownloadFile(ctx, "/home/user/file.txt", &localPath) ``` Returns an error if the file doesn't exist or cannot be read. ### func \(\*FileSystemService\) FindFiles ```go func (f *FileSystemService) FindFiles(ctx context.Context, path, pattern string) (any, error) ``` FindFiles searches for text content within files. Parameters: - path: The directory to search in - pattern: The text pattern to search for \(supports regex\) Returns a list of matches, each containing the file path, line number, and matching content. Example: ``` result, err := sandbox.FileSystem.FindFiles(ctx, "/home/user/project", "TODO:") if err != nil { return err } matches := result.([]map[string]any) for _, match := range matches { fmt.Printf("%s:%d: %s\n", match["file"], match["line"], match["content"]) } ``` Returns an error if the search fails. ### func \(\*FileSystemService\) GetFileInfo ```go func (f *FileSystemService) GetFileInfo(ctx context.Context, path string) (*types.FileInfo, error) ``` GetFileInfo retrieves metadata for a file or directory. The path parameter specifies the file or directory path. Returns \[types.FileInfo\] containing the file's name, size, permissions, modification time, and whether it's a directory. Example: ``` info, err := sandbox.FileSystem.GetFileInfo(ctx, "/home/user/file.txt") if err != nil { return err } fmt.Printf("Size: %d bytes, Modified: %s\n", info.Size, info.ModifiedTime) ``` Returns an error if the path doesn't exist. ### func \(\*FileSystemService\) ListFiles ```go func (f *FileSystemService) ListFiles(ctx context.Context, path string) ([]*types.FileInfo, error) ``` ListFiles lists files and directories in the specified path. The path parameter specifies the directory to list. Returns a slice of \[types.FileInfo\] containing metadata for each file and directory, including name, size, permissions, modification time, and whether it's a directory. Example: ``` files, err := sandbox.FileSystem.ListFiles(ctx, "/home/user") if err != nil { return err } for _, file := range files { if file.IsDirectory { fmt.Printf("[DIR] %s\n", file.Name) } else { fmt.Printf("[FILE] %s (%d bytes)\n", file.Name, file.Size) } } ``` Returns an error if the path doesn't exist or isn't accessible. ### func \(\*FileSystemService\) MoveFiles ```go func (f *FileSystemService) MoveFiles(ctx context.Context, source, destination string) error ``` MoveFiles moves or renames a file or directory. Parameters: - source: The current path of the file or directory - destination: The new path for the file or directory This operation can be used for both moving and renaming: - Same directory, different name = rename - Different directory = move Example: ``` // Rename a file err := sandbox.FileSystem.MoveFiles(ctx, "/home/user/old.txt", "/home/user/new.txt") // Move a file to another directory err := sandbox.FileSystem.MoveFiles(ctx, "/home/user/file.txt", "/home/user/backup/file.txt") ``` Returns an error if the operation fails. ### func \(\*FileSystemService\) ReplaceInFiles ```go func (f *FileSystemService) ReplaceInFiles(ctx context.Context, files []string, pattern, newValue string) (any, error) ``` ReplaceInFiles replaces text in multiple files. Parameters: - files: List of file paths to process - pattern: The text pattern to search for \(supports regex\) - newValue: The replacement text Returns a list of results for each file, indicating success or failure. Example: ``` files := []string{"/home/user/file1.txt", "/home/user/file2.txt"} result, err := sandbox.FileSystem.ReplaceInFiles(ctx, files, "oldValue", "newValue") if err != nil { return err } results := result.([]map[string]any) for _, r := range results { if r["success"].(bool) { fmt.Printf("Updated: %s\n", r["file"]) } else { fmt.Printf("Failed: %s - %s\n", r["file"], r["error"]) } } ``` Returns an error if the operation fails entirely. ### func \(\*FileSystemService\) SearchFiles ```go func (f *FileSystemService) SearchFiles(ctx context.Context, path, pattern string) (any, error) ``` SearchFiles searches for files matching a pattern in a directory. Parameters: - path: The directory to search in - pattern: The glob pattern to match file names \(e.g., "\*.txt", "test\_\*"\) Returns a map containing a "files" key with a list of matching file paths. Example: ``` result, err := sandbox.FileSystem.SearchFiles(ctx, "/home/user", "*.go") if err != nil { return err } files := result.(map[string]any)["files"].([]string) for _, file := range files { fmt.Println(file) } ``` Returns an error if the search fails. ### func \(\*FileSystemService\) SetFilePermissions ```go func (f *FileSystemService) SetFilePermissions(ctx context.Context, path string, opts ...func(*options.SetFilePermissions)) error ``` SetFilePermissions sets file permissions, owner, and group. The path parameter specifies the file or directory to modify. Optional parameters can be configured using functional options: - \[options.WithPermissionMode\]: Set Unix file permissions \(e.g., "0644"\) - \[options.WithOwner\]: Set file owner username - \[options.WithGroup\]: Set file group name Example: ``` // Set permissions only err := sandbox.FileSystem.SetFilePermissions(ctx, "/home/user/script.sh", options.WithPermissionMode("0755"), ) // Set owner and group err := sandbox.FileSystem.SetFilePermissions(ctx, "/home/user/file.txt", options.WithOwner("root"), options.WithGroup("users"), ) // Set all at once err := sandbox.FileSystem.SetFilePermissions(ctx, "/home/user/file.txt", options.WithPermissionMode("0640"), options.WithOwner("user"), options.WithGroup("staff"), ) ``` Returns an error if the operation fails. ### func \(\*FileSystemService\) UploadFile ```go func (f *FileSystemService) UploadFile(ctx context.Context, source any, destination string) error ``` UploadFile uploads a file to the sandbox. Parameters: - source: Either a local file path \(string\) or file contents \(\[\]byte\) - destination: The destination path in the sandbox Example: ``` // Upload from local file path err := sandbox.FileSystem.UploadFile(ctx, "/local/path/file.txt", "/home/user/file.txt") // Upload from byte slice content := []byte("Hello, World!") err := sandbox.FileSystem.UploadFile(ctx, content, "/home/user/hello.txt") ``` Returns an error if the upload fails. ## type GitService GitService provides Git operations for a sandbox. GitService enables common Git workflows including cloning repositories, staging and committing changes, managing branches, and syncing with remote repositories. It is accessed through the \[Sandbox.Git\] field. Example: ``` // Clone a repository err := sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "/home/user/repo") // Make changes and commit err = sandbox.Git.Add(ctx, "/home/user/repo", []string{"."}) resp, err := sandbox.Git.Commit(ctx, "/home/user/repo", "Initial commit", "John Doe", "john@example.com") // Push to remote err = sandbox.Git.Push(ctx, "/home/user/repo", options.WithPushUsername("username"), options.WithPushPassword("token"), ) ``` ```go type GitService struct { // contains filtered or unexported fields } ``` ### func NewGitService ```go func NewGitService(toolboxClient *toolbox.APIClient, otel *otelState) *GitService ``` NewGitService creates a new GitService with the provided toolbox client. This is typically called internally by the SDK when creating a [Sandbox](https://www.daytona.io/docs/%3C.md#Sandbox%3E). Users should access GitService through \[Sandbox.Git\] rather than creating it directly. ### func \(\*GitService\) Add ```go func (g *GitService) Add(ctx context.Context, path string, files []string) error ``` Add stages files for the next commit. The path parameter specifies the repository directory. The files parameter is a list of file paths \(relative to the repository root\) to stage. Use "." to stage all changes. Example: ``` // Stage specific files err := sandbox.Git.Add(ctx, "/home/user/repo", []string{"file1.txt", "src/main.go"}) // Stage all changes err := sandbox.Git.Add(ctx, "/home/user/repo", []string{"."}) ``` Returns an error if the add operation fails. ### func \(\*GitService\) Branches ```go func (g *GitService) Branches(ctx context.Context, path string) ([]string, error) ``` Branches lists all branches in a Git repository. The path parameter specifies the repository directory. Example: ``` branches, err := sandbox.Git.Branches(ctx, "/home/user/repo") if err != nil { return err } for _, branch := range branches { fmt.Println(branch) } ``` Returns a slice of branch names or an error if the operation fails. ### func \(\*GitService\) Checkout ```go func (g *GitService) Checkout(ctx context.Context, path, name string) error ``` Checkout switches to a different branch or commit. The path parameter specifies the repository directory. The name parameter specifies the branch name or commit SHA to checkout. Example: ``` // Switch to a branch err := sandbox.Git.Checkout(ctx, "/home/user/repo", "develop") // Checkout a specific commit err := sandbox.Git.Checkout(ctx, "/home/user/repo", "abc123def") ``` Returns an error if the checkout fails \(e.g., branch doesn't exist, uncommitted changes\). ### func \(\*GitService\) Clone ```go func (g *GitService) Clone(ctx context.Context, url, path string, opts ...func(*options.GitClone)) error ``` Clone clones a Git repository into the specified path. The url parameter specifies the repository URL \(HTTPS or SSH format\). The path parameter specifies the destination directory for the cloned repository. Optional parameters can be configured using functional options: - \[options.WithBranch\]: Clone a specific branch instead of the default - \[options.WithCommitId\]: Checkout a specific commit after cloning - \[options.WithUsername\]: Username for authentication \(HTTPS\) - \[options.WithPassword\]: Password or token for authentication \(HTTPS\) Example: ``` // Clone the default branch err := sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "/home/user/repo") // Clone a specific branch with authentication err := sandbox.Git.Clone(ctx, "https://github.com/user/private-repo.git", "/home/user/repo", options.WithBranch("develop"), options.WithUsername("username"), options.WithPassword("github_token"), ) // Clone and checkout a specific commit err := sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "/home/user/repo", options.WithCommitId("abc123"), ) ``` Returns an error if the clone operation fails. ### func \(\*GitService\) Commit ```go func (g *GitService) Commit(ctx context.Context, path, message, author, email string, opts ...func(*options.GitCommit)) (*types.GitCommitResponse, error) ``` Commit creates a new Git commit with the staged changes. Parameters: - path: The repository directory - message: The commit message - author: The author name for the commit - email: The author email for the commit Optional parameters can be configured using functional options: - \[options.WithAllowEmpty\]: Allow creating commits with no changes Example: ``` // Create a commit resp, err := sandbox.Git.Commit(ctx, "/home/user/repo", "Add new feature", "John Doe", "john@example.com", ) if err != nil { return err } fmt.Printf("Created commit: %s\n", resp.SHA) // Create an empty commit resp, err := sandbox.Git.Commit(ctx, "/home/user/repo", "Empty commit for CI trigger", "John Doe", "john@example.com", options.WithAllowEmpty(true), ) ``` Returns the \[types.GitCommitResponse\] containing the commit SHA, or an error if the commit fails. ### func \(\*GitService\) CreateBranch ```go func (g *GitService) CreateBranch(ctx context.Context, path, name string) error ``` CreateBranch creates a new branch at the current HEAD. The path parameter specifies the repository directory. The name parameter specifies the name for the new branch. Note: This creates the branch but does not switch to it. Use [GitService.Checkout](https://www.daytona.io/docs/%3C.md#GitService.Checkout%3E) to switch to the new branch after creation. Example: ``` // Create a new branch err := sandbox.Git.CreateBranch(ctx, "/home/user/repo", "feature/new-feature") if err != nil { return err } // Switch to the new branch err = sandbox.Git.Checkout(ctx, "/home/user/repo", "feature/new-feature") ``` Returns an error if the branch creation fails \(e.g., branch already exists\). ### func \(\*GitService\) DeleteBranch ```go func (g *GitService) DeleteBranch(ctx context.Context, path, name string, opts ...func(*options.GitDeleteBranch)) error ``` DeleteBranch deletes a branch from the repository. The path parameter specifies the repository directory. The name parameter specifies the branch to delete. Optional parameters can be configured using functional options: - \[options.WithForce\]: Force delete the branch even if not fully merged Note: You cannot delete the currently checked out branch. Example: ``` // Delete a merged branch err := sandbox.Git.DeleteBranch(ctx, "/home/user/repo", "feature/old-feature") // Force delete an unmerged branch err := sandbox.Git.DeleteBranch(ctx, "/home/user/repo", "feature/abandoned", options.WithForce(true), ) ``` Returns an error if the deletion fails. ### func \(\*GitService\) Pull ```go func (g *GitService) Pull(ctx context.Context, path string, opts ...func(*options.GitPull)) error ``` Pull fetches and merges changes from the remote repository. The path parameter specifies the repository directory. Optional parameters can be configured using functional options: - \[options.WithPullUsername\]: Username for authentication - \[options.WithPullPassword\]: Password or token for authentication Example: ``` // Pull from a public repository err := sandbox.Git.Pull(ctx, "/home/user/repo") // Pull with authentication err := sandbox.Git.Pull(ctx, "/home/user/repo", options.WithPullUsername("username"), options.WithPullPassword("github_token"), ) ``` Returns an error if the pull fails \(e.g., merge conflicts, authentication failure\). ### func \(\*GitService\) Push ```go func (g *GitService) Push(ctx context.Context, path string, opts ...func(*options.GitPush)) error ``` Push pushes local commits to the remote repository. The path parameter specifies the repository directory. Optional parameters can be configured using functional options: - \[options.WithPushUsername\]: Username for authentication - \[options.WithPushPassword\]: Password or token for authentication Example: ``` // Push to a public repository (no auth required) err := sandbox.Git.Push(ctx, "/home/user/repo") // Push with authentication err := sandbox.Git.Push(ctx, "/home/user/repo", options.WithPushUsername("username"), options.WithPushPassword("github_token"), ) ``` Returns an error if the push fails \(e.g., authentication failure, remote rejection\). ### func \(\*GitService\) Status ```go func (g *GitService) Status(ctx context.Context, path string) (*types.GitStatus, error) ``` Status returns the current Git status of a repository. The path parameter specifies the repository directory to check. The returned \[types.GitStatus\] contains: - CurrentBranch: The name of the currently checked out branch - Ahead: Number of commits ahead of the remote tracking branch - Behind: Number of commits behind the remote tracking branch - BranchPublished: Whether the branch has been pushed to remote - FileStatus: List of files with their staging and working tree status Example: ``` status, err := sandbox.Git.Status(ctx, "/home/user/repo") if err != nil { return err } fmt.Printf("On branch %s\n", status.CurrentBranch) fmt.Printf("Ahead: %d, Behind: %d\n", status.Ahead, status.Behind) for _, file := range status.FileStatus { fmt.Printf("%s %s\n", file.Status, file.Path) } ``` Returns an error if the status operation fails or the path is not a Git repository. ## type KeyboardService KeyboardService provides keyboard input operations. KeyboardService enables typing text, pressing keys, and executing keyboard shortcuts. Access through [ComputerUseService.Keyboard](https://www.daytona.io/docs/%3C.md#ComputerUseService.Keyboard%3E). ```go type KeyboardService struct { // contains filtered or unexported fields } ``` ### func NewKeyboardService ```go func NewKeyboardService(toolboxClient *toolbox.APIClient, otel *otelState) *KeyboardService ``` NewKeyboardService creates a new KeyboardService. ### func \(\*KeyboardService\) Hotkey ```go func (k *KeyboardService) Hotkey(ctx context.Context, keys string) error ``` Hotkey executes a keyboard shortcut. Parameters: - keys: The hotkey combination as a string \(e.g., "ctrl\+c", "alt\+tab"\) Example: ``` // Copy (Ctrl+C) err := keyboard.Hotkey(ctx, "ctrl+c") // Paste (Ctrl+V) err := keyboard.Hotkey(ctx, "ctrl+v") // Switch windows (Alt+Tab) err := keyboard.Hotkey(ctx, "alt+tab") ``` Returns an error if the hotkey fails. ### func \(\*KeyboardService\) Press ```go func (k *KeyboardService) Press(ctx context.Context, key string, modifiers []string) error ``` Press simulates pressing a key with optional modifiers. Parameters: - key: The key to press \(e.g., "a", "Enter", "Tab", "F1"\) - modifiers: Modifier keys to hold \(e.g., "ctrl", "alt", "shift", "meta"\) Example: ``` // Press Enter err := keyboard.Press(ctx, "Enter", nil) // Press Ctrl+S err := keyboard.Press(ctx, "s", []string{"ctrl"}) // Press Ctrl+Shift+N err := keyboard.Press(ctx, "n", []string{"ctrl", "shift"}) ``` Returns an error if the key press fails. ### func \(\*KeyboardService\) Type ```go func (k *KeyboardService) Type(ctx context.Context, text string, delay *int) error ``` Type simulates typing the specified text. Parameters: - text: The text to type - delay: Delay in milliseconds between keystrokes, nil for default Example: ``` // Type text with default speed err := keyboard.Type(ctx, "Hello, World!", nil) // Type with custom delay between keystrokes delay := 50 err := keyboard.Type(ctx, "Slow typing", &delay) ``` Returns an error if typing fails. ## type LspServerService LspServerService provides Language Server Protocol \(LSP\) operations for a sandbox. LspServerService enables IDE\-like features such as code completion, symbol search, and document analysis through LSP. The service manages a language server instance for a specific language and project path. Access through \[Sandbox.Lsp\]. Example: ``` // Get LSP service for Python lsp := sandbox.Lsp(types.LspLanguageIDPython, "/home/user/project") // Start the language server if err := lsp.Start(ctx); err != nil { return err } defer lsp.Stop(ctx) // Open a file for analysis if err := lsp.DidOpen(ctx, "/home/user/project/main.py"); err != nil { return err } // Get code completions completions, err := lsp.Completions(ctx, "/home/user/project/main.py", types.Position{Line: 10, Character: 5}) ``` ```go type LspServerService struct { // contains filtered or unexported fields } ``` ### func NewLspServerService ```go func NewLspServerService(toolboxClient *toolbox.APIClient, languageID types.LspLanguageID, projectPath string, otel *otelState) *LspServerService ``` NewLspServerService creates a new LspServerService. This is typically called internally by the SDK through \[Sandbox.Lsp\]. Users should access LspServerService through \[Sandbox.Lsp\] rather than creating it directly. Parameters: - toolboxClient: The toolbox API client - languageID: The language identifier \(e.g., \[types.LspLanguageIDPython\]\) - projectPath: The root path of the project for LSP analysis ### func \(\*LspServerService\) Completions ```go func (l *LspServerService) Completions(ctx context.Context, path string, position types.Position) (any, error) ``` Completions returns code completion suggestions at a position. The file should be opened with [LspServerService.DidOpen](https://www.daytona.io/docs/%3C.md#LspServerService.DidOpen%3E) before requesting completions. Parameters: - path: Absolute path to the file - position: Cursor position \(line and character, 0\-indexed\) Example: ``` lsp.DidOpen(ctx, "/home/user/project/main.py") completions, err := lsp.Completions(ctx, "/home/user/project/main.py", types.Position{Line: 10, Character: 5}) if err != nil { return err } fmt.Printf("Completions: %v\n", completions) ``` Returns completion items or an error. ### func \(\*LspServerService\) DidClose ```go func (l *LspServerService) DidClose(ctx context.Context, path string) error ``` DidClose notifies the language server that a file was closed. Call this when you're done working with a file to allow the server to release resources associated with it. Parameters: - path: Absolute path to the file Example: ``` err := lsp.DidClose(ctx, "/home/user/project/main.py") ``` Returns an error if the notification fails. ### func \(\*LspServerService\) DidOpen ```go func (l *LspServerService) DidOpen(ctx context.Context, path string) error ``` DidOpen notifies the language server that a file was opened. This should be called before requesting completions or symbols for a file. The path is automatically converted to a file:// URI if needed. Parameters: - path: Absolute path to the file Example: ``` err := lsp.DidOpen(ctx, "/home/user/project/main.py") ``` Returns an error if the notification fails. ### func \(\*LspServerService\) DocumentSymbols ```go func (l *LspServerService) DocumentSymbols(ctx context.Context, path string) ([]any, error) ``` DocumentSymbols returns all symbols \(functions, classes, variables\) in a document. Parameters: - path: Absolute path to the file Example: ``` symbols, err := lsp.DocumentSymbols(ctx, "/home/user/project/main.py") if err != nil { return err } for _, sym := range symbols { fmt.Printf("Symbol: %v\n", sym) } ``` Returns a slice of symbol information or an error. ### func \(\*LspServerService\) SandboxSymbols ```go func (l *LspServerService) SandboxSymbols(ctx context.Context, query string) ([]any, error) ``` SandboxSymbols searches for symbols across the entire workspace. Use this to find symbols \(functions, classes, etc.\) by name across all files in the project. Parameters: - query: Search query to match symbol names Example: ``` symbols, err := lsp.SandboxSymbols(ctx, "MyClass") if err != nil { return err } for _, sym := range symbols { fmt.Printf("Found: %v\n", sym) } ``` Returns a slice of matching symbols or an error. ### func \(\*LspServerService\) Start ```go func (l *LspServerService) Start(ctx context.Context) error ``` Start initializes and starts the language server. The language server must be started before using other LSP operations. Call [LspServerService.Stop](https://www.daytona.io/docs/%3C.md#LspServerService.Stop%3E) when finished to release resources. Example: ``` if err := lsp.Start(ctx); err != nil { return err } defer lsp.Stop(ctx) ``` Returns an error if the server fails to start. ### func \(\*LspServerService\) Stop ```go func (l *LspServerService) Stop(ctx context.Context) error ``` Stop shuts down the language server and releases resources. Example: ``` err := lsp.Stop(ctx) ``` Returns an error if the server fails to stop gracefully. ## type MouseService MouseService provides mouse control operations. MouseService enables cursor movement, clicking, dragging, and scrolling. Access through [ComputerUseService.Mouse](https://www.daytona.io/docs/%3C.md#ComputerUseService.Mouse%3E). ```go type MouseService struct { // contains filtered or unexported fields } ``` ### func NewMouseService ```go func NewMouseService(toolboxClient *toolbox.APIClient, otel *otelState) *MouseService ``` NewMouseService creates a new MouseService. ### func \(\*MouseService\) Click ```go func (m *MouseService) Click(ctx context.Context, x, y int, button *string, double *bool) (map[string]any, error) ``` Click performs a mouse click at the specified coordinates. Parameters: - x: X coordinate to click - y: Y coordinate to click - button: Mouse button \("left", "right", "middle"\), nil for left click - double: Whether to double\-click, nil for single click Example: ``` // Single left click pos, err := mouse.Click(ctx, 100, 200, nil, nil) // Right click button := "right" pos, err := mouse.Click(ctx, 100, 200, &button, nil) // Double click doubleClick := true pos, err := mouse.Click(ctx, 100, 200, nil, &doubleClick) ``` Returns a map with the click "x" and "y" coordinates. ### func \(\*MouseService\) Drag ```go func (m *MouseService) Drag(ctx context.Context, startX, startY, endX, endY int, button *string) (map[string]any, error) ``` Drag performs a mouse drag operation from start to end coordinates. Parameters: - startX, startY: Starting coordinates - endX, endY: Ending coordinates - button: Mouse button to use, nil for left button Example: ``` // Drag from (100, 100) to (300, 300) pos, err := mouse.Drag(ctx, 100, 100, 300, 300, nil) ``` Returns a map with the final "x" and "y" coordinates. ### func \(\*MouseService\) GetPosition ```go func (m *MouseService) GetPosition(ctx context.Context) (map[string]any, error) ``` GetPosition returns the current cursor position. Example: ``` pos, err := mouse.GetPosition(ctx) if err != nil { return err } fmt.Printf("Cursor at (%v, %v)\n", pos["x"], pos["y"]) ``` Returns a map with "x" and "y" coordinates. ### func \(\*MouseService\) Move ```go func (m *MouseService) Move(ctx context.Context, x, y int) (map[string]any, error) ``` Move moves the cursor to the specified coordinates. Parameters: - x: Target X coordinate - y: Target Y coordinate Example: ``` pos, err := mouse.Move(ctx, 500, 300) ``` Returns a map with the new "x" and "y" coordinates. ### func \(\*MouseService\) Scroll ```go func (m *MouseService) Scroll(ctx context.Context, x, y int, direction string, amount *int) (bool, error) ``` Scroll performs a mouse scroll operation at the specified coordinates. Parameters: - x, y: Coordinates where the scroll occurs - direction: Scroll direction \("up", "down", "left", "right"\) - amount: Scroll amount, nil for default Example: ``` // Scroll down at position (500, 400) success, err := mouse.Scroll(ctx, 500, 400, "down", nil) // Scroll up with specific amount amount := 5 success, err := mouse.Scroll(ctx, 500, 400, "up", &amount) ``` Returns true if the scroll was successful. ## type OutputChannels OutputChannels provides channels for streaming execution output. All channels are closed when execution completes or encounters an error. The Done channel always receives exactly one message with the final result. ```go type OutputChannels struct { Stdout <-chan *types.OutputMessage // Receives stdout messages as they occur Stderr <-chan *types.OutputMessage // Receives stderr messages as they occur Errors <-chan *types.ExecutionError // Receives execution errors Done <-chan *types.ExecutionResult // Receives final result when execution completes } ``` ## type PaginatedSandboxes PaginatedSandboxes represents a paginated list of sandboxes. ```go type PaginatedSandboxes struct { Items []*Sandbox // Sandboxes in this page Total int // Total number of sandboxes Page int // Current page number TotalPages int // Total number of pages } ``` ## type ProcessService ProcessService provides process execution operations for a sandbox. ProcessService enables command execution, session management, and PTY \(pseudo\-terminal\) operations. It supports both synchronous command execution and interactive terminal sessions. Access through \[Sandbox.Process\]. Example: ``` // Execute a command result, err := sandbox.Process.ExecuteCommand(ctx, "echo 'Hello, World!'") fmt.Println(result.Result) // Execute with options result, err := sandbox.Process.ExecuteCommand(ctx, "ls -la", options.WithCwd("/home/user/project"), options.WithExecuteTimeout(30*time.Second), ) // Create an interactive PTY session handle, err := sandbox.Process.CreatePty(ctx, "my-terminal") defer handle.Disconnect() ``` ```go type ProcessService struct { // contains filtered or unexported fields } ``` ### func NewProcessService ```go func NewProcessService(toolboxClient *toolbox.APIClient, otel *otelState) *ProcessService ``` NewProcessService creates a new ProcessService with the provided toolbox client. This is typically called internally by the SDK when creating a [Sandbox](https://www.daytona.io/docs/%3C.md#Sandbox%3E). Users should access ProcessService through \[Sandbox.Process\] rather than creating it directly. ### func \(\*ProcessService\) CodeRun ```go func (p *ProcessService) CodeRun(ctx context.Context, code string, opts ...func(*options.CodeRun)) (*types.ExecuteResponse, error) ``` CodeRun executes code in a language\-specific way. NOTE: This method is currently unavailable as the toolbox\-api\-client\-go does not expose a CodeRun endpoint. For code execution, use [ProcessService.ExecuteCommand](https://www.daytona.io/docs/%3C.md#ProcessService.ExecuteCommand%3E) or [CodeInterpreterService](https://www.daytona.io/docs/%3C.md#CodeInterpreterService%3E). Optional parameters can be configured using functional options: - \[options.WithCodeRunParams\]: Set code execution parameters - \[options.WithCodeRunTimeout\]: Set execution timeout ### func \(\*ProcessService\) ConnectPty ```go func (p *ProcessService) ConnectPty(ctx context.Context, sessionID string) (*PtyHandle, error) ``` ConnectPty establishes a WebSocket connection to an existing PTY session. Returns a [PtyHandle](https://www.daytona.io/docs/%3C.md#PtyHandle%3E) for interacting with the terminal. The handle provides: - DataChan\(\): Channel for receiving terminal output - SendInput\(\): Method for sending keyboard input - Resize\(\): Method for changing terminal size - Disconnect\(\): Method for closing the connection Parameters: - sessionID: The PTY session to connect to Example: ``` handle, err := sandbox.Process.ConnectPty(ctx, "my-terminal") if err != nil { return err } defer handle.Disconnect() // Wait for connection if err := handle.WaitForConnection(ctx); err != nil { return err } // Read output for data := range handle.DataChan() { fmt.Print(string(data)) } ``` Returns a [PtyHandle](https://www.daytona.io/docs/%3C.md#PtyHandle%3E) for terminal interaction, or an error. ### func \(\*ProcessService\) CreatePty ```go func (p *ProcessService) CreatePty(ctx context.Context, id string, opts ...func(*options.CreatePty)) (*PtyHandle, error) ``` CreatePty creates a new PTY session and immediately connects to it. This is a convenience method that combines [ProcessService.CreatePtySession](https://www.daytona.io/docs/%3C.md#ProcessService.CreatePtySession%3E) and [ProcessService.ConnectPty](https://www.daytona.io/docs/%3C.md#ProcessService.ConnectPty%3E) into a single operation. Parameters: - id: Unique identifier for the PTY session Optional parameters can be configured using functional options: - \[options.WithCreatePtySize\]: Set terminal dimensions - \[options.WithCreatePtyEnv\]: Set environment variables Example: ``` handle, err := sandbox.Process.CreatePty(ctx, "interactive-shell", options.WithCreatePtySize(types.PtySize{Rows: 24, Cols: 80}), options.WithCreatePtyEnv(map[string]string{"TERM": "xterm-256color"}), ) if err != nil { return err } defer handle.Disconnect() // Wait for connection if err := handle.WaitForConnection(ctx); err != nil { return err } // Send a command handle.SendInput([]byte("ls -la\n")) // Read output for data := range handle.DataChan() { fmt.Print(string(data)) } ``` Returns a [PtyHandle](https://www.daytona.io/docs/%3C.md#PtyHandle%3E) for terminal interaction, or an error. ### func \(\*ProcessService\) CreatePtySession ```go func (p *ProcessService) CreatePtySession(ctx context.Context, id string, opts ...func(*options.PtySession)) (*types.PtySessionInfo, error) ``` CreatePtySession creates a PTY \(pseudo\-terminal\) session. A PTY session provides a terminal interface for interactive applications. Use [ProcessService.ConnectPty](https://www.daytona.io/docs/%3C.md#ProcessService.ConnectPty%3E) to connect to the session after creation. Parameters: - id: Unique identifier for the session Optional parameters can be configured using functional options: - \[options.WithPtySize\]: Set terminal dimensions \(rows and columns\) - \[options.WithPtyEnv\]: Set environment variables Example: ``` // Create with default settings session, err := sandbox.Process.CreatePtySession(ctx, "my-terminal") // Create with custom size session, err := sandbox.Process.CreatePtySession(ctx, "my-terminal", options.WithPtySize(types.PtySize{Rows: 24, Cols: 80}), ) ``` Returns \[types.PtySessionInfo\] containing session details, or an error. ### func \(\*ProcessService\) CreateSession ```go func (p *ProcessService) CreateSession(ctx context.Context, sessionID string) error ``` CreateSession creates a named session for executing multiple commands. Sessions allow you to execute multiple commands while maintaining state \(like environment variables and working directory\) between commands. Example: ``` // Create a session err := sandbox.Process.CreateSession(ctx, "my-session") if err != nil { return err } defer sandbox.Process.DeleteSession(ctx, "my-session") // Execute commands in the session result, err := sandbox.Process.ExecuteSessionCommand(ctx, "my-session", "cd /home/user", false) result, err = sandbox.Process.ExecuteSessionCommand(ctx, "my-session", "pwd", false) ``` Returns an error if session creation fails. ### func \(\*ProcessService\) DeleteSession ```go func (p *ProcessService) DeleteSession(ctx context.Context, sessionID string) error ``` DeleteSession removes a session and releases its resources. The sessionID parameter identifies the session to delete. Example: ``` err := sandbox.Process.DeleteSession(ctx, "my-session") ``` Returns an error if the session doesn't exist or deletion fails. ### func \(\*ProcessService\) ExecuteCommand ```go func (p *ProcessService) ExecuteCommand(ctx context.Context, command string, opts ...func(*options.ExecuteCommand)) (*types.ExecuteResponse, error) ``` ExecuteCommand executes a shell command and returns the result. The command is executed in a shell context. For complex commands, consider using proper shell escaping or wrapping in a script. Optional parameters can be configured using functional options: - \[options.WithCwd\]: Set the working directory for command execution - \[options.WithCommandEnv\]: Set environment variables - \[options.WithExecuteTimeout\]: Set execution timeout Example: ``` // Simple command result, err := sandbox.Process.ExecuteCommand(ctx, "echo 'Hello'") if err != nil { return err } fmt.Println(result.Result) // Command with options result, err := sandbox.Process.ExecuteCommand(ctx, "npm install", options.WithCwd("/home/user/project"), options.WithExecuteTimeout(5*time.Minute), ) // Check exit code if result.ExitCode != 0 { fmt.Printf("Command failed with exit code %d\n", result.ExitCode) } ``` Returns \[types.ExecuteResponse\] containing the output and exit code, or an error. ### func \(\*ProcessService\) ExecuteSessionCommand ```go func (p *ProcessService) ExecuteSessionCommand(ctx context.Context, sessionID, command string, runAsync bool, suppressInputEcho bool) (map[string]any, error) ``` ExecuteSessionCommand executes a command within a session. Parameters: - sessionID: The session to execute the command in - command: The command to execute - runAsync: If true, return immediately without waiting for completion - suppressInputEcho: If true, suppress input echo When runAsync is true, use [ProcessService.GetSessionCommand](https://www.daytona.io/docs/%3C.md#ProcessService.GetSessionCommand%3E) to check status and [ProcessService.GetSessionCommandLogs](https://www.daytona.io/docs/%3C.md#ProcessService.GetSessionCommandLogs%3E) to retrieve output. Example: ``` // Synchronous execution result, err := sandbox.Process.ExecuteSessionCommand(ctx, "my-session", "ls -la", false) if err != nil { return err } fmt.Println(result["stdout"]) // Asynchronous execution result, err := sandbox.Process.ExecuteSessionCommand(ctx, "my-session", "long-running-cmd", true) cmdID := result["id"].(string) // Later: check status with GetSessionCommand(ctx, "my-session", cmdID) ``` Returns command result including id, exitCode \(if completed\), stdout, and stderr. ### func \(\*ProcessService\) GetEntrypointLogs ```go func (p *ProcessService) GetEntrypointLogs(ctx context.Context) (string, error) ``` GetEntrypointLogs retrieves the output logs of the sandbox entrypoint. Example: ``` logs, err := sandbox.Process.GetEntrypointLogs(ctx) if err != nil { return err } fmt.Println(logs) ``` Returns a string containing the entrypoint command output logs. ### func \(\*ProcessService\) GetEntrypointLogsStream ```go func (p *ProcessService) GetEntrypointLogsStream(ctx context.Context, stdout, stderr chan<- string) error ``` GetEntrypointLogsStream streams entrypoint logs as they become available. This method establishes a WebSocket connection to stream sandbox entrypoint logs in real\-time. The stdout and stderr channels receive log chunks as strings and are closed when the stream ends or an error occurs. Parameters: - stdout: Channel to receive stdout output - stderr: Channel to receive stderr output The caller should provide buffered channels to avoid blocking. Example: ``` stdout := make(chan string, 100) stderr := make(chan string, 100) go func() { err := sandbox.Process.GetEntrypointLogsStream(ctx, stdout, stderr) if err != nil { log.Printf("Stream error: %v", err) } }() for { select { case chunk, ok := <-stdout: if !ok { stdout = nil } else { fmt.Print(chunk) } case chunk, ok := <-stderr: if !ok { stderr = nil } else { fmt.Fprint(os.Stderr, chunk) } } if stdout == nil && stderr == nil { break } } ``` Returns an error if the connection fails or stream encounters an error. ### func \(\*ProcessService\) GetEntrypointSession ```go func (p *ProcessService) GetEntrypointSession(ctx context.Context) (*toolbox.Session, error) ``` GetEntrypointSession retrieves information about the entrypoint session. Returns an entrypoint session information containing: - SessionId: The entrypoint session identifier - Commands: List of commands executed in the entrypoint session Example: ``` info, err := sandbox.Process.GetEntrypointSession(ctx) if err != nil { return err } fmt.Printf("Session: %s\n", info.SessionId) ``` Returns an error if the session doesn't exist. ### func \(\*ProcessService\) GetPtySessionInfo ```go func (p *ProcessService) GetPtySessionInfo(ctx context.Context, sessionID string) (*types.PtySessionInfo, error) ``` GetPtySessionInfo retrieves information about a PTY session. Parameters: - sessionID: The PTY session identifier Example: ``` info, err := sandbox.Process.GetPtySessionInfo(ctx, "my-terminal") if err != nil { return err } fmt.Printf("Terminal size: %dx%d\n", info.Cols, info.Rows) ``` Returns \[types.PtySessionInfo\] with session details, or an error. ### func \(\*ProcessService\) GetSession ```go func (p *ProcessService) GetSession(ctx context.Context, sessionID string) (map[string]any, error) ``` GetSession retrieves information about a session. The sessionID parameter identifies the session to query. Returns a map containing: - sessionId: The session identifier - commands: List of commands executed in the session Example: ``` info, err := sandbox.Process.GetSession(ctx, "my-session") if err != nil { return err } fmt.Printf("Session: %s\n", info["sessionId"]) ``` Returns an error if the session doesn't exist. ### func \(\*ProcessService\) GetSessionCommand ```go func (p *ProcessService) GetSessionCommand(ctx context.Context, sessionID, commandID string) (map[string]any, error) ``` GetSessionCommand retrieves the status of a command in a session. Parameters: - sessionID: The session containing the command - commandID: The command identifier \(from ExecuteSessionCommand result\) Example: ``` status, err := sandbox.Process.GetSessionCommand(ctx, "my-session", cmdID) if err != nil { return err } if exitCode, ok := status["exitCode"]; ok { fmt.Printf("Command completed with exit code: %v\n", exitCode) } else { fmt.Println("Command still running") } ``` Returns command status including id, command text, and exitCode \(if completed\). ### func \(\*ProcessService\) GetSessionCommandLogs ```go func (p *ProcessService) GetSessionCommandLogs(ctx context.Context, sessionID, commandID string) (map[string]any, error) ``` GetSessionCommandLogs retrieves the output logs of a command. Parameters: - sessionID: The session containing the command - commandID: The command identifier Example: ``` logs, err := sandbox.Process.GetSessionCommandLogs(ctx, "my-session", cmdID) if err != nil { return err } fmt.Println(logs["logs"]) ``` Returns a map containing the "logs" key with command output. ### func \(\*ProcessService\) GetSessionCommandLogsStream ```go func (p *ProcessService) GetSessionCommandLogsStream(ctx context.Context, sessionID, commandID string, stdout, stderr chan<- string) error ``` GetSessionCommandLogsStream streams command logs as they become available. This method establishes a WebSocket connection to stream logs in real\-time. The stdout and stderr channels receive log chunks as strings and are closed when the stream ends or an error occurs. Parameters: - sessionID: The session containing the command - commandID: The command identifier - stdout: Channel to receive stdout output - stderr: Channel to receive stderr output The caller should provide buffered channels to avoid blocking. Example: ``` stdout := make(chan string, 100) stderr := make(chan string, 100) go func() { err := sandbox.Process.GetSessionCommandLogsStream(ctx, "session", "cmd", stdout, stderr) if err != nil { log.Printf("Stream error: %v", err) } }() for { select { case chunk, ok := <-stdout: if !ok { stdout = nil } else { fmt.Print(chunk) } case chunk, ok := <-stderr: if !ok { stderr = nil } else { fmt.Fprint(os.Stderr, chunk) } } if stdout == nil && stderr == nil { break } } ``` Returns an error if the connection fails or stream encounters an error. ### func \(\*ProcessService\) KillPtySession ```go func (p *ProcessService) KillPtySession(ctx context.Context, sessionID string) error ``` KillPtySession terminates a PTY session. This ends the terminal session and any processes running in it. Parameters: - sessionID: The PTY session to terminate Example: ``` err := sandbox.Process.KillPtySession(ctx, "my-terminal") ``` Returns an error if the session doesn't exist or termination fails. ### func \(\*ProcessService\) ListPtySessions ```go func (p *ProcessService) ListPtySessions(ctx context.Context) ([]*types.PtySessionInfo, error) ``` ListPtySessions returns all active PTY sessions. Example: ``` sessions, err := sandbox.Process.ListPtySessions(ctx) if err != nil { return err } for _, session := range sessions { fmt.Printf("PTY: %s (%dx%d)\n", session.ID, session.Cols, session.Rows) } ``` Returns a slice of \[types.PtySessionInfo\], or an error. ### func \(\*ProcessService\) ListSessions ```go func (p *ProcessService) ListSessions(ctx context.Context) ([]map[string]any, error) ``` ListSessions returns all active sessions. Example: ``` sessions, err := sandbox.Process.ListSessions(ctx) if err != nil { return err } for _, session := range sessions { fmt.Printf("Session: %s\n", session["sessionId"]) } ``` Returns a slice of session information maps, or an error. ### func \(\*ProcessService\) ResizePtySession ```go func (p *ProcessService) ResizePtySession(ctx context.Context, sessionID string, ptySize types.PtySize) (*types.PtySessionInfo, error) ``` ResizePtySession changes the terminal dimensions of a PTY session. This sends a SIGWINCH signal to applications, notifying them of the size change. Parameters: - sessionID: The PTY session to resize - ptySize: New terminal dimensions Example: ``` newSize := types.PtySize{Rows: 40, Cols: 120} info, err := sandbox.Process.ResizePtySession(ctx, "my-terminal", newSize) if err != nil { return err } fmt.Printf("New size: %dx%d\n", info.Cols, info.Rows) ``` Returns updated \[types.PtySessionInfo\], or an error. ## type PtyHandle PtyHandle manages a WebSocket connection to a PTY \(pseudo\-terminal\) session. PtyHandle provides methods for sending input, receiving output via channels, resizing the terminal, and managing the connection lifecycle. It implements [io.Reader](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/io.md#Reader%3E) and [io.Writer](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/io.md#Writer%3E) interfaces for integration with standard Go I/O. Create a PtyHandle using [ProcessService.CreatePty](https://www.daytona.io/docs/%3C.md#ProcessService.CreatePty%3E). Example: ``` // Create a PTY session handle, err := sandbox.Process.CreatePty(ctx, "my-pty", nil) if err != nil { return err } defer handle.Disconnect() // Wait for connection to be established if err := handle.WaitForConnection(ctx); err != nil { return err } // Send input handle.SendInput([]byte("ls -la\n")) // Read output from channel for data := range handle.DataChan() { fmt.Print(string(data)) } // Or use as io.Reader io.Copy(os.Stdout, handle) ``` ```go type PtyHandle struct { // contains filtered or unexported fields } ``` ### func \(\*PtyHandle\) DataChan ```go func (h *PtyHandle) DataChan() <-chan []byte ``` DataChan returns a channel for receiving PTY output. The channel receives raw bytes from the terminal. It is closed when the PTY session ends or the connection is closed. Example: ``` for data := range handle.DataChan() { fmt.Print(string(data)) } ``` ### func \(\*PtyHandle\) Disconnect ```go func (h *PtyHandle) Disconnect() error ``` Disconnect closes the WebSocket connection and releases resources. Call this when done with the PTY session. This does not terminate the underlying process \- use [PtyHandle.Kill](https://www.daytona.io/docs/%3C.md#PtyHandle.Kill%3E) for that. Example: ``` defer handle.Disconnect() ``` Returns an error if the WebSocket close fails. ### func \(\*PtyHandle\) Error ```go func (h *PtyHandle) Error() *string ``` Error returns the error message if the PTY session failed, or nil otherwise. ### func \(\*PtyHandle\) ExitCode ```go func (h *PtyHandle) ExitCode() *int ``` ExitCode returns the exit code of the PTY process, or nil if still running. ### func \(\*PtyHandle\) IsConnected ```go func (h *PtyHandle) IsConnected() bool ``` IsConnected returns true if the WebSocket connection is active. ### func \(\*PtyHandle\) Kill ```go func (h *PtyHandle) Kill(ctx context.Context) error ``` Kill terminates the PTY session and its associated process. This operation is irreversible. The process receives a SIGKILL signal and terminates immediately. Example: ``` err := handle.Kill(ctx) ``` Returns an error if the kill operation fails. ### func \(\*PtyHandle\) Read ```go func (h *PtyHandle) Read(p []byte) (n int, err error) ``` Read implements [io.Reader](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/io.md#Reader%3E) for reading PTY output. This method blocks until data is available or the PTY closes \(returns [io.EOF](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/io.md#EOF%3E)\). Use with [io.Copy](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/io.md#Copy%3E), [bufio.Scanner](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/bufio.md#Scanner%3E), or any standard Go I/O utilities. Example: ``` // Copy all output to stdout io.Copy(os.Stdout, handle) // Use with bufio.Scanner scanner := bufio.NewScanner(handle) for scanner.Scan() { fmt.Println(scanner.Text()) } ``` ### func \(\*PtyHandle\) Resize ```go func (h *PtyHandle) Resize(ctx context.Context, cols, rows int) (*types.PtySessionInfo, error) ``` Resize changes the PTY terminal dimensions. This notifies terminal applications about the new dimensions via SIGWINCH signal. Call this when the terminal display size changes. Parameters: - cols: Number of columns \(width in characters\) - rows: Number of rows \(height in characters\) Example: ``` info, err := handle.Resize(ctx, 120, 40) ``` Returns updated \[types.PtySessionInfo\] or an error. ### func \(\*PtyHandle\) SendInput ```go func (h *PtyHandle) SendInput(data []byte) error ``` SendInput sends input data to the PTY session. The data is sent as raw bytes and will be processed as if typed in the terminal. Use this to send commands, keystrokes, or any terminal input. Example: ``` // Send a command handle.SendInput([]byte("ls -la\n")) // Send Ctrl+C handle.SendInput([]byte{0x03}) ``` Returns an error if the PTY is not connected or sending fails. ### func \(\*PtyHandle\) SessionID ```go func (h *PtyHandle) SessionID() string ``` SessionID returns the unique identifier for this PTY session. ### func \(\*PtyHandle\) Wait ```go func (h *PtyHandle) Wait(ctx context.Context) (*types.PtyResult, error) ``` Wait blocks until the PTY process exits and returns the result. Example: ``` result, err := handle.Wait(ctx) if err != nil { return err } if result.ExitCode != nil { fmt.Printf("Process exited with code: %d\n", *result.ExitCode) } ``` Returns \[types.PtyResult\] with exit code and any error, or an error if the context is cancelled. ### func \(\*PtyHandle\) WaitForConnection ```go func (h *PtyHandle) WaitForConnection(ctx context.Context) error ``` WaitForConnection waits for the WebSocket connection to be established. This method blocks until the PTY session is ready to receive input and send output, or until a timeout \(10 seconds\) expires. Always call this after creating a PTY to ensure the connection is ready. Example: ``` handle, _ := sandbox.Process.CreatePty(ctx, "my-pty", nil) if err := handle.WaitForConnection(ctx); err != nil { return fmt.Errorf("PTY connection failed: %w", err) } ``` Returns an error if the connection times out or fails. ### func \(\*PtyHandle\) Write ```go func (h *PtyHandle) Write(p []byte) (n int, err error) ``` Write implements [io.Writer](https://www.daytona.io/docs/%3Chttps:/pkg.go.dev/io.md#Writer%3E) for sending input to the PTY. Example: ``` // Write directly handle.Write([]byte("echo hello\n")) // Use with io.Copy io.Copy(handle, strings.NewReader("echo hello\n")) ``` ## type PushAccessCredentials PushAccessCredentials holds temporary credentials for uploading to object storage. These credentials are obtained from the API and used for uploading build contexts when creating snapshots with custom [DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage%3E) definitions. ```go type PushAccessCredentials struct { StorageURL string `json:"storageUrl"` AccessKey string `json:"accessKey"` Secret string `json:"secret"` SessionToken string `json:"sessionToken"` Bucket string `json:"bucket"` OrganizationID string `json:"organizationId"` } ``` ## type RecordingService RecordingService provides screen recording operations. RecordingService enables starting, stopping, and managing screen recordings. Access through [ComputerUseService.Recording](https://www.daytona.io/docs/%3C.md#ComputerUseService.Recording%3E). ```go type RecordingService struct { // contains filtered or unexported fields } ``` ### func NewRecordingService ```go func NewRecordingService(toolboxClient *toolbox.APIClient) *RecordingService ``` NewRecordingService creates a new RecordingService. ### func \(\*RecordingService\) Delete ```go func (r *RecordingService) Delete(ctx context.Context, id string) error ``` Delete deletes a recording by ID. Parameters: - id: The ID of the recording to delete Example: ``` err := cu.Recording().Delete(ctx, recordingID) if err != nil { return err } fmt.Println("Recording deleted") ``` Returns an error if the deletion fails. ### func \(\*RecordingService\) Download ```go func (r *RecordingService) Download(ctx context.Context, id string, localPath string) error ``` Download downloads a recording file and saves it to a local path. The file is streamed directly to disk without loading the entire content into memory. Parameters: - id: The ID of the recording to download - localPath: Path to save the recording file locally Example: ``` err := cu.Recording().Download(ctx, recordingID, "local_recording.mp4") if err != nil { return err } fmt.Println("Recording downloaded") ``` Returns an error if the download fails. ### func \(\*RecordingService\) Get ```go func (r *RecordingService) Get(ctx context.Context, id string) (*toolbox.Recording, error) ``` Get gets details of a specific recording by ID. Parameters: - id: The ID of the recording to retrieve Example: ``` recording, err := cu.Recording().Get(ctx, recordingID) if err != nil { return err } fmt.Printf("Recording: %s\n", recording.GetFileName()) fmt.Printf("Status: %s\n", recording.GetStatus()) fmt.Printf("Duration: %v seconds\n", recording.GetDurationSeconds()) ``` Returns \[toolbox.Recording\] with recording details. ### func \(\*RecordingService\) List ```go func (r *RecordingService) List(ctx context.Context) (*toolbox.ListRecordingsResponse, error) ``` List lists all recordings \(active and completed\). Example: ``` recordings, err := cu.Recording().List(ctx) if err != nil { return err } fmt.Printf("Found %d recordings\n", len(recordings.GetRecordings())) for _, rec := range recordings.GetRecordings() { fmt.Printf("- %s: %s\n", rec.GetFileName(), rec.GetStatus()) } ``` Returns \[toolbox.ListRecordingsResponse\] with all recordings. ### func \(\*RecordingService\) Start ```go func (r *RecordingService) Start(ctx context.Context, label *string) (*toolbox.Recording, error) ``` Start starts a new screen recording session. Parameters: - label: Optional custom label for the recording Example: ``` // Start a recording with a label recording, err := cu.Recording().Start(ctx, stringPtr("my-test-recording")) if err != nil { return err } fmt.Printf("Recording started: %s\n", recording.GetId()) fmt.Printf("File: %s\n", recording.GetFilePath()) ``` Returns \[toolbox.Recording\] with recording details. ### func \(\*RecordingService\) Stop ```go func (r *RecordingService) Stop(ctx context.Context, id string) (*toolbox.Recording, error) ``` Stop stops an active screen recording session. Parameters: - id: The ID of the recording to stop Example: ``` result, err := cu.Recording().Stop(ctx, recordingID) if err != nil { return err } fmt.Printf("Recording stopped: %v seconds\n", result.GetDurationSeconds()) fmt.Printf("Saved to: %s\n", result.GetFilePath()) ``` Returns \[toolbox.Recording\] with recording details. ## type Sandbox Sandbox represents a Daytona sandbox environment. A Sandbox provides an isolated development environment with file system, git, process execution, code interpretation, and desktop automation capabilities. Sandboxes can be started, stopped, archived, and deleted. Access sandbox capabilities through the service fields: - FileSystem: File and directory operations - Git: Git repository operations - Process: Command execution and PTY sessions - CodeInterpreter: Python code execution - ComputerUse: Desktop automation \(mouse, keyboard, screenshots\) Example: ``` // Create and use a sandbox sandbox, err := client.Create(ctx) if err != nil { return err } defer sandbox.Delete(ctx) // Execute a command result, err := sandbox.Process.ExecuteCommand(ctx, "echo 'Hello'") // Work with files err = sandbox.FileSystem.UploadFile(ctx, "local.txt", "/home/user/remote.txt") ``` ```go type Sandbox struct { ID string // Unique sandbox identifier Name string // Human-readable sandbox name State apiclient.SandboxState // Current sandbox state Target string // Target region/environment where the sandbox runs ToolboxClient *toolbox.APIClient // Internal API client // AutoArchiveInterval is the time in minutes after stopping before auto-archiving. // Set to 0 to disable auto-archiving. AutoArchiveInterval int // AutoDeleteInterval is the time in minutes after stopping before auto-deletion. // Set to -1 to disable auto-deletion. // Set to 0 to delete immediately upon stopping. AutoDeleteInterval int // NetworkBlockAll blocks all network access when true. NetworkBlockAll bool // NetworkAllowList is a comma-separated list of allowed CIDR addresses. NetworkAllowList *string FileSystem *FileSystemService // File system operations Git *GitService // Git operations Process *ProcessService // Process and PTY operations CodeInterpreter *CodeInterpreterService // Python code execution ComputerUse *ComputerUseService // Desktop automation // contains filtered or unexported fields } ``` ### func NewSandbox ```go func NewSandbox(client *Client, toolboxClient *toolbox.APIClient, id string, name string, state apiclient.SandboxState, target string, autoArchiveInterval int, autoDeleteInterval int, networkBlockAll bool, networkAllowList *string) *Sandbox ``` NewSandbox creates a new Sandbox instance. This is typically called internally by the SDK. Users should create sandboxes using [Client.Create](https://www.daytona.io/docs/%3C.md#Client.Create%3E) rather than calling this directly. ### func \(\*Sandbox\) Archive ```go func (s *Sandbox) Archive(ctx context.Context) error ``` Archive archives the sandbox, preserving its state in cost\-effective storage. When sandboxes are archived, the entire filesystem state is moved to object storage, making it possible to keep sandboxes available for extended periods at reduced cost. Use [Sandbox.Start](https://www.daytona.io/docs/%3C.md#Sandbox.Start%3E) to unarchive and resume. Example: ``` err := sandbox.Archive(ctx) if err != nil { return err } // Sandbox is now archived and can be restored later ``` ### func \(\*Sandbox\) Delete ```go func (s *Sandbox) Delete(ctx context.Context) error ``` Delete deletes the sandbox with a default timeout of 60 seconds. This operation is irreversible. All data in the sandbox will be lost. For custom timeout, use [Sandbox.DeleteWithTimeout](https://www.daytona.io/docs/%3C.md#Sandbox.DeleteWithTimeout%3E). Example: ``` err := sandbox.Delete(ctx) ``` ### func \(\*Sandbox\) DeleteWithTimeout ```go func (s *Sandbox) DeleteWithTimeout(ctx context.Context, timeout time.Duration) error ``` DeleteWithTimeout deletes the sandbox with a custom timeout. 0 means no timeout. Example: ``` err := sandbox.DeleteWithTimeout(ctx, 2*time.Minute) ``` ### func \(\*Sandbox\) GetPreviewLink ```go func (s *Sandbox) GetPreviewLink(ctx context.Context, port int) (*types.PreviewLink, error) ``` GetPreviewLink returns a preview link for accessing a port on the sandbox. The returned PreviewLink contains both the URL and an authentication token. For private sandboxes, the token must be sent via the "x\-daytona\-preview\-token" request header. Example: ``` preview, err := sandbox.GetPreviewLink(ctx, 3000) if err != nil { return err } fmt.Printf("URL: %s\nToken: %s\n", preview.URL, preview.Token) ``` ### func \(\*Sandbox\) GetUserHomeDir ```go func (s *Sandbox) GetUserHomeDir(ctx context.Context) (string, error) ``` GetUserHomeDir returns the user's home directory path in the sandbox. Example: ``` homeDir, err := sandbox.GetUserHomeDir(ctx) if err != nil { return err } fmt.Printf("Home directory: %s\n", homeDir) // e.g., "/home/daytona" ``` ### func \(\*Sandbox\) GetWorkingDir ```go func (s *Sandbox) GetWorkingDir(ctx context.Context) (string, error) ``` GetWorkingDir returns the current working directory in the sandbox. Example: ``` workDir, err := sandbox.GetWorkingDir(ctx) if err != nil { return err } fmt.Printf("Working directory: %s\n", workDir) ``` ### func \(\*Sandbox\) RefreshData ```go func (s *Sandbox) RefreshData(ctx context.Context) error ``` RefreshData refreshes the sandbox data from the API. This updates the sandbox's State and other properties from the server. Useful for checking if the sandbox state has changed. Example: ``` err := sandbox.RefreshData(ctx) if err != nil { return err } fmt.Printf("Current state: %s\n", sandbox.State) ``` ### func \(\*Sandbox\) Resize ```go func (s *Sandbox) Resize(ctx context.Context, resources *types.Resources) error ``` Resize resizes the sandbox resources with a default timeout of 60 seconds. Changes the CPU, memory, or disk allocation for the sandbox. Resizing a started sandbox allows increasing CPU and memory. To resize disk or decrease resources, the sandbox must be stopped first. Example: ``` // Resize a started sandbox (CPU and memory can be increased) err := sandbox.Resize(ctx, &types.Resources{CPU: 4, Memory: 8}) // Resize a stopped sandbox (CPU, memory, and disk can be changed) sandbox.Stop(ctx) err := sandbox.Resize(ctx, &types.Resources{CPU: 2, Memory: 4, Disk: 30}) ``` ### func \(\*Sandbox\) ResizeWithTimeout ```go func (s *Sandbox) ResizeWithTimeout(ctx context.Context, resources *types.Resources, timeout time.Duration) error ``` ResizeWithTimeout resizes the sandbox resources with a custom timeout. Changes the CPU, memory, or disk allocation for the sandbox. Resizing a started sandbox allows increasing CPU and memory. To resize disk or decrease resources, the sandbox must be stopped first. 0 means no timeout. Example: ``` err := sandbox.ResizeWithTimeout(ctx, &types.Resources{CPU: 4, Memory: 8}, 2*time.Minute) ``` ### func \(\*Sandbox\) SetAutoArchiveInterval ```go func (s *Sandbox) SetAutoArchiveInterval(ctx context.Context, intervalMinutes *int) error ``` SetAutoArchiveInterval sets the auto\-archive interval in minutes. The sandbox will be automatically archived after being stopped for this many minutes. Set to 0 to disable auto\-archiving \(sandbox will never auto\-archive\). Example: ``` // Archive after 30 minutes of being stopped interval := 30 err := sandbox.SetAutoArchiveInterval(ctx, &interval) // Disable auto-archiving interval := 0 err := sandbox.SetAutoArchiveInterval(ctx, &interval) ``` ### func \(\*Sandbox\) SetAutoDeleteInterval ```go func (s *Sandbox) SetAutoDeleteInterval(ctx context.Context, intervalMinutes *int) error ``` SetAutoDeleteInterval sets the auto\-delete interval in minutes. The sandbox will be automatically deleted after being stopped for this many minutes. Special values: - \-1: Disable auto\-deletion \(sandbox will never auto\-delete\) - 0: Delete immediately upon stopping Example: ``` // Delete after 60 minutes of being stopped interval := 60 err := sandbox.SetAutoDeleteInterval(ctx, &interval) // Delete immediately when stopped interval := 0 err := sandbox.SetAutoDeleteInterval(ctx, &interval) // Never auto-delete interval := -1 err := sandbox.SetAutoDeleteInterval(ctx, &interval) ``` ### func \(\*Sandbox\) SetLabels ```go func (s *Sandbox) SetLabels(ctx context.Context, labels map[string]string) error ``` SetLabels sets custom labels on the sandbox. Labels are key\-value pairs that can be used for organization and filtering. This replaces all existing labels. Example: ``` err := sandbox.SetLabels(ctx, map[string]string{ "environment": "development", "team": "backend", "project": "api-server", }) ``` ### func \(\*Sandbox\) Start ```go func (s *Sandbox) Start(ctx context.Context) error ``` Start starts the sandbox with a default timeout of 60 seconds. If the sandbox is already running, this is a no\-op. For custom timeout, use [Sandbox.StartWithTimeout](https://www.daytona.io/docs/%3C.md#Sandbox.StartWithTimeout%3E). Example: ``` err := sandbox.Start(ctx) if err != nil { return err } // Sandbox is now running ``` ### func \(\*Sandbox\) StartWithTimeout ```go func (s *Sandbox) StartWithTimeout(ctx context.Context, timeout time.Duration) error ``` StartWithTimeout starts the sandbox with a custom timeout. The method blocks until the sandbox reaches the "started" state or the timeout is exceeded. 0 means no timeout. Example: ``` err := sandbox.StartWithTimeout(ctx, 2*time.Minute) if err != nil { return err } ``` ### func \(\*Sandbox\) Stop ```go func (s *Sandbox) Stop(ctx context.Context) error ``` Stop stops the sandbox with a default timeout of 60 seconds. Stopping a sandbox preserves its state. Use [Sandbox.Start](https://www.daytona.io/docs/%3C.md#Sandbox.Start%3E) to resume. For custom timeout, use [Sandbox.StopWithTimeout](https://www.daytona.io/docs/%3C.md#Sandbox.StopWithTimeout%3E). Example: ``` err := sandbox.Stop(ctx) ``` ### func \(\*Sandbox\) StopWithTimeout ```go func (s *Sandbox) StopWithTimeout(ctx context.Context, timeout time.Duration) error ``` StopWithTimeout stops the sandbox with a custom timeout. The method blocks until the sandbox reaches the "stopped" state or the timeout is exceeded. 0 means no timeout. Example: ``` err := sandbox.StopWithTimeout(ctx, 2*time.Minute) ``` ### func \(\*Sandbox\) WaitForResize ```go func (s *Sandbox) WaitForResize(ctx context.Context, timeout time.Duration) error ``` WaitForResize waits for the sandbox resize operation to complete. This method polls the sandbox state until it's no longer resizing, encounters an error state, or the timeout is exceeded. 0 means no timeout. Example: ``` err := sandbox.WaitForResize(ctx, 2*time.Minute) ``` ### func \(\*Sandbox\) WaitForStart ```go func (s *Sandbox) WaitForStart(ctx context.Context, timeout time.Duration) error ``` WaitForStart waits for the sandbox to reach the "started" state. This method polls the sandbox state until it's started, encounters an error state, or the timeout is exceeded. 0 means no timeout. Example: ``` err := sandbox.WaitForStart(ctx, 2*time.Minute) if err != nil { return err } // Sandbox is now running ``` ### func \(\*Sandbox\) WaitForStop ```go func (s *Sandbox) WaitForStop(ctx context.Context, timeout time.Duration) error ``` WaitForStop waits for the sandbox to reach the "stopped" state. This method polls the sandbox state until it's stopped or the timeout is exceeded. 0 means no timeout. Example: ``` err := sandbox.WaitForStop(ctx, 2*time.Minute) ``` ## type ScreenshotService ScreenshotService provides screen capture operations. ScreenshotService enables capturing full screen or region screenshots. Access through [ComputerUseService.Screenshot](https://www.daytona.io/docs/%3C.md#ComputerUseService.Screenshot%3E). ```go type ScreenshotService struct { // contains filtered or unexported fields } ``` ### func NewScreenshotService ```go func NewScreenshotService(toolboxClient *toolbox.APIClient, otel *otelState) *ScreenshotService ``` NewScreenshotService creates a new ScreenshotService. ### func \(\*ScreenshotService\) TakeFullScreen ```go func (s *ScreenshotService) TakeFullScreen(ctx context.Context, showCursor *bool) (*types.ScreenshotResponse, error) ``` TakeFullScreen captures a screenshot of the entire screen. Parameters: - showCursor: Whether to include the cursor in the screenshot, nil for default Example: ``` // Capture full screen screenshot, err := ss.TakeFullScreen(ctx, nil) if err != nil { return err } // screenshot.Image contains the base64-encoded image data // Capture with cursor visible showCursor := true screenshot, err := ss.TakeFullScreen(ctx, &showCursor) ``` Returns \[types.ScreenshotResponse\] with the captured image. ### func \(\*ScreenshotService\) TakeRegion ```go func (s *ScreenshotService) TakeRegion(ctx context.Context, region types.ScreenshotRegion, showCursor *bool) (*types.ScreenshotResponse, error) ``` TakeRegion captures a screenshot of a specific screen region. Parameters: - region: The region to capture \(X, Y, Width, Height\) - showCursor: Whether to include the cursor in the screenshot, nil for default Example: ``` // Capture a 200x100 region starting at (50, 50) region := types.ScreenshotRegion{X: 50, Y: 50, Width: 200, Height: 100} screenshot, err := ss.TakeRegion(ctx, region, nil) if err != nil { return err } ``` Returns \[types.ScreenshotResponse\] with the captured image. ## type SnapshotService SnapshotService provides snapshot \(image template\) management operations. SnapshotService enables creating, managing, and deleting snapshots that serve as templates for sandboxes. Snapshots can be built from Docker images or custom [DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage%3E) definitions with build contexts. Access through \[Client.Snapshots\]. Example: ``` // Create a snapshot from an existing image snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "my-python-env", Image: "python:3.11-slim", }) if err != nil { return err } // Stream build logs for log := range logChan { fmt.Println(log) } // Create a snapshot from a custom Image definition image := daytona.Base("python:3.11-slim"). PipInstall([]string{"numpy", "pandas"}). Workdir("/app") snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "custom-python-env", Image: image, }) ``` ```go type SnapshotService struct { // contains filtered or unexported fields } ``` ### func NewSnapshotService ```go func NewSnapshotService(client *Client) *SnapshotService ``` NewSnapshotService creates a new SnapshotService. This is typically called internally by the SDK when creating a [Client](https://www.daytona.io/docs/%3C.md#Client%3E). Users should access SnapshotService through \[Client.Snapshots\] rather than creating it directly. ### func \(\*SnapshotService\) Create ```go func (s *SnapshotService) Create(ctx context.Context, params *types.CreateSnapshotParams) (*types.Snapshot, <-chan string, error) ``` Create builds a new snapshot from an image and streams build logs. The image parameter can be either a Docker image reference string \(e.g., "python:3.11"\) or an [DockerImage](https://www.daytona.io/docs/%3C.md#DockerImage%3E) builder object for custom Dockerfile definitions. Parameters: - params: Snapshot creation parameters including name, image, resources, and entrypoint Example: ``` // Create from Docker Hub image snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "my-env", Image: "python:3.11-slim", }) if err != nil { return err } // Stream build logs for log := range logChan { fmt.Println(log) } // Create with custom image and resources image := daytona.Base("python:3.11").PipInstall([]string{"numpy"}) snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "custom-env", Image: image, Resources: &types.Resources{CPU: 2, Memory: 4096}, }) ``` Returns the created \[types.Snapshot\], a channel for streaming build logs, or an error. The log channel is closed when the build completes or fails. ### func \(\*SnapshotService\) Delete ```go func (s *SnapshotService) Delete(ctx context.Context, snapshot *types.Snapshot) error ``` Delete permanently removes a snapshot. Sandboxes created from this snapshot will continue to work, but no new sandboxes can be created from it after deletion. Parameters: - snapshot: The snapshot to delete Example: ``` err := client.Snapshots.Delete(ctx, snapshot) if err != nil { return err } ``` Returns an error if deletion fails. ### func \(\*SnapshotService\) Get ```go func (s *SnapshotService) Get(ctx context.Context, nameOrID string) (*types.Snapshot, error) ``` Get retrieves a snapshot by name or ID. Parameters: - nameOrID: The snapshot name or unique ID Example: ``` snapshot, err := client.Snapshots.Get(ctx, "my-python-env") if err != nil { return err } fmt.Printf("Snapshot %s: %s\n", snapshot.Name, snapshot.State) ``` Returns the \[types.Snapshot\] or an error if not found. ### func \(\*SnapshotService\) List ```go func (s *SnapshotService) List(ctx context.Context, page *int, limit *int) (*types.PaginatedSnapshots, error) ``` List returns snapshots with optional pagination. Parameters: - page: Page number \(1\-indexed\), nil for first page - limit: Maximum snapshots per page, nil for default Example: ``` // List first page with default limit result, err := client.Snapshots.List(ctx, nil, nil) if err != nil { return err } // List with pagination page, limit := 2, 10 result, err := client.Snapshots.List(ctx, &page, &limit) fmt.Printf("Page %d of %d, total: %d\n", result.Page, result.TotalPages, result.Total) ``` Returns \[types.PaginatedSnapshots\] containing the snapshots and pagination info. ## type VolumeService VolumeService provides persistent storage volume management operations. VolumeService enables creating, managing, and deleting persistent storage volumes that can be attached to sandboxes. Volumes persist data independently of sandbox lifecycle and can be shared between sandboxes. Access through \[Client.Volumes\]. Example: ``` // Create a new volume volume, err := client.Volumes.Create(ctx, "my-data-volume") if err != nil { return err } // Wait for volume to be ready volume, err = client.Volumes.WaitForReady(ctx, volume, 60*time.Second) if err != nil { return err } // List all volumes volumes, err := client.Volumes.List(ctx) ``` ```go type VolumeService struct { // contains filtered or unexported fields } ``` ### func NewVolumeService ```go func NewVolumeService(client *Client) *VolumeService ``` NewVolumeService creates a new VolumeService. This is typically called internally by the SDK when creating a [Client](https://www.daytona.io/docs/%3C.md#Client%3E). Users should access VolumeService through \[Client.Volumes\] rather than creating it directly. ### func \(\*VolumeService\) Create ```go func (v *VolumeService) Create(ctx context.Context, name string) (*types.Volume, error) ``` Create creates a new persistent storage volume. The volume starts in "pending" state and transitions to "ready" when available. Use [VolumeService.WaitForReady](https://www.daytona.io/docs/%3C.md#VolumeService.WaitForReady%3E) to wait for the volume to become ready. Parameters: - name: Unique name for the volume Example: ``` volume, err := client.Volumes.Create(ctx, "my-data-volume") if err != nil { return err } // Wait for volume to be ready volume, err = client.Volumes.WaitForReady(ctx, volume, 60*time.Second) ``` Returns the created \[types.Volume\] or an error. ### func \(\*VolumeService\) Delete ```go func (v *VolumeService) Delete(ctx context.Context, volume *types.Volume) error ``` Delete permanently removes a volume and all its data. This operation is irreversible. Ensure no sandboxes are using the volume before deletion. Parameters: - volume: The volume to delete Example: ``` err := client.Volumes.Delete(ctx, volume) if err != nil { return err } ``` Returns an error if deletion fails. ### func \(\*VolumeService\) Get ```go func (v *VolumeService) Get(ctx context.Context, name string) (*types.Volume, error) ``` Get retrieves a volume by its name. Parameters: - name: The volume name Example: ``` volume, err := client.Volumes.Get(ctx, "my-data-volume") if err != nil { return err } fmt.Printf("Volume state: %s\n", volume.State) ``` Returns the \[types.Volume\] or an error if not found. ### func \(\*VolumeService\) List ```go func (v *VolumeService) List(ctx context.Context) ([]*types.Volume, error) ``` List returns all volumes in the organization. Example: ``` volumes, err := client.Volumes.List(ctx) if err != nil { return err } for _, vol := range volumes { fmt.Printf("Volume %s: %s\n", vol.Name, vol.State) } ``` Returns a slice of \[types.Volume\] or an error if the request fails. ### func \(\*VolumeService\) WaitForReady ```go func (v *VolumeService) WaitForReady(ctx context.Context, volume *types.Volume, timeout time.Duration) (*types.Volume, error) ``` WaitForReady waits for a volume to reach the "ready" state. This method polls the volume status until it becomes ready, reaches an error state, or the timeout expires. The polling interval is 1 second. Parameters: - volume: The volume to wait for - timeout: Maximum time to wait for the volume to become ready Example: ``` volume, err := client.Volumes.Create(ctx, "my-volume") if err != nil { return err } // Wait up to 2 minutes for the volume to be ready volume, err = client.Volumes.WaitForReady(ctx, volume, 2*time.Minute) if err != nil { return fmt.Errorf("volume failed to become ready: %w", err) } ``` Returns the updated \[types.Volume\] when ready, or an error if the timeout expires or the volume enters an error state. {/* Code generated by gomarkdoc. DO NOT EDIT */} # errors ```go import "github.com/daytonaio/daytona/libs/sdk-go/pkg/errors" ``` ## Index - [func ConvertAPIError\(err error, httpResp \*http.Response\) error](https://www.daytona.io/docs/%3C.md#ConvertAPIError%3E) - [func ConvertToolboxError\(err error, httpResp \*http.Response\) error](https://www.daytona.io/docs/%3C.md#ConvertToolboxError%3E) - [type DaytonaError](https://www.daytona.io/docs/%3C.md#DaytonaError%3E) - [func NewDaytonaError\(message string, statusCode int, headers http.Header\) \*DaytonaError](https://www.daytona.io/docs/%3C.md#NewDaytonaError%3E) - [func \(e \*DaytonaError\) Error\(\) string](https://www.daytona.io/docs/%3C.md#DaytonaError.Error%3E) - [type DaytonaNotFoundError](https://www.daytona.io/docs/%3C.md#DaytonaNotFoundError%3E) - [func NewDaytonaNotFoundError\(message string, headers http.Header\) \*DaytonaNotFoundError](https://www.daytona.io/docs/%3C.md#NewDaytonaNotFoundError%3E) - [func \(e \*DaytonaNotFoundError\) Error\(\) string](https://www.daytona.io/docs/%3C.md#DaytonaNotFoundError.Error%3E) - [type DaytonaRateLimitError](https://www.daytona.io/docs/%3C.md#DaytonaRateLimitError%3E) - [func NewDaytonaRateLimitError\(message string, headers http.Header\) \*DaytonaRateLimitError](https://www.daytona.io/docs/%3C.md#NewDaytonaRateLimitError%3E) - [func \(e \*DaytonaRateLimitError\) Error\(\) string](https://www.daytona.io/docs/%3C.md#DaytonaRateLimitError.Error%3E) - [type DaytonaTimeoutError](https://www.daytona.io/docs/%3C.md#DaytonaTimeoutError%3E) - [func NewDaytonaTimeoutError\(message string\) \*DaytonaTimeoutError](https://www.daytona.io/docs/%3C.md#NewDaytonaTimeoutError%3E) - [func \(e \*DaytonaTimeoutError\) Error\(\) string](https://www.daytona.io/docs/%3C.md#DaytonaTimeoutError.Error%3E) ## func ConvertAPIError ```go func ConvertAPIError(err error, httpResp *http.Response) error ``` ConvertAPIError converts api\-client\-go errors to SDK error types ## func ConvertToolboxError ```go func ConvertToolboxError(err error, httpResp *http.Response) error ``` ConvertToolboxError converts toolbox\-api\-client\-go errors to SDK error types ## type DaytonaError DaytonaError is the base error type for all Daytona SDK errors ```go type DaytonaError struct { Message string StatusCode int Headers http.Header } ``` ### func NewDaytonaError ```go func NewDaytonaError(message string, statusCode int, headers http.Header) *DaytonaError ``` NewDaytonaError creates a new DaytonaError ### func \(\*DaytonaError\) Error ```go func (e *DaytonaError) Error() string ``` ## type DaytonaNotFoundError DaytonaNotFoundError represents a resource not found error \(404\) ```go type DaytonaNotFoundError struct { *DaytonaError } ``` ### func NewDaytonaNotFoundError ```go func NewDaytonaNotFoundError(message string, headers http.Header) *DaytonaNotFoundError ``` NewDaytonaNotFoundError creates a new DaytonaNotFoundError ### func \(\*DaytonaNotFoundError\) Error ```go func (e *DaytonaNotFoundError) Error() string ``` ## type DaytonaRateLimitError DaytonaRateLimitError represents a rate limit error \(429\) ```go type DaytonaRateLimitError struct { *DaytonaError } ``` ### func NewDaytonaRateLimitError ```go func NewDaytonaRateLimitError(message string, headers http.Header) *DaytonaRateLimitError ``` NewDaytonaRateLimitError creates a new DaytonaRateLimitError ### func \(\*DaytonaRateLimitError\) Error ```go func (e *DaytonaRateLimitError) Error() string ``` ## type DaytonaTimeoutError DaytonaTimeoutError represents a timeout error ```go type DaytonaTimeoutError struct { *DaytonaError } ``` ### func NewDaytonaTimeoutError ```go func NewDaytonaTimeoutError(message string) *DaytonaTimeoutError ``` NewDaytonaTimeoutError creates a new DaytonaTimeoutError ### func \(\*DaytonaTimeoutError\) Error ```go func (e *DaytonaTimeoutError) Error() string ``` The Daytona Go SDK provides a powerful interface for programmatically interacting with Daytona Sandboxes. ## Installation Install the Daytona Go SDK using go get: ```bash go get github.com/daytonaio/daytona/libs/sdk-go ``` ## Getting Started ### Create a Sandbox Create a Daytona Sandbox to run your code securely in an isolated environment. The following snippet is an example "Hello World" program that runs securely inside a Daytona Sandbox. ```go package main import ( "context" "fmt" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) func main() { // Initialize the SDK (uses environment variables by default) client, err := daytona.NewClient() if err != nil { log.Fatal(err) } // Create a new sandbox sandbox, err := client.Create(context.Background(), nil) if err != nil { log.Fatal(err) } // Execute a command response, err := sandbox.Process.ExecuteCommand(context.Background(), "echo 'Hello, World!'") if err != nil { log.Fatal(err) } fmt.Println(response.Result) } ``` ## Configuration The Daytona SDK can be configured using environment variables or by passing options to the constructor: ```go package main import ( "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { // Using environment variables (DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET) client, _ := daytona.NewClient() // Using explicit configuration config := &types.DaytonaConfig{ APIKey: "YOUR_API_KEY", APIUrl: "https://app.daytona.io/api", Target: "us", } client, _ = daytona.NewClientWithConfig(config) } ``` For more information on configuring the Daytona SDK, see [configuration](https://www.daytona.io/docs/en/configuration.md). {/* Code generated by gomarkdoc. DO NOT EDIT */} # options ```go import "github.com/daytonaio/daytona/libs/sdk-go/pkg/options" ``` Package options provides functional option types for configuring SDK operations. This package uses the functional options pattern to provide a clean, extensible API for configuring optional parameters. Each option function returns a closure that modifies the corresponding options struct. ### Usage Options are passed as variadic arguments to SDK methods: ``` err := sandbox.Git.Clone(ctx, url, path, options.WithBranch("develop"), options.WithUsername("user"), options.WithPassword("token"), ) ``` ### Generic Apply Function The [Apply](https://www.daytona.io/docs/%3C.md#Apply%3E) function creates a new options struct and applies all provided option functions to it: ``` opts := options.Apply( options.WithBranch("main"), options.WithUsername("user"), ) // opts.Branch == "main", opts.Username == "user" ``` ## Index - [func Apply\[T any\]\(opts ...func\(\*T\)\) \*T](<#Apply>) - [func WithAllowEmpty\(allowEmpty bool\) func\(\*GitCommit\)](https://www.daytona.io/docs/%3C.md#WithAllowEmpty%3E) - [func WithBranch\(branch string\) func\(\*GitClone\)](https://www.daytona.io/docs/%3C.md#WithBranch%3E) - [func WithCodeRunParams\(params types.CodeRunParams\) func\(\*CodeRun\)](https://www.daytona.io/docs/%3C.md#WithCodeRunParams%3E) - [func WithCodeRunTimeout\(timeout time.Duration\) func\(\*CodeRun\)](https://www.daytona.io/docs/%3C.md#WithCodeRunTimeout%3E) - [func WithCommandEnv\(env map\[string\]string\) func\(\*ExecuteCommand\)](<#WithCommandEnv>) - [func WithCommitId\(commitID string\) func\(\*GitClone\)](https://www.daytona.io/docs/%3C.md#WithCommitId%3E) - [func WithCreatePtyEnv\(env map\[string\]string\) func\(\*CreatePty\)](<#WithCreatePtyEnv>) - [func WithCreatePtySize\(ptySize types.PtySize\) func\(\*CreatePty\)](https://www.daytona.io/docs/%3C.md#WithCreatePtySize%3E) - [func WithCustomContext\(contextID string\) func\(\*RunCode\)](https://www.daytona.io/docs/%3C.md#WithCustomContext%3E) - [func WithCwd\(cwd string\) func\(\*ExecuteCommand\)](https://www.daytona.io/docs/%3C.md#WithCwd%3E) - [func WithEnv\(env map\[string\]string\) func\(\*RunCode\)](<#WithEnv>) - [func WithExecuteTimeout\(timeout time.Duration\) func\(\*ExecuteCommand\)](https://www.daytona.io/docs/%3C.md#WithExecuteTimeout%3E) - [func WithExtraIndexURLs\(urls ...string\) func\(\*PipInstall\)](https://www.daytona.io/docs/%3C.md#WithExtraIndexURLs%3E) - [func WithExtraOptions\(options string\) func\(\*PipInstall\)](https://www.daytona.io/docs/%3C.md#WithExtraOptions%3E) - [func WithFindLinks\(links ...string\) func\(\*PipInstall\)](https://www.daytona.io/docs/%3C.md#WithFindLinks%3E) - [func WithForce\(force bool\) func\(\*GitDeleteBranch\)](https://www.daytona.io/docs/%3C.md#WithForce%3E) - [func WithGroup\(group string\) func\(\*SetFilePermissions\)](https://www.daytona.io/docs/%3C.md#WithGroup%3E) - [func WithIndexURL\(url string\) func\(\*PipInstall\)](https://www.daytona.io/docs/%3C.md#WithIndexURL%3E) - [func WithInterpreterTimeout\(timeout time.Duration\) func\(\*RunCode\)](https://www.daytona.io/docs/%3C.md#WithInterpreterTimeout%3E) - [func WithLogChannel\(logChannel chan string\) func\(\*CreateSandbox\)](https://www.daytona.io/docs/%3C.md#WithLogChannel%3E) - [func WithMode\(mode string\) func\(\*CreateFolder\)](https://www.daytona.io/docs/%3C.md#WithMode%3E) - [func WithOwner\(owner string\) func\(\*SetFilePermissions\)](https://www.daytona.io/docs/%3C.md#WithOwner%3E) - [func WithPassword\(password string\) func\(\*GitClone\)](https://www.daytona.io/docs/%3C.md#WithPassword%3E) - [func WithPermissionMode\(mode string\) func\(\*SetFilePermissions\)](https://www.daytona.io/docs/%3C.md#WithPermissionMode%3E) - [func WithPre\(\) func\(\*PipInstall\)](https://www.daytona.io/docs/%3C.md#WithPre%3E) - [func WithPtyEnv\(env map\[string\]string\) func\(\*PtySession\)](<#WithPtyEnv>) - [func WithPtySize\(size types.PtySize\) func\(\*PtySession\)](https://www.daytona.io/docs/%3C.md#WithPtySize%3E) - [func WithPullPassword\(password string\) func\(\*GitPull\)](https://www.daytona.io/docs/%3C.md#WithPullPassword%3E) - [func WithPullUsername\(username string\) func\(\*GitPull\)](https://www.daytona.io/docs/%3C.md#WithPullUsername%3E) - [func WithPushPassword\(password string\) func\(\*GitPush\)](https://www.daytona.io/docs/%3C.md#WithPushPassword%3E) - [func WithPushUsername\(username string\) func\(\*GitPush\)](https://www.daytona.io/docs/%3C.md#WithPushUsername%3E) - [func WithTimeout\(timeout time.Duration\) func\(\*CreateSandbox\)](https://www.daytona.io/docs/%3C.md#WithTimeout%3E) - [func WithUsername\(username string\) func\(\*GitClone\)](https://www.daytona.io/docs/%3C.md#WithUsername%3E) - [func WithWaitForStart\(waitForStart bool\) func\(\*CreateSandbox\)](https://www.daytona.io/docs/%3C.md#WithWaitForStart%3E) - [type CodeRun](https://www.daytona.io/docs/%3C.md#CodeRun%3E) - [type CreateFolder](https://www.daytona.io/docs/%3C.md#CreateFolder%3E) - [type CreatePty](https://www.daytona.io/docs/%3C.md#CreatePty%3E) - [type CreateSandbox](https://www.daytona.io/docs/%3C.md#CreateSandbox%3E) - [type ExecuteCommand](https://www.daytona.io/docs/%3C.md#ExecuteCommand%3E) - [type GitClone](https://www.daytona.io/docs/%3C.md#GitClone%3E) - [type GitCommit](https://www.daytona.io/docs/%3C.md#GitCommit%3E) - [type GitDeleteBranch](https://www.daytona.io/docs/%3C.md#GitDeleteBranch%3E) - [type GitPull](https://www.daytona.io/docs/%3C.md#GitPull%3E) - [type GitPush](https://www.daytona.io/docs/%3C.md#GitPush%3E) - [type PipInstall](https://www.daytona.io/docs/%3C.md#PipInstall%3E) - [type PtySession](https://www.daytona.io/docs/%3C.md#PtySession%3E) - [type RunCode](https://www.daytona.io/docs/%3C.md#RunCode%3E) - [type SetFilePermissions](https://www.daytona.io/docs/%3C.md#SetFilePermissions%3E) ## func Apply ```go func Apply[T any](https://www.daytona.io/docs/opts%20...func(*T.md)) *T ``` Apply creates a new instance of type T and applies all provided option functions. This generic function enables a consistent pattern for applying functional options across different option types. It allocates a zero\-value instance of T, then applies each option function in order. Example: ``` opts := options.Apply( options.WithBranch("main"), options.WithUsername("user"), ) ``` ## func WithAllowEmpty ```go func WithAllowEmpty(allowEmpty bool) func(*GitCommit) ``` WithAllowEmpty allows creating a commit even when there are no staged changes. This is useful for triggering CI/CD pipelines or marking points in history without actual code changes. Example: ``` resp, err := sandbox.Git.Commit(ctx, path, "Trigger rebuild", author, email, options.WithAllowEmpty(true), ) ``` ## func WithBranch ```go func WithBranch(branch string) func(*GitClone) ``` WithBranch sets the branch to clone instead of the repository's default branch. Example: ``` err := sandbox.Git.Clone(ctx, url, path, options.WithBranch("develop")) ``` ## func WithCodeRunParams ```go func WithCodeRunParams(params types.CodeRunParams) func(*CodeRun) ``` WithCodeRunParams sets the code execution parameters. Example: ``` result, err := sandbox.Process.CodeRun(ctx, code, options.WithCodeRunParams(types.CodeRunParams{Language: "python"}), ) ``` ## func WithCodeRunTimeout ```go func WithCodeRunTimeout(timeout time.Duration) func(*CodeRun) ``` WithCodeRunTimeout sets the timeout for code execution. Example: ``` result, err := sandbox.Process.CodeRun(ctx, code, options.WithCodeRunTimeout(30*time.Second), ) ``` ## func WithCommandEnv ```go func WithCommandEnv(env map[string]string) func(*ExecuteCommand) ``` WithCommandEnv sets environment variables for the command. These variables are added to the command's environment in addition to the sandbox's default environment. Example: ``` result, err := sandbox.Process.ExecuteCommand(ctx, "echo $MY_VAR", options.WithCommandEnv(map[string]string{"MY_VAR": "hello"}), ) ``` ## func WithCommitId ```go func WithCommitId(commitID string) func(*GitClone) ``` WithCommitId sets a specific commit SHA to checkout after cloning. The repository is first cloned, then the specified commit is checked out, resulting in a detached HEAD state. Example: ``` err := sandbox.Git.Clone(ctx, url, path, options.WithCommitId("abc123def")) ``` ## func WithCreatePtyEnv ```go func WithCreatePtyEnv(env map[string]string) func(*CreatePty) ``` WithCreatePtyEnv sets environment variables for CreatePty. Example: ``` handle, err := sandbox.Process.CreatePty(ctx, "my-pty", options.WithCreatePtyEnv(map[string]string{"TERM": "xterm-256color"}), ) ``` ## func WithCreatePtySize ```go func WithCreatePtySize(ptySize types.PtySize) func(*CreatePty) ``` WithCreatePtySize sets the PTY terminal dimensions for CreatePty. Example: ``` handle, err := sandbox.Process.CreatePty(ctx, "my-pty", options.WithCreatePtySize(types.PtySize{Rows: 24, Cols: 80}), ) ``` ## func WithCustomContext ```go func WithCustomContext(contextID string) func(*RunCode) ``` WithCustomContext sets the interpreter context ID for code execution. Using a context allows you to maintain state \(variables, imports, etc.\) across multiple code executions. Create a context with CreateContext first. Example: ``` ctx, _ := sandbox.CodeInterpreter.CreateContext(ctx, nil) channels, err := sandbox.CodeInterpreter.RunCode(ctx, "x = 42", options.WithCustomContext(ctx["id"].(string)), ) ``` ## func WithCwd ```go func WithCwd(cwd string) func(*ExecuteCommand) ``` WithCwd sets the working directory for command execution. Example: ``` result, err := sandbox.Process.ExecuteCommand(ctx, "ls -la", options.WithCwd("/home/user/project"), ) ``` ## func WithEnv ```go func WithEnv(env map[string]string) func(*RunCode) ``` WithEnv sets environment variables for code execution. These variables are available to the code during execution. Example: ``` channels, err := sandbox.CodeInterpreter.RunCode(ctx, "import os; print(os.environ['API_KEY'])", options.WithEnv(map[string]string{"API_KEY": "secret"}), ) ``` ## func WithExecuteTimeout ```go func WithExecuteTimeout(timeout time.Duration) func(*ExecuteCommand) ``` WithExecuteTimeout sets the timeout for command execution. If the command doesn't complete within the timeout, it will be terminated. Example: ``` result, err := sandbox.Process.ExecuteCommand(ctx, "sleep 60", options.WithExecuteTimeout(5*time.Second), ) ``` ## func WithExtraIndexURLs ```go func WithExtraIndexURLs(urls ...string) func(*PipInstall) ``` WithExtraIndexURLs adds extra index URLs for pip install. Extra indexes are checked in addition to the main index URL. Useful for installing packages from both PyPI and a private index. Example: ``` image := daytona.Base("python:3.11").PipInstall( []string{"mypackage"}, options.WithExtraIndexURLs("https://private.example.com/simple/"), ) ``` ## func WithExtraOptions ```go func WithExtraOptions(options string) func(*PipInstall) ``` WithExtraOptions adds extra command\-line options for pip install. Use this for pip options not covered by other With\* functions. Example: ``` image := daytona.Base("python:3.11").PipInstall( []string{"mypackage"}, options.WithExtraOptions("--no-cache-dir --upgrade"), ) ``` ## func WithFindLinks ```go func WithFindLinks(links ...string) func(*PipInstall) ``` WithFindLinks adds find\-links URLs for pip install. Find\-links URLs are searched for packages before the package index. Useful for installing packages from local directories or custom URLs. Example: ``` image := daytona.Base("python:3.11").PipInstall( []string{"mypackage"}, options.WithFindLinks("/path/to/wheels", "https://example.com/wheels/"), ) ``` ## func WithForce ```go func WithForce(force bool) func(*GitDeleteBranch) ``` WithForce enables force deletion of a branch even if it's not fully merged. Use with caution as this can result in lost commits if the branch contains work that hasn't been merged elsewhere. Example: ``` err := sandbox.Git.DeleteBranch(ctx, path, "feature/abandoned", options.WithForce(true), ) ``` ## func WithGroup ```go func WithGroup(group string) func(*SetFilePermissions) ``` WithGroup sets the file group. The group should be a valid group name on the sandbox system. Example: ``` err := sandbox.FileSystem.SetFilePermissions(ctx, "/home/user/file.txt", options.WithGroup("users"), ) ``` ## func WithIndexURL ```go func WithIndexURL(url string) func(*PipInstall) ``` WithIndexURL sets the base URL of the Python Package Index. Replaces the default PyPI \(https://pypi.org/simple\) with a custom index. Example: ``` image := daytona.Base("python:3.11").PipInstall( []string{"mypackage"}, options.WithIndexURL("https://my-pypi.example.com/simple/"), ) ``` ## func WithInterpreterTimeout ```go func WithInterpreterTimeout(timeout time.Duration) func(*RunCode) ``` WithInterpreterTimeout sets the execution timeout for code. If the code doesn't complete within the timeout, execution is terminated. Example: ``` channels, err := sandbox.CodeInterpreter.RunCode(ctx, "import time; time.sleep(60)", options.WithInterpreterTimeout(5*time.Second), ) ``` ## func WithLogChannel ```go func WithLogChannel(logChannel chan string) func(*CreateSandbox) ``` WithLogChannel provides a channel for receiving build logs during sandbox creation. When creating a sandbox from a custom image that requires building, build logs are streamed to the provided channel. The channel is closed when streaming completes. If no build is required, no logs are sent and the channel remains unused. Example: ``` logChan := make(chan string) go func() { for log := range logChan { fmt.Println(log) } }() sandbox, err := client.Create(ctx, params, options.WithLogChannel(logChan), ) ``` ## func WithMode ```go func WithMode(mode string) func(*CreateFolder) ``` WithMode sets the Unix file permissions for the created folder. The mode should be specified as an octal string \(e.g., "0755", "0700"\). If not specified, defaults to "0755". Example: ``` err := sandbox.FileSystem.CreateFolder(ctx, "/home/user/mydir", options.WithMode("0700"), ) ``` ## func WithOwner ```go func WithOwner(owner string) func(*SetFilePermissions) ``` WithOwner sets the file owner. The owner should be a valid username on the sandbox system. Example: ``` err := sandbox.FileSystem.SetFilePermissions(ctx, "/home/user/file.txt", options.WithOwner("root"), ) ``` ## func WithPassword ```go func WithPassword(password string) func(*GitClone) ``` WithPassword sets the password or access token for HTTPS authentication when cloning. For GitHub, use a Personal Access Token \(PAT\). For GitLab, use a Project Access Token or Personal Access Token. For Bitbucket, use an App Password. Example: ``` err := sandbox.Git.Clone(ctx, url, path, options.WithUsername("username"), options.WithPassword("ghp_xxxxxxxxxxxx"), ) ``` ## func WithPermissionMode ```go func WithPermissionMode(mode string) func(*SetFilePermissions) ``` WithPermissionMode sets the Unix file permissions. The mode should be specified as an octal string \(e.g., "0644", "0755"\). Example: ``` err := sandbox.FileSystem.SetFilePermissions(ctx, "/home/user/file.txt", options.WithPermissionMode("0644"), ) ``` ## func WithPre ```go func WithPre() func(*PipInstall) ``` WithPre enables installation of pre\-release and development versions. Example: ``` image := daytona.Base("python:3.11").PipInstall( []string{"mypackage"}, options.WithPre(), ) ``` ## func WithPtyEnv ```go func WithPtyEnv(env map[string]string) func(*PtySession) ``` WithPtyEnv sets environment variables for the PTY session. Example: ``` session, err := sandbox.Process.CreatePtySession(ctx, "my-session", options.WithPtyEnv(map[string]string{"TERM": "xterm-256color"}), ) ``` ## func WithPtySize ```go func WithPtySize(size types.PtySize) func(*PtySession) ``` WithPtySize sets the PTY terminal dimensions. Example: ``` session, err := sandbox.Process.CreatePtySession(ctx, "my-session", options.WithPtySize(types.PtySize{Rows: 24, Cols: 80}), ) ``` ## func WithPullPassword ```go func WithPullPassword(password string) func(*GitPull) ``` WithPullPassword sets the password or access token for HTTPS authentication when pulling. Example: ``` err := sandbox.Git.Pull(ctx, path, options.WithPullUsername("username"), options.WithPullPassword("ghp_xxxxxxxxxxxx"), ) ``` ## func WithPullUsername ```go func WithPullUsername(username string) func(*GitPull) ``` WithPullUsername sets the username for HTTPS authentication when pulling. Example: ``` err := sandbox.Git.Pull(ctx, path, options.WithPullUsername("username"), options.WithPullPassword("github_token"), ) ``` ## func WithPushPassword ```go func WithPushPassword(password string) func(*GitPush) ``` WithPushPassword sets the password or access token for HTTPS authentication when pushing. Example: ``` err := sandbox.Git.Push(ctx, path, options.WithPushUsername("username"), options.WithPushPassword("ghp_xxxxxxxxxxxx"), ) ``` ## func WithPushUsername ```go func WithPushUsername(username string) func(*GitPush) ``` WithPushUsername sets the username for HTTPS authentication when pushing. Example: ``` err := sandbox.Git.Push(ctx, path, options.WithPushUsername("username"), options.WithPushPassword("github_token"), ) ``` ## func WithTimeout ```go func WithTimeout(timeout time.Duration) func(*CreateSandbox) ``` WithTimeout sets the maximum duration to wait for sandbox creation to complete. If the timeout is exceeded before the sandbox is ready, Create returns an error. The default timeout is 60 seconds. Example: ``` sandbox, err := client.Create(ctx, params, options.WithTimeout(5*time.Minute), ) ``` ## func WithUsername ```go func WithUsername(username string) func(*GitClone) ``` WithUsername sets the username for HTTPS authentication when cloning. For GitHub, GitLab, and similar services, the username is typically your account username or a placeholder like "git" when using tokens. Example: ``` err := sandbox.Git.Clone(ctx, url, path, options.WithUsername("username"), options.WithPassword("github_token"), ) ``` ## func WithWaitForStart ```go func WithWaitForStart(waitForStart bool) func(*CreateSandbox) ``` WithWaitForStart controls whether \[daytona.Client.Create\] waits for the sandbox to reach the started state before returning. When true \(the default\), Create blocks until the sandbox is fully started and ready for use. When false, Create returns immediately after the sandbox is created, which may be in a pending or building state. Example: ``` // Return immediately without waiting for the sandbox to start sandbox, err := client.Create(ctx, params, options.WithWaitForStart(false), ) ``` ## type CodeRun CodeRun holds optional parameters for \[daytona.ProcessService.CodeRun\]. ```go type CodeRun struct { Params *types.CodeRunParams // Code execution parameters Timeout *time.Duration // Execution timeout } ``` ## type CreateFolder CreateFolder holds optional parameters for \[daytona.FileSystemService.CreateFolder\]. ```go type CreateFolder struct { Mode *string // Unix file permissions (e.g., "0755") } ``` ## type CreatePty CreatePty holds optional parameters for \[daytona.ProcessService.CreatePty\]. ```go type CreatePty struct { PtySize *types.PtySize // Terminal dimensions (rows and columns) Env map[string]string // Environment variables for the PTY session } ``` ## type CreateSandbox CreateSandbox holds optional parameters for \[daytona.Client.Create\]. ```go type CreateSandbox struct { Timeout *time.Duration // Maximum time to wait for sandbox creation WaitForStart bool // Whether to wait for the sandbox to reach started state LogChannel chan string // Channel for receiving build logs during image builds } ``` ## type ExecuteCommand ExecuteCommand holds optional parameters for \[daytona.ProcessService.ExecuteCommand\]. ```go type ExecuteCommand struct { Cwd *string // Working directory for command execution Env map[string]string // Environment variables Timeout *time.Duration // Command execution timeout } ``` ## type GitClone GitClone holds optional parameters for \[daytona.GitService.Clone\]. Fields are pointers to distinguish between unset values and zero values. Use the corresponding With\* functions to set these options. ```go type GitClone struct { Branch *string // Branch to clone (defaults to repository's default branch) CommitId *string // Specific commit SHA to checkout after cloning Username *string // Username for HTTPS authentication Password *string // Password or token for HTTPS authentication } ``` ## type GitCommit GitCommit holds optional parameters for \[daytona.GitService.Commit\]. ```go type GitCommit struct { AllowEmpty *bool // Allow creating commits with no staged changes } ``` ## type GitDeleteBranch GitDeleteBranch holds optional parameters for \[daytona.GitService.DeleteBranch\]. ```go type GitDeleteBranch struct { Force *bool // Force delete even if branch is not fully merged } ``` ## type GitPull GitPull holds optional parameters for \[daytona.GitService.Pull\]. ```go type GitPull struct { Username *string // Username for HTTPS authentication Password *string // Password or token for HTTPS authentication } ``` ## type GitPush GitPush holds optional parameters for \[daytona.GitService.Push\]. ```go type GitPush struct { Username *string // Username for HTTPS authentication Password *string // Password or token for HTTPS authentication } ``` ## type PipInstall PipInstall holds optional parameters for \[daytona.Image.PipInstall\]. ```go type PipInstall struct { FindLinks []string // URLs to search for packages IndexURL string // Base URL of the Python Package Index ExtraIndexURLs []string // Extra index URLs for package lookup Pre bool // Allow pre-release and development versions ExtraOptions string // Additional pip command-line options } ``` ## type PtySession PtySession holds optional parameters for \[daytona.ProcessService.CreatePtySession\]. ```go type PtySession struct { PtySize *types.PtySize // Terminal dimensions (rows and columns) Env map[string]string // Environment variables for the PTY session } ``` ## type RunCode RunCode holds optional parameters for \[daytona.CodeInterpreterService.RunCode\]. ```go type RunCode struct { ContextID string // Interpreter context ID for persistent state Env map[string]string // Environment variables for code execution Timeout *time.Duration // Execution timeout } ``` ## type SetFilePermissions SetFilePermissions holds optional parameters for \[daytona.FileSystemService.SetFilePermissions\]. ```go type SetFilePermissions struct { Mode *string // Unix file permissions (e.g., "0644") Owner *string // File owner username Group *string // File group name } ``` {/* Code generated by gomarkdoc. DO NOT EDIT */} # types ```go import "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ``` ## Index - [type Chart](https://www.daytona.io/docs/%3C.md#Chart%3E) - [type ChartType](https://www.daytona.io/docs/%3C.md#ChartType%3E) - [type CodeLanguage](https://www.daytona.io/docs/%3C.md#CodeLanguage%3E) - [type CodeRunParams](https://www.daytona.io/docs/%3C.md#CodeRunParams%3E) - [type CreateSnapshotParams](https://www.daytona.io/docs/%3C.md#CreateSnapshotParams%3E) - [type DaytonaConfig](https://www.daytona.io/docs/%3C.md#DaytonaConfig%3E) - [type ExecuteResponse](https://www.daytona.io/docs/%3C.md#ExecuteResponse%3E) - [type ExecutionArtifacts](https://www.daytona.io/docs/%3C.md#ExecutionArtifacts%3E) - [type ExecutionError](https://www.daytona.io/docs/%3C.md#ExecutionError%3E) - [type ExecutionResult](https://www.daytona.io/docs/%3C.md#ExecutionResult%3E) - [type ExperimentalConfig](https://www.daytona.io/docs/%3C.md#ExperimentalConfig%3E) - [type FileDownloadRequest](https://www.daytona.io/docs/%3C.md#FileDownloadRequest%3E) - [type FileDownloadResponse](https://www.daytona.io/docs/%3C.md#FileDownloadResponse%3E) - [type FileInfo](https://www.daytona.io/docs/%3C.md#FileInfo%3E) - [type FileStatus](https://www.daytona.io/docs/%3C.md#FileStatus%3E) - [type FileUpload](https://www.daytona.io/docs/%3C.md#FileUpload%3E) - [type GitCommitResponse](https://www.daytona.io/docs/%3C.md#GitCommitResponse%3E) - [type GitStatus](https://www.daytona.io/docs/%3C.md#GitStatus%3E) - [type ImageParams](https://www.daytona.io/docs/%3C.md#ImageParams%3E) - [type LspLanguageID](https://www.daytona.io/docs/%3C.md#LspLanguageID%3E) - [type OutputMessage](https://www.daytona.io/docs/%3C.md#OutputMessage%3E) - [type PaginatedSnapshots](https://www.daytona.io/docs/%3C.md#PaginatedSnapshots%3E) - [type Position](https://www.daytona.io/docs/%3C.md#Position%3E) - [type PreviewLink](https://www.daytona.io/docs/%3C.md#PreviewLink%3E) - [type PtyResult](https://www.daytona.io/docs/%3C.md#PtyResult%3E) - [type PtySessionInfo](https://www.daytona.io/docs/%3C.md#PtySessionInfo%3E) - [type PtySize](https://www.daytona.io/docs/%3C.md#PtySize%3E) - [type Resources](https://www.daytona.io/docs/%3C.md#Resources%3E) - [type SandboxBaseParams](https://www.daytona.io/docs/%3C.md#SandboxBaseParams%3E) - [type ScreenshotOptions](https://www.daytona.io/docs/%3C.md#ScreenshotOptions%3E) - [type ScreenshotRegion](https://www.daytona.io/docs/%3C.md#ScreenshotRegion%3E) - [type ScreenshotResponse](https://www.daytona.io/docs/%3C.md#ScreenshotResponse%3E) - [type Snapshot](https://www.daytona.io/docs/%3C.md#Snapshot%3E) - [type SnapshotParams](https://www.daytona.io/docs/%3C.md#SnapshotParams%3E) - [type Volume](https://www.daytona.io/docs/%3C.md#Volume%3E) - [type VolumeMount](https://www.daytona.io/docs/%3C.md#VolumeMount%3E) ## type Chart Chart represents a chart ```go type Chart struct { Type ChartType Title string Elements any PNG *string // Optional base64-encoded PNG representation } ``` ## type ChartType ```go type ChartType string ``` ```go const ( ChartTypeLine ChartType = "line" ChartTypeScatter ChartType = "scatter" ChartTypeBar ChartType = "bar" ChartTypePie ChartType = "pie" ChartTypeBoxAndWhisker ChartType = "box_and_whisker" ChartTypeCompositeChart ChartType = "composite_chart" ChartTypeUnknown ChartType = "unknown" ) ``` ## type CodeLanguage CodeLanguage ```go type CodeLanguage string ``` ```go const ( CodeLanguagePython CodeLanguage = "python" CodeLanguageJavaScript CodeLanguage = "javascript" CodeLanguageTypeScript CodeLanguage = "typescript" ) ``` ## type CodeRunParams CodeRunParams represents parameters for code execution ```go type CodeRunParams struct { Argv []string Env map[string]string } ``` ## type CreateSnapshotParams CreateSnapshotParams represents parameters for creating a snapshot ```go type CreateSnapshotParams struct { Name string Image any // string or *Image Resources *Resources Entrypoint []string SkipValidation *bool } ``` ## type DaytonaConfig DaytonaConfig represents the configuration for the Daytona client. When a field is nil, the client will fall back to environment variables or defaults. ```go type DaytonaConfig struct { APIKey string JWTToken string OrganizationID string APIUrl string Target string Experimental *ExperimentalConfig } ``` ## type ExecuteResponse ExecuteResponse represents a command execution response ```go type ExecuteResponse struct { ExitCode int Result string Artifacts *ExecutionArtifacts // nil when no artifacts available } ``` ## type ExecutionArtifacts ExecutionArtifacts represents execution output artifacts ```go type ExecutionArtifacts struct { Stdout string Charts []Chart } ``` ## type ExecutionError ExecutionError represents a code execution error ```go type ExecutionError struct { Name string Value string Traceback *string // Optional stack trace; nil when not available } ``` ## type ExecutionResult ExecutionResult represents code interpreter execution result ```go type ExecutionResult struct { Stdout string Stderr string Charts []Chart // Optional charts from matplotlib Error *ExecutionError // nil = success, non-nil = execution failed } ``` ## type ExperimentalConfig ExperimentalConfig holds experimental feature flags for the Daytona client. ```go type ExperimentalConfig struct { OtelEnabled bool // Enable OpenTelemetry tracing and metrics } ``` ## type FileDownloadRequest FileDownloadRequest ```go type FileDownloadRequest struct { Source string Destination *string // nil = download to memory (return []byte), non-nil = save to file path } ``` ## type FileDownloadResponse FileDownloadResponse represents a file download response ```go type FileDownloadResponse struct { Source string Result any // []byte or string (path) Error *string // nil = success, non-nil = error message } ``` ## type FileInfo FileInfo represents file metadata ```go type FileInfo struct { Name string Size int64 Mode string ModifiedTime time.Time IsDirectory bool } ``` ## type FileStatus FileStatus represents the status of a file in git ```go type FileStatus struct { Path string Status string } ``` ## type FileUpload FileUpload represents a file to upload ```go type FileUpload struct { Source any // []byte or string (path) Destination string } ``` ## type GitCommitResponse GitCommitResponse ```go type GitCommitResponse struct { SHA string } ``` ## type GitStatus GitStatus represents git repository status ```go type GitStatus struct { CurrentBranch string Ahead int Behind int BranchPublished bool FileStatus []FileStatus } ``` ## type ImageParams ImageParams represents parameters for creating a sandbox from an image ```go type ImageParams struct { SandboxBaseParams Image any // string or *Image Resources *Resources } ``` ## type LspLanguageID ```go type LspLanguageID string ``` ```go const ( LspLanguagePython LspLanguageID = "python" LspLanguageJavaScript LspLanguageID = "javascript" LspLanguageTypeScript LspLanguageID = "typescript" ) ``` ## type OutputMessage OutputMessage represents an output message ```go type OutputMessage struct { Type string `json:"type"` Text string `json:"text"` Name string `json:"name"` Value string `json:"value"` Traceback string `json:"traceback"` } ``` ## type PaginatedSnapshots PaginatedSnapshots represents a paginated list of snapshots ```go type PaginatedSnapshots struct { Items []*Snapshot Total int Page int TotalPages int } ``` ## type Position Position represents a position in a document ```go type Position struct { Line int // zero-based Character int // zero-based } ``` ## type PreviewLink PreviewLink contains the URL and authentication token for a sandbox preview. ```go type PreviewLink struct { URL string Token string } ``` ## type PtyResult PtyResult represents PTY session exit information ```go type PtyResult struct { ExitCode *int // nil = process still running, non-nil = exit code Error *string // nil = success, non-nil = error message } ``` ## type PtySessionInfo PtySessionInfo represents PTY session information ```go type PtySessionInfo struct { ID string Active bool CWD string // Current working directory; may be empty unavailable Cols int Rows int ProcessID *int // Process ID; may be nil if unavailable CreatedAt time.Time } ``` ## type PtySize PtySize represents terminal dimensions ```go type PtySize struct { Rows int Cols int } ``` ## type Resources Resources represents resource allocation for a sandbox. ```go type Resources struct { CPU int GPU int Memory int Disk int } ``` ## type SandboxBaseParams SandboxBaseParams contains common parameters for sandbox creation. ```go type SandboxBaseParams struct { Name string User string Language CodeLanguage EnvVars map[string]string Labels map[string]string Public bool AutoStopInterval *int // nil = no auto-stop, 0 = immediate stop AutoArchiveInterval *int // nil = no auto-archive, 0 = immediate archive AutoDeleteInterval *int // nil = no auto-delete, 0 = immediate delete Volumes []VolumeMount NetworkBlockAll bool NetworkAllowList *string Ephemeral bool } ``` ## type ScreenshotOptions ```go type ScreenshotOptions struct { ShowCursor *bool // nil = default, true = show, false = hide Format *string // nil = default format (PNG), or "jpeg", "webp", etc. Quality *int // nil = default quality, 0-100 for JPEG/WebP Scale *float64 // nil = 1.0, scaling factor for the screenshot } ``` ## type ScreenshotRegion ScreenshotRegion represents a screenshot region ```go type ScreenshotRegion struct { X int Y int Width int Height int } ``` ## type ScreenshotResponse ```go type ScreenshotResponse struct { Image string // base64-encoded image data Width int Height int SizeBytes *int // Size in bytes } ``` ## type Snapshot Snapshot represents a Daytona snapshot ```go type Snapshot struct { ID string `json:"id"` OrganizationID string `json:"organizationId,omitempty"` General bool `json:"general"` Name string `json:"name"` ImageName string `json:"imageName,omitempty"` State string `json:"state"` Size *float64 `json:"size,omitempty"` Entrypoint []string `json:"entrypoint,omitempty"` CPU int `json:"cpu"` GPU int `json:"gpu"` Memory int `json:"mem"` // API uses "mem" not "memory" Disk int `json:"disk"` ErrorReason *string `json:"errorReason,omitempty"` // nil = success, non-nil = error reason if snapshot failed SkipValidation bool `json:"skipValidation"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` LastUsedAt *time.Time `json:"lastUsedAt,omitempty"` } ``` ## type SnapshotParams SnapshotParams represents parameters for creating a sandbox from a snapshot ```go type SnapshotParams struct { SandboxBaseParams Snapshot string } ``` ## type Volume Volume represents a Daytona volume ```go type Volume struct { ID string `json:"id"` Name string `json:"name"` OrganizationID string `json:"organizationId"` State string `json:"state"` ErrorReason *string `json:"errorReason,omitempty"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` LastUsedAt time.Time `json:"lastUsedAt,omitempty"` } ``` ## type VolumeMount VolumeMount represents a volume mount configuration ```go type VolumeMount struct { VolumeID string MountPath string Subpath *string // Optional subpath within the volume; nil = mount entire volume } ``` import { Image } from 'astro:assets' import notesAppResult from '../../../../../assets/docs/images/inngest-agentkit-notes-app.gif' This guide demonstrates how to set up and use a fully autonomous coding agent that performs software development tasks in a [Daytona](https://daytona.io) sandbox environment. The agent is built using [AgentKit](https://agentkit.inngest.com/) and leverages Daytona sandboxes for secure, isolated execution. It can create web apps, run tests, execute scripts, and more; automating multi-step workflows based on user prompts. --- ### 1. Workflow Overview You provide a natural language prompt describing the software task. The agent reasons about your request, plans the steps, and executes them securely in a Daytona sandbox; handling everything from project setup to live previews. ### 2. Project Setup #### Clone the Repository Clone the [repository](https://github.com/daytonaio/daytona) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/agentkit-inngest/coding-agent/anthropic ``` #### Configure Environment Get your API keys: - **Daytona API key:** [Daytona Dashboard](https://app.daytona.io/dashboard/keys) - **Anthropic API key:** [Anthropic Console](https://console.anthropic.com/) Copy `.env.example` to `.env` and add your keys: ```bash DAYTONA_API_KEY=your_daytona_key ANTHROPIC_API_KEY=your_anthropic_key ``` #### Local Usage :::note[Node.js Version] Node.js 18 or newer is required to run the coding agent locally. Please ensure your environment meets this requirement before proceeding. ::: Install dependencies: ```bash npm install ``` Run the agent: ```bash npm run start ``` #### Docker Build the Docker image: ```bash docker buildx build . -t coding-agent ``` Run the container: ```bash docker run --rm -it coding-agent ``` ### 3. Configuration - **Prompt Setting:** Edit the main prompt in `network.run(...)` in `src/index.ts` to change the agent's task. - **Debug Logs:** Set `enableDebugLogs=true` for detailed agent flow tracking. ### 4. Example Usage Try the default prompt in `src/index.ts`: ```typescript const result = await network.run( `Create a minimal React app called "Notes" that lets users add, view, and delete notes. Each note should have a title and content. Use Create React App or Vite for setup. Include a simple UI with a form to add notes and a list to display them.` ) ``` **The agent will:** - Scaffold the app - Install dependencies - Start the dev server - Generate a preview link Terminal output example: ``` ✔️ App is ready! Preview: https://5173-3a828150-1573-42e3-bf9f-9793a2c2c0c2.proxy.daytona.works ``` The image below shows the result generated in this run: Notes app demo generated by coding agent ### 5. Understanding the Agent's Execution Flow The agent operates by leveraging a large language model (LLM) under the hood and has access to a suite of specialized tools. These tools enable the agent to perform everything needed inside the Daytona sandbox environment; from project setup to app deployment. At each step, the agent reasons about the current goal, decides which tool to call, and orchestrates the workflow to achieve the desired outcome. Below is a step-by-step breakdown of how the agent builds the demo Notes app showing each iteration, the agent's message, and the tool used: #### Project Initialization **Agent message:** ``` I'll create a React app for Notes using Vite, which provides a faster and more modern setup compared to Create React App. I'll break this down into steps: - First, I'll create the project using Vite - Install necessary dependencies - Create the components for the Notes app - Implement the core functionality Let's get started: ``` **Tool used:** `shellTool` was called with command: ``` npm create vite@latest notes -- --template react ``` #### Install Dependencies **Agent message:** ``` Now, I'll navigate to the project directory and install dependencies: ``` **Tool used:** `shellTool` was called with command: ``` cd notes && npm install ``` #### Create Components & Update App Structure **Agent message:** ``` Now, I'll create the necessary components and update the app structure: 1. Update App.jsx 2. Update App.css for basic styling ``` **Tool used:** `uploadFilesTool` was called to upload: ``` App.jsx (main component logic) App.css (basic styling) ``` #### Start Development Server **Agent message:** ``` Now, I'll start the development server: ``` **Tool used:** `startDevServerTool` was called with command: ``` cd notes && npm run dev ``` #### Check Dev Server Health **Agent message:** ``` Let's check the dev server health: ``` **Tool used:** `checkDevServerHealthTool` was called to verify that the development server is running and accessible. #### App Summary & Features **Agent message:** ``` Great! I've created a minimal React Notes app with the following features: - Add notes with a title and content - View the list of notes - Delete individual notes - Basic responsive styling Key details: - Used Vite for project setup - Implemented state management with React hooks (useState) - Simple form for adding notes - Notes are stored in local state - Each note has a unique ID, title, and content - Delete functionality for individual notes DEV_SERVER_PORT=5173 TASK_COMPLETED The app is now running and ready to use. Users can: 1. Enter a note title in the first input 2. Enter note content in the textarea 3. Click "Add Note" to save the note 4. View notes in the list below 5. Delete notes by clicking the "Delete" button next to each note Would you like me to explain any part of the implementation or make any modifications? ``` Notice `DEV_SERVER_PORT` and `TASK_COMPLETED` fields in the agent output message. `DEV_SERVER_PORT` value is auto-detected by the agent and used to generate the preview link for your app. `TASK_COMPLETED` signals that the task is finished which is used inside the agent routing logic. --- **Key advantages:** - Secure, isolated execution - Multi-language support - Auto-detects dev server, starts it, and generates preview link - Detailed debug logs for agent actions This guide demonstrates how to run a two-agent autonomous coding system using the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) and Daytona sandboxes. The system consists of a **Project Manager Agent** (local) and a **Developer Agent** (in-sandbox), enabling advanced delegation, planning, and secure code execution. The Project Manager Agent runs locally and uses the basic Anthropic interface with the `claude-sonnet-4-20250514` model for high-level planning and task delegation. The Developer Agent runs inside the Daytona sandbox and is created using the Claude Agent SDK, which leverages Claude Code for advanced coding and automation capabilities. This architecture separates high-level planning from low-level code execution for more robust automation. A key advantage of this approach is its **extensibility**: you can easily replace the Project Manager Agent with your own custom orchestrator logic, or even another agent, making the system highly reusable and adaptable to a wide range of advanced automation and coordination use cases. --- ### 1. Workflow Overview When the main module is launched, a Daytona sandbox is created for the Developer Agent, and a Project Manager Agent is initialized locally. Interaction with the system occurs via a command line chat interface. The Project Manager Agent receives prompts, plans the workflow, and delegates coding tasks to the Developer Agent. The Developer Agent executes tasks in the sandbox and streams results back to the Project Manager, who reviews and coordinates further actions. All logs and outputs from both agents are streamed in real time to the terminal, providing full visibility into the process as it is managed by the Project Manager Agent. The Developer Agent can also host web apps and provide preview links using [Daytona Preview Links](https://www.daytona.io/docs/en/preview-and-authentication.md). The Project Manager Agent will present these links and summarize the results for you. You can continue interacting with the system until you are finished. When you exit the program, the sandbox is deleted automatically. --- ### 2. Project Setup #### Clone the Repository First, clone the daytona [repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/anthropic/multi-agent-claude-sdk ``` #### Configure Environment To run this example, you need to set the following environment variables: - `DAYTONA_API_KEY`: Required for access to Daytona sandboxes. Get it from [Daytona Dashboard](https://app.daytona.io/dashboard/keys) - `ANTHROPIC_API_KEY`: Required for the **Project Manager Agent** (runs locally). Get it from [Claude Developer Platform](https://console.anthropic.com/settings/keys) - `SANDBOX_ANTHROPIC_API_KEY`: **Optional** for the **Developer Agent** (runs in sandbox). If not provided, defaults to using `ANTHROPIC_API_KEY`. Get it from [Claude Developer Platform](https://console.anthropic.com/settings/keys) Copy `.env.example` to `.env` and add your keys: ```bash DAYTONA_API_KEY=your_daytona_key ANTHROPIC_API_KEY=your_anthropic_key SANDBOX_ANTHROPIC_API_KEY=your_anthropic_key ``` :::tip[Agent API Key Options] You can use a single `ANTHROPIC_API_KEY` for both agents, or provide a separate `SANDBOX_ANTHROPIC_API_KEY` for billing/tracking purposes. ::: :::caution[API Key Security] The `SANDBOX_ANTHROPIC_API_KEY` is passed into the Daytona sandbox environment and is accessible to any code executed inside the sandbox. ::: #### Local Usage :::note[Node.js Version] Node.js 18 or newer is required to run this example. Please ensure your environment meets this requirement before proceeding. ::: Install dependencies: ```bash npm install ``` Run the two-agent system: ```bash npm run start ``` The system will start and wait for your prompt. --- ### 3. Example Usage Example chat session: ``` $ npm run start Creating Developer Agent sandbox... Installing Developer Agent SDK... Initializing Developer Agent... Initializing Project Manager Agent... === Two-Agent System Ready === Project Manager Agent: Manages tasks and delegates to Developer (Green text) Developer Agent: Executes code in Daytona sandbox (White text) Press Ctrl+C at any time to exit. User: make a lunar lander web app [Project Manager] Processing your request... [Project Manager]: I'll help you create a lunar lander web app! Let me delegate this task to the Developer Agent. Create a lunar lander web game with the following features: - HTML/CSS/JavaScript based - Canvas graphics for the game - Physics simulation (gravity, thrust, velocity) - Keyboard controls (arrow keys) - Landing detection (safe landing vs crash) - Fuel management system - Start the game on port 80 and provide the preview URL [Delegating to Developer Agent]... I'll help you create a lunar lander web app! Let me build a complete game with physics simulation, graphics, and controls. 🔨 Write 🔨 Write 🔨 Bash Perfect! The web server is now running. Your Lunar Lander game is live at: 🌐 https://80-17ac1c0f-d684-4122-93b5-8f52fd5393f8.proxy.daytona.works [Project Manager]: Excellent! The Developer Agent has successfully created your lunar lander web app. The game is now running and accessible at the preview URL above. The implementation includes: ✓ Physics simulation with gravity and thrust ✓ Canvas-based graphics ✓ Keyboard controls for gameplay ✓ Landing detection system ✓ Fuel management ✓ Web server running on port 80 TASK_COMPLETE [Project Manager] All tasks completed! ``` --- ### 4. Understanding the Agent Architecture This system is composed of two collaborating agents, each with a distinct role and implementation. Below is a step-by-step guide to how each agent operates and interacts within the workflow. #### Project Manager Agent (Terminal Orchestration) 1. **User Interaction:** - All user interaction occurs via the terminal with the Project Manager Agent. - The Project Manager Agent is configured with a system prompt that defines its role and maintains the full conversation history. 2. **Awareness of Developer Agent:** - The Project Manager Agent knows that a Developer Agent is available inside a Daytona sandbox and can be invoked as needed. 3. **Task Delegation:** - When the Project Manager Agent determines that a coding task should be delegated, it encapsulates the task within `` tags in its response. - The system parses these tags and, when present, invokes the Developer Agent with the specified task. 4. **Iterative Workflow:** - This process can repeat multiple times, with the Project Manager Agent reasoning about progress and delegating further tasks as needed. 5. **Session Completion:** - When the Project Manager Agent determines the overall task is complete, it outputs `TASK_COMPLETE`, which signals the system to terminate the session. #### Developer Agent (Sandbox Execution) 1. **Provisioning:** - The Developer Agent is provisioned inside a Daytona sandbox and is responsible for executing coding tasks. 2. **SDK Installation:** - The system installs the Claude Agent SDK in the sandbox by running `pip install` (see [process execution](https://www.daytona.io/docs/en/process-code-execution.md#process-execution)). 3. **Interpreter Context:** - A new [code interpreter context](https://www.daytona.io/docs/en/process-code-execution.md#stateful-code-interpreter) is created for isolated execution. 4. **Script Upload:** - The coding agent script is uploaded to the sandbox using [file uploading](https://www.daytona.io/docs/file-system-operations.md#uploading-a-single-file). 5. **SDK Initialization:** - The Claude Agent SDK is initialized in the interpreter context (e.g., `import coding_agent`). 6. **Task Execution:** - When a `` is received, the system sends the task to the Developer Agent by running a Python command in the interpreter context: ```typescript const result = await sandbox.codeInterpreter.runCode( `coding_agent.run_query_sync(os.environ.get('PROMPT', ''))`, { context: ctx, envs: { PROMPT: task }, onStdout, onStderr, } ); ``` - The Developer Agent executes the task, streams output, and returns results to the Project Manager Agent for review and further coordination. --- ### 5. Customization You can customize the Project Manager Agent's behavior by modifying the system prompt in `src/index.ts`. The current implementation: - Uses `` tags for delegation - Automatically reviews Developer Agent outputs - Says "TASK_COMPLETE" when finished --- ### 6. Cleanup When you exit the main program, the Daytona sandbox and all files are automatically deleted. --- **Key advantages:** - Secure, isolated execution in Daytona sandboxes - Hierarchical agent architecture for robust automation - Extensible and reusable architecture - Automatic dev server detection and live preview links - Multi-language and full-stack support - Simple setup and automatic cleanup import { Image } from 'astro:assets' import claudeAgentSDKInteractiveTerminalSandboxResult from '../../../../../assets/docs/images/claude-agent-sdk-interactive-terminal-sandbox-result.gif' This guide demonstrates how to run an autonomous coding agent based on [Claude Code](https://code.claude.com/docs/en/overview) inside a Daytona sandbox environment. The agent uses the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) to follow user prompts. The agent can develop full-stack web apps, write code in any language, install dependencies, and run scripts. It can also start and manage dev servers, and generate preview links for live apps. --- ### 1. Workflow Overview When you launch the main module, a Daytona sandbox is created and a Python agent is initialized inside it. The agent is based on the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview). You interact with the main program via a command line chat interface. The program sends your prompts to the agent inside the sandbox, which executes them and returns the results: ``` $ npm run start 174s Creating sandbox... Installing Agent SDK... Initializing Agent SDK... Press Ctrl+C at any time to exit. User: Build a Zelda-like game where I can move around the screen and talk to famous programmers Thinking... I'll build a Zelda-like game for you! This will be a fun project with player movement and NPC interactions with famous programmers. 🔨 Write 🔨 Write Now let me start a simple HTTP server to host the game: 🔨 Bash Perfect! I've created a Zelda-like game called "Programmer's Quest" for you! 🎮 ## Game Features: ✨ Zelda-style gameplay: - Top-down 2D view with classic retro aesthetics - Player character with sword and shield - Grid-based movement system - Environmental obstacles (trees and rocks) 👥 Famous Programmers as NPCs: 1. Linus Torvalds - Creator of Linux 2. Grace Hopper - COBOL pioneer and Admiral 3. Alan Turing - Father of computer science 4. Ada Lovelace - First computer programmer 5. Dennis Ritchie - Creator of C and UNIX 🎮 Controls: - Arrow Keys or WASD - Move your character - SPACE - Talk to NPCs when you're near them 🌟 Gameplay: - Explore the grassy map and find all 5 legendary programmers - Each NPC has multiple quotes that cycle when you talk to them - NPCs glow when you're near them - Dialog boxes appear with their famous quotes - Track your progress in the HUD ## Play Now: 🎯 [Click here to play the game!](https://80-8e2c4d23-212a-4f1e-bb6c-abfa71aeed3a.proxy.daytona.works) The game features smooth movement, collision detection with trees and rocks, and an immersive dialog system. Try to find and talk to all 5 famous programmers to learn their wisdom! Each has 3 different quotes that cycle as you keep talking to them. Enjoy your adventure! 🗡️✨ User: ``` The agent can also host web apps and provide you with a preview link using the [Daytona Preview Links](https://www.daytona.io/docs/en/preview-and-authentication.md) feature. When your task involves running or previewing a web application, the agent automatically reasons about this need, hosts the app, and generates a preview link for you to inspect the live result: RPG game demo generated by coding agent You can continue interacting with your agent until you are finished. When you exit the program, the sandbox will be deleted automatically. ### 2. Project Setup #### Clone the Repository First, clone the daytona [repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/anthropic/single-claude-agent-sdk ``` #### Configure Environment Get your API keys: - **Daytona API key:** [Daytona Dashboard](https://app.daytona.io/dashboard/keys) - **Anthropic API key:** [Anthropic Console](https://console.anthropic.com/) Copy `.env.example` to `.env` and add your keys: ```bash DAYTONA_API_KEY=your_daytona_key SANDBOX_ANTHROPIC_API_KEY=your_anthropic_key ``` :::caution[API Key Security] Note: The `SANDBOX_ANTHROPIC_API_KEY` key is passed into the Daytona sandbox environment and is accessible to any code executed inside the sandbox. ::: #### Local Usage :::note[Node.js Version] Node.js 18 or newer is required to run this example. Please ensure your environment meets this requirement before proceeding. ::: Install dependencies: ```bash npm install ``` Run the agent: ```bash npm run start ``` The agent will start and wait for your prompt. ### 3. Example Usage Example chat session: ``` $ npm run start Creating sandbox... Installing Agent SDK... Initializing Agent SDK... Press Ctrl+C at any time to exit. User: Create a fun pet store landing page in Svelte Thinking... I'll create a fun pet store landing page in Svelte for you! Let me set up the project and build an engaging landing page with animations and a colorful design. 🔨 Bash 🔨 Bash Now let me create a fun and engaging pet store landing page with animations, colorful sections, and interactive elements: 🔨 Read > 🔨 Write Now let me create the component files: 🔨 Write 🔨 Write 🔨 Write 🔨 Write 🔨 Write Now let's update the main CSS file and start the development server: 🔨 Read 🔨 Write Now let's start the development server: 🔨 Bash 🔨 TaskOutput Perfect! 🎉 I've created a fun and colorful pet store landing page in Svelte! Here's what I built: ## Features: ✨ Hero Section - Beautiful gradient background with animated floating cards - Eye-catching navigation bar - Call-to-action buttons with hover effects - Bouncing emoji animations 🎯 Features Section - 4 key benefits (Free Delivery, Premium Quality, Special Offers, Award Winning) - Interactive cards with hover animations - Icons that rotate and scale on hover 🛍️ Products Section - 6 featured products with colorful backgrounds - Star ratings - Add to cart functionality - Smooth hover animations 📧 Newsletter Section - Vibrant gradient background with floating pet emojis - Email subscription form - Success message animation - Special 20% off offer 👣 Footer - Comprehensive navigation links - Social media icons - Dark gradient design ## Live Preview: Your pet store is now running at: https://80-b3739199-d90e-4bde-ab18-450d74c950e8.proxy.daytona.works The page includes: - Smooth scroll behavior - Responsive design for mobile devices - Fun animations throughout - Interactive elements with hover effects - Colorful gradients and modern styling - Emoji-based icons for a playful feel Click the link to see your fun pet store landing page in action! 🐾 User: ``` ### 4. Understanding the Agent's Architecture This example consists of two main components: - **Main Program:** The main program is a Node.js script (`index.ts`) that runs on your local machine. It uses the Daytona SDK to create and manage a Daytona sandbox. The main program provides a command line interface for interacting with the agent inside the sandbox. - **Sandbox Agent:** The sandbox agent is a Python script (`coding_agent.py`) that runs inside the Daytona sandbox. It uses the Claude Agent SDK to create a customized coding agent similar to Claude Code. #### Initialization On initialization, the main program: 1. Creates a new [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md) with your Anthropic API key included in the environment variables. 2. Installs the Claude Agent SDK by running `pip install` in the sandbox with [process execution](https://www.daytona.io/docs/en/process-code-execution.md#process-execution). 3. Creates a new [code interpreter context](https://www.daytona.io/docs/en/process-code-execution.md#stateful-code-interpreter). 4. Uploads the coding agent script to the sandbox with [file uploading](https://www.daytona.io/docs/file-system-operations.md#uploading-a-single-file). 5. Initializes the Claude Agent SDK by running `import coding_agent` in the code interpreter context. 6. Waits for user input and sends prompts to the agent in the code interpreter context as shown below. #### Main Program Code Once the agent is running, the program creates a readline interface to read user input and sends it to the agent. Each user request is passed to the agent by running a Python command in the code interpreter context: ```typescript const result = await sandbox.codeInterpreter.runCode( `coding_agent.run_query_sync(os.environ.get('PROMPT', ''))`, { context: ctx, envs: { PROMPT: prompt }, onStdout, onStderr, } ) ``` The `onStdout` and `onStderr` callbacks are used to pass the agent's output back to the main program. After the agent finishes responding to the prompt, the main program waits for the next user input. #### Sandbox Agent Code The sandbox agent uses the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) to create a customized coding agent based on Claude Code. The agent is initialized with a system prompt that includes the workspace directory and an example of the [preview URL format](https://www.daytona.io/docs/en/preview-and-authentication.md): ```python system_prompt = """ You are running in a Daytona sandbox. Use the /home/daytona directory instead of /workspace for file operations. Your public preview URL for port 80 is: {}. """.format(preview_url) ``` It also specifies the [tools and permission mode](https://platform.claude.com/docs/en/agent-sdk/quickstart#key-concepts) of the agent: ```python client = ClaudeSDKClient( options=ClaudeAgentOptions( allowed_tools=["Read", "Edit", "Glob", "Grep", "Bash"], permission_mode="acceptEdits", system_prompt=system_prompt ) ) ``` The code to run queries and receive responses follows the examples in Anthropic's [Claude Agent Python SDK documentation](https://platform.claude.com/docs/en/agent-sdk/python). #### Clean up When you exit the main program, the Daytona sandbox and all files are automatically deleted. **Key advantages:** - Secure, isolated execution in Daytona sandboxes - Communicate with the agent directly in your terminal - Automatic dev server detection and live preview links - Multi-language and full-stack support - Simple setup and automatic cleanup This guide walks you through running Claude Code inside a Daytona sandbox using the Daytona CLI. ### Prerequisites - Daytona account and API key (Get it from [Daytona Dashboard](https://app.daytona.io/dashboard/keys)) - Local terminal (macOS, Linux, or Windows) ### Install the Daytona CLI ```bash brew install daytonaio/cli/daytona ``` ```bash powershell -Command "irm https://get.daytona.io/windows | iex" ``` :::note Already have the CLI? Check your version with `daytona --version`. If it's below **0.135.0**, [upgrade to the latest version](https://www.daytona.io/docs/en/getting-started.md#cli). ::: ### Authenticate with Daytona Log in to your Daytona account using your API key: ```bash daytona login --api-key=YOUR_API_KEY ``` Replace `YOUR_API_KEY` with your actual Daytona API key. ### Create a Sandbox Create a new sandbox for running Claude Code: ```bash daytona sandbox create --name claude-sandbox ``` This creates a sandbox named `claude-sandbox`, visible in your [Dashboard](https://app.daytona.io/dashboard/sandboxes). The default Daytona snapshot includes Claude Code, so the command above is all you need. :::tip Need more power? Pass `--snapshot daytona-large` or `--snapshot daytona-medium` flag to increase your sandbox resources. See [default snapshots](https://www.daytona.io/docs/en/snapshots.md#default-snapshots) for resource details. ::: ### Connect to the Sandbox SSH into your sandbox: ```bash daytona ssh claude-sandbox ``` You now have an interactive terminal session inside the sandbox. ### Run Claude Code Inside the SSH session, start Claude Code: ```bash claude ``` On first run, Claude Code will prompt you to authenticate: 1. Copy the authentication URL displayed in the terminal 2. Open the URL in your local browser 3. Complete the authentication flow 4. Copy the code provided by the browser 5. Paste the code back into the terminal Once authenticated, you're all set. Claude Code runs inside the sandbox while you control it from your terminal. Claude Code allows you to automate and orchestrate tasks using natural language and code. With Daytona, you can easily run Claude Code inside isolated sandboxes, making it simple to experiment and execute tasks securely. ## Running Claude Code in a Daytona Sandbox You can run Claude Code and execute tasks with it directly inside a Daytona sandbox. The following examples show how to set up a sandbox, install Claude Code, run tasks programmatically, and stream logs in real time. > **Note:** While both sync and async modes support streaming PTY output, `AsyncDaytona` is recommended as it provides automatic background callbacks via `on_data`. The synchronous API requires blocking iteration or manual threading to handle output. ```python import os import asyncio from daytona import AsyncDaytona async def run_claude_code(): async with AsyncDaytona() as daytona: sandbox = await daytona.create() # Define the Claude Code command to be executed claude_command = "claude --dangerously-skip-permissions -p 'write a dad joke about penguins' --output-format stream-json --verbose" # Install Claude Code in the sandbox await sandbox.process.exec("npm install -g @anthropic-ai/claude-code") pty_handle = await sandbox.process.create_pty_session( id="claude", on_data=lambda data: print(data.decode(), end="") ) await pty_handle.wait_for_connection() # Run the Claude Code command inside the sandbox await pty_handle.send_input( f"ANTHROPIC_API_KEY={os.environ['ANTHROPIC_API_KEY']} {claude_command}\n" ) # Use this to close the terminal session if no more commands will be executed # await pty_handle.send_input("exit\n") await pty_handle.wait() # If you are done and have closed the PTY terminal, it is recommended to clean up resources by deleting the sandbox # await sandbox.delete() if __name__ == "__main__": asyncio.run(run_claude_code()) ```` ```typescript import { Daytona } from "@daytonaio/sdk"; const daytona = new Daytona(); try { const sandbox = await daytona.create(); // Define the Claude Code command to be executed const claudeCommand = "claude --dangerously-skip-permissions -p 'write a dad joke about penguins' --output-format stream-json --verbose"; // Install Claude Code in the sandbox await sandbox.process.executeCommand("npm install -g @anthropic-ai/claude-code"); const ptyHandle = await sandbox.process.createPty({ id: "claude", onData: (data) => { process.stdout.write(data); }, }); await ptyHandle.waitForConnection(); // Run the Claude Code command inside the sandbox ptyHandle.sendInput( `ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY} ${claudeCommand}\n` ); // Use this to close the terminal session if no more commands will be executed // ptyHandle.sendInput("exit\n") await ptyHandle.wait(); // If you are done and have closed the PTY terminal, it is recommended to clean up resources by deleting the sandbox // await sandbox.delete(); } catch (error) { console.error("Failed to run Claude Code in Daytona sandbox:", error); } ```` Guides for integrating Claude with Daytona. import { Image } from 'astro:assets' import codexSdkLunarLanderResult from '../../../../../assets/docs/images/codex-sdk-lunar-lander-result.gif' This guide demonstrates how to run an autonomous coding agent based on [OpenAI Codex](https://chatgpt.com/features/codex) inside a Daytona sandbox environment. The agent can develop full-stack web apps, write code in any language, install dependencies, and run scripts. It can also start and manage dev servers, and generate preview links for live apps. --- ### 1. Workflow Overview When you launch the main module, a Daytona sandbox is created and a Node.js agent is initialized inside it. The agent is based on the [Codex SDK](https://developers.openai.com/codex/sdk/). You interact with the main program via a command line chat interface. The program sends your prompts to the agent inside the sandbox, which executes them and returns the results: ``` $ npm run start Creating sandbox... Installing Codex agent in sandbox... Press Ctrl+C at any time to exit. User: create a 3d animated web-based, lunar lander game Thinking... 🔨 ✓ Run: /bin/sh -lc ls 🔨 ✓ Run: /bin/sh -lc 'ls -a' 🔨 ✓ Run: /bin/sh -lc 'ls .daytona' 🔨 ✓ Run: /bin/sh -lc 'find /home/daytona -maxdepth 4 -name .git' 📝 Add /home/daytona/index.html 📝 Add /home/daytona/style.css 📝 Add /home/daytona/main.js 📝 Update /home/daytona/main.js - Built a self-contained 3D lunar lander experience with HUD in index.html wired to main.js. - Styled a glassy mission card, typography, and neon accents in style.css. - Implemented the Three.js scene in main.js: starfield + noisy terrain with a flattened pad, modeled lander, thrust/fuel/rotation controls, gravity/drag physics, landing/crash checks, exhaust particles, and a chase camera. Controls: Space/↑ thrust, ←/→ yaw, W/S pitch, R restart. Next steps: 1) Serve locally (e.g., cd /home/daytona && python3 -m http.server 8080) and open https://8080-e7c5deb5-7723-4bb8-93c6-25258d9b7c53.proxy.daytona.works. 2) Tune physics constants or terrain size if you want a harder/easier landing. 🗒️ To-do list: - [x] Inspect workspace and set up project structure for web-based lunar lander game - [x] Implement 3D scene, lunar lander controls, physics, and game loop - [x] Add UI elements, polish, and quick sanity check (open file if feasible) Usage Summary: Cached: 71936, Input: 103238, Output: 11311 User: start the server Thinking... 🔨 ✓ Run: /bin/sh -lc 'cd /home/daytona && nohup python3 -m http.server 8080 --bind 0.0.0.0 >/home/daytona/server.log 2>&1 & echo $!' Server started on port 8080 (pid 274). Open the game at: https://8080-e7c5deb5-7723-4bb8-93c6-25258d9b7c53.proxy.daytona.works If you need to stop it later: kill 274. Usage Summary: Cached: 4096, Input: 22231, Output: 272 User: Cleaning up... ``` The agent can also host web apps and provide you with a preview link using the [Daytona Preview Links](https://www.daytona.io/docs/en/preview-and-authentication.md) feature. When your task involves running or previewing a web application, the agent automatically reasons about this need, hosts the app, and generates a preview link for you to inspect the live result: Lunar lander game demo generated by Codex coding agent You can continue interacting with your agent until you are finished. When you exit the program, the sandbox will be deleted automatically. ### 2. Project Setup #### Clone the Repository First, clone the daytona [repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/openai/codex-sdk ``` #### Configure Environment Get your API keys: - **Daytona API key:** [Daytona Dashboard](https://app.daytona.io/dashboard/keys) - **OpenAI API key:** [OpenAI Developer Platform](https://platform.openai.com/api-keys) Copy `.env.example` to `.env` and add your keys: ```bash DAYTONA_API_KEY=your_daytona_key SANDBOX_OPENAI_API_KEY=your_openai_key ``` :::caution[API Key Security] Note: The `SANDBOX_OPENAI_API_KEY` key is passed into the Daytona sandbox environment and is accessible to any code executed inside the sandbox. ::: #### Local Usage :::note[Node.js Version] Node.js 18 or newer is required to run this example. Please ensure your environment meets this requirement before proceeding. ::: Install dependencies: ```bash npm install ``` Run the agent: ```bash npm run start ``` The agent will start and wait for your prompt. ### 3. Understanding the Agent's Architecture This example consists of two main components: - **Main Program:** The main program is a Node.js script (`src/index.ts`) that runs on your local machine. It uses the Daytona SDK to create and manage a Daytona sandbox. The main program provides a command line interface for interacting with the agent inside the sandbox. - **Sandbox Agent:** The sandbox agent is a Node.js script (`agent/index.ts`) that runs inside the Daytona sandbox. It uses the Codex SDK to create a customized coding agent. #### Initialization On initialization, the main program: 1. Creates a new [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md) with your OpenAI API key included in the environment variables. 2. Configures the Codex system prompt with Daytona-specific instructions and writes it to a `.codex/config.toml` file in the sandbox. 3. Uploads the agent package to the sandbox with [file uploading](https://www.daytona.io/docs/file-system-operations.md#uploading-a-single-file). 4. Installs the agent dependencies by running `npm install` in the uploaded agent directory. 5. Waits for user input and runs the agent asynchronously for each prompt. #### Main Program Code Custom system prompts for Codex must be configured via a `.codex/config.toml` file, so the main program creates this file in the sandbox before starting the agent: ```typescript const systemPrompt = [ 'You are running in a Daytona sandbox.', 'Use the /home/daytona directory instead of /workspace for file operations.', `When running services on localhost, they will be accessible as: ${previewUrlPattern}`, ].join(' ') const config = `developer_instructions = "${systemPrompt}"` await sandbox.fs.createFolder('.codex', '755') await sandbox.fs.uploadFile(Buffer.from(config, 'utf8'), '.codex/config.toml') ``` This prompt instructs the agent to use the correct file paths and preview link format for Daytona sandboxes. After installing dependencies, the main program enters a loop to read user input and send it to the agent. For each user prompt it receives, it creates a new Daytona process session to run the agent command asynchronously and stream back the output: ```typescript // Create a session to stream the agent output const sessionId = `codex-session-${Date.now()}` await sandbox.process.createSession(sessionId) // Run the agent asynchronously, passing the prompt and OpenAI API key const command = await sandbox.process.executeSessionCommand(sessionId, { command: `${environmentPrefix({ PROMPT: prompt })} npm exec --prefix /tmp/agent tsx -- /tmp/agent/index.ts`, runAsync: true, }) // Stream agent output as it arrives if (!command.cmdId) throw new Error('Failed to start agent command in sandbox') await sandbox.process.getSessionCommandLogs( sessionId, command.cmdId, onStdout, onStderr, ) // Delete the session await sandbox.process.deleteSession(sessionId) ``` The `onStdout` and `onStderr` callbacks are used to pass the agent's output back to the main program. After the agent finishes responding to the prompt, the main program waits for the next user input. #### Sandbox Agent Code The sandbox agent uses the [Codex SDK](https://developers.openai.com/codex/sdk/) to create a customized coding agent. The agent is initialized with custom options that include the workspace directory: ```typescript // Configure Codex options const options: ThreadOptions = { workingDirectory: '/home/daytona', skipGitRepoCheck: true, sandboxMode: 'danger-full-access', } ``` The agent maintains thread state between requests by writing the thread ID to a file, allowing it to maintain context across multiple interactions: ```typescript const threadIdPath = '/tmp/codex-thread-id' const threadId = (await readFileIfExisting(threadIdPath))?.trim() const thread: Thread = threadId ? codex.resumeThread(threadId, options) : codex.startThread(options) ``` Additional code to stream agent responses follows the examples in OpenAI's [Codex SDK documentation](https://github.com/openai/codex/blob/main/sdk/typescript/README.md). #### Clean up When you exit the main program, the Daytona sandbox and all files are automatically deleted. **Key advantages:** - Secure, isolated execution in Daytona sandboxes - Communicate with the agent directly in your terminal - Automatic dev server detection and live preview links - Multi-language and full-stack support - Thread persistence across multiple requests - Simple setup and automatic cleanup import { Image } from 'astro:assets' import chartImage from '../../../../assets/docs/images/chart-0.png' You can use Daytona Sandbox to run AI-generated code to analyze data. Here's how the AI data analysis workflow typically looks: 1. Your user has a dataset in CSV format or other formats. 2. You prompt the LLM to generate code (usually Python) based on the user's data. 3. The sandbox runs the AI-generated code and returns the results. 4. The LLM receives feedback from the execution and can iterate multiple times to refine the code if needed. 5. You display the final results to the user. --- ## Build an AI Data Analyst with Daytona This example shows how to build an AI-powered data analyst that automatically generates insights and visualizations from CSV data using Daytona's secure sandbox environment. **What we'll build:** A system that analyzes a vehicle valuation dataset, identifies price relation to manufacturing year, and generates professional visualizations - all through natural language prompts to Claude. The system uses an agentic loop that allows Claude to iteratively refine the code based on execution results. ### 1. Project Setup #### 1.1 Install Dependencies Install the Daytona SDK and Anthropic SDK to your project: `bash pip install daytona anthropic python-dotenv ` `bash npm install @daytonaio/sdk @anthropic-ai/sdk dotenv ` `bash gem install daytona anthropic dotenv ` #### 1.2 Configure Environment Get your API keys and configure your environment: 1. **Daytona API key:** Get it from [Daytona Dashboard](https://app.daytona.io/dashboard/keys) 2. **Anthropic API key:** Get it from [Anthropic Console](https://console.anthropic.com/) Create a `.env` file in your project: ```bash DAYTONA_API_KEY=dtn_*** ANTHROPIC_API_KEY=sk-ant-*** ``` ### 2. Dataset Preparation #### 2.1 Download Dataset We'll be using a publicly available dataset of vehicle valuation. You can download it directly from: [https://download.daytona.io/dataset.csv](https://download.daytona.io/dataset.csv) Download the file and save it as `dataset.csv` in your project directory. #### 2.2 Initialize Sandbox Now create a [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md#basic-sandbox-creation) and upload your dataset: ```python from dotenv import load_dotenv from daytona import Daytona import os load_dotenv() # Create sandbox daytona = Daytona() # The sandbox language is Python by default. sandbox = daytona.create() # Upload the dataset to the sandbox sandbox.fs.upload_file("dataset.csv", "/home/daytona/dataset.csv") ``` ```typescript import 'dotenv/config' import { Daytona } from '@daytonaio/sdk'; // Create sandbox const daytona = new Daytona(); // The sandbox language is Python by default. const sandbox = await daytona.create() // Upload the dataset to the sandbox await sandbox.fs.uploadFile('dataset.csv', '/home/daytona/dataset.csv') ``` ```ruby require 'daytona' require 'dotenv/load' # Create sandbox daytona = Daytona::Daytona.new # The sandbox language is Python by default. sandbox = daytona.create # Upload the dataset to the sandbox sandbox.fs.upload_file(File.read('dataset.csv'), '/home/daytona/dataset.csv') ``` ### 3. Building the AI Data Analyst Now we'll create the core functionality that connects Claude with Daytona to analyze data and generate visualizations. #### 3.1 Code Execution Handler First, let's create a function to handle code execution and chart extraction. This function returns execution results that can be fed back to the AI model: ```python import base64 from typing import TypedDict class ExecutionResult(TypedDict): stdout: str exit_code: int charts: list def run_ai_generated_code(sandbox, ai_generated_code: str) -> ExecutionResult: execution = sandbox.process.code_run(ai_generated_code) result = ExecutionResult( stdout=execution.result or "", exit_code=execution.exit_code, charts=execution.artifacts.charts if execution.artifacts else [] ) # Save any charts that were generated if execution.artifacts and execution.artifacts.charts: result_idx = 0 for chart in execution.artifacts.charts: if chart.png: filename = f'chart-{result_idx}.png' with open(filename, 'wb') as f: f.write(base64.b64decode(chart.png)) print(f'✓ Chart saved to {filename}') result_idx += 1 return result ``` ```typescript import fs from 'fs' import { Sandbox } from '@daytonaio/sdk' interface ExecutionResult { stdout: string exitCode: number charts?: Array<{ png?: string }> } async function runAIGeneratedCode( sandbox: Sandbox, aiGeneratedCode: string ): Promise { const execution = await sandbox.process.codeRun(aiGeneratedCode) const result: ExecutionResult = { stdout: execution.result || "", exitCode: execution.exitCode, charts: execution.artifacts?.charts } // Save any charts that were generated if (execution.artifacts?.charts) { let resultIdx = 0 for (const chart of execution.artifacts.charts) { if (chart.png) { const filename = `chart-${resultIdx}.png` fs.writeFileSync(filename, chart.png, { encoding: 'base64' }) console.log(`✓ Chart saved to ${filename}`) resultIdx++ } } } return result } ``` #### 3.2 Creating the Analysis Prompt Next, we'll create the prompt that tells Claude about our dataset and what analysis we want. This prompt includes: - Dataset schema and column descriptions - The specific analysis request (vehicle price variation by manufacturing year) - Instructions for code generation ```python from anthropic import Anthropic prompt = f""" I have a CSV file with vehicle valuations saved in the sandbox at /home/daytona/dataset.csv. Relevant columns: - 'year': integer, the manufacturing year of the vehicle - 'price_in_euro': float, the listed price of the vehicle in Euros Analyze how price varies by manufacturing year. Drop rows where 'year' or 'price_in_euro' is missing, non-numeric, or an outlier. Create a line chart showing average price per year. Write Python code that analyzes the dataset based on my request and produces a matplotlib chart accordingly. Always finish with plt.show() to display the chart.""" anthropic = Anthropic() ``` ```typescript import Anthropic from '@anthropic-ai/sdk' const prompt = ` I have a CSV file with vehicle valuations saved in the sandbox at /home/daytona/dataset.csv. Relevant columns: - 'year': integer, the manufacturing year of the vehicle - 'price_in_euro': float, the listed price of the vehicle in Euros Analyze how price varies by manufacturing year. Drop rows where 'year' or 'price_in_euro' is missing, non-numeric, or an outlier. Create a line chart showing average price per year. Write Python code that analyzes the dataset based on my request and produces a matplotlib chart accordingly. Always finish with plt.show() to display the chart.` const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }) ``` #### 3.3 Tool Definition Define the tool that allows Claude to execute Python code in the sandbox: ```python tools = [ { 'name': 'run_python_code', 'description': 'Run Python code in the sandbox environment and get execution results', 'input_schema': { 'type': 'object', 'properties': { 'code': { 'type': 'string', 'description': 'The Python code to run', }, }, 'required': ['code'], }, }, ] ``` ```typescript import type { Tool, ToolUseBlock } from '@anthropic-ai/sdk/resources/messages.mjs' const tools: Tool[] = [ { name: 'run_python_code', description: 'Run Python code in the sandbox environment and get execution results', input_schema: { type: 'object', properties: { code: { type: 'string', description: 'The Python code to run', }, }, required: ['code'], }, }, ] ``` #### 3.4 Agentic Loop Implementation Now we'll implement the agentic loop that allows Claude to iteratively refine the code based on execution feedback. This enables Claude to fix errors, handle edge cases, and improve the analysis through multiple iterations: ```python # Initialize conversation history messages = [{'role': 'user', 'content': prompt}] continue_loop = True iteration_count = 0 max_iterations = 10 print("Starting agentic loop...\n") while continue_loop and iteration_count < max_iterations: iteration_count += 1 print(f"\n=== Iteration {iteration_count} ===") print("Waiting for the model response...") # Get response from Claude msg = anthropic.messages.create( model='claude-sonnet-4-5', max_tokens=64000, messages=messages, tools=tools ) # Log Claude's text response for content_block in msg.content: if content_block.type == 'text': print("\nClaude's response:") print(content_block.text) # Check if Claude wants to use any tools tool_uses = [block for block in msg.content if block.type == 'tool_use'] if len(tool_uses) == 0: # No more tool uses, Claude is done print("\nTask completed - no more actions needed.") continue_loop = False break # Add Claude's response to message history messages.append({'role': 'assistant', 'content': msg.content}) # Execute all tool calls and collect results tool_results = [] for tool_use in tool_uses: if tool_use.name == 'run_python_code': code = tool_use.input['code'] print("\n--- Executing Python code in sandbox ---") print(code) print("--- End of code ---\n") # Execute the code in the sandbox execution_result = run_ai_generated_code(sandbox, code) # Format the tool result result_content = "" if execution_result['exit_code'] == 0: result_content += "Execution successful!\n\n" if execution_result['stdout']: result_content += f"Output:\n{execution_result['stdout']}\n" if execution_result['charts'] and len(execution_result['charts']) > 0: result_content += f"\nGenerated {len(execution_result['charts'])} chart(s)." else: result_content += "\nNote: No charts were generated. Make sure to use plt.show() to display the chart." else: result_content += f"Execution failed with exit code {execution_result['exit_code']}\n\n" if execution_result['stdout']: result_content += f"Output:\n{execution_result['stdout']}\n" tool_results.append({ 'type': 'tool_result', 'tool_use_id': tool_use.id, 'content': result_content }) print("Execution result sent back to Claude.") # Add tool results to conversation history messages.append({'role': 'user', 'content': tool_results}) if iteration_count >= max_iterations: print("\n⚠️ Reached maximum iteration limit. Task may not be complete.") print("\n=== Agentic loop completed ===") ``` ```typescript import type { MessageParam } from '@anthropic-ai/sdk/resources/messages.mjs' interface CodeRunToolInput { code: string } // Initialize conversation history const messages: MessageParam[] = [ { role: 'user', content: initialPrompt } ] let continueLoop = true let iterationCount = 0 const maxIterations = 10 console.log("Starting agentic loop...\n") while (continueLoop && iterationCount < maxIterations) { iterationCount++ console.log(`\n=== Iteration ${iterationCount} ===`) console.log("Waiting for the model response...") // Get response from Claude const stream = anthropic.messages.stream({ model: 'claude-sonnet-4-5', max_tokens: 64000, messages: messages, tools: tools }) const message = await stream.finalMessage() // Log Claude's text response for (const contentBlock of message.content) { if (contentBlock.type === 'text') { console.log("\nClaude's response:") console.log(contentBlock.text) } } // Check if Claude wants to use any tools const toolUses = message.content.filter( (block): block is ToolUseBlock => block.type === 'tool_use' ) if (toolUses.length === 0) { // No more tool uses, Claude is done console.log("\nTask completed - no more actions needed.") continueLoop = false break } // Add Claude's response to message history messages.push({ role: 'assistant', content: message.content }) // Execute all tool calls and collect results const toolResults = [] for (const toolUse of toolUses) { if (toolUse.name === 'run_python_code') { const code = (toolUse.input as CodeRunToolInput).code console.log("\n--- Executing Python code in sandbox ---") console.log(code) console.log("--- End of code ---\n") // Execute the code in the sandbox const executionResult = await runAIGeneratedCode(sandbox, code) // Format the tool result let resultContent = "" if (executionResult.exitCode === 0) { resultContent += "Execution successful!\n\n" if (executionResult.stdout) { resultContent += `Output:\n${executionResult.stdout}\n` } if (executionResult.charts && executionResult.charts.length > 0) { resultContent += `\nGenerated ${executionResult.charts.length} chart(s).` } else { resultContent += "\nNote: No charts were generated. Make sure to use plt.show() to display the chart." } } else { resultContent += `Execution failed with exit code ${executionResult.exitCode}\n\n` if (executionResult.stdout) { resultContent += `Output:\n${executionResult.stdout}\n` } } toolResults.push({ type: 'tool_result' as const, tool_use_id: toolUse.id, content: resultContent }) console.log("Execution result sent back to Claude.") } } // Add tool results to conversation history messages.push({ role: 'user', content: toolResults }) } if (iterationCount >= maxIterations) { console.log("\n⚠️ Reached maximum iteration limit. Task may not be complete.") } console.log("\n=== Agentic loop completed ===") ``` The agentic loop works as follows: 1. **Initial Request**: Send the initial prompt to Claude with the tool definition 2. **Iteration Loop**: For each iteration (up to 10 times): - Claude generates a response with optional tool calls - If there are tool calls, execute the Python code in the sandbox - Send execution results back to Claude (including errors or success messages) - Claude can then refine the code based on the feedback 3. **Completion**: Loop ends when Claude signals no more tool calls are needed or max iterations reached This approach allows Claude to: - Fix errors if the initial code fails - Iterate on the analysis if results aren't satisfactory - Handle edge cases discovered during execution - Improve visualizations based on the actual data **Key advantages of this approach:** - **Secure execution:** Code runs in isolated Daytona sandboxes - **Automatic artifact capture:** Charts, tables, and outputs are automatically extracted - **Error handling:** Built-in error detection and logging - **Language agnostic:** While we used Python here, Daytona supports multiple languages ### 4. Running Your Analysis Now you can run the complete code to see the results. ```bash python data-analysis.py ``` ```bash npx tsx data-analysis.ts ``` You should see the chart in your project directory that will look similar to this: Vehicle valuation by manufacturing year chart ### 5. Complete Implementation Here are the complete, ready-to-run examples with the agentic loop: ```python import base64 from dotenv import load_dotenv from daytona import Daytona, Sandbox from anthropic import Anthropic from typing import TypedDict class ExecutionResult(TypedDict): stdout: str exit_code: int charts: list def main(): load_dotenv() # Create sandbox daytona = Daytona() sandbox = daytona.create() # Upload the dataset to the sandbox sandbox.fs.upload_file("dataset.csv", "/home/daytona/dataset.csv") initial_prompt = """ I have a CSV file with vehicle valuations saved in the sandbox at /home/daytona/dataset.csv. Relevant columns: - 'year': integer, the manufacturing year of the vehicle - 'price_in_euro': float, the listed price of the vehicle in Euros Analyze how price varies by manufacturing year. Drop rows where 'year' or 'price_in_euro' is missing, non-numeric, or an outlier. Create a line chart showing average price per year. Write Python code that analyzes the dataset based on my request and produces a matplotlib chart accordingly. Always finish with plt.show() to display the chart.""" anthropic = Anthropic() tools = [ { 'name': 'run_python_code', 'description': 'Run Python code in the sandbox environment and get execution results', 'input_schema': { 'type': 'object', 'properties': { 'code': { 'type': 'string', 'description': 'The Python code to run', }, }, 'required': ['code'], }, }, ] # Initialize conversation history messages = [{'role': 'user', 'content': initial_prompt}] continue_loop = True iteration_count = 0 max_iterations = 10 print("Starting agentic loop...\n") while continue_loop and iteration_count < max_iterations: iteration_count += 1 print(f"\n=== Iteration {iteration_count} ===") print("Waiting for the model response...") # Get response from Claude msg = anthropic.messages.create( model='claude-sonnet-4-5', max_tokens=64000, messages=messages, tools=tools ) # Log Claude's text response for content_block in msg.content: if content_block.type == 'text': print("\nClaude's response:") print(content_block.text) # Check if Claude wants to use any tools tool_uses = [block for block in msg.content if block.type == 'tool_use'] if len(tool_uses) == 0: # No more tool uses, Claude is done print("\nTask completed - no more actions needed.") continue_loop = False break # Add Claude's response to message history messages.append({'role': 'assistant', 'content': msg.content}) # Execute all tool calls and collect results tool_results = [] for tool_use in tool_uses: if tool_use.name == 'run_python_code': code = tool_use.input['code'] print("\n--- Executing Python code in sandbox ---") print(code) print("--- End of code ---\n") # Execute the code in the sandbox execution_result = run_ai_generated_code(sandbox, code) # Format the tool result result_content = "" if execution_result['exit_code'] == 0: result_content += "Execution successful!\n\n" if execution_result['stdout']: result_content += f"Output:\n{execution_result['stdout']}\n" if execution_result['charts'] and len(execution_result['charts']) > 0: result_content += f"\nGenerated {len(execution_result['charts'])} chart(s)." else: result_content += "\nNote: No charts were generated. Make sure to use plt.show() to display the chart." else: result_content += f"Execution failed with exit code {execution_result['exit_code']}\n\n" if execution_result['stdout']: result_content += f"Output:\n{execution_result['stdout']}\n" tool_results.append({ 'type': 'tool_result', 'tool_use_id': tool_use.id, 'content': result_content }) print("Execution result sent back to Claude.") # Add tool results to conversation history messages.append({'role': 'user', 'content': tool_results}) if iteration_count >= max_iterations: print("\n⚠️ Reached maximum iteration limit. Task may not be complete.") print("\n=== Agentic loop completed ===") def run_ai_generated_code(sandbox: Sandbox, ai_generated_code: str) -> ExecutionResult: execution = sandbox.process.code_run(ai_generated_code) result = ExecutionResult( stdout=execution.result or "", exit_code=execution.exit_code, charts=execution.artifacts.charts if execution.artifacts else [] ) # Save any charts that were generated if execution.artifacts and execution.artifacts.charts: result_idx = 0 for chart in execution.artifacts.charts: if chart.png: filename = f'chart-{result_idx}.png' with open(filename, 'wb') as f: f.write(base64.b64decode(chart.png)) print(f'✓ Chart saved to {filename}') result_idx += 1 return result if __name__ == "__main__": main() ``` ```typescript import "dotenv/config"; import fs from "fs"; import Anthropic from "@anthropic-ai/sdk"; import { Daytona, Sandbox } from "@daytonaio/sdk"; import type { MessageParam, Tool, ToolUseBlock, } from "@anthropic-ai/sdk/resources/messages.mjs"; interface CodeRunToolInput { code: string; } interface ExecutionResult { stdout: string; exitCode: number; charts?: Array<{ png?: string }>; } async function main() { // Create sandbox const daytona = new Daytona(); const sandbox = await daytona.create(); // Upload the dataset to the sandbox await sandbox.fs.uploadFile("dataset.csv", "/home/daytona/dataset.csv"); const initialPrompt = ` I have a CSV file with vehicle valuations saved in the sandbox at /home/daytona/dataset.csv. Relevant columns: - 'year': integer, the manufacturing year of the vehicle - 'price_in_euro': float, the listed price of the vehicle in Euros Analyze how price varies by manufacturing year. Drop rows where 'year' or 'price_in_euro' is missing, non-numeric, or an outlier. Create a line chart showing average price per year. Write Python code that analyzes the dataset based on my request and produces a matplotlib chart accordingly. Always finish with plt.show() to display the chart.`; const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); const tools: Tool[] = [ { name: "run_python_code", description: "Run Python code in the sandbox environment and get execution results", input_schema: { type: "object", properties: { code: { type: "string", description: "The Python code to run", }, }, required: ["code"], }, }, ]; // Initialize conversation history const messages: MessageParam[] = [ { role: "user", content: initialPrompt }, ]; let continueLoop = true; let iterationCount = 0; const maxIterations = 10; console.log("Starting agentic loop...\n"); while (continueLoop && iterationCount < maxIterations) { iterationCount++; console.log(`\n=== Iteration ${iterationCount} ===`); console.log("Waiting for the model response..."); // Get response from Claude const stream = anthropic.messages.stream({ model: "claude-sonnet-4-5", max_tokens: 64000, messages: messages, tools: tools, }); const message = await stream.finalMessage(); // Log Claude's text response for (const contentBlock of message.content) { if (contentBlock.type === "text") { console.log("\nClaude's response:"); console.log(contentBlock.text); } } // Check if Claude wants to use any tools const toolUses = message.content.filter( (block): block is ToolUseBlock => block.type === "tool_use" ); if (toolUses.length === 0) { // No more tool uses, Claude is done console.log("\nTask completed - no more actions needed."); continueLoop = false; break; } // Add Claude's response to message history messages.push({ role: "assistant", content: message.content, }); // Execute all tool calls and collect results const toolResults = []; for (const toolUse of toolUses) { if (toolUse.name === "run_python_code") { const code = (toolUse.input as CodeRunToolInput).code; console.log("\n--- Executing Python code in sandbox ---"); console.log(code); console.log("--- End of code ---\n"); // Execute the code in the sandbox const executionResult = await runAIGeneratedCode(sandbox, code); // Format the tool result let resultContent = ""; if (executionResult.exitCode === 0) { resultContent += `Execution successful!\n\n`; if (executionResult.stdout) { resultContent += `Output:\n${executionResult.stdout}\n`; } if (executionResult.charts && executionResult.charts.length > 0) { resultContent += `\nGenerated ${executionResult.charts.length} chart(s).`; } else { resultContent += `\nNote: No charts were generated. Make sure to use plt.show() to display the chart.`; } } else { resultContent += `Execution failed with exit code ${executionResult.exitCode}\n\n`; if (executionResult.stdout) { resultContent += `Output:\n${executionResult.stdout}\n`; } } toolResults.push({ type: "tool_result" as const, tool_use_id: toolUse.id, content: resultContent, }); console.log("Execution result sent back to Claude."); } } // Add tool results to conversation history messages.push({ role: "user", content: toolResults, }); } if (iterationCount >= maxIterations) { console.log( "\n⚠️ Reached maximum iteration limit. Task may not be complete." ); } console.log("\n=== Agentic loop completed ==="); } async function runAIGeneratedCode( sandbox: Sandbox, aiGeneratedCode: string ): Promise { const execution = await sandbox.process.codeRun(aiGeneratedCode); const result: ExecutionResult = { stdout: execution.result || "", exitCode: execution.exitCode, charts: execution.artifacts?.charts, }; // Save any charts that were generated if (execution.artifacts?.charts) { let resultIdx = 0; for (const chart of execution.artifacts.charts) { if (chart.png) { const filename = `chart-${resultIdx}.png`; fs.writeFileSync(filename, chart.png, { encoding: "base64", }); console.log(`✓ Chart saved to ${filename}`); resultIdx++; } } } return result; } main().catch(console.error); ``` This guide demonstrates how to use the `DaytonaPlugin` for Google ADK to build an agent that generates, tests, and verifies code in a secure sandbox environment. The plugin enables agents to execute Python, JavaScript, and TypeScript code, run shell commands, and manage files within isolated Daytona sandboxes. In this example, we build a code generator agent that takes a natural language description of a function, generates the implementation in TypeScript, creates test cases, executes them in the sandbox, and iterates until all tests pass before returning the verified code. --- ### 1. Workflow Overview You describe the function you want in plain English, specifying the language (Python, JavaScript, or TypeScript). The agent generates the implementation, writes tests for it, and executes everything in a Daytona sandbox. If tests fail, the agent automatically fixes the code and re-runs until all tests pass. Only then does it return the verified, working code. The key benefit: you receive code that has already been tested and verified, not just generated. ### 2. Project Setup #### Clone the Repository Clone the Daytona repository and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona cd daytona/guides/python/google-adk/code-generator-agent/gemini ``` #### Install Dependencies :::note[Python Version Requirement] This example requires **Python 3.10 or higher**. It's recommended to use a virtual environment (e.g., `venv` or `poetry`) to isolate project dependencies. ::: Install the required packages for this example: ```bash pip install -U google-adk daytona-adk python-dotenv ``` The packages include: - `google-adk`: Google's Agent Development Kit for building AI agents - `daytona-adk`: Provides the `DaytonaPlugin` that enables secure code execution in Daytona sandboxes - `python-dotenv`: Used for loading environment variables from `.env` file #### Configure Environment Get your API keys and configure your environment: 1. **Daytona API key:** Get it from [Daytona Dashboard](https://app.daytona.io/dashboard/keys) 2. **Google API key:** Get it from [Google AI Studio](https://aistudio.google.com/apikey) Create a `.env` file in your project: ```bash DAYTONA_API_KEY=dtn_*** GOOGLE_API_KEY=*** ``` ### 3. Understanding the Core Components Before diving into the implementation, let's understand the key components we'll use: #### Google ADK Components - **Agent**: The AI model wrapper that processes requests and decides which tools to use. It receives instructions, has access to tools, and generates responses. - **App**: A top-level container that bundles agents with plugins into a single configuration unit. It provides centralized management for shared resources and defines the root agent for your workflow. - **InMemoryRunner**: The execution engine that runs agents and manages conversation state. It orchestrates the event-driven execution loop, handles message processing, and manages services like session history and artifact storage. :::note[Running the Agent] There are two ways to run Google ADK agents: using the `App` class with `InMemoryRunner`, or using `InMemoryRunner` directly with just an agent. The `App` serves as a configuration container that bundles agents with plugins, while the `Runner` handles actual execution and lifecycle management. This guide uses the `App` approach for cleaner organization of agents and plugins. ::: #### Daytona Plugin The `DaytonaPlugin` provides tools that allow the agent to: - Execute code in Python, JavaScript, or TypeScript - Run shell commands - Upload and read files - Start long-running background processes All operations happen in an isolated sandbox that is automatically cleaned up when done. ### 4. Initialize Environment and Imports First, we set up our imports and load environment variables: ```python import asyncio import logging from dotenv import load_dotenv from google.adk.agents import Agent from google.adk.apps import App from google.adk.runners import InMemoryRunner from daytona_adk import DaytonaPlugin load_dotenv() logging.basicConfig(level=logging.DEBUG) ``` **What each import does:** - `asyncio`: Required for running the async ADK runner - `logging`: Enables debug output to see agent reasoning - `load_dotenv`: Loads API keys from your `.env` file - `Agent`, `App`, `InMemoryRunner`: Core Google ADK components - `DaytonaPlugin`: Provides sandbox execution tools to the agent **Logging configuration:** The `logging.basicConfig(level=logging.DEBUG)` line configures Python's logging to show detailed debug output. You can adjust the logging level by passing different values: - `logging.DEBUG`: Most verbose, shows all internal operations including DaytonaPlugin sandbox creation and tool invocations - `logging.INFO`: Shows informational messages about agent progress - `logging.WARNING`: Shows only warnings and errors - `logging.ERROR`: Shows only errors :::tip[Behind the Scenes] With `DEBUG` level logging enabled, you can see the DaytonaPlugin's internal operations, including when the sandbox is created, when the `execute_code_in_daytona` tool is invoked, and when cleanup occurs. The plugin's `plugin_name` (configurable, defaults to `daytona_plugin`) appears in these log messages, making it easy to trace plugin activity. ::: ### 5. Define the Response Extractor The ADK runner returns a list of events from the agent's execution. We need a helper function to extract the final text response: ```python def extract_final_response(response: list) -> str: """Extract the final text response from a list of ADK events.""" for event in reversed(response): text_parts = [] if hasattr(event, "text") and event.text: return event.text if hasattr(event, "content") and event.content: content = event.content if hasattr(content, "parts") and content.parts: for part in content.parts: if hasattr(part, "text") and part.text: text_parts.append(part.text) if text_parts: return "".join(text_parts) if hasattr(content, "text") and content.text: return content.text if isinstance(event, dict): text = event.get("text") or event.get("content", {}).get("text") if text: return text return "" ``` This function iterates through events in reverse order to find the last text response. It handles multiple possible event structures that the ADK may return. ### 6. Define the Agent Instruction The instruction is critical - it defines how the agent behaves. Our instruction enforces a test-driven workflow: ```python AGENT_INSTRUCTION = """You are a code generator agent that writes verified, working code. You support Python, JavaScript, and TypeScript. Your workflow for every code request: 1. Write the function 2. Write tests for it 3. EXECUTE the code in the sandbox to verify it works - do not skip this step 4. If execution fails, fix and re-execute until tests pass 5. Once verified, respond with ONLY the function (no tests) You must always execute code before responding. Never return untested code. Only include tests in your response if the user explicitly asks for them. """ ``` **Key aspects of this instruction:** - **Enforces execution**: The agent must run code in the sandbox before responding - **Iterative fixing**: If tests fail, the agent fixes and retries - **Controlled output**: By default, the final response contains only the working function. If you want to see the tests, include an instruction to return them in your prompt. - **Multi-language**: Supports Python, JavaScript, and TypeScript ### 7. Configure the Daytona Plugin Initialize the plugin that provides sandbox execution capabilities: ```python plugin = DaytonaPlugin( labels={"example": "code-generator"}, ) ``` **Configuration options:** - `labels`: Custom metadata tags for the sandbox (useful for tracking/filtering) - `api_key`: Daytona API key (defaults to `DAYTONA_API_KEY` env var) - `sandbox_name`: Custom name for the sandbox - `plugin_name`: Name displayed in logs when the plugin logs messages (defaults to `daytona_plugin`) - `env_vars`: Environment variables to set in the sandbox - `auto_stop_interval`: Minutes before auto-stop (default: 15) - `auto_delete_interval`: Minutes before auto-delete (disabled by default) ### 8. Create the Agent Create the agent with the Gemini model, our instruction, and the Daytona tools: ```python agent = Agent( model="gemini-2.5-pro", name="code_generator_agent", instruction=AGENT_INSTRUCTION, tools=plugin.get_tools(), ) ``` **Parameters explained:** - `model`: The Gemini model to use for reasoning and code generation - `name`: Identifier for the agent - `instruction`: The behavioral guidelines we defined - `tools`: List of tools from the Daytona plugin that the agent can use ### 9. Create the App and Runner Bundle the agent and plugin into an App, then run it: ```python app = App( name="code_generator_app", root_agent=agent, plugins=[plugin], ) async with InMemoryRunner(app=app) as runner: prompt = "Write a TypeScript function called 'groupBy' that takes an array and a key function, and groups array elements by the key. Use proper type annotations." response = await runner.run_debug(prompt) final_response = extract_final_response(response) print(final_response) ``` **What happens here:** 1. The `App` bundles the agent with the plugin for proper lifecycle management 2. `InMemoryRunner` is used as an async context manager (the `async with` statement). A context manager in Python automatically handles setup and cleanup - when the code enters the `async with` block, the runner initializes; when it exits (either normally or due to an error), the runner cleans up resources. 3. `run_debug` sends the prompt and returns all execution events 4. The sandbox is automatically deleted when the `async with` block exits - this cleanup happens regardless of whether the code completed successfully or raised an exception ### 10. Running the Example Run the complete example: ```bash python main.py ``` #### Understanding the Agent's Execution Flow When you run the code, the agent works through your request step by step. With `logging.DEBUG` enabled, you'll see detailed output including: - **DaytonaPlugin operations**: Sandbox creation, tool invocations (`execute_code_in_daytona`), and cleanup - **LLM requests and responses**: The prompts sent to Gemini and the responses received - **Plugin registration**: Confirmation that the `daytona_plugin` was registered with the agent Here's what the debug output reveals about each step: **Step 1: Sandbox Creation** ``` DEBUG:daytona_adk.plugin:Daytona sandbox created: e38f8574-48ac-48f1-a0ff-d922d02b0fcb INFO:google_adk.google.adk.plugins.plugin_manager:Plugin 'daytona_plugin' registered. ``` The DaytonaPlugin creates an isolated sandbox and registers itself with the agent. **Step 2: Agent receives the request** The agent receives your prompt and understands it needs to create a TypeScript `groupBy` function with proper type annotations. **Step 3: Agent generates code and tests** The agent writes both the implementation and test cases, then calls the `execute_code_in_daytona` tool: ``` DEBUG:google_adk.google.adk.models.google_llm: LLM Response: ----------------------------------------------------------- Function calls: name: execute_code_in_daytona, args: {'code': "...", 'language': 'typescript'} ``` **Step 4: Code execution in sandbox** ``` DEBUG:daytona_adk.plugin:Before tool: execute_code_in_daytona DEBUG:daytona_adk.tools:Executing typescript code (length: 1570 chars) DEBUG:daytona_adk.tools:Code execution completed with exit_code: 0 DEBUG:daytona_adk.plugin:After tool: execute_code_in_daytona ``` The plugin executes the code in the isolated TypeScript environment and returns the result. **Step 5: Agent iterates if needed** If tests fail (exit_code != 0), the agent analyzes the error, fixes the code, and re-executes until all tests pass. **Step 6: Agent returns verified code** Once tests pass, the agent responds with only the working function. If you included an instruction to return tests in your prompt, the tests will also be included in the response. **Step 7: Cleanup** ``` INFO:daytona_adk.plugin:Deleting Daytona sandbox... INFO:daytona_adk.plugin:Daytona sandbox deleted. INFO:google_adk.google.adk.runners:Runner closed. ``` When the context manager exits, the sandbox is automatically deleted. #### Example Output When the agent completes the task, you'll see output like: ```` AGENT RESPONSE: ------------------------------------------------------------ ```typescript function groupBy( array: T[], keyFn: (item: T) => K ): Record { return array.reduce((result, item) => { const key = keyFn(item); if (!result[key]) { result[key] = []; } result[key].push(item); return result; }, {} as Record); } ``` ============================================================ App closed, sandbox cleaned up. Done! ```` The agent has already tested this code in the sandbox before returning it, so you can trust that the implementation works correctly. #### Requesting Tests in the Response If you want to see the tests that were executed in the sandbox, include an instruction to return them in your prompt: ```python prompt = "Write a TypeScript function called 'groupBy' that takes an array and a key function, and groups array elements by the key. Use proper type annotations. Return the tests also in a separate code block" ``` With this prompt, the agent will return both the function and the tests: ```` ```typescript function groupBy( array: T[], keyFn: (item: T) => K ): Record { return array.reduce((result, item) => { const key = keyFn(item); if (!result[key]) { result[key] = []; } result[key].push(item); return result; }, {} as Record); } ``` ```typescript import { deepStrictEqual } from 'assert'; // Test case 1: Group by a property of an object const array1 = [ { id: 1, category: 'A' }, { id: 2, category: 'B' }, { id: 3, category: 'A' }, ]; const result1 = groupBy(array1, (item) => item.category); deepStrictEqual(result1, { A: [ { id: 1, category: 'A' }, { id: 3, category: 'A' }, ], B: [{ id: 2, category: 'B' }], }); // Test case 2: Group by length of strings const array2 = ['apple', 'banana', 'cherry', 'date']; const result2 = groupBy(array2, (item) => item.length); deepStrictEqual(result2, { 5: ['apple'], 6: ['banana', 'cherry'], 4: ['date'], }); console.log('All tests passed!'); ``` ```` ### 11. Complete Implementation Here is the complete, ready-to-run example with additional output formatting for better readability: ```python """Code Generator & Tester Agent Example.""" import asyncio import logging from dotenv import load_dotenv from google.adk.agents import Agent from google.adk.apps import App from google.adk.runners import InMemoryRunner from daytona_adk import DaytonaPlugin load_dotenv() logging.basicConfig(level=logging.DEBUG) def extract_final_response(response: list) -> str: """Extract the final text response from a list of ADK events.""" for event in reversed(response): text_parts = [] if hasattr(event, "text") and event.text: return event.text if hasattr(event, "content") and event.content: content = event.content if hasattr(content, "parts") and content.parts: for part in content.parts: if hasattr(part, "text") and part.text: text_parts.append(part.text) if text_parts: return "".join(text_parts) if hasattr(content, "text") and content.text: return content.text if isinstance(event, dict): text = event.get("text") or event.get("content", {}).get("text") if text: return text return "" AGENT_INSTRUCTION = """You are a code generator agent that writes verified, working code. You support Python, JavaScript, and TypeScript. Your workflow for every code request: 1. Write the function 2. Write tests for it 3. EXECUTE the code in the sandbox to verify it works - do not skip this step 4. If execution fails, fix and re-execute until tests pass 5. Once verified, respond with ONLY the function (no tests) You must always execute code before responding. Never return untested code. Only include tests in your response if the user explicitly asks for them. """ async def main() -> None: """Run the code generator agent example.""" plugin = DaytonaPlugin( labels={"example": "code-generator"}, ) agent = Agent( model="gemini-2.5-pro", name="code_generator_agent", instruction=AGENT_INSTRUCTION, tools=plugin.get_tools(), ) app = App( name="code_generator_app", root_agent=agent, plugins=[plugin], ) async with InMemoryRunner(app=app) as runner: prompt = "Write a TypeScript function called 'groupBy' that takes an array and a key function, and groups array elements by the key. Use proper type annotations." print("\n" + "=" * 60) print("USER PROMPT:") print("=" * 60) print(prompt) print("-" * 60) response = await runner.run_debug(prompt) final_response = extract_final_response(response) print("\nAGENT RESPONSE:") print("-" * 60) print(final_response) print("=" * 60) print("\nApp closed, sandbox cleaned up. Done!") if __name__ == "__main__": asyncio.run(main()) ``` **Key advantages of this approach:** - **Verified code:** Every response has been tested in a real execution environment - **Secure execution:** Code runs in isolated Daytona sandboxes, not on your machine - **Multi-language support:** Generate and test Python, JavaScript, or TypeScript - **Automatic iteration:** Agent fixes issues until tests pass - **Flexible output:** Returns only the working function by default, or includes tests if explicitly requested in the prompt ### 12. API Reference For the complete API reference of the Daytona ADK plugin, including all available tools and configuration options, see the [daytona-adk documentation](https://github.com/daytonaio/daytona-adk-plugin#available-tools). Daytona provides a comprehensive set of guides to help you get started. The guides cover a wide range of topics, from basic usage to advanced topics, and showcase various types of integrations between Daytona and other tools. import { Image } from 'astro:assets' import chartImage from '../../../../../assets/docs/images/langchain-data-analysis-chart.png' This package provides the `DaytonaDataAnalysisTool` - LangChain tool integration that enables agents to perform secure Python data analysis in a sandboxed environment. It supports multi-step workflows, file uploads/downloads, and custom result handling, making it ideal for automating data analysis tasks with LangChain agents. This page demonstrates the use of this tool with a basic example analyzing a vehicle valuations dataset. Our goal is to analyze how vehicle prices vary by manufacturing year and create a line chart showing average price per year. --- ### 1. Workflow Overview You upload your dataset and provide a natural language prompt describing the analysis you want. The agent reasons about your request, determines how to use the `DaytonaDataAnalysisTool` to perform the task on your dataset, and executes the analysis securely in a Daytona sandbox. You provide the data and describe what insights you need - the agent handles the rest. ### 2. Project Setup #### Clone the Repository Clone the [repository](https://github.com/daytonaio/daytona) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/python/langchain/data-analysis/anthropic ``` #### Install Dependencies :::note[Python Version Requirement] This example requires **Python 3.10 or higher** because it uses LangChain 1.0+ syntax. It's recommended to use a virtual environment (e.g., `venv` or `poetry`) to isolate project dependencies. ::: Install the required packages for this example: ```bash pip install -U langchain langchain-anthropic langchain-daytona-data-analysis python-dotenv ``` The packages include: - `langchain`: LangChain framework for building AI agents - `langchain-anthropic`: Integration package connecting Claude (Anthropic) APIs and LangChain - `langchain-daytona-data-analysis`: Provides the `DaytonaDataAnalysisTool` for LangChain agents - `python-dotenv`: Used for loading environment variables from `.env` file #### Configure Environment Get your API keys and configure your environment: 1. **Daytona API key:** Get it from [Daytona Dashboard](https://app.daytona.io/dashboard/keys) 2. **Anthropic API key:** Get it from [Anthropic Console](https://console.anthropic.com/) Create a `.env` file in your project: ```bash DAYTONA_API_KEY=dtn_*** ANTHROPIC_API_KEY=sk-ant-*** ``` ### 3. Download Dataset We'll be using a publicly available dataset of vehicle valuation. You can download it directly from: [https://download.daytona.io/dataset.csv](https://download.daytona.io/dataset.csv) Download the file and save it as `dataset.csv` in your project directory. ### 4. Initialize the Language Model Models are the reasoning engine of LangChain agents - they drive decision-making, determine which tools to call, and interpret results. In this example, we'll use Anthropic's Claude model, which excels at code generation and analytical tasks. Configure the Claude model with the following parameters: ```python from langchain_anthropic import ChatAnthropic model = ChatAnthropic( model_name="claude-sonnet-4-5-20250929", temperature=0, timeout=None, max_retries=2, stop=None ) ``` **Parameters explained:** - `model_name`: Specifies the Claude model to use - `temperature`: Tunes the degree of randomness in generation - `max_retries`: Number of retries allowed for Anthropic API requests :::tip[Learn More About Models] For detailed information about LangChain models, different providers, and how to choose the right model for your use case, visit the [LangChain Models documentation](https://docs.langchain.com/oss/python/langchain/models). ::: ### 5. Define the Result Handler When the agent executes Python code in the sandbox, it generates artifacts like charts and output logs. We can define a handler function to process these results. This function will extract chart data from the execution artifacts and save them as PNG files: ```python import base64 from daytona import ExecutionArtifacts def process_data_analysis_result(result: ExecutionArtifacts): # Print the standard output from code execution print("Result stdout", result.stdout) result_idx = 0 for chart in result.charts: if chart.png: # Charts are returned in base64 format # Decode and save them as PNG files with open(f'chart-{result_idx}.png', 'wb') as f: f.write(base64.b64decode(chart.png)) print(f'Chart saved to chart-{result_idx}.png') result_idx += 1 ``` This handler processes execution artifacts by: - Logging stdout output from the executed code - Extracting chart data from the artifacts - Decoding base64-encoded PNG charts - Saving them to local files ### 6. Configure the Data Analysis Tool Now we'll initialize the `DaytonaDataAnalysisTool` and upload our dataset. ```python from langchain_daytona_data_analysis import DaytonaDataAnalysisTool # Initialize the tool with our result handler DataAnalysisTool = DaytonaDataAnalysisTool( on_result=process_data_analysis_result ) # Upload the dataset with metadata describing its structure with open("./dataset.csv", "rb") as f: DataAnalysisTool.upload_file( f, description=( "This is a CSV file containing vehicle valuations. " "Relevant columns:\n" "- 'year': integer, the manufacturing year of the vehicle\n" "- 'price_in_euro': float, the listed price of the vehicle in Euros\n" "Drop rows where 'year' or 'price_in_euro' is missing, non-numeric, or an outlier." ) ) ``` **Key points:** - The `on_result` parameter connects our custom result handler - The `description` provides context about the dataset structure to the agent - Column descriptions help the agent understand how to process the data - Data cleaning instructions ensure quality analysis ### 7. Create and Run the Agent Finally, we'll create the LangChain agent with our configured model and tool, then invoke it with our analysis request. ```python from langchain.agents import create_agent # Create the agent with the model and data analysis tool agent = create_agent(model, tools=[DataAnalysisTool], debug=True) # Invoke the agent with our analysis request agent_response = agent.invoke({ "messages": [{ "role": "user", "content": "Analyze how vehicles price varies by manufacturing year. Create a line chart showing average price per year." }] }) # Always close the tool to clean up sandbox resources DataAnalysisTool.close() ``` **What happens here:** 1. The agent receives your natural language request 2. It determines it needs to use the `DaytonaDataAnalysisTool` 3. Agent generates Python code to analyze the data 4. Code executes securely in the Daytona sandbox 5. Results are processed by our handler function 6. Charts are saved to your local directory 7. Sandbox resources are cleaned up at the end ### 8. Running Your Analysis Now you can run the complete code to see the results. ```bash python data_analysis.py ``` #### Understanding the Agent's Execution Flow When you run the code, the agent works through your request step by step. Here's what happens in the background: **Step 1: Agent receives and interprets the request** The agent acknowledges your analysis request: ``` AI Message: "I'll analyze how vehicle prices vary by manufacturing year and create a line chart showing the average price per year." ``` **Step 2: Agent generates Python code** The agent generates Python code to explore the dataset first: ```python import pandas as pd import matplotlib.pyplot as plt import numpy as np # Load the dataset df = pd.read_csv('/home/daytona/dataset.csv') # Display basic info about the dataset print("Dataset shape:", df.shape) print("\nFirst few rows:") print(df.head()) print("\nColumn names:") print(df.columns.tolist()) print("\nData types:") print(df.dtypes) ``` **Step 3: Code executes in Daytona sandbox** The tool runs this code in a secure sandbox and returns the output: ``` Result stdout Dataset shape: (100000, 15) First few rows: Unnamed: 0 ... offer_description 0 75721 ... ST-Line Hybrid Adapt.LED+Head-Up-Display Klima 1 80184 ... blue Trend,Viele Extras,Top-Zustand 2 19864 ... 35 e-tron S line/Matrix/Pano/ACC/SONOS/LM 21 3 76699 ... 2.0 Lifestyle Plus Automatik Navi FAP 4 92991 ... 1.6 T 48V 2WD Spirit LED, WR [5 rows x 15 columns] Column names: ['Unnamed: 0', 'brand', 'model', 'color', 'registration_date', 'year', 'price_in_euro', 'power_kw', 'power_ps', 'transmission_type', 'fuel_type', 'fuel_consumption_l_100km', 'fuel_consumption_g_km', 'mileage_in_km', 'offer_description'] Data types: Unnamed: 0 int64 brand object model object color object registration_date object year object price_in_euro object power_kw object power_ps object transmission_type object fuel_type object fuel_consumption_l_100km object fuel_consumption_g_km object mileage_in_km float64 offer_description object dtype: object ``` **Step 4: Agent generates detailed analysis code** Based on the initial dataset information, the agent generates more specific code to examine the key columns: ```python import pandas as pd import matplotlib.pyplot as plt import numpy as np # Load the dataset df = pd.read_csv('/home/daytona/dataset.csv') print("Dataset shape:", df.shape) print("\nColumn names:") print(df.columns.tolist()) # Check for year and price_in_euro columns print("\nChecking 'year' column:") print(df['year'].describe()) print("\nMissing values in 'year':", df['year'].isna().sum()) print("\nChecking 'price_in_euro' column:") print(df['price_in_euro'].describe()) print("\nMissing values in 'price_in_euro':", df['price_in_euro'].isna().sum()) ``` **Step 5: Execution results from sandbox** The code executes and returns column statistics: ``` Result stdout Dataset shape: (100000, 15) Column names: ['Unnamed: 0', 'brand', 'model', 'color', 'registration_date', 'year', 'price_in_euro', 'power_kw', 'power_ps', 'transmission_type', 'fuel_type', 'fuel_consumption_l_100km', 'fuel_consumption_g_km', 'mileage_in_km', 'offer_description'] Checking 'year' column: count 100000 unique 49 top 2019 freq 12056 Name: year, dtype: object Missing values in 'year': 0 Checking 'price_in_euro' column: count 100000 unique 11652 top 19990 freq 665 Name: price_in_euro, dtype: object Missing values in 'price_in_euro': 0 ``` **Step 6: Agent generates final analysis and visualization code** Now that the agent understands the data structure, it generates the complete analysis code with data cleaning, processing, and visualization: ```python import pandas as pd import matplotlib.pyplot as plt import numpy as np # Load the dataset df = pd.read_csv('/home/daytona/dataset.csv') print("Original dataset shape:", df.shape) # Clean the data - remove rows with missing values in year or price_in_euro df_clean = df.dropna(subset=['year', 'price_in_euro']) print(f"After removing missing values: {df_clean.shape}") # Convert to numeric and remove non-numeric values df_clean['year'] = pd.to_numeric(df_clean['year'], errors='coerce') df_clean['price_in_euro'] = pd.to_numeric(df_clean['price_in_euro'], errors='coerce') # Remove rows where conversion failed df_clean = df_clean.dropna(subset=['year', 'price_in_euro']) print(f"After removing non-numeric values: {df_clean.shape}") # Remove outliers using IQR method for both year and price def remove_outliers(df, column): Q1 = df[column].quantile(0.25) Q3 = df[column].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR return df[(df[column] >= lower_bound) & (df[column] <= upper_bound)] df_clean = remove_outliers(df_clean, 'year') print(f"After removing year outliers: {df_clean.shape}") df_clean = remove_outliers(df_clean, 'price_in_euro') print(f"After removing price outliers: {df_clean.shape}") print("\nCleaned data summary:") print(df_clean[['year', 'price_in_euro']].describe()) # Calculate average price per year avg_price_by_year = df_clean.groupby('year')['price_in_euro'].mean().sort_index() print("\nAverage price by year:") print(avg_price_by_year) # Create line chart plt.figure(figsize=(14, 7)) plt.plot(avg_price_by_year.index, avg_price_by_year.values, marker='o', linewidth=2, markersize=6, color='#2E86AB') plt.xlabel('Manufacturing Year', fontsize=12, fontweight='bold') plt.ylabel('Average Price (€)', fontsize=12, fontweight='bold') plt.title('Average Vehicle Price by Manufacturing Year', fontsize=14, fontweight='bold', pad=20) plt.grid(True, alpha=0.3, linestyle='--') plt.xticks(rotation=45) # Format y-axis to show currency ax = plt.gca() ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'€{x:,.0f}')) plt.tight_layout() plt.show() # Additional statistics print(f"\nTotal number of vehicles analyzed: {len(df_clean)}") print(f"Year range: {int(df_clean['year'].min())} - {int(df_clean['year'].max())}") print(f"Price range: €{df_clean['price_in_euro'].min():.2f} - €{df_clean['price_in_euro'].max():.2f}") print(f"Overall average price: €{df_clean['price_in_euro'].mean():.2f}") ``` This comprehensive code performs data cleaning, outlier removal, calculates averages by year, and creates a professional visualization. **Step 7: Final execution and chart generation** The code executes successfully in the sandbox, processes the data, and generates the visualization: ``` Result stdout Original dataset shape: (100000, 15) After removing missing values: (100000, 15) After removing non-numeric values: (99946, 15) After removing year outliers: (96598, 15) After removing price outliers: (90095, 15) Cleaned data summary: year price_in_euro count 90095.000000 90095.000000 mean 2016.698563 22422.266707 std 4.457647 12964.727116 min 2005.000000 150.000000 25% 2014.000000 12980.000000 50% 2018.000000 19900.000000 75% 2020.000000 29500.000000 max 2023.000000 62090.000000 Average price by year: year 2005.0 5968.124319 2006.0 6870.881523 2007.0 8015.234473 2008.0 8788.644495 2009.0 8406.198576 2010.0 10378.815972 2011.0 11540.640435 2012.0 13306.642261 2013.0 14512.707025 2014.0 15997.682899 2015.0 18563.864358 2016.0 20124.556294 2017.0 22268.083322 2018.0 24241.123673 2019.0 26757.469111 2020.0 29400.163494 2021.0 30720.168646 2022.0 33861.717552 2023.0 33119.840175 Name: price_in_euro, dtype: float64 Total number of vehicles analyzed: 90095 Year range: 2005 - 2023 Price range: €150.00 - €62090.00 Overall average price: €22422.27 Chart saved to chart-0.png ``` The agent successfully completed the analysis, showing that vehicle prices generally increased from 2005 (€5,968) to 2022 (€33,862), with a slight decrease in 2023. The result handler captured the generated chart and saved it as `chart-0.png`. You should see the chart in your project directory that will look similar to this: Vehicle valuation by manufacturing year chart ### 9. Complete Implementation Here is the complete, ready-to-run example: ```python import base64 from dotenv import load_dotenv from langchain.agents import create_agent from langchain_anthropic import ChatAnthropic from daytona import ExecutionArtifacts from langchain_daytona_data_analysis import DaytonaDataAnalysisTool load_dotenv() model = ChatAnthropic( model_name="claude-sonnet-4-5-20250929", temperature=0, timeout=None, max_retries=2, stop=None ) def process_data_analysis_result(result: ExecutionArtifacts): # Print the standard output from code execution print("Result stdout", result.stdout) result_idx = 0 for chart in result.charts: if chart.png: # Save the png to a file # The png is in base64 format. with open(f'chart-{result_idx}.png', 'wb') as f: f.write(base64.b64decode(chart.png)) print(f'Chart saved to chart-{result_idx}.png') result_idx += 1 def main(): DataAnalysisTool = DaytonaDataAnalysisTool( on_result=process_data_analysis_result ) try: with open("./dataset.csv", "rb") as f: DataAnalysisTool.upload_file( f, description=( "This is a CSV file containing vehicle valuations. " "Relevant columns:\n" "- 'year': integer, the manufacturing year of the vehicle\n" "- 'price_in_euro': float, the listed price of the vehicle in Euros\n" "Drop rows where 'year' or 'price_in_euro' is missing, non-numeric, or an outlier." ) ) agent = create_agent(model, tools=[DataAnalysisTool], debug=True) agent_response = agent.invoke( {"messages": [{"role": "user", "content": "Analyze how vehicles price varies by manufacturing year. Create a line chart showing average price per year."}]} ) finally: DataAnalysisTool.close() if __name__ == "__main__": main() ``` **Key advantages of this approach:** - **Secure execution:** Code runs in isolated Daytona sandbox - **Automatic artifact capture:** Charts, tables, and outputs are automatically extracted - **Natural language interface:** Describe analysis tasks in plain English - **Framework integration:** Seamlessly works with LangChain's agent ecosystem ### 10. API Reference The following public methods are available on `DaytonaDataAnalysisTool`: #### download_file ```python def download_file(remote_path: str) -> bytes ``` Downloads a file from the sandbox by its remote path. **Arguments**: - `remote_path` - str: Path to the file in the sandbox. **Returns**: - `bytes` - File contents. **Example**: ```python # Download a file from the sandbox file_bytes = tool.download_file("/home/daytona/results.csv") ``` #### upload_file ```python def upload_file(file: IO, description: str) -> SandboxUploadedFile ``` Uploads a file to the sandbox. The file is placed in `/home/daytona/`. **Arguments**: - `file` - IO: File-like object to upload. - `description` - str: Description of the file, explaining its purpose and the type of data it contains. **Returns**: - [`SandboxUploadedFile`](#sandboxuploadedfile) - Metadata about the uploaded file. **Example**: Suppose you want to analyze sales data for a retail business. You have a CSV file named `sales_q3_2025.csv` containing columns like `transaction_id`, `date`, `product`, `quantity`, and `revenue`. You want to upload this file and provide a description that gives context for the analysis. ```python with open("sales_q3_2025.csv", "rb") as f: uploaded = tool.upload_file( f, "CSV file containing Q3 2025 retail sales transactions. Columns: transaction_id, date, product, quantity, revenue." ) ``` #### remove_uploaded_file ```python def remove_uploaded_file(uploaded_file: SandboxUploadedFile) -> None ``` Removes a previously uploaded file from the sandbox. **Arguments**: - `uploaded_file` - [`SandboxUploadedFile`](#sandboxuploadedfile): The file to remove. **Returns**: - None **Example**: ```python # Remove an uploaded file tool.remove_uploaded_file(uploaded) ``` #### get_sandbox ```python def get_sandbox() -> Sandbox ``` Gets the current sandbox instance. This method provides access to the Daytona sandbox instance, allowing you to inspect sandbox properties and metadata, as well as perform any sandbox-related operations. For details on available attributes and methods, see the [Sandbox](#sandbox) data structure section below. **Arguments**: - None **Returns**: - [`Sandbox`](#sandbox) - Sandbox instance. **Example**: ```python sandbox = tool.get_sandbox() ``` #### install_python_packages ```python def install_python_packages(package_names: str | list[str]) -> None ``` Installs one or more Python packages in the sandbox using pip. **Arguments**: - `package_names` - str | list[str]: Name(s) of the package(s) to install. **Returns**: - None :::note The list of preinstalled packages in a sandbox can be found at [Daytona's Default Snapshot documentation](https://www.daytona.io/docs/en/snapshots.md#default-snapshots). ::: **Example**: ```python # Install a single package tool.install_python_packages("pandas") # Install multiple packages tool.install_python_packages(["numpy", "matplotlib"]) ``` #### close ```python def close() -> None ``` Closes and deletes the sandbox environment. **Arguments**: - None **Returns**: - None :::note Call this method when you are finished with all data analysis tasks to properly clean up resources and avoid unnecessary usage. ::: **Example**: ```python # Close the sandbox and clean up tool.close() ``` ### 11. Data Structures #### SandboxUploadedFile Represents metadata about a file uploaded to the sandbox. - `name`: `str` - Name of the uploaded file in the sandbox - `remote_path`: `str` - Full path to the file in the sandbox - `description`: `str` - Description provided during upload #### Sandbox Represents a Daytona sandbox instance. See the full structure and API in the [Daytona Python SDK Sandbox documentation](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandbox). import { Image } from 'astro:assets' import lettaCodeAgentResult from '../../../../../assets/docs/images/letta-code-agent-result.gif' This guide demonstrates how to run an autonomous coding agent based on [Letta Code](https://docs.letta.com/letta-code/) inside a Daytona sandbox environment. The agent can develop web apps, write code in any language, install dependencies, and run scripts. Letta Code uses stateful agents with built-in memory, allowing conversations to persist across sessions. --- ### 1. Workflow Overview When you launch the main script, a Daytona sandbox is created and Letta Code is installed inside it. The agent is configured with a custom Daytona-aware system prompt. The script provides an interactive CLI interface where you can chat with the agent and issue commands: ``` $ npm run start Creating sandbox... Installing Letta Code... Starting Letta Code... Initializing agent... Agent initialized. Press Ctrl+C at any time to exit. User: create a beautiful, professional themed app that lets me write markdown documents and render them live Thinking... 🔧 TodoWrite 🔧 Write /home/daytona/markdown-editor/index.html 🔧 TodoWrite 🔧 Start HTTP server on port 8080 🔧 TodoWrite Perfect! I've created a beautiful markdown editor with live preview for you! 🎉 ## Access your app here: https://8080-c157e5cb-5e11-4bb6-883d-c873169223b8.proxy.daytona.works ## Features: ✨ **Live Preview** — Real-time markdown rendering 📝 **Full Markdown Support** — Headers, text styles, lists, code blocks, tables, links, images 💾 **Auto-Save** — Persists to browser localStorage 📥 **Export** — Download as `.md` or standalone `.html` ``` The agent can host web apps and provide you with a preview link using the [Daytona Preview Links](https://www.daytona.io/docs/en/preview-and-authentication.md) feature. When your task involves running or previewing a web application, the agent automatically hosts the app and generates a link for you to inspect the live result: Markdown editor demo generated by Letta Code agent You can continue interacting with your agent until you are finished. When you exit the program, the sandbox will be deleted automatically. ### 2. Project Setup #### Clone the Repository First, clone the daytona [repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/letta-code ``` #### Configure Environment Get your Daytona API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys) and your Letta API key from [Letta Platform](https://app.letta.com/api-keys). Copy `.env.example` to `.env` and add your keys: ```bash DAYTONA_API_KEY=your_daytona_key SANDBOX_LETTA_API_KEY=your_letta_api_key ``` :::caution[API Key Security] In this example, your Letta API key is passed into the sandbox environment and may be accessible to any code executed within it. ::: #### Local Usage :::note[Node.js Version] Node.js 18 or newer is required to run this example. Please ensure your environment meets this requirement before proceeding. ::: Install dependencies: ```bash npm install ``` Run the example: ```bash npm run start ``` The Letta Code agent will initialize and present an interactive prompt where you can issue commands. ### 3. Understanding the Agent's Architecture This example consists of two main TypeScript files: - **index.ts**: The main program that creates the Daytona sandbox, installs Letta Code, configures the system prompt, and provides an interactive CLI interface. - **letta-session.ts**: A helper class that manages PTY-based bidirectional communication with Letta Code, handling JSON message streaming and response parsing. #### Initialization On initialization, the main program: 1. Creates a new [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md) with your Letta API key included in the environment variables. 2. Installs Letta Code globally inside the sandbox by running `npm install` with [process execution](https://www.daytona.io/docs/en/process-code-execution.md#process-execution). 3. Creates a [PTY (pseudoterminal)](https://www.daytona.io/docs/en/pty.md) session in the sandbox for bidirectional communication with Letta Code. 4. Launches Letta Code in [bidirectional headless mode](https://docs.letta.com/letta-code/headless/) with stream-json format through the PTY. 5. Waits for user input and sends prompts to the agent through the PTY session. #### Main Program Code The program creates a [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md) with the Letta API key passed as an environment variable: ```typescript sandbox = await daytona.create({ envVars: { LETTA_API_KEY: process.env.SANDBOX_LETTA_API_KEY }, }) ``` #### Running Letta Code in a Pseudoterminal A [PTY (pseudoterminal)](https://www.daytona.io/docs/en/pty.md) is created for bidirectional communication with Letta Code: ```typescript this.ptyHandle = await this.sandbox.process.createPty({ id: `letta-pty-${Date.now()}`, onData: (data: Uint8Array) => this.handleData(data), }) ``` Letta Code is then launched in [bidirectional headless mode](https://docs.letta.com/letta-code/headless/#bidirectional-mode) through the PTY: ```typescript await this.ptyHandle.sendInput( `letta --new --system-custom "${systemPrompt.replace(/"/g, '\\"')}" --input-format stream-json --output-format stream-json --yolo -p\n`, ) ``` The `stream-json` setting is used for the input and output formats, enabling our program to send and receive JSON messages to and from the agent in real-time. The `--system-custom` prompt allows us to pass a custom system prompt to the agent. Our prompt configures the agent with Daytona-specific instructions, including a URL pattern so the agent can generate preview links. The `--yolo` flag allows the agent to run shell commands without requiring explicit user approval for each command. #### Message Handling To send prompts to the agent, the main script calls the `processPrompt()` method, which formats the user input as a JSON message and sends it to the PTY using `this.ptyHandle.sendInput()` as demonstrated above. Formatted user messages look like this: ```json {"type": "user", "message": {"role": "user", "content": "create a simple web server"}} ``` The agent responds with streaming JSON messages. Tool calls arrive as fragments: ```json {"type": "message", "message_type": "approval_request_message", "tool_call": {"tool_call_id": "call_123", "name": "Bash", "arguments": "{\"command\": \"python3 -m http.server 8080\"}"}} ``` These JSON fragments are parsed by the `handleParsedMessage()` method. When multiple consecutive fragments are received for the same tool call, they are combined into a single tool call object. When a tool call or message is finished, the result is formatted and displayed to the user. #### Clean up When you exit the main program, the Daytona sandbox and all files are automatically deleted. **Key advantages:** - Secure, isolated execution in Daytona sandboxes - Stateful agents with persistent memory across sessions - Full Letta Code capabilities including file operations and shell commands - Agents can be viewed in [Letta's Agent Development Environment](https://app.letta.com/) - Automatic preview link generation for hosted services - Multi-language and full-stack support - Simple setup and automatic cleanup This guide demonstrates how to configure the [Mastra coding agent](https://github.com/mastra-ai/template-coding-agent) to use Daytona sandboxes, enabling you to leverage AI capabilities for any coding-related task in a secure, isolated environment. --- ### 1. Workflow Overview Once configured, you can use Mastra Studio to interact with the coding agent through a ChatGPT-like interface. This enables human-in-the-loop workflows where you can guide the agent, review its decisions, and iterate on solutions in real-time; all while the agent executes tasks securely within Daytona sandboxes. ### 2. Project Setup :::note[Node.js Version] Node.js version 20 or higher is required to run the coding agent. Please ensure your environment meets this requirement before proceeding. ::: #### Clone the Repository Clone the Mastra coding agent template repository, which includes the agent implementation and Daytona integration: ```bash git clone https://github.com/mastra-ai/template-coding-agent.git cd template-coding-agent ``` #### Configure Environment Create a `.env` file in the project root directory: ```bash touch .env ``` The `.env` file requires the following configuration: - **LLM Provider**: The AI model provider for your coding agent - **Model**: The specific model to use from your chosen provider - **Sandbox Provider**: Daytona configuration for isolated execution For this guide, we'll use OpenAI as the LLM provider with the `gpt-4o-mini` model: ```env OPENAI_API_KEY=your_openai_key MODEL=openai/gpt-4o-mini ``` Next, configure Daytona as your sandbox provider by adding your API key (available from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys)): ```env DAYTONA_API_KEY=your-daytona-api-key-here ``` #### Install Dependencies Install the required packages using pnpm: ```bash pnpm install ``` ### 3. Running the Agent Mastra Studio provides a ChatGPT-like interface for interacting with your coding agent. This mode offers: - **Conversation History**: Previous conversations are stored and organized in threads - **Visual Debugging**: Inspect agent execution steps, workflow, and tool calls - **Model Switching**: Easily switch between different AI models - **Tool Inspection**: View which tools your agent is using in real-time For a complete overview of all features and capabilities, visit the [Mastra Studio documentation](https://mastra.ai/docs/getting-started/studio). Start the dev server with: ```bash pnpm run dev ``` If the dev server starts successfully, you'll see the terminal output displaying the URLs where you can access Mastra Studio: ```bash │ Studio: http://localhost:4111 │ API: http://localhost:4111/api ``` Once started, open the provided URL in your browser to access the interactive interface. You can interact with your agent while monitoring its workflow in the terminal, where detailed logs show execution steps and low-level parameters. Below is an example of terminal logs generated when the agent calls the `writeFile` tool to create a JavaScript file with a basic "Hello, world!" output: ```json { "text": "", "toolCalls": [ { "type": "tool-call", "runId": "ab2a1d08-91c6-4028-9046-3446a721527f", "from": "AGENT", "payload": { "toolCallId": "call_NiLLgBmgrYLSL0MsrG54E4A5", "toolName": "writeFile", "args": { "sandboxId": "2152d23b-5742-47c2-9992-4414d4144869", "path": "hello.js", "content": "console.log('Hello, world!');" }, "providerMetadata": { "openai": { "itemId": "fc_00bba3412cd22a2b0069399fbaeef881909b0583f359cbc33c" } } } } ], "toolResults": [ { "type": "tool-result", "runId": "ab2a1d08-91c6-4028-9046-3446a721527f", "from": "AGENT", "payload": { "args": { "sandboxId": "2152d23b-5742-47c2-9992-4414d4144869", "path": "hello.js", "content": "console.log('Hello, world!');" }, "toolCallId": "call_NiLLgBmgrYLSL0MsrG54E4A5", "toolName": "writeFile", "result": { "success": true, "path": "/home/daytona/hello.js" }, "providerMetadata": { "openai": { "itemId": "fc_00bba3412cd22a2b0069399fbaeef881909b0583f359cbc33c" } } } } ], "finishReason": "tool-calls", "usage": { "inputTokens": 4243, "outputTokens": 53, "totalTokens": 4296, "reasoningTokens": 0, "cachedInputTokens": 4096 }, "runId": "ab2a1d08-91c6-4028-9046-3446a721527f" } ``` These logs show complete visibility into tool execution including arguments, results, token usage with caching metrics, and unique identifiers for debugging. ### 4. Example Usage Let's walk through a practical example to see the Mastra coding agent and Daytona sandbox integration in action. We'll ask the agent to complete the following task: > _"Create a Python file with a function that reverses a string, write a test file for it, and run the tests."_ #### Agent Workflow The agent executes this task through a series of coordinated steps, utilizing different tools to interact with the Daytona sandbox: ##### 1. Create Sandbox The agent first provisions a new Daytona sandbox for Python development: **Tool:** `createSandbox` **Arguments:** ```json { "name": "reverse_string_project", "labels": null, "language": "python", "envVars": null } ``` **Result:** ```json { "sandboxId": "bdfa9456-4945-43a7-97df-b9bfbcbdc62e" } ``` ##### 2. Write Project Files Next, the agent creates both the implementation and test files in a single operation: **Tool:** `writeFiles` **Arguments:** ```json { "sandboxId": "bdfa9456-4945-43a7-97df-b9bfbcbdc62e", "files": [ { "path": "reverse_string.py", "data": "def reverse_string(s):\n \"\"\"Return the reversed version of the input string s.\"\"\"\n return s[::-1]\n" }, { "path": "test_reverse_string.py", "data": "import unittest\nfrom reverse_string import reverse_string\n\nclass TestReverseString(unittest.TestCase):\n def test_regular(self):\n self.assertEqual(reverse_string(\"hello\"), \"olleh\")\n def test_empty(self):\n self.assertEqual(reverse_string(\"\"), \"\")\n def test_single_char(self):\n self.assertEqual(reverse_string(\"a\"), \"a\")\n def test_numbers(self):\n self.assertEqual(reverse_string(\"12345\"), \"54321\")\n\nif __name__ == \"__main__\":\n unittest.main()\n" } ] } ``` **Result:** ```json { "success": true, "filesWritten": [ "/home/daytona/reverse_string.py", "/home/daytona/test_reverse_string.py" ] } ``` ##### 3. Execute Tests Finally, the agent runs the test suite to verify the implementation: **Tool:** `runCommand` **Arguments:** ```json { "sandboxId": "bdfa9456-4945-43a7-97df-b9bfbcbdc62e", "command": "python3 test_reverse_string.py", "envs": null, "workingDirectory": null, "timeoutSeconds": 20, "captureOutput": true } ``` **Result:** ```json { "success": true, "exitCode": 0, "stdout": "....\n----------------------------------------------------------------------\nRan 4 tests in 0.000s\n\nOK\n", "command": "python3 test_reverse_string.py", "executionTime": 218 } ``` #### Agent Response After successfully completing all steps, the agent provides a detailed summary: ``` The project is complete! Here's what was done: ✓ Created reverse_string.py with a function to reverse a string. ✓ Created test_reverse_string.py using Python's unittest to test the function with several cases. ✓ Ran the tests—all tests passed successfully. Test Output: .... ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK Would you like to see the code for either file or make any changes? ``` This example demonstrates how the agent autonomously handles the entire development workflow, from environment setup to test execution, all within the secure Daytona sandbox environment. :::tip[Sandbox Management] After the agent completes its task, you'll see the active sandbox in your [Daytona Dashboard](https://app.daytona.io/dashboard). It's recommended to clean up resources when finished, unless your use case requires the sandbox to remain active (e.g. for preview URLs or ongoing development). ::: **Key Advantages** - **Secure Isolation**: All agent operations run in isolated Daytona sandboxes, protecting your local environment - **Multi-Language Support**: Execute code across different programming languages without local setup - **Enhanced Debugging**: Use Mastra Studio to visualize and debug agent workflows in real-time - **Scalable Execution**: Leverage Daytona's cloud infrastructure for resource-intensive tasks Guides for running OpenClaw with Daytona. This guide walks you through setting up [OpenClaw](https://openclaw.ai/) inside a Daytona sandbox and configuring Telegram and WhatsApp channels. Running OpenClaw in a Daytona sandbox keeps your AI assistant isolated from your local machine, provides a secure environment for code execution, and ensures your bot stays online 24/7 without tying up your personal computer. ### Prerequisites - Daytona account and API key (Get it from [Daytona Dashboard](https://app.daytona.io/dashboard/keys)) - Local terminal (macOS, Linux, or Windows) ### Install the Daytona CLI ```bash brew install daytonaio/cli/daytona ``` ```bash powershell -Command "irm https://get.daytona.io/windows | iex" ``` :::note Already have the CLI? Check your version with `daytona --version`. If it's below **0.135.0**, [upgrade to the latest version](https://www.daytona.io/docs/en/getting-started.md#cli). ::: ### Authenticate with Daytona Log in to your Daytona account using your API key: ```bash daytona login --api-key=YOUR_API_KEY ``` Replace `YOUR_API_KEY` with your actual Daytona API key. ### Create a Sandbox Create a sandbox for running OpenClaw: ```bash daytona sandbox create --name openclaw --snapshot daytona-medium --auto-stop 0 ``` OpenClaw comes preinstalled in the default Daytona snapshot, so the command above is all you need. :::note The `--auto-stop 0` flag disables automatic shutdown, keeping OpenClaw accessible until you manually stop or delete the sandbox. The `daytona-medium` snapshot is required because the OpenClaw gateway needs a minimum of 2GB memory. ::: ### Connect to the Sandbox SSH into your sandbox: ```bash daytona ssh openclaw ``` ### Run OpenClaw Onboarding Start the onboarding process: ```bash openclaw onboard ``` :::note The model provider steps below are for Anthropic. If using a different provider, follow the prompts for your chosen option. ::: Follow the prompts: 1. **Security acknowledgment:** Accept to continue 2. **Onboarding mode:** Select **Quickstart** 3. **Model/auth provider:** Select **Anthropic** 4. **Anthropic auth method:** Select **Anthropic API key** 5. **Enter Anthropic API key:** Paste your API key 6. **Default model:** Keep current (default: `anthropic/claude-opus-4-5`) 7. **Select channel:** Choose **Skip for now** (we'll configure channels later) 8. **Configure skills:** Select **No** (configure later based on your needs) 9. **Enable hooks:** Select **Skip for now** (configure later based on your needs) 10. **Gateway service:** Select **Skip** (already installed) When onboarding finishes, the output will display a **Dashboard ready** section with a dashboard link. Your gateway token is the value after `?token=` in the URL. Save this token - you'll need it to connect to the dashboard. Also, OpenClaw will ask you to **Install shell completion script?** - choose whatever you prefer, this is optional and doesn't affect functionality. ### Start the Gateway Run the gateway in the background: ```bash nohup openclaw gateway run > /tmp/gateway.log 2>&1 & ``` The `&` runs the gateway as a background process, keeping your terminal free for other commands. The `nohup` ensures the gateway keeps running even after you close the SSH connection. ### Access the Dashboard The OpenClaw dashboard is a web interface for managing your assistant, monitoring connections, and configuring channels. To access it, you need a [preview URL](https://www.daytona.io/docs/en/preview.md) that exposes the gateway port running inside your sandbox. In your local terminal (not inside the sandbox SSH session), generate the preview URL: ```bash daytona preview-url openclaw --port 18789 ``` This command generates a [signed preview URL](https://www.daytona.io/docs/en/preview.md#signed-preview-url) that securely exposes the port. Open the URL in your browser, go to the **Overview** section, paste your gateway token in the **Gateway Token** field, and click **Connect**. :::tip The preview URL expires after 1 hour by default (customizable with `--expires` flag). When it expires, simply run the same CLI command to generate a new one. ::: ### Pair Your Browser OpenClaw uses device pairing as a security measure - only approved devices can connect to and control your assistant. When you first attempt to connect from the dashboard, your browser registers as a new device that needs approval. List pending device requests: ```bash openclaw devices list ``` Approve your device: ```bash openclaw devices approve REQUEST_ID ``` Replace `REQUEST_ID` with the value from the **Request** column. Click **Connect** again in the dashboard. Once connected, you should see a green status indicator - your OpenClaw is now ready to use. ### Security Running OpenClaw this way provides three layers of security: 1. **Preview URL:** Time-limited access to the dashboard port 2. **Gateway token:** Required to authenticate with the dashboard 3. **Device approval:** Only approved devices can connect and control your assistant Even if someone obtains your dashboard URL, they cannot connect without the gateway token and an approved device. :::caution Keep your gateway token and preview URL secret. Do not share them publicly. ::: --- ### Configure Telegram Set up a Telegram bot to chat with OpenClaw. #### Create a Telegram Bot 1. Open Telegram and search for **@BotFather** 2. Send `/start`, then `/newbot` 3. Enter a name for your bot 4. Enter a username for your bot 5. Copy the bot token provided #### Configure OpenClaw Enable Telegram and set your bot token: ```bash openclaw config set channels.telegram.enabled true openclaw config set channels.telegram.botToken YOUR_BOT_TOKEN ``` Verify the configuration: ```bash openclaw config get channels.telegram ``` #### Restart the Gateway ```bash openclaw gateway stop nohup openclaw gateway run > /tmp/gateway.log 2>&1 & ``` #### Complete Verification 1. Open your bot's chat in Telegram and click **Start** 2. A pairing code will appear. Approve the pairing request: ```bash openclaw pairing approve telegram PAIRING_CODE ``` You can now message your OpenClaw through Telegram. --- ### Configure WhatsApp Set up WhatsApp to chat with OpenClaw. #### Run Configuration ```bash openclaw config --section channels ``` When prompted: 1. Select **Local (this machine)** for gateway location 2. Choose **Configure/link** 3. Select **WhatsApp (QR link)** 4. Select **Yes** for "Link WhatsApp now (QR)?" #### Scan the QR Code Open WhatsApp on your phone, go to **Settings → Linked Devices → Link a Device**, and scan the QR code displayed in your terminal. Once paired, you'll see: ``` ✅ Linked after restart; web session ready. ``` #### Set Up Your Phone Number Select **This is my personal phone number** (or choose the other option if you have a separate phone for OpenClaw) and enter your phone number when prompted. #### Finish Configuration When prompted to select another channel, choose **Finished**. You'll see: ``` └ Configure complete. ``` #### Start Chatting Send a message to yourself in WhatsApp - OpenClaw will respond. You can give it instructions and information on how to behave directly in the chat. :::tip To allow other users to chat with OpenClaw, add their phone numbers to the **Allow From** list in **Channels → WhatsApp** inside the dashboard. When they send a message, OpenClaw will respond. ::: import { Image } from 'astro:assets' import openclawSandbox from '../../../../../assets/docs/images/openclaw-sandbox.gif' This guide shows how to run [OpenClaw](https://openclaw.ai/) inside a Daytona sandbox using the Daytona SDK. The script automatically creates and configures a sandbox with OpenClaw and provides an authenticated [preview URL](https://www.daytona.io/docs/en/preview.md) for using OpenClaw in the browser. --- ### 1. Workflow Overview When you run the script, it creates a Daytona sandbox, starts the OpenClaw gateway inside it, and prints a preview link for the dashboard: ``` $ npm start Creating Daytona sandbox... Configuring OpenClaw... Starting OpenClaw... (Ctrl+C to shut down and delete the sandbox) 🔗 Secret link to Control UI: https://18789-xxxx.proxy.daytona.works?token=... ``` Open the provided link in your browser to connect to the OpenClaw Control UI. This link contains a configuration token, and anyone can use it to connect to OpenClaw without device approval. OpenClaw Control UI running in a Daytona sandbox You can use the Control UI to chat with your assistant, configure Telegram and WhatsApp, and manage sessions. When you exit the script (Ctrl+C), the sandbox will not be deleted unless [sandbox persistence is disabled](https://www.daytona.io/docs/en/guides/openclaw/openclaw-sdk-sandbox.md#4-key-constants). ### 2. Project Setup #### Clone the Repository Clone the Daytona [repository](https://github.com/daytonaio/daytona) and go to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/openclaw ``` #### Configure Environment Get your API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys). Copy `.env.example` to `.env` and add your Daytona API key: ```bash DAYTONA_API_KEY=your_daytona_key ``` A default OpenClaw configuration is stored in `openclaw.json`. You can customize it according to the [configuration reference](https://docs.openclaw.ai/gateway/configuration-reference). You can also add additional environment variables to `.env.sandbox` (e.g. `ANTHROPIC_API_KEY` for Claude) and they will be loaded into the sandbox. #### Run the Example :::note[Node.js] Node.js 18 or newer is required. ::: Install dependencies and run: ```bash npm install npm start ``` The script creates the sandbox, starts the OpenClaw gateway, and prints a secret link with the token in the URL. ### 3. How It Works 1. The script creates a [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md) with `DAYTONA_SNAPSHOT` (e.g. `daytona-medium`) and loads env vars from `.env.sandbox`. 2. Your local `openclaw.json` is merged with built-in config and written to `~/.openclaw/openclaw.json` in the sandbox. 3. The OpenClaw gateway is started inside the sandbox on `OPENCLAW_PORT` via [process execution](https://www.daytona.io/docs/en/process-code-execution.md). 4. A signed [preview link](https://www.daytona.io/docs/en/preview.md) is generated and the token is appended as `?token=...`; this link is printed so you can open the Control UI. 5. On Ctrl+C, the sandbox is deleted unless `PERSIST_SANDBOX` is `true`. ### 4. Key Constants You can change behavior by editing the constants in [`src/index.ts`](https://github.com/daytonaio/daytona/blob/main/guides/typescript/openclaw/src/index.ts): | Constant | Default | Description | |----------|---------|-------------| | `PERSIST_SANDBOX` | true | When true, the sandbox is not deleted when the script exits | | `MAKE_PUBLIC` | true | Allow anyone to access the sandbox instead of limiting to your Daytona organization | | `OPENCLAW_PORT` | 18789 | OpenClaw Gateway and Control UI port | | `SHOW_LOGS` | true | Stream OpenClaw stdout/stderr to the terminal | **Key advantages:** - Secure, isolated execution in a Daytona sandbox - No device approval — token in URL and `allowInsecureAuth` skip pairing - Control UI and channels accessible via the secret preview link - Optional: keep the sandbox running after exit (`PERSIST_SANDBOX`) Guides for running [OpenCode](https://opencode.ai/) with Daytona. import { Image } from 'astro:assets' import opencodePluginGif from '../../../../../assets/docs/images/opencode-plugin.gif' This guide demonstrates how to run the [Daytona OpenCode plugin](https://www.npmjs.com/package/@daytonaio/opencode) which integrates Daytona sandboxes and OpenCode. When the plugin is active, all agent operations occur in secure sandboxes, with one sandbox per OpenCode session. The plugin also has the ability to sync changes between sandboxes and local Git branches. ### 1. Workflow Overview When you run OpenCode with the Daytona plugin, sandboxes are created automatically inside OpenCode sessions. Operations such as running code, installing dependencies, and starting servers occur in the sandbox. OpenCode with Daytona plugin — sandbox toast and git branches Sandboxes are preserved until you delete the OpenCode session. If a local Git repository is detected, the plugin syncs changes between the sandbox and branches with the `opencode/` prefix. ### 2. Project Setup #### Add the Plugin Add the Daytona plugin to your project by creating or editing `opencode.json` in the project directory: ```json { "$schema": "https://opencode.ai/config.json", "plugin": ["@daytonaio/opencode"] } ``` OpenCode downloads the plugin automatically when it starts. To install the plugin globally instead, edit `~/.config/opencode/opencode.json` and add the same `plugin` entry. #### Configure Environment This plugin requires a [Daytona account](https://www.daytona.io/) and [Daytona API key](https://app.daytona.io/dashboard/keys) to create sandboxes. Set your API key: ```bash export DAYTONA_API_KEY="your-api-key" ``` Or create a `.env` file in your project root: ```env DAYTONA_API_KEY=your-api-key ``` #### Run OpenCode :::note[Git required] Ensure your project is a Git repository to enable syncing changes between the sandbox and your machine. ::: Initialize Git if needed, then start OpenCode: ```bash git init opencode ``` You can now use OpenCode as usual. As you work, you will see notifications in OpenCode indicating sandboxes are being created and changes are being synced to local branches. To confirm the plugin is working, type `pwd` in the chat and you should see a path like `/home/daytona/project`. To view live logs from the plugin for debugging: ```bash tail -f ~/.local/share/opencode/log/daytona.log ``` #### Version control In your project directory, use Git to list and check out the branches OpenCode creates: ```bash git branch git checkout opencode/1 ``` By default, new sessions start from the branch that was checked out when OpenCode was started. After this, synchronization only goes one way: from the sandbox to your local branch. To start working from a different branch, use git to check out that branch and start OpenCode again: ```bash git checkout opencode/1 opencode ``` You can run as many OpenCode sessions in parallel as you want. Use Git to review and merge changes. ### 3. Understanding the Plugin Architecture The Daytona plugin consists of several modules that provide custom tools, hooks for events, connections from sessions to sandboxes and system prompt transforms. These modules ensure every agent action runs in a [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md) and that changes sync to local Git branches: - **Custom tools:** Overrides bash, read, write, edit, etc., so they run in the sandbox. - **System prompt transform:** Injects sandbox path and instructions into the agent's system prompt. - **Event handlers:** Handles session lifecycle events including cleanup (deleting sandboxes) and idle auto-commit (syncing changes to local git branches). - **Session management:** Manages the creation and deletion of sandboxes and the mapping of sessions to sandboxes. #### Custom tools The custom tools module registers overrides for OpenCode's built-in tools so that every file and process operation goes through the Daytona SDK. It receives the project `id` and `worktree` from the plugin context and returns a tool map: ```typescript export async function customTools(ctx: PluginInput, sessionManager: DaytonaSessionManager) { logger.info('OpenCode started with Daytona plugin') const projectId = ctx.project.id const worktree = ctx.project.worktree return { bash: bashTool(sessionManager, projectId, worktree, ctx), // ... read, write, edit, multiedit, patch, ls, glob, grep, lsp, getPreviewURL } } ``` For example, the plugin implementation of the bash tool uses the Daytona SDK to run the command in the sandbox: ```typescript async execute(args: { command: string; background?: boolean }, ctx: ToolContext) { const sessionId = ctx.sessionID const sandbox = await sessionManager.getSandbox(sessionId, projectId, worktree, pluginCtx) if (args.background) { // ... create or get exec session, then: const result = await sandbox.process.executeSessionCommand(execSessionId, { command: args.command, runAsync: true, }) return `Command started in background (cmdId: ${result.cmdId})` } else { const result = await sandbox.process.executeCommand(args.command, repoPath) return `Exit code: ${result.exitCode}\n${result.result}` } } ``` All stateful tools (bash, read, write, edit, glob, grep, ls, lsp, multiedit, patch) are overridden the same way. The plugin also adds a custom tool for [preview links](https://www.daytona.io/docs/en/preview.md). #### System prompt transform The system prompt transform extends the system prompt to include instructions for the agent to work in the sandbox and use the background option for long-running commands: ```typescript export async function systemPromptTransform(ctx: PluginInput, repoPath: string) { return async (input: ExperimentalChatSystemTransformInput, output: ExperimentalChatSystemTransformOutput) => { output.system.push( [ '## Daytona Sandbox Integration', 'This session is integrated with a Daytona sandbox.', `The main project repository is located at: ${repoPath}.`, 'Bash commands will run in this directory.', 'Put all projects in the project directory. Do NOT try to use the current working directory of the host system.', "When executing long-running commands, use the 'background' option to run them asynchronously.", 'Before showing a preview URL, ensure the server is running in the sandbox on that port.', ].join('\n'), ) } } ``` #### Session events The session events handler listens for OpenCode session lifecycle events and handles them appropriately. When you delete a session, the handler cleans up the corresponding sandbox. When a session becomes idle, it triggers auto-commit and sync: ```typescript export async function eventHandlers(ctx: PluginInput, sessionManager: DaytonaSessionManager, repoPath: string) { const projectId = ctx.project.id const worktree = ctx.project.worktree return async (args: any) => { const event = args.event if (event.type === EVENT_TYPE_SESSION_DELETED) { const sessionId = (event as EventSessionDeleted).properties.info.id await sessionManager.deleteSandbox(sessionId, projectId) toast.show({ title: 'Session deleted', message: 'Sandbox deleted successfully.', variant: 'success' }) } else if (event.type === EVENT_TYPE_SESSION_IDLE) { const sessionId = event.properties.sessionID const sandbox = await sessionManager.getSandbox(sessionId, projectId, worktree, ctx) const branchNumber = sessionManager.getBranchNumberForSandbox(projectId, sandbox.id) if (!branchNumber) return const sessionGit = new SessionGitManager(sandbox, repoPath, worktree, branchNumber) await sessionGit.autoCommitAndPull(ctx) } } } ``` #### File synchronization While OpenCode is in use, the plugin uses Git to keep session sandboxes and your local Git repository in sync. This only occurs if a git repository is detected in the project directory. On plugin start: 1. The plugin looks for a Git repository in the local directory. 2. A parallel repository is created in the sandbox with a single `opencode` branch, mirroring your current local branch. 3. A `sandbox` remote is added to your local repo using an SSH connection to the sandbox. 4. Your current `HEAD` is pushed to `opencode`, and the sandbox repo is reset to that state. 5. On session idle, the plugin commits in the sandbox on `opencode`, then pulls into a local branch (`opencode/1`, `opencode/2`, etc.) which is unique to each sandbox. A notification is shown when the sync is complete. For more information on how the sync is implemented, see the [SessionGitManager](https://github.com/daytonaio/daytona/blob/main/libs/opencode-plugin/.opencode/plugin/daytona/git/session-git-manager.ts) class. :::caution When the plugin syncs to local `opencode` branches, any local changes on those branches are overwritten. ::: #### Session storage The session manager stores which sandbox belongs to each project in JSON files (using the same base path as OpenCode via `xdg-basedir`). - **macOS:** `~/.local/share/opencode/storage/daytona/[projectid].json` - **Windows:** `%LOCALAPPDATA%\opencode\storage\daytona\[projectid].json` Each file holds sandbox metadata for that project's sessions so that sandboxes are retained between OpenCode uses. **Key advantages:** - Secure, isolated execution: each OpenCode session runs in its own Daytona sandbox - Sandboxes persist until you delete the OpenCode session - Live [preview links](https://www.daytona.io/docs/en/preview.md) when a server starts in the sandbox - Automatic git sync to local branches so you can review and merge agent changes - No script to run: add the plugin and use OpenCode as usual import { Image } from 'astro:assets' import opencodeSdkSyncboard from '../../../../../assets/docs/images/opencode-sdk-syncboard.gif' This guide walks you through running the [OpenCode](https://opencode.ai/) autonomous coding agent inside a secure Daytona sandbox. The OpenCode server runs fully isolated in the sandbox and the script connects to the server using the [OpenCode SDK](https://www.npmjs.com/package/@opencode-ai/sdk). The agent can develop full-stack web apps, write code in any language, install dependencies, and run scripts. It can also start and manage dev servers, and generate [preview links](https://www.daytona.io/docs/en/preview.md) for live apps. ### 1. Workflow Overview When you run the script, it creates a Daytona sandbox, installs OpenCode, and starts the OpenCode server inside the sandbox. You send prompts and see responses in your terminal. On exit, the sandbox is deleted. ``` $ npm run start Creating sandbox... Installing OpenCode in sandbox... Preview: https://4096-0626a08c-08e7-4fbe-9799-d160bac66b08.daytonaproxy01.net Press Ctrl+C at any time to exit. User: Create a minimalist collaborative whiteboard app Thinking... 🔨 ✓ Run: Check current directory structure ✓ 3 todos 📝 Add home/daytona/SPEC.md ✓ 2 todos 📝 Add home/daytona/index.html ✓ 1 todos ✓ home/daytona/SPEC.md ✓ https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Outfit:wght@400;500;700&display=swap (text/css; charset=utf-8) ✓ home/daytona/index.html 🔨 ✓ Run: List files in directory 🔨 ✓ Run: Start HTTP server for whiteboard 🔨 ✓ Run: Check if server is running ✓ 0 todos Your minimalist collaborative whiteboard app is ready! **Preview URL:** https://8080-0626a08c-08e7-4fbe-9799-d160bac66b08.daytonaproxy01.net ## SyncBoard - Features **Drawing Tools:** - Pencil (freehand drawing) - Line, Rectangle, Ellipse (shape tools with preview) - Eraser (removes intersecting strokes) **Customization:** - 6 vibrant color presets - 3 stroke widths (thin/medium/thick) - Keyboard shortcuts: `P` `L` `R` `E` `X` for tools, `1` `2` `3` for stroke widths **Collaboration:** - Simulated real-time collaboration with other users - Unique user colors for each participant - Auto-saves to localStorage every 2 seconds **Actions:** - Undo/Redo (stores 20 actions, Ctrl+Z / Ctrl+Shift+Z) - Clear canvas (with confirmation dialog) - Coordinates display in status bar **Design:** - Dark theme with coral/teal accents - Dot grid background pattern - Smooth animations and hover effects - Responsive layout for mobile devices User: Cleaning up... ``` When your task involves running or previewing a web application, the agent can host the app and generate a [preview link](https://www.daytona.io/docs/en/preview.md) for you to inspect the live result: SyncBoard collaborative whiteboard app generated by OpenCode agent You can continue interacting with your agent until you are finished. When you exit the program, the sandbox will be deleted automatically. ### 2. Project Setup #### Clone the Repository First, clone the Daytona [repository](https://github.com/daytonaio/daytona.git) and navigate to the OpenCode SDK example: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/opencode/opencode-sdk ``` #### Configure Environment Get your API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys). Copy `.env.example` to `.env` and add your key: ```bash DAYTONA_API_KEY=your_daytona_key ``` #### Local Usage :::note[Node.js Version] Node.js 18 or newer is required to run this example. Please ensure your environment meets this requirement before proceeding. ::: Install dependencies and run the example: ```bash npm install npm run start ``` The agent will start and wait for your prompt. ### 3. Understanding the Script OpenCode uses a client-server model: The [server](https://opencode.ai/docs/server/) manages coding agents, sessions and configuration. Clients communicate with the server [over HTTP](https://opencode.ai/docs/server/#apis) to run prompts in sessions and receive streamed responses. #### Initialization On startup, the script: 1. Creates a new [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md). 2. Installs OpenCode globally in the sandbox. 3. Starts the OpenCode server in the sandbox. 4. Gets the preview URL for the server and creates a client with that base URL. 5. Enters the readline loop to send prompts to the server and receive streamed responses. 6. On Ctrl+C, deletes the sandbox and exits. #### OpenCode Server The OpenCode server runs inside the sandbox and handles all agent work: LLM calls, tools (bash, write, etc.), and code execution. The script starts it with: ```ts const envVar = injectEnvVar('OPENCODE_CONFIG_CONTENT', opencodeConfig) const command = await sandbox.process.executeSessionCommand(sessionId, { command: `${envVar} opencode serve --port ${PORT} --hostname ${HOSTNAME}`, runAsync: true, }) ``` A custom configuration is injected which includes a system prompt. The system prompt tells the agent it runs in a sandbox, to use `/home/daytona` for file operations, and the preview URL pattern so it can provide correct preview links. #### OpenCode Client The client runs on your machine and talks to the server using the [OpenCode SDK](https://opencode.ai/docs/sdk/). `Session.create` sets up the SDK client and subscribes to the event stream so the client can show tool activity (e.g. “✓ Run: …”, “📝 Add …”) as the agent works: ```ts const client = createOpencodeClient({ baseUrl }) const sessionRes = await client.session.create({ body: { title: 'Daytona query' } }) const sessionId = sessionRes.data?.id if (!sessionId) throw new Error('Failed to create OpenCode session:' + sessionRes.error) const events = await client.event.subscribe() ``` To send a prompt, the client calls `session.prompt` and processes events from the existing stream to show tool activity: ```ts const promptPromise = this.client.session.prompt({ path: { id: this.sessionId }, body: { parts: [{ type: 'text', text: query } satisfies TextPartInput] }, }) for await (const event of takeUntil(this.events.stream, promptPromise)) { printEvent(this.sessionId, event) } ``` #### Main loop When the server is ready, the script creates a session and runs a readline loop: ```ts const session = await Session.create(baseUrl) const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) while (true) { const query = await new Promise((resolve) => rl.question('User: ', resolve)) if (!query.trim()) continue await session.runQuery(query) } ``` The readline loop waits for user input, sends it to the agent, and prints the response. **Key advantages:** - Secure, isolated execution in Daytona sandboxes - OpenCode SDK client in your terminal; server runs in the sandbox - Support for 75+ LLM providers - All agent code execution happens inside the sandbox - Automatic preview link generation for deployed services - Custom agent configuration for Daytona-specific workflows import { Image } from 'astro:assets' import opencodeResult from '../../../../../assets/docs/images/opencode-web-agent.gif' This guide demonstrates how to run the [OpenCode](https://opencode.ai/) coding agent inside a Daytona sandbox environment using OpenCode's easy-to-use [web interface](https://opencode.ai/docs/web/). The agent can develop web apps, write code in any language, install dependencies, and run scripts. It supports over 75 different LLM providers and can start dev servers with preview links for live apps. --- ### 1. Workflow Overview When you launch the main script, a Daytona sandbox is created and OpenCode is installed inside it. OpenCode is configured with a custom Daytona-aware agent. The script provides a preview link to access the web interface, where you can create, configure and interact with agent sessions: ``` $ npm run start Creating sandbox... Installing OpenCode... Starting OpenCode web server... Press Ctrl+C to stop. ▄ █▀▀█ █▀▀█ █▀▀█ █▀▀▄ █▀▀▀ █▀▀█ █▀▀█ █▀▀█ █░░█ █░░█ █▀▀▀ █░░█ █░░░ █░░█ █░░█ █▀▀▀ ▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ Web interface: https://3000-1e0f775c-c01b-40e7-8c64-062fd3dadd75.proxy.daytona.works/ ``` The agent can host web apps and provide you with a preview link using the [Daytona Preview Links](https://www.daytona.io/docs/en/preview-and-authentication.md) feature. When your task involves running or previewing a web application, the agent automatically reasons about this need, hosts the app, and generates a preview link for you to inspect the live result: Web app demo generated by OpenCode coding agent You can continue interacting with your agent until you are finished. When you exit the program, the sandbox will be deleted automatically. ### 2. Project Setup #### Clone the Repository First, clone the Daytona [repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/typescript/opencode ``` #### Configure Environment Get your API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys). Copy `.env.example` to `.env` and add your key: ```bash DAYTONA_API_KEY=your_daytona_key ``` #### Local Usage :::note[Node.js Version] Node.js 18 or newer is required to run this example. Please ensure your environment meets this requirement before proceeding. ::: Install dependencies: ```bash npm install ``` Run the example: ```bash npm run start ``` The OpenCode web interface will start and wait for you to open it in your browser. ### Models and API Providers OpenCode works with [over 75 LLM providers](https://opencode.ai/docs/providers/), with a free provider selected by default. You can change the model or provider at any time using the menu below the prompt input in the web interface. If your chosen provider needs an API key, you’ll be prompted to enter it. #### Persisting API Keys To persist API keys between uses of the script, you can set them as environment variables when creating the Daytona sandbox. For example, to use an Anthropic API key, modify the `daytona.create()` call in `src/index.ts` to include your desired API key: ```typescript sandbox = await daytona.create({ envVars: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY || '', }, }) ``` ### 3. Understanding the Script This example consists of a Node.js script that installs, configures and runs OpenCode inside a Daytona sandbox. #### Initialization On initialization, the main script: 1. Creates a new [Daytona sandbox](https://www.daytona.io/docs/en/sandboxes.md). 2. Installs OpenCode globally inside the sandbox using npm with [process execution](https://www.daytona.io/docs/en/process-code-execution.md#process-execution). 3. Creates and uploads a [custom agent configuration](https://opencode.ai/docs/agents/) with Daytona-specific system prompt. 4. Starts the OpenCode web server inside the sandbox on port 3000. 5. Substitutes the URL in OpenCode's output with a [Daytona preview link](https://www.daytona.io/docs/en/preview-and-authentication.md) for the web interface. #### Main Script Code The script creates a session and executes OpenCode as an asynchronous command, which allows it to stream output while keeping the process alive: ```typescript const command = await sandbox.process.executeSessionCommand(sessionId, { command: `${envVar} opencode web --port ${OPENCODE_PORT}`, runAsync: true, }) ``` When OpenCode starts its web server, it prints a link to its web UI using a localhost address (e.g., `http://127.0.0.1:3000`). However, since the sandbox runs remotely, this localhost link is only accessible inside the sandbox itself. To solve this, the script parses OpenCode’s output, and replaces the URL with the corresponding Daytona preview link. ```typescript const opencodePreviewLink = await sandbox.getPreviewLink(OPENCODE_PORT) const replaceUrl = (text: string) => text.replace( new RegExp(`http:\\/\\/127\\.0\\.0\\.1:${OPENCODE_PORT}`, 'g'), opencodePreviewLink.url ) ``` #### OpenCode Agent Configuration A custom system prompt is used to instruct the agent on how to use Daytona sandbox paths and preview links. This prompt is packaged into a JSON configuration string, which is passed to the sandbox as the `OPENCODE_CONFIG_CONTENT` environment variable: ```json { "$schema": "https://opencode.ai/config.json", "default_agent": "daytona", "agent": { "daytona": { "description": "Daytona sandbox-aware coding agent", "mode": "primary", "prompt": "You are running in a Daytona sandbox. Use the /home/daytona directory instead of /workspace for file operations. When running services on localhost, they will be accessible as: . When starting a server, always give the user the preview URL to access it. When starting a server, start it in the background with & so the command does not block further instructions." } } } ``` The `` in the agent prompt is a template URL where `{PORT}` is a placeholder for the port to access on the Daytona sandbox. This template string is created by generating a [preview link](https://www.daytona.io/docs/en/preview-and-authentication.md) for a specific port number and then replacing the port number with `{PORT}`. #### Clean up When you press `Ctrl+C`, the script automatically cleans up by deleting the sandbox: ```typescript process.once('SIGINT', async () => { console.log('\nCleaning up...') if (sandbox) await sandbox.delete() process.exit(0) }) ``` **Key advantages:** - Secure, isolated execution in Daytona sandboxes - OpenCode Web interface accessible via browser - Support for 75+ LLM providers - All agent code execution happens inside the sandbox - Automatic preview link generation for deployed services - Custom agent configuration for Daytona-specific workflows - Clean resource management with automatic sandbox cleanup import { Image } from 'astro:assets' import rewardsPlot from '../../../../../assets/docs/images/trl-grpo-rewards-plot.png' This guide demonstrates how to use Daytona sandboxes to safely execute hundreds of code completions in parallel during reinforcement learning training. We use [TRL](https://huggingface.co/docs/trl/)'s GRPOTrainer together with 500 Daytona sandboxes evaluating completions concurrently, in order to train the `Qwen3-1.7B-Base` model on some basic code-writing tasks. --- ### 1. Workflow Overview This guide presents a simple, self-contained script that performs reinforcement learning training of `Qwen3-1.7B-Base`. In particular, we use **reinforcement learning with verifiable rewards**, with the reward being computed from the test pass rate of model-written functions. The training loop consists of following steps: 1. **Generate**: The model produces many code completions for each prompt (e.g., 250 completions per prompt per step) 2. **Evaluate**: Each completion runs in its own Daytona sandbox against a test suite 3. **Reward**: Completions that pass more tests get higher rewards; errors or banned patterns get negative rewards 4. **Update**: GRPO reinforces completions that scored above their group average The evaluation step happens in parallel across all 500 sandboxes. The sandboxes are spawned once at the start of the training and reused throughout it, and cleaned up after the training completes. ### 2. Setup #### Clone the Repository :::note[GPU Requirement] This guide is written to run on a single 80GB VRAM GPU. If you want to run it on a GPU with less VRAM, you can decrease `per_device_train_batch_size` parameter, possibly increasing `gradient_accumulation_steps` proportionally if you wish to keep effective batch size at 500. ::: Clone the [Daytona repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/python/reinforcement-learning/trl ``` #### Create Virtual Environment :::note[Python Version] Python 3.10 or higher is required. A GPU with 80GB+ VRAM is recommended for training. ::: ```bash python3 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate ``` #### Install Dependencies ```bash pip install -e . ``` This installs: - `daytona` - Daytona SDK for sandbox management - `trl[vllm]` - TRL with vLLM integration for fast inference - `datasets` - HuggingFace datasets library - `python-dotenv` - Environment variable management #### Configure Environment Get your Daytona API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys) and create a `.env` file: ```bash DAYTONA_API_KEY=your_daytona_api_key ``` ### 3. Understanding the Code Let's walk through the key components of the training script. #### Task Definitions The script defines coding tasks as prompts with test cases. Note that the prompts are written in completion mode rather than QA mode because `Qwen3-1.7B-Base` is a base rather than an instruct model. Each task specifies what the model should generate and how to verify correctness: ```python SORTING_PROMPT = """# I've been fiddling with different ways to sort numbers in Python. # At first I just used sorted() and list.sort(), but then I decided to try # my hand at writing some original sorting functions. And I succeeded! # I don't call sorted(), list.sort(), heapq, or use any imports here - just plain # Python and an original algorithm. def sort_numbers(xs: list[int]) -> list[int]: \"\"\"Sort a list of integers in ascending order. Args: xs: A list of integers to be sorted. Returns: A new list containing the same integers, sorted from smallest to largest. \"\"\" """ TASKS = { "sorting": { "prompt": SORTING_PROMPT, "func_name": "sort_numbers", "banned_patterns": ["sorted(", ".sort(", "heapq", "import ", "__import__"], "tests": [ "[]", "[1, 3, 2]", "[random.randint(-1000, 1000) for _ in range(200)]", "[random.randint(-100, 100) for _ in range(1000)]", "list(range(0, 100)) + list(range(200, 100, -1)) + list(range(200, 300))", ], "reference": "sorted", }, # Additional tasks can be added here... } ``` Each task includes: - **prompt**: The code context the model continues from - **func_name**: The function name being implemented - **banned_patterns**: Patterns that disqualify a completion (e.g., using built-in `sorted()`) - **tests**: Test inputs to verify correctness - **reference**: The reference implementation to compare against #### How Prompts Become Completions When the model receives the sorting prompt, it continues the text as if completing a Python file. A typical model output might look like: ``` if len(xs) <= 1: return xs pivot = xs[len(xs) // 2] left = [x for x in xs if x < pivot] middle = [x for x in xs if x == pivot] right = [x for x in xs if x > pivot] return sort_numbers(left) + middle + sort_numbers(right) # Example usage: print(sort_numbers([3, 1, 4, 1, 5, 9, 2, 6])) ``` Notice the model generates the indented function body, but may also add extra content after (comments, example usage, etc.). The `sanitize_completion` function extracts only the indented lines that form the function body: ```python def sanitize_completion(text: str) -> str: # Take lines until the first unindented line lines = text.splitlines() kept: List[str] = [] for line in lines: if line and (not line.startswith(" ")): break kept.append(line) return "\n".join(kept).rstrip() ``` After sanitization, the example above becomes just the function body: ```python if len(xs) <= 1: return xs pivot = xs[len(xs) // 2] left = [x for x in xs if x < pivot] middle = [x for x in xs if x == pivot] right = [x for x in xs if x > pivot] return sort_numbers(left) + middle + sort_numbers(right) ``` #### Sandbox Pool Management We create the sandbox pool upfront and reuse sandboxes throughout training: ```python EFFECTIVE_BATCH_SIZE = 500 # We evaluate each completion concurrently, in its own sandbox, # so we spawn EFFECTIVE_BATCH_SIZE number of sandboxes. async def _create_sandbox_pool_async( daytona: AsyncDaytona, n: int = 10 ) -> List[AsyncSandbox]: print(f"Creating {n} sandboxes...") tasks = [daytona.create() for _ in range(n)] sandboxes = await asyncio.gather(*tasks) print(f"Successfully created all {len(sandboxes)} sandboxes") return list(sandboxes) async def _cleanup_sandbox_pool_async(sandbox_pool: List[AsyncSandbox]) -> None: if not sandbox_pool: return print("Cleaning up sandboxes...") tasks = [sandbox.delete() for sandbox in sandbox_pool] results = await asyncio.gather(*tasks, return_exceptions=True) for r in results: if isinstance(r, Exception): print(f" Sandbox delete error: {type(r).__name__}: {r}") print("All sandboxes cleaned up") ``` The pool size (500) is chosen to match the total batch size (`per_device_train_batch_size * gradient_accumulation_steps`), ensuring every completion in a batch can be evaluated in parallel. #### Code Evaluation The main evaluation function ties everything together - it sanitizes the completion, checks for banned patterns, builds the test harness, executes it in a sandbox, and parses the results: ```python async def evaluate_single_completion_async( sandbox: AsyncSandbox, raw_completion: str, prompt: str, ) -> EvalResult: task = PROMPT_TO_TASK[prompt] num_task_tests = len(task["tests"]) body = sanitize_completion(raw_completion) if not body.strip(): return _fail_result(num_task_tests) if has_banned_pattern(body, task): return _fail_result(num_task_tests) code = build_test_harness(task, body) try: response = await sandbox.code_interpreter.run_code( code, timeout=MAX_TIMEOUT_SECONDS ) except DaytonaTimeoutError: print( f"Completion timed out after {MAX_TIMEOUT_SECONDS}s " f"in sandbox {getattr(sandbox, 'id', '?')}" ) return _fail_result(num_task_tests) except Exception as e: print( f"Error evaluating completion in sandbox {getattr(sandbox, 'id', '?')}: " f"{type(e).__name__}: {e}", ) return _fail_result(num_task_tests) if response.error is not None: return _fail_result(num_task_tests) raw_output = response.stdout.strip() if not raw_output: return _fail_result(num_task_tests) last_line = raw_output.splitlines()[-1] try: results = json.loads(last_line) except Exception: return _fail_result(num_task_tests) correct = results.get("results", []) return { "no_error": True, "num_passed": sum(bool(x) for x in correct), "num_tests": len(correct), } ``` #### The Test Harness The `build_test_harness` function combines the original prompt, the model's completion, and a test runner into Python code that ultimately executes on the sandbox: ```python def build_test_harness(task: Dict[str, Any], function_body: str) -> str: prompt = task["prompt"] func_name = task["func_name"] reference_function = task["reference"] tests = task["tests"] tests_tuple = ",\n ".join(tests) return f"""{prompt} {function_body} import json import random random.seed(0) def _kadane(xs): max_sum = current = xs[0] for x in xs[1:]: current = max(x, current + x) max_sum = max(max_sum, current) return max_sum def _run_tests(): tests = ( {tests_tuple} ) results = [] for xs in tests: try: out = {func_name}(xs.copy()) expected = {reference_function}(xs.copy()) results.append(out == expected) except Exception: results.append(False) print(json.dumps({{"results": results}})) if __name__ == "__main__": _run_tests() """ ``` For the sorting task with a quicksort completion, the assembled code looks like: ```python # I've been fiddling with different ways to sort numbers in Python... def sort_numbers(xs: list[int]) -> list[int]: """Sort a list of integers in ascending order...""" if len(xs) <= 1: return xs pivot = xs[len(xs) // 2] left = [x for x in xs if x < pivot] middle = [x for x in xs if x == pivot] right = [x for x in xs if x > pivot] return sort_numbers(left) + middle + sort_numbers(right) import json import random random.seed(0) def _run_tests(): tests = ( [], [1, 3, 2], [random.randint(-1000, 1000) for _ in range(200)], # ... more tests ) results = [] for xs in tests: try: out = sort_numbers(xs.copy()) expected = sorted(xs.copy()) results.append(out == expected) except Exception: results.append(False) print(json.dumps({"results": results})) if __name__ == "__main__": _run_tests() ``` When executed in the sandbox, this prints JSON to stdout: ```json {"results": [true, true, true, false, true]} ``` The evaluation function parses this JSON to count how many tests passed. #### Banned Pattern Detection Before running code in the sandbox, we check for banned patterns. This prevents the model from "cheating" by using built-in functions: ```python def has_banned_pattern(text: str, task: Dict[str, Any]) -> bool: banned = task.get("banned_patterns", []) if not banned: return False lowered = text.lower() return any(p.lower() in lowered for p in banned) ``` For the sorting task, banned patterns include `sorted(`, `.sort(`, `heapq`, and `import`. If the model generates `return sorted(xs)`, it gets a reward of -1.0 instead of being executed - we want the model to learn to write actual sorting algorithms, not to call built-in functions. #### Parallel Batch Evaluation The batch evaluator distributes completions across the sandbox pool: ```python async def _evaluate_batch_async( sandbox_pool: List[AsyncSandbox], completions: List[str], prompts: List[str] ) -> List[EvalResult]: print( f"Evaluating {len(completions)} completions in parallel across " f"{len(sandbox_pool)} sandboxes..." ) async def run_one( i: int, sandbox: AsyncSandbox, completion: str, prompt: str ) -> EvalResult: task = PROMPT_TO_TASK[prompt] num_task_tests = len(task["tests"]) try: stats = await evaluate_single_completion_async(sandbox, completion, prompt) print(f" Completion {i + 1}/{len(completions)} done") return stats except Exception as e: print( f" Completion {i + 1}/{len(completions)} failed: " f"{type(e).__name__}: {e}" ) return _fail_result(num_task_tests) tasks = [ run_one(i, sandbox_pool[i % len(sandbox_pool)], completion, prompt) for i, (completion, prompt) in enumerate(zip(completions, prompts)) ] stats_list = await asyncio.gather(*tasks) print(f" Done: {len(completions)}/{len(completions)} completions evaluated") return stats_list ``` Each completion is assigned to a sandbox using round-robin distribution (`i % len(sandbox_pool)`), ensuring even load distribution. #### Reward Function The reward function receives the results from the sandboxes and computes the corresponding scalar reward. ```python def reward_func(prompts, completions, **kwargs): stats_list = run_async( _evaluate_batch_async(sandbox_pool, completions, prompts) ) rewards = [] for s in stats_list: if not s["no_error"]: rewards.append(-1.0) elif s["num_tests"] == 0: rewards.append(0.0) else: rewards.append(s["num_passed"] / s["num_tests"]) return rewards ``` The reward scheme: - **-1.0**: Error, timeout, or banned pattern detected - **0.0**: No tests were present (shouldn't happen with valid tasks) - **0.0 to 1.0**: Fraction of tests passed #### Bridging Sync and Async TRL's `GRPOTrainer` expects a synchronous reward function, but the Daytona SDK uses async/await for parallel sandbox operations. We bridge these two worlds with a helper: ```python def main(): # Create a dedicated event loop for async operations loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) def run_async(coro: Awaitable[Any]) -> Any: """Run async code from sync context.""" return loop.run_until_complete(coro) # ... training code ... def reward_func(prompts, completions, **kwargs): # This sync function is called by TRL # We use run_async to call our async evaluation stats_list = run_async( _evaluate_batch_async(sandbox_pool, completions, prompts) ) # ... compute rewards ... return rewards ``` This pattern lets us keep the async parallelism benefits of the Daytona SDK while working within TRL's synchronous training loop. The `run_async` helper blocks until all 500 parallel sandbox evaluations complete, then returns the results. #### Training Configuration The GRPO trainer is configured with these parameters: ```python training_args = GRPOConfig( output_dir="training_results", per_device_train_batch_size=20, # batch size chosen so the training runs comfortably on a single 80GB GPU, # if running this on a GPU with less memory, reduce the batch size accordingly gradient_accumulation_steps=25, num_generations=EFFECTIVE_BATCH_SIZE // len(TASKS), max_prompt_length=256, max_completion_length=512, learning_rate=8e-6, num_train_epochs=1, logging_steps=1, report_to="none", max_steps=8, bf16=True, use_vllm=True, vllm_mode="colocate", vllm_gpu_memory_utilization=0.15, gradient_checkpointing=True, loss_type="dapo", beta=0.01, ) ``` Key settings explained: **Batch size and sandbox pool alignment:** ``` per_device_train_batch_size (20) × gradient_accumulation_steps (25) = 500 ``` This equals `EFFECTIVE_BATCH_SIZE`. Each training step generates exactly 500 completions, and we have exactly 500 sandboxes - so every completion evaluates in parallel with no waiting. If we had fewer sandboxes, some completions would queue up. If we had more, sandboxes would sit idle. **vLLM colocate mode:** ```python use_vllm=True, vllm_mode="colocate", vllm_gpu_memory_utilization=0.15, ``` This runs vLLM for fast inference on the same GPU as training. We use 15% of the GPU's memory for model generation, and the rest for training (optimizer states). **Generation settings:** - `num_generations=EFFECTIVE_BATCH_SIZE // len(TASKS)`: Generate 250 completions per prompt (500 / 2 tasks). With 2 prompts (sorting and max_subarray), that's 500 total per step - `max_completion_length=512`: Limit completion length to prevent runaway generation ### 4. Running the Training Start training with: ```bash python train.py ``` You'll see output like: ``` Creating 500 sandboxes... Successfully created all 500 sandboxes Evaluating 500 completions in parallel across 500 sandboxes... Completion 1/500 done Completion 2/500 done ... Done: 500/500 completions evaluated ``` After training completes, metrics are saved to `training_results/metrics.jsonl` and the model is saved as `training_results/checkpoint-8`. ### 5. Example Evaluation Walkthrough Let's trace through what happens when evaluating a single completion: **Step 1: Model generates a completion** The model receives the sorting prompt and generates: ``` if len(xs) <= 1: return xs pivot = xs[0] less = [x for x in xs[1:] if x <= pivot] greater = [x for x in xs[1:] if x > pivot] return sort_numbers(less) + [pivot] + sort_numbers(greater) # Test print(sort_numbers([3, 1, 2])) ``` **Step 2: Sanitization extracts the function body** `sanitize_completion` keeps only the indented lines: ```python if len(xs) <= 1: return xs pivot = xs[0] less = [x for x in xs[1:] if x <= pivot] greater = [x for x in xs[1:] if x > pivot] return sort_numbers(less) + [pivot] + sort_numbers(greater) ``` **Step 3: Check for banned patterns** `has_banned_pattern` scans for `sorted(`, `.sort(`, `heapq`, `import`. None found, so we proceed. **Step 4: Build the test harness** `build_test_harness` assembles the full script: prompt + completion + test runner. This becomes ~50 lines of executable Python. **Step 5: Execute in sandbox** ```python response = await sandbox.code_interpreter.run_code(code, timeout=1) ``` The sandbox runs the code and returns within the 1-second timeout. **Step 6: Parse results** The test runner printed: ```json {"results": [true, true, true, true, true]} ``` We parse this from `response.stdout`: ```python results = json.loads(response.stdout.strip().splitlines()[-1]) # {"results": [true, true, true, true, true]} ``` **Step 7: Compute reward** All 5 tests passed: ```python reward = 5 / 5 # = 1.0 ``` This completion gets a perfect reward of 1.0, reinforcing the model to generate similar quicksort implementations. ### 6. Training Results The plot below shows average rewards over training steps. At the start, the model is very rarely writing functions that meet the task specifications, and it is often writing code that either errors out or times out. Given our large effective batch size of 500, the model achieves near-perfect performance after only 8 steps. Rewards over training steps showing improvement ### 7. Adding Custom Tasks To add a new coding task, extend the `TASKS` dictionary: ```python TASKS = { "your_task": { "prompt": "Your prompt here...", "func_name": "function_name", "banned_patterns": ["patterns", "to", "ban"], "tests": [ "test_input_1", "test_input_2", ], "reference": "reference_function", }, } ``` The reference function should be defined in the test harness that `build_test_harness` generates. ### 8. Configuration Options | Parameter | Default | Description | |-----------|---------|-------------| | `EFFECTIVE_BATCH_SIZE` | 500 | Effective batch size, also equal to the number of parallel sandboxes | | `MAX_TIMEOUT_SECONDS` | 1 | Timeout per code execution | | `MODEL_NAME` | `Qwen/Qwen3-1.7B-Base` | Base model to train | :::tip[Scaling Tips] - Keep `per_device_train_batch_size * gradient_accumulation_steps` equal to `EFFECTIVE_BATCH_SIZE` for optimal parallelism - Increase `MAX_TIMEOUT_SECONDS` for tasks with more (algorithmically) complex test cases ::: --- **Key advantages of this approach:** - **Massive parallelism**: 500 sandboxes evaluate completions simultaneously - **Safe execution**: Generated code runs in isolated environments, protecting your system - **Fast feedback**: vLLM + parallel evaluation minimizes training iteration time - **Extensible**: Add new coding tasks by defining prompts and test cases import { Image } from 'astro:assets' import wealthTrajectories from '../../../../../assets/docs/images/wealth-trajectories.png' [DSPy](https://dspy.ai/)'s RLM implements [recursive language models](https://arxiv.org/abs/2512.24601), a system where an LLM writes Python code through which it can pass parts of its context to LLM calls, leading to significantly enhanced long-context reasoning. The generated code runs in a REPL, and in this guide we use and present `DaytonaInterpreter`, which plugs into DSPy as the code-execution backend so that all generated code runs inside an isolated Daytona cloud sandbox rather than on your machine. --- ### 1. Setup #### Clone the Repository Clone the [Daytona repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/python/dspy-rlms ``` #### Create Virtual Environment ```bash python3.10 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate ``` #### Install Dependencies ```bash pip install -e . ``` This installs the DSPy framework and the Daytona SDK. To also run the included demo (which plots results with matplotlib), use ```bash pip install -e ".[demo]" ``` #### Configure Environment Create a `.env` file with your API keys: ```bash cp .env.example .env # Edit .env with your keys ``` The file needs two variables: ```bash DAYTONA_API_KEY=your_daytona_api_key OPENROUTER_API_KEY=your_openrouter_api_key # or OPENAI_API_KEY / ANTHROPIC_API_KEY ``` :::note Get your Daytona API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys). The LLM provider key depends on which model you configure in your code — the examples use OpenRouter. ::: ### 2. Basic Usage The following example shows the basic setup — configure a model, create a `DaytonaInterpreter`, and pass it to an RLM. The generated code can call `llm_query()` to delegate semantic work back to the LLM: ```python import dspy from dotenv import load_dotenv from daytona_interpreter import DaytonaInterpreter load_dotenv() lm = dspy.LM("openrouter/google/gemini-3-flash-preview") dspy.configure(lm=lm) interpreter = DaytonaInterpreter() rlm = dspy.RLM( signature="documents: list[str], question: str -> answer: str", interpreter=interpreter, verbose=True, ) documents = [...] # your documents result = rlm(documents=documents, question="Summarize the key findings across these documents.") print(result.answer) interpreter.shutdown() ``` Inside the sandbox, the RLM might loop over the documents, call `llm_query()` to summarize each one, then aggregate the results with Python before calling `SUBMIT(answer=...)`. ### 3. Workflow Overview Each RLM call runs an iterative REPL loop. The LLM writes Python code, the code executes in a Daytona sandbox, and the output is fed back to the LLM for the next iteration. Crucially, the generated code can call `llm_query()` to invoke a sub-LLM call — this is how the LLM delegates semantic work (understanding, extraction, classification) to itself while keeping the orchestration logic in Python. 1. **Prompt** — RLM sends the task inputs and previous turns to the LLM 2. **Code** — The LLM responds with reasoning and a Python code snippet 3. **Execute** — The code runs inside a Daytona sandbox; any `llm_query()` calls are bridged back to the host LLM 4. **Repeat** — Steps 1–3 repeat until the code calls `SUBMIT()` or the iteration limit is reached #### How Bridging Works Step 3 above mentions that `llm_query()` calls are "bridged back to the host." Here's a diagram and an explanation of that process: ``` Host Process Daytona Sandbox ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ DaytonaInterpreter │ │ Broker Server (Flask) │ │ │ │ │ │ • polls the broker for │ tool call, │ • accepts requests from │ │ pending requests │ e.g. llm_query │ the wrapper functions │ │ │◄───────────────│ │ │ • calls the LLM API │ │ • queues them for the host │ │ or runs tool functions │ result │ • returns results once the │ │ • posts results back │───────────────►│ host replies │ │ │ │ │ └──────────────────────────────┘ │ Generated Code │ │ │ • llm_query() │ ▼ │ • llm_query_batched() │ LLM API │ • custom tool wrappers │ └──────────────────────────────┘ ``` When `DaytonaInterpreter` starts, it launches a small Flask broker server inside the sandbox and injects wrapper functions (`llm_query`, `llm_query_batched`, and any custom tools you provide). These wrappers POST requests to the broker and block until a result arrives. On the host side, a polling loop picks up pending requests, executes them (e.g. calls the LLM API or runs your tool function), and posts the results back to the broker. From the generated code's perspective, the wrappers look and behave like ordinary Python functions. Custom tools passed via the `tools` dict use the same mechanism, so that the host generates a matching wrapper inside the sandbox and bridges calls identically. State persists across iterations: variables, imports, and function definitions all carry over. #### Sub-LLM Calls Two built-in functions are available inside the sandbox: - **`llm_query(prompt)`** — send a single natural-language prompt to the LLM, get a string back - **`llm_query_batched(prompts)`** — send multiple prompts concurrently, get a list of strings back These execute on the host (they need LLM API access) and are bridged into the sandbox. From the generated code's perspective they are ordinary Python functions that take strings and return strings. This is what makes the pattern powerful: the LLM can write a `for` loop over 100 chapters, call `llm_query_batched()` to extract structured data from each one in parallel, then aggregate and use the results with additional Python code. ### 4. Example Walkthrough The included `demo.py` shows a realistic use of sub-LLM calls: literary analysis of _The Count of Monte Cristo_ — a ~1,300-page novel with 117 chapters — tracking the wealth trajectory of five major characters. The RLM uses `llm_query_batched()` to process chapters in parallel batches, then aggregates the results with Python. #### How the Demo Works The script fetches the full novel text from Project Gutenberg, splits it into chapters, and passes them to an RLM configured with a typed signature: ```python interpreter = DaytonaInterpreter() rlm = dspy.RLM( signature="chapters: list[str], task: str -> wealth_data: list[dict]", interpreter=interpreter, max_iterations=40, max_llm_calls=500, verbose=True, ) chapters = fetch_chapters() print(f"Fetched {len(chapters)} chapters") TASK = ( "Analyze the economic trajectory of each major character across the novel. " "For each chapter where a character's wealth status is mentioned or implied, " "produce a dict with keys: chapter (int), character (str), wealth (int 1-10 " "where 1=destitute and 10=richest in Paris), and event (str, brief description " "of what changed). Track the following characters: Dantès, Danglars, Fernand/" "Morcerf, Villefort, and Mercédès. You need to cover each chapter in the book." ) result = rlm(chapters=chapters, task=TASK) wealth_data = result.wealth_data ``` #### What the RLM Does The RLM's generated code follows a pattern typical of sub-LLM workloads: 1. **Batch the input** — Split the 117 chapters into manageable groups 2. **Fan out with `llm_query_batched()`** — For each batch, send a prompt like _"Extract wealth events from these chapters as JSON"_ — the sub-LLM calls run concurrently on the host 3. **Parse and accumulate** — Each sub-call returns a string; the code parses the JSON and appends to a running list 4. **Iterate** — Repeat for the next batch; state (the accumulated list) persists across REPL iterations 5. **Submit** — Once all chapters are processed, call `SUBMIT(wealth_data=accumulated_results)` This is the core RLM pattern: Python handles the data plumbing (batching, parsing, aggregating) while `llm_query_batched()` handles the parts that need language understanding (reading prose, identifying wealth events, rating severity). #### Running the Demo ```bash python demo.py ``` The script plots the results with matplotlib after the RLM finishes. :::tip The demo runs up to 40 iterations and 500 sub-LLM calls. Depending on the model and provider, a full run may take several minutes and consume significant API credits. ::: #### Results The output is a list of `{chapter, character, wealth, event}` dictionaries that the script plots as smoothed time series: Wealth trajectory chart showing five character arcs across 117 chapters of The Count of Monte Cristo. ### 5. Conclusion RLMs combine the LLM's language understanding with Python's ability to loop, branch, and aggregate — the generated code calls the LLM whenever it needs semantic reasoning and handles everything else with ordinary computation. `DaytonaInterpreter` makes this safe to run by executing all generated code in an isolated Daytona cloud sandbox: - **Sub-LLM recursion** — `llm_query()` and `llm_query_batched()` are bridged from the sandbox to the host, letting generated code invoke the LLM for semantic tasks like extraction, classification, and summarisation - **Isolation** — All generated code runs in a Daytona cloud sandbox, not on your machine - **Persistent state** — Variables, imports, and definitions survive across REPL iterations, so the LLM can accumulate results across batches Guides for building and running Recursive Language Models with Daytona. This guide demonstrates how to build a recursive language model (RLM) agent system that uses Daytona sandboxes, based on the approach pioneered in [Recursive Language Models](https://arxiv.org/abs/2512.24601) (Zhang, Kraska, Khattab) and further explored by [Prime Intellect](https://www.primeintellect.ai/blog/rlm). While the original paper and Prime Intellect's implementation focus on single-level recursion (depth=1), this guide extends the concept to **unlimited recursion depth** — agents can spawn sub-agents, which can spawn their own sub-agents, and so on. Each agent runs in its own isolated Daytona sandbox with a fresh clone of the target repository. --- ### 1. Workflow Overview The system implements a recursive agent architecture where agents can delegate subtasks to child agents: 1. **Initialize**: Root agent receives a task and gets a Daytona sandbox with a fresh repository clone 2. **Iterate**: Agent runs a loop: LLM call → extract Python code → execute in REPL 3. **Delegate**: Code can call `rlm_query()` to spawn sub-agents, each with their own sandbox 4. **Aggregate**: Sub-agents return results; parent synthesizes findings and optionally runs more code 5. **Complete**: Root agent receives all sub-agent results, produces a git patch; all sandboxes are cleaned up ``` Root Agent (depth=0) ├── Sub-Agent A (depth=1) │ ├── Sub-Agent A1 (depth=2) │ └── Sub-Agent A2 (depth=2) └── Sub-Agent B (depth=1) ├── Sub-Agent B1 (depth=2) └── Sub-Agent B2 (depth=2) ``` Each agent runs in its own isolated Daytona sandbox with a fresh repository clone, enabling parallel exploration. ### 2. Setup #### Clone the Repository Clone the [Daytona repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory: ```bash git clone https://github.com/daytonaio/daytona.git cd daytona/guides/python/recursive-language-models ``` #### Create Virtual Environment ```bash python3.10 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate ``` #### Install Dependencies ```bash pip install -e . ``` This installs: - `daytona` - Daytona SDK for sandbox management - `litellm` - Unified LLM interface for any provider - `typer` - CLI framework - `pyyaml` - Configuration parsing #### Configure Environment Get your Daytona API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys) and create a `.env` file: ```bash DAYTONA_API_KEY=your_daytona_api_key LLM_API_KEY=your_llm_api_key ``` The `LLM_API_KEY` is used via [LiteLLM](https://docs.litellm.ai/), supporting OpenRouter, OpenAI, Anthropic, and other providers. ### 3. Running an Agent With setup complete, let's run an agent. Here's an example that investigates TODO comments in scikit-learn: ```bash python run.py https://github.com/scikit-learn/scikit-learn \ -p "Investigate TODO comments across this repository. Spawn sub-agents to explore different modules. Find the easiest TODO and fix it." ``` This spawns a root agent that explores the codebase, delegates to sub-agents for parallel investigation, and produces a git patch fixing the easiest TODO it finds. We'll walk through the results and trace the execution in detail later, but first, let's look at how the code works. #### CLI Options | Option | Description | |--------|-------------| | `repo` | GitHub repository URL (required) | | `-p, --prompt` | Task prompt for the agent (required) | | `-b, --branch` | Branch name (optional) | | `--commit` | Specific commit SHA (optional) | | `-c, --config` | Path to config file (default: `config.yaml`) | | `-o, --output` | Output file for patch (default: stdout) | ### 4. Understanding the Code Let's walk through the key components of the agent system. #### Agent Execution Loop Each agent runs an iteration loop that calls the LLM, extracts code blocks, and executes them. The core loop in `agent.py`: ```python def _run_loop(self) -> None: """Run the main iteration loop.""" system_prompt = build_system_prompt(depth=self.depth) messages = [{"role": "system", "content": system_prompt}] execution_result = None for iteration in range(self.config.rlm.max_iterations): # Check global timeout if self._is_timeout(): break # Build user prompt with previous execution result user_prompt = build_user_prompt(iteration, execution_result) messages.append({"role": "user", "content": user_prompt}) # Get model completion response = self.client.completion(messages) messages.append({"role": "assistant", "content": response}) # Execute code blocks in REPL repl_result = self.repl.execute_response(response) # Check for final answer if repl_result.final_answer is not None: self._result = repl_result.final_answer break # Format result for next iteration execution_result = format_execution_result(...) ``` Each iteration: 1. Builds a prompt with context from previous execution 2. Gets an LLM completion 3. Extracts and executes Python code blocks 4. Checks if the agent called `FINAL()` to submit results 5. Formats the output for the next iteration #### Sub-Agent Spawning When agent code calls `rlm_query()`, a new sub-agent is created with its own sandbox: ```python def _handle_rlm_query(self, task: str) -> str: """Spawn a sub-agent for a specific task.""" # Check sandbox budget if not self.sandbox_manager.budget.can_acquire(): return "Error: sandbox budget exhausted" # Create sub-agent at depth + 1 sub_agent = RLMAgent( client=self.client, sandbox_manager=self.sandbox_manager, config=self.config, depth=self.depth + 1, task=task, # ... other params ) # Run sub-agent (blocking) result = sub_agent.run() # Return result, truncated if necessary return result.result or "No result" ``` For parallel spawning, `rlm_query_batched()` uses a thread pool: ```python def _handle_rlm_query_batched(self, tasks: list[str]) -> list[str]: """Spawn multiple sub-agents in parallel.""" results = [""] * len(tasks) with ThreadPoolExecutor(max_workers=10) as executor: future_to_idx = { executor.submit(self._handle_rlm_query, task): i for i, task in enumerate(tasks) } for future in as_completed(future_to_idx): idx = future_to_idx[future] results[idx] = future.result() return results ``` #### Agent Code Interface Inside the REPL, agents have access to these functions: | Function | Description | |----------|-------------| | `rlm_query(task)` | Spawn a single sub-agent, returns result string | | `rlm_query_batched(tasks)` | Spawn multiple sub-agents in parallel | | `FINAL(answer)` | Submit final result (root: triggers patch extraction) | | `FINAL_VAR(var_name)` | Submit the value of a variable as result | | `edit_file(path, old, new)` | Edit a file with syntax validation | Example spawning pattern used by agents: ```python # Spawn multiple sub-agents to explore different modules results = rlm_query_batched([ "Search for TODO comments in sklearn/linear_model/ and assess difficulty", "Search for TODO comments in sklearn/ensemble/ and assess difficulty", "Search for TODO comments in sklearn/tree/ and assess difficulty", ]) for i, result in enumerate(results): print(f"=== Sub-agent {i+1} findings ===") print(result) ``` ### 5. Example Walkthrough Let's trace what happens when we run an agent on a popular machine learning library, scikit-learn: ```bash python run.py https://github.com/scikit-learn/scikit-learn \ -p "Investigate TODO comments across this repository. Spawn sub-agents to explore different modules under sklearn/ in parallel. For each TODO found, assess how difficult it would be to fix (easy/medium/hard). After gathering results, pick the easiest TODO and fix it." ``` Note that there are about 400 lines in scikit-learn that contain the substring "# TODO". **Step 1: Root agent explores and spawns depth-1 sub-agents** The root agent (depth=0) examines the repository structure, identifies all sklearn modules, and spawns 25 sub-agents in parallel: ```python # Define the subdirectories to investigate subdirs = [ "cluster", "compose", "covariance", "cross_decomposition", "datasets", "decomposition", "ensemble", "feature_extraction", "feature_selection", "gaussian_process", "impute", "inspection", "linear_model", "manifold", "metrics", "mixture", "model_selection", "neighbors", "neural_network", "preprocessing", "semi_supervised", "svm", "tree", "utils" ] # Create queries for sub-agents queries = [ f"Search for 'TODO' comments in 'sklearn/{subdir}/'. For each TODO found, provide: " f"1. The file path and line number. 2. The content of the TODO. 3. An assessment " f"of how difficult it would be to fix (easy/medium/hard) with a brief justification." for subdir in subdirs ] results = rlm_query_batched(queries) ``` Each of these 25 sub-agents gets its own Daytona sandbox with a fresh clone of scikit-learn. **Step 2: Depth-1 agents spawn depth-2 agents** Some depth-1 agents decide their module is too large and spawn their own sub-agents. For example, the `sklearn/metrics/` agent spawned 3 depth-2 agents: ```python # Inside the sklearn/metrics/ agent (depth=1) # To efficiently handle the large number of TODOs, spawn sub-agents for sub-directories tasks = [ "Identify and assess TODOs in 'sklearn/metrics/cluster/'. Provide file, line, content, and difficulty.", "Identify and assess TODOs in 'sklearn/metrics/tests/'. Provide file, line, content, and difficulty.", "Identify and assess TODOs in 'sklearn/metrics/_plot/' and its 'tests' sub-directory." ] results = rlm_query_batched(tasks) ``` **Step 3: Results propagate back** Each sub-agent returns findings via `FINAL()`. Results flow back up: - Depth-2 → Depth-1: Detailed analysis of specific subdirectories - Depth-1 → Root: Module-level summaries with difficulty ratings **Step 4: Root agent synthesizes and acts** The root agent reviews all findings, identifies the easiest TODO, and makes the fix. **Step 5: Git patch produced** ```python import subprocess subprocess.run(['git', 'add', '-A'], cwd='/workspace') result = subprocess.run(['git', 'diff', '--cached', 'HEAD'], capture_output=True, text=True, cwd='/workspace') FINAL(result.stdout) ``` #### Results - Execution time: **316 seconds** (~5.3 minutes) - Agents spawned: **40** (25 at depth 1, 15 at depth 2) **Generated patch:** ```diff diff --git a/sklearn/utils/_array_api.py b/sklearn/utils/_array_api.py --- a/sklearn/utils/_array_api.py +++ b/sklearn/utils/_array_api.py @@ -19,8 +19,7 @@ from sklearn.externals.array_api_compat import numpy as np_compat from sklearn.utils._dataframe import is_df_or_series from sklearn.utils.fixes import parse_version -# TODO: complete __all__ -__all__ = ["xpx"] # we import xpx here just to re-export it, need this to appease ruff +__all__ = ['device', 'get_namespace', 'get_namespace_and_device', 'indexing_dtype', 'move_to', 'size', 'supported_float_dtypes', 'xpx', 'yield_namespace_device_dtype_combinations', 'yield_namespaces'] ``` The agent found the easiest TODO (`# TODO: complete __all__` in `sklearn/utils/_array_api.py`) and completed the `__all__` list with all public symbols from the module. ### 6. Configuration Configure the agent in `config.yaml`: ```yaml # Model configuration - using LiteLLM format model: name: "openrouter/google/gemini-3-flash-preview" # RLM configuration rlm: max_sandboxes: 50 max_iterations: 50 global_timeout: 3600 result_truncation_limit: 10000 ``` | Parameter | Default | Description | |-----------|---------|-------------| | `model.name` | `openrouter/google/gemini-3-flash-preview` | LLM model in LiteLLM format | | `rlm.max_sandboxes` | 50 | Maximum total sandboxes across entire rollout | | `rlm.max_iterations` | 50 | Maximum iterations per agent | | `rlm.global_timeout` | 3600 | Total timeout in seconds | | `rlm.result_truncation_limit` | 10000 | Max chars in sub-agent results | :::tip[Scaling Tips] - Increase `max_sandboxes` for tasks requiring more parallel exploration - The sandbox budget tracks total sandboxes created over the lifetime of the rollout - Sub-agent sandboxes are deleted immediately after completion ::: ### 7. Viewing Results Results are saved to the `results/` directory as JSON files. Use the built-in viewer: ```bash python -m http.server 8000 # Open http://localhost:8000/viewer/ ``` The viewer provides: - Interactive tree visualization of the agent hierarchy - Iteration details with code and output for each agent - Statistics: agent count, max depth, total iterations ### 8. Conclusion Current language models aren't specifically trained to leverage recursive delegation, so RLMs don't necessarily outperform single-agent approaches on benchmarks yet. However, the architecture demonstrates compelling properties for complex tasks. In our scikit-learn example, 40 agents ran in parallel across the agent tree, each with its own isolated sandbox, completing the entire run in just over 5 minutes. This level of parallelism, where each agent can freely modify files, run tests, and explore without affecting others, would be difficult to achieve without per-agent sandboxes. **Key advantages of this approach:** - **Recursive decomposition**: Complex tasks naturally break into sub-tasks handled by specialized agents - **Isolated execution**: Each agent gets a fresh sandbox, preventing interference - **Parallel exploration**: `rlm_query_batched()` enables concurrent investigation Daytona is an open-source, secure and elastic infrastructure for running AI-generated code. Daytona provides full composable computers — [sandboxes](https://www.daytona.io/docs/en/sandboxes.md) — that you can manage programmatically using the Daytona SDKs, [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md) to run and control code execution. Daytona SDK is available for [Python](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby](https://www.daytona.io/docs/en/ruby-sdk.md) and [Go](https://www.daytona.io/docs/en/go-sdk.md) interfaces. ## 1. Create an account Open the [Daytona Dashboard ↗](https://app.daytona.io/) to create your account. Daytona supports account creation using an email and password, or by connecting your Google or GitHub account. ## 2. Obtain an API key Generate an API key from the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/keys) or using the [Daytona API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/api-keys/POST/api-keys) to authenticate SDK requests and access Daytona services. ## 3. Install the SDK Install the Daytona [Python](https://www.daytona.io/docs/python-sdk.md), [TypeScript](https://www.daytona.io/docs/typescript-sdk.md), [Ruby](https://www.daytona.io/docs/ruby-sdk.md) or [Go](https://www.daytona.io/docs/go-sdk.md) SDKs to interact with sandboxes from code. ```bash pip install daytona ``` ```bash npm install @daytonaio/sdk ``` ```bash gem install daytona ``` ```bash go get github.com/daytonaio/daytona/libs/sdk-go ``` ## 4. Create a Sandbox Create a [sandbox](https://www.daytona.io/docs/en/sandboxes.md) to run your code securely in an isolated environment. `main.py` ```python # Import the Daytona SDK from daytona import Daytona, DaytonaConfig # Define the configuration config = DaytonaConfig(api_key="YOUR_API_KEY") # Replace with your API key # Initialize the Daytona client daytona = Daytona(config) # Create the Sandbox instance sandbox = daytona.create() ``` `index.mts` ```typescript // Import the Daytona SDK import { Daytona } from '@daytonaio/sdk' // Initialize the Daytona client const daytona = new Daytona({ apiKey: 'YOUR_API_KEY' }) // Replace with your API key // Create the Sandbox instance const sandbox = await daytona.create() ``` `main.rb` ```ruby require 'daytona' # Initialize the Daytona client config = Daytona::Config.new(api_key: 'YOUR_API_KEY') # Replace with your API key # Create the Daytona client daytona = Daytona::Daytona.new(config) # Create the Sandbox instance sandbox = daytona.create ``` `main.go` ```go package main import ( "context" "fmt" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { config := &types.DaytonaConfig{ APIKey: "YOUR_API_KEY", // Replace with your API key } client, _ := daytona.NewClientWithConfig(config) ctx := context.Background() sandbox, _ := client.Create(ctx, nil) fmt.Println(sandbox.ID) } ``` ```bash curl https://app.daytona.io/api/sandbox \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data '{}' ``` :::tip Daytona supports multiple options to configure your environment: [in code](https://www.daytona.io/docs/en/configuration.md#configuration-in-code), [environment variables](https://www.daytona.io/docs/en/configuration.md#environment-variables), [.env file](https://www.daytona.io/docs/en/configuration.md#env-file), and [default values](https://www.daytona.io/docs/en/configuration.md#default-values). ::: ## 5. Write and run code Create a program that runs code inside a sandbox. The following snippets are examples of "Hello World" programs that run securely inside a sandbox. `main.py` ```python # Import the Daytona SDK from daytona import Daytona, DaytonaConfig # Define the configuration config = DaytonaConfig(api_key="YOUR_API_KEY") # Replace with your API key # Initialize the Daytona client daytona = Daytona(config) # Create the Sandbox instance sandbox = daytona.create() # Run the code securely inside the Sandbox response = sandbox.process.code_run('print("Hello World")') # Check the response if response.exit_code != 0: print(f"Error: {response.exit_code} {response.result}") else: print(response.result) # Clean up sandbox.delete() ``` `index.mts` ```typescript // Import the Daytona SDK import { Daytona } from '@daytonaio/sdk' // Initialize the Daytona client const daytona = new Daytona({ apiKey: 'YOUR_API_KEY' }) // Replace with your API key // Create the Sandbox instance const sandbox = await daytona.create({ language: 'typescript', }) // Run the code securely inside the Sandbox const response = await sandbox.process.codeRun('console.log("Hello World")') // Check the response if (response.exitCode !== 0) { console.error(`Error: ${response.exitCode} ${response.result}`) } else { console.log(response.result) } // Clean up await sandbox.delete() ``` `main.rb` ```ruby require 'daytona' # Initialize the Daytona client config = Daytona::Config.new(api_key: 'YOUR_API_KEY') daytona = Daytona::Daytona.new(config) # Create the Sandbox instance sandbox = daytona.create # Run the code securely inside the Sandbox response = sandbox.process.code_run(code: 'print("Hello World")') puts response.result ``` `main.go` ```go // Import the Daytona SDK package main import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { // Define the configuration config := &types.DaytonaConfig{ APIKey: "YOUR_API_KEY", // Replace with your API key } // Initialize the Daytona client client, err := daytona.NewClientWithConfig(config) if err != nil { log.Fatal(err) } ctx := context.Background() // Create the Sandbox instance params := types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ Language: types.CodeLanguagePython, }, } sandbox, err := client.Create(ctx, params) if err != nil { log.Fatal(err) } // Run the code securely inside the Sandbox result, err := sandbox.Process.ExecuteCommand(ctx, `echo "Hello World"`) // Check the response if err != nil { log.Fatalf("Error: %v", err) } if result.ExitCode != 0 { log.Printf("Error: %d %s", result.ExitCode, result.Result) } else { log.Println(result.Result) } // Clean up sandbox.Delete(ctx) } ``` ## Summary By following the steps above, you successfully create a Daytona account, obtain an API key, install the SDK, create a sandbox, write code, and run it securely in a sandbox. ## Next steps Use the following resources to interact with sandboxes: - Learn more about Daytona with the [Getting Started](https://www.daytona.io/docs/en/getting-started.md) guide - Get started with [Python](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby](https://www.daytona.io/docs/en/ruby-sdk.md) or [Go](https://www.daytona.io/docs/en/go-sdk.md) **SDKs** - Install the [CLI](https://www.daytona.io/docs/en/getting-started.md#cli) to manage sandboxes from the command line - Use the [API](https://www.daytona.io/docs/en/tools/api.md) to manage sandboxes programmatically - View [examples](https://www.daytona.io/docs/en/getting-started.md#examples) for common sandbox operations and best practices - Explore [guides](https://www.daytona.io/docs/en/guides.md) to connect Daytona with [Claude](https://www.daytona.io/docs/en/guides/claude.md), [OpenCode](https://www.daytona.io/docs/en/guides/opencode/opencode-web-agent.md), [Codex](https://www.daytona.io/docs/en/guides/codex/codex-sdk-interactive-terminal-sandbox.md), [LangChain](https://www.daytona.io/docs/en/guides/langchain/langchain-data-analysis.md) and more :::tip For faster development with AI agents and assistants, use our LLMs context files. Copy the [llms-full.txt](https://www.daytona.io/docs/llms-full.txt.md) and [llms.txt](https://www.daytona.io/docs/llms.txt.md) files and include them in your projects or chat contexts. ::: Daytona provides Language Server Protocol (LSP) support through sandbox instances. This enables advanced language features like code completion, diagnostics, and more. ## Create LSP servers Daytona provides methods to create LSP servers. The `path_to_project` argument is relative to the current sandbox working directory when no leading `/` is used. The working directory is specified by WORKDIR when it is present in the Dockerfile, and otherwise falls back to the user's home directory. ```python from daytona import Daytona, LspLanguageId # Create Sandbox daytona = Daytona() sandbox = daytona.create() # Create LSP server for Python lsp_server = sandbox.create_lsp_server( language_id=LspLanguageId.PYTHON, path_to_project="workspace/project" ) ``` ```typescript import { Daytona, LspLanguageId } from '@daytonaio/sdk' // Create sandbox const daytona = new Daytona() const sandbox = await daytona.create({ language: 'typescript', }) // Create LSP server for TypeScript const lspServer = await sandbox.createLspServer( LspLanguageId.TYPESCRIPT, 'workspace/project' ) ``` ```ruby require 'daytona' # Create Sandbox daytona = Daytona::Daytona.new sandbox = daytona.create # Create LSP server for Python lsp_server = sandbox.create_lsp_server( language_id: Daytona::LspServer::Language::PYTHON, path_to_project: 'workspace/project' ) ``` ```go // Create sandbox client, err := daytona.NewClient() if err != nil { log.Fatal(err) } ctx := context.Background() sandbox, err := client.Create(ctx, nil) if err != nil { log.Fatal(err) } // Get LSP service for Python lsp := sandbox.Lsp(types.LspLanguagePython, "workspace/project") ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references: > [**create_lsp_server (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxcreate_lsp_server) > > [**createLspServer (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#createlspserver) > > [**create_lsp_server (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#create_lsp_server) ### Supported languages The supported languages for creating LSP servers with Daytona are defined by the `LspLanguageId` enum: | Enum Value | Description | | ------------------------------ | -------------------------------------- | | **`LspLanguageId.PYTHON`** | Python language server | | **`LspLanguageId.TYPESCRIPT`** | TypeScript/JavaScript language server | For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lsplanguageid) and [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#lsplanguageid) references: > [**LspLanguageId (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lsplanguageid) > > [**LspLanguageId (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#lsplanguageid) ## Start LSP servers Daytona provides methods to start LSP servers. ```python lsp = sandbox.create_lsp_server("typescript", "workspace/project") lsp.start() # Initialize the server # Now ready for LSP operations ``` ```typescript const lsp = await sandbox.createLspServer('typescript', 'workspace/project') await lsp.start() // Initialize the server // Now ready for LSP operations ``` ```ruby lsp = sandbox.create_lsp_server( language_id: Daytona::LspServer::Language::PYTHON, path_to_project: 'workspace/project' ) lsp.start # Initialize the server # Now ready for LSP operations ``` ```go lsp := sandbox.Lsp(types.LspLanguagePython, "workspace/project") err := lsp.Start(ctx) // Initialize the server if err != nil { log.Fatal(err) } // Now ready for LSP operations ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/lsp/start' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "languageId": "", "pathToProject": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/) references: > [**start (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lspserverstart) > > [**start (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#start) > > [**start (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md#start) > > [**Start (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#LspServerService.Start) > > [**start (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/POST/lsp/start) ## Stop LSP servers Daytona provides methods to stop LSP servers. ```python # When done with LSP features lsp.stop() # Clean up resources ``` ```typescript // When done with LSP features await lsp.stop() // Clean up resources ``` ```ruby # When done with LSP features lsp.stop # Clean up resources ``` ```go // When done with LSP features err := lsp.Stop(ctx) // Clean up resources if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/lsp/stop' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "languageId": "", "pathToProject": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/) references: > [**stop (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lspserverstop) > > [**stop (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#stop) > > [**stop (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md#stop) > > [**Stop (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#LspServerService.Stop) > > [**stop (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/POST/lsp/stop) ## Code completions Daytona provides methods to get code completions for a specific position in a file. ```python completions = lsp_server.completions( path="workspace/project/main.py", position={"line": 10, "character": 15} ) print(f"Completions: {completions}") ``` ```typescript const completions = await lspServer.completions('workspace/project/main.ts', { line: 10, character: 15, }) console.log('Completions:', completions) ``` ```ruby completions = lsp_server.completions( path: 'workspace/project/main.py', position: { line: 10, character: 15 } ) puts "Completions: #{completions}" ``` ```go completions, err := lsp.Completions(ctx, "workspace/project/main.py", types.Position{Line: 10, Character: 15}, ) if err != nil { log.Fatal(err) } fmt.Printf("Completions: %v\n", completions) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/lsp/completions' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "context": { "triggerCharacter": "", "triggerKind": 1 }, "languageId": "", "pathToProject": "", "position": { "character": 1, "line": 1 }, "uri": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/) references: > [**completions (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lspservercompletions) > > [**completions (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#completions) > > [**completions (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md#completions) > > [**Completions (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#LspServerService.Completions) > > [**completions (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/POST/lsp/completions) ## File notifications Daytona provides methods to notify the LSP server when files are opened or closed. This enables features like diagnostics and completion tracking for the specified files. ### Open file Notifies the language server that a file has been opened for editing. ```python # Notify server that a file is open lsp_server.did_open("workspace/project/main.py") ``` ```typescript // Notify server that a file is open await lspServer.didOpen('workspace/project/main.ts') ``` ```ruby # Notify server that a file is open lsp_server.did_open('workspace/project/main.py') ``` ```go // Notify server that a file is open err := lsp.DidOpen(ctx, "workspace/project/main.py") if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/lsp/did-open' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "languageId": "", "pathToProject": "", "uri": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/) references: > [**did_open (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lspserverdid_open) > > [**didOpen (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#didopen) > > [**did_open (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md#did_open) > > [**DidOpen (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#LspServerService.DidOpen) > > [**did_open (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/POST/lsp/did-open) ### Close file Notifies the language server that a file has been closed. This allows the server to clean up resources associated with that file. ```python # Notify server that a file is closed lsp_server.did_close("workspace/project/main.py") ``` ```typescript // Notify server that a file is closed await lspServer.didClose('workspace/project/main.ts') ``` ```ruby # Notify server that a file is closed lsp_server.did_close('workspace/project/main.py') ``` ```go // Notify server that a file is closed err := lsp.DidClose(ctx, "workspace/project/main.py") if err != nil { log.Fatal(err) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/lsp/did-close' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "languageId": "", "pathToProject": "", "uri": "" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/) references: > [**did_close (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lspserverdid_close) > > [**didClose (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#didclose) > > [**did_close (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md#did_close) > > [**DidClose (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#LspServerService.DidClose) > > [**did_close (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/POST/lsp/did-close) ## Document symbols Daytona provides methods to retrieve symbols (functions, classes, variables, etc.) from a document. ```python symbols = lsp_server.document_symbols("workspace/project/main.py") for symbol in symbols: print(f"Symbol: {symbol.name}, Kind: {symbol.kind}") ``` ```typescript const symbols = await lspServer.documentSymbols('workspace/project/main.ts') symbols.forEach((symbol) => { console.log(`Symbol: ${symbol.name}, Kind: ${symbol.kind}`) }) ``` ```ruby symbols = lsp_server.document_symbols('workspace/project/main.py') symbols.each do |symbol| puts "Symbol: #{symbol.name}, Kind: #{symbol.kind}" end ``` ```go symbols, err := lsp.DocumentSymbols(ctx, "workspace/project/main.py") if err != nil { log.Fatal(err) } for _, symbol := range symbols { fmt.Printf("Symbol: %v\n", symbol) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/lsp/document-symbols?languageId=&pathToProject=&uri=' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/) references: > [**document_symbols (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lspserverdocument_symbols) > > [**documentSymbols (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#documentsymbols) > > [**document_symbols (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md#document_symbols) > > [**DocumentSymbols (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#LspServerService.DocumentSymbols) > > [**document_symbols (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/GET/lsp/document-symbols) ## Sandbox symbols Daytona provides methods to search for symbols across all files in the sandbox. ```python symbols = lsp_server.sandbox_symbols("MyClass") for symbol in symbols: print(f"Found: {symbol.name} at {symbol.location}") ``` ```typescript const symbols = await lspServer.sandboxSymbols('MyClass') symbols.forEach((symbol) => { console.log(`Found: ${symbol.name} at ${symbol.location}`) }) ``` ```ruby symbols = lsp_server.sandbox_symbols('MyClass') symbols.each do |symbol| puts "Found: #{symbol.name} at #{symbol.location}" end ``` ```go symbols, err := lsp.SandboxSymbols(ctx, "MyClass") if err != nil { log.Fatal(err) } for _, symbol := range symbols { fmt.Printf("Found: %v\n", symbol) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/lsp/workspacesymbols?query=&languageId=&pathToProject=' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp) references: > [**sandbox_symbols (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/lsp-server.md#lspserversandbox_symbols) > > [**sandboxSymbols (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/lsp-server.md#sandboxsymbols) > > [**sandbox_symbols (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/lsp-server.md#sandbox_symbols) > > [**SandboxSymbols (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#LspServerService.SandboxSymbols) > > [**sandbox_symbols (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/lsp/GET/lsp/workspacesymbols) Daytona enforces resource and requests limits to ensure fair usage and stability across all organizations. [Daytona Limits ↗](https://app.daytona.io/dashboard/limits) provides an overview of your organization's resource limits and usage. ## Resources Resources are shared across all running sandboxes. The number of sandboxes you can run at once depends on their individual usage. Organizations are automatically placed into a tier based on verification status and have access to a compute pool consisting of: - **Compute**: Total CPU cores available - **Memory**: Total RAM available - **Storage**: Total disk space available Limits are applied to your organization's default region. To unlock higher limits, complete the following steps: | **Tier** | **Resources (vCPU / RAM / Storage)** | **Access Requirements** | | ---------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------- | | **Tier 1** | **`10`** / **`10GiB`** / **`30GiB`** | Email verified | | **Tier 2** | **`100`** / **`200GiB`** / **`300GiB`** | Credit card linked, $25 top-up, [GitHub connected](https://www.daytona.io/docs/en/linked-accounts.md#how-to-link-an-account). | | **Tier 3** | **`250`** / **`500GiB`** / **`2000GiB`** | Business email verified, $500 top-up. | | **Tier 4** | **`500`** / **`1000GiB`** / **`5000GiB`** | $2000 top-up every 30 days. | | **Custom** | Custom limits | Contact [support@daytona.io](mailto:support@daytona.io) | Once you meet the criteria for a higher tier, upgrade your tier in the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/limits). ### Resource usage Daytona supports managing your resources by [changing the state](https://www.daytona.io/docs/sandboxes.md#sandbox-lifecycle) of your Sandboxes. The table below summarizes how each state affects resource usage: | **State** | **vCPU** | **Memory** | **Storage** | **Description** | | ------------ | -------- | ---------- | ----------- | --------------------------------------------- | | **Running** | ✅ | ✅ | ✅ | Counts against all limits | | **Stopped** | ❌ | ❌ | ✅ | Frees CPU & memory, but storage is still used | | **Archived** | ❌ | ❌ | ❌ | Data moved to cold storage, no quota impact | | **Deleted** | ❌ | ❌ | ❌ | All resources freed | ## Rate limits Rate limits control how many API requests you can make within a specific time window. These limits are applied based on your tier, authentication status, and the type of operation you're performing. Rate limits for general authenticated requests are tracked per organization. The following rate limits are applied for each tier: - **General requests** - **[Sandbox creation](#sandbox-creation)** - **[Sandbox lifecycle](#sandbox-lifecycle-operations)** | **Tier** | **General Requests (per min)** | **Sandbox Creation (per min)** | **Sandbox Lifecycle (per min)** | | ---------- | ------------------------------ | ------------------------------ | ------------------------------- | | **Tier 1** | 10,000 | 300 | 10,000 | | **Tier 2** | 20,000 | 400 | 20,000 | | **Tier 3** | 40,000 | 500 | 40,000 | | **Tier 4** | 50,000 | 600 | 50,000 | | **Custom** | Custom limits | Custom limits | Custom limits | The general rate limit for authenticated API requests that don't fall under sandbox creation or lifecycle operations includes: - **Listing sandboxes** - **Getting sandbox details** - **Retrieving sandbox regions** - **Listing snapshots** - **Managing volumes** - **Viewing audit logs** - and other read/management operations When you exceed a rate limit, subsequent requests will fail with: - **HTTP Status**: `429 Too Many Requests` - **Error Response**: JSON body with rate limit details - **Retry-After Header**: Time to wait before retrying (in seconds) Understanding these limits helps you build robust applications that handle rate limiting gracefully and avoid service interruptions. For more information, see [best practices](#best-practices). ### Rate limit headers Daytona includes rate limit information in API response headers. Header names include a suffix based on which rate limit is triggered (e.g., `-anonymous`, `-authenticated`, `-sandbox-create`, `-sandbox-lifecycle`): | Header Pattern | Description | | --------------------------------------- | ------------------------------------------------------------------------- | | **`X-RateLimit-Limit-{throttler}`** | Maximum number of requests allowed in the time window | | **`X-RateLimit-Remaining-{throttler}`** | Number of requests remaining in the current window | | **`X-RateLimit-Reset-{throttler}`** | Time in seconds until the rate limit window resets | | **`Retry-After-{throttler}`** | Time in seconds to wait before retrying (included when limit is exceeded) | ### Sandbox creation This rate limit applies to all sandbox creation methods, including [creation from snapshots](https://www.daytona.io/docs/snapshots.md#create-snapshots), [declarative builds](https://www.daytona.io/docs/declarative-builder.md) and any other parameters passed to `daytona.create()` ([SDK](https://www.daytona.io/docs/getting-started.md#sdks)) or POST requests to `/api/sandbox` ([API](https://www.daytona.io/docs/getting-started.md#api)). This independent limit prevents resource exhaustion while allowing you to perform lifecycle operations on existing sandboxes without restriction. :::note To create sandboxes at a higher rate for your use case, contact [support@daytona.io](mailto:support@daytona.io). ::: ### Sandbox lifecycle operations This rate limit applies to lifecycle and state management operations on existing sandboxes: - [**Starting** sandboxes](https://www.daytona.io/docs/tools/api.md#post-sandboxsandboxidornamestart) (`POST /api/sandbox/:id/start`) - [**Stopping** sandboxes](https://www.daytona.io/docs/tools/api.md#post-sandboxsandboxidornamestop) (`POST /api/sandbox/:id/stop`) - [**Deleting** sandboxes](https://www.daytona.io/docs/tools/api.md#delete-sandboxsandboxidorname) (`DELETE /api/sandbox/:id`) - [**Archiving** sandboxes](https://www.daytona.io/docs/tools/api.md#post-sandboxsandboxidornamearchive) (`POST /api/sandbox/:id/archive`) - and all corresponding SDK methods These operations have a higher limit since they're often performed more frequently during development workflows. ### Rate limit errors Daytona [Python](https://www.daytona.io/docs/python-sdk.md) or [TypeScript](https://www.daytona.io/docs/en/typescript-sdk.md) SDKs raise or throw a `DaytonaRateLimitError` exception (Python) or error (TypeScript) when you exceed a rate limit. All errors include [**`headers`**](#rate-limit-headers) and [**`statusCode`**](#example-rate-limit-error-response) properties, allowing access to rate limit headers directly from the error object. Headers support case-insensitive access: ```typescript try { await daytona.create() } catch (error) { if (error instanceof DaytonaRateLimitError) { console.log(error.headers?.get('x-ratelimit-remaining-sandbox-create')) console.log(error.headers?.get('X-RateLimit-Remaining-Sandbox-Create')) // also works } } ``` ```python try: daytona.create(snapshot="my-snapshot") except DaytonaRateLimitError as e: print(e.headers['x-ratelimit-remaining-sandbox-create']) print(e.headers['X-RateLimit-Remaining-Sandbox-Create']) # also works ``` ```ruby begin daytona.create rescue Daytona::Sdk::Error => e puts "Error: #{e.message}" end ``` For more information, see the [Python SDK](https://www.daytona.io/docs/python-sdk/common/errors.md) and [TypeScript SDK](https://www.daytona.io/docs/typescript-sdk/errors.md) references. > [**DaytonaRateLimitError (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/common/errors.md#daytonaratelimiteerror) > > [**DaytonaRateLimitError (TypeScript SDK)**](https://www.daytona.io/docs/python-sdk/common/errors.md#daytonaratelimiterror) > > [**DaytonaRateLimitError (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/errors.md#daytonaratelimiteerror) ### Rate limit error response The rate limit error response is a JSON object with the following properties: - **`statusCode`**: The HTTP status code of the error - **`message`**: The error message - **`error`**: The error type ```json { "statusCode": 429, "message": "Rate limit exceeded", "error": "Too Many Requests" } ``` ## Tier upgrade Unlock more resources and higher rate limits by completing verification steps. For more information, see the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/limits). :::note For access to custom tier requirements or resources in other regions, please contact [sales@daytona.io](mailto:sales@daytona.io). ::: ## Best practices To work effectively within rate limits, always handle `429` errors gracefully with proper retry logic. When you receive a rate limit error, implement exponential backoff—wait progressively longer between retries (1s, 2s, 4s, 8s, etc.) to avoid overwhelming the API. The following snippet demonstrates how to create a sandbox with retry logic using the TypeScript SDK: ```typescript async function createSandboxWithRetry() { let retries = 0 const maxRetries = 5 while (retries < maxRetries) { try { return await daytona.create({ snapshot: 'my-snapshot' }) } catch (error) { if (error instanceof DaytonaRateLimitError && retries < maxRetries - 1) { // Use Retry-After header if available, otherwise exponential backoff const retryAfter = error.headers?.get('retry-after-sandbox-create') const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, retries) * 1000 await new Promise(resolve => setTimeout(resolve, delay)) retries++ } else { throw error } } } } ``` **Monitor [rate limit headers](#rate-limit-headers)** (e.g., `X-RateLimit-Remaining-{throttler}`, `X-RateLimit-Reset-{throttler}`) to track your consumption and implement proactive throttling before hitting limits. These headers are available on all error objects via the `headers` property. **Cache API responses** that don't frequently change, such as [sandbox lists](https://www.daytona.io/docs/sandboxes.md#list-sandboxes) (when relatively static), [available regions](https://www.daytona.io/docs/regions.md), and [snapshot information](https://www.daytona.io/docs/snapshots.md). This reduces unnecessary API calls and helps you stay well within your limits. **Batch and optimize operations** by creating multiple sandboxes in parallel (within rate limits) rather than sequentially. Consider reusing existing sandboxes when possible instead of creating new ones for every task. **Efficiently manage sandbox lifecycle** to reduce API calls. [Archive sandboxes](https://www.daytona.io/docs/sandboxes.md#archive-sandboxes) instead of deleting and recreating them, stop sandboxes when not in use rather than deleting them, and leverage [auto-stop intervals](https://www.daytona.io/docs/sandboxes.md#auto-stop-interval) to automatically manage running sandboxes without manual intervention. **Implement request queuing** to prevent bursts that exceed limits, and use [webhooks](https://www.daytona.io/docs/webhooks.md) instead of polling for state changes to avoid unnecessary API calls. Set up monitoring and alerts for `429` errors in your application logs so you can proactively address rate limiting issues before they impact your users. Daytona supports linking user accounts from various identity providers. At the moment, the following providers are supported: - Google - GitHub :::tip GitHub account is one of the requirements to automatically [upgrade your organization to **Tier 2**](https://www.daytona.io/docs/en/limits.md#tiers--rate-limit-increases). ::: ## Link account 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard/user/account-settings) account settings. 2. Click the **Link Account** button next to the provider you want to link. 3. Follow the prompts to link your account. ## Unlink account 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard/user/account-settings) account settings. 2. Click the **Unlink** button next to the provider you want to unlink. 3. Follow the prompts to unlink your account. Log streaming allows you to access and process logs as they are being produced, while the process is still running. When executing long-running processes in a sandbox, you often want to access and process their logs in **real-time**. Real-time streaming is especially useful for **debugging**, **monitoring**, or integrating with **observability tools**. - [**Log streaming**](#stream-logs-with-callbacks): stream logs as they are being produced, while the process is still running. - [**Fetching log snapshot**](#retrieve-all-existing-logs): retrieve all logs up to a certain point. This guide covers how to use log streaming with callbacks and fetching log snapshots in both asynchronous and synchronous modes. :::note Starting with version `0.27.0`, you can retrieve session command logs in two distinct streams: **stdout** and **stderr**. ::: ## Stream logs with callbacks If your sandboxed process is part of a larger system and is expected to run for an extended period (or indefinitely), you can process logs asynchronously **in the background**, while the rest of your system continues executing. This is ideal for: - Continuous monitoring - Debugging long-running jobs - Live log forwarding or visualizations ```python import asyncio from daytona import Daytona, SessionExecuteRequest async def main(): daytona = Daytona() sandbox = daytona.create() session_id = "streaming-session" sandbox.process.create_session(session_id) command = sandbox.process.execute_session_command( session_id, SessionExecuteRequest( command='for i in {1..5}; do echo "Step $i"; echo "Error $i" >&2; sleep 1; done', var_async=True, ), ) # Stream logs with separate callbacks logs_task = asyncio.create_task( sandbox.process.get_session_command_logs_async( session_id, command.cmd_id, lambda stdout: print(f"[STDOUT]: {stdout}"), lambda stderr: print(f"[STDERR]: {stderr}"), ) ) print("Continuing execution while logs are streaming...") await asyncio.sleep(3) print("Other operations completed!") # Wait for the logs to complete await logs_task sandbox.delete() if __name__ == "__main__": asyncio.run(main()) ``` ```typescript import { Daytona, SessionExecuteRequest } from '@daytonaio/sdk' async function main() { const daytona = new Daytona() const sandbox = await daytona.create() const sessionId = "exec-session-1" await sandbox.process.createSession(sessionId) const command = await sandbox.process.executeSessionCommand( sessionId, { command: 'for i in {1..5}; do echo "Step $i"; echo "Error $i" >&2; sleep 1; done', runAsync: true, }, ) // Stream logs with separate callbacks const logsTask = sandbox.process.getSessionCommandLogs( sessionId, command.cmdId!, (stdout) => console.log('[STDOUT]:', stdout), (stderr) => console.log('[STDERR]:', stderr), ) console.log('Continuing execution while logs are streaming...') await new Promise((resolve) => setTimeout(resolve, 3000)) console.log('Other operations completed!') // Wait for the logs to complete await logsTask await sandbox.delete() } main() ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create session_id = 'streaming-session' sandbox.process.create_session(session_id) command = sandbox.process.execute_session_command( session_id, Daytona::SessionExecuteRequest.new( command: 'for i in {1..5}; do echo "Step $i"; echo "Error $i" >&2; sleep 1; done', var_async: true ) ) # Stream logs using a thread log_thread = Thread.new do sandbox.process.get_session_command_logs_stream( session_id, command.cmd_id, on_stdout: ->(stdout) { puts "[STDOUT]: #{stdout}" }, on_stderr: ->(stderr) { puts "[STDERR]: #{stderr}" } ) end puts 'Continuing execution while logs are streaming...' sleep(3) puts 'Other operations completed!' # Wait for the logs to complete log_thread.join daytona.delete(sandbox) ``` ```go package main import ( "context" "fmt" "log" "os" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) func main() { client, _ := daytona.NewClient() ctx := context.Background() sandbox, _ := client.Create(ctx, nil) sessionID := "streaming-session" sandbox.Process.CreateSession(ctx, sessionID) // Execute async command that outputs to stdout and stderr cmd := `for i in 1 2 3 4 5; do echo "Step $i"; echo "Error $i" >&2; sleep 1; done` cmdResult, _ := sandbox.Process.ExecuteSessionCommand(ctx, sessionID, cmd, true) cmdID, _ := cmdResult["id"].(string) // Create channels for stdout and stderr stdout := make(chan string, 100) stderr := make(chan string, 100) // Stream logs in a goroutine go func() { err := sandbox.Process.GetSessionCommandLogsStream(ctx, sessionID, cmdID, stdout, stderr) if err != nil { log.Printf("Stream error: %v", err) } }() fmt.Println("Continuing execution while logs are streaming...") // Read from channels until both are closed stdoutOpen, stderrOpen := true, true for stdoutOpen || stderrOpen { select { case chunk, ok := <-stdout: if !ok { stdoutOpen = false } else { fmt.Fprintf(os.Stdout, "[STDOUT]: %s", chunk) } case chunk, ok := <-stderr: if !ok { stderrOpen = false } else { fmt.Fprintf(os.Stderr, "[STDERR]: %s", chunk) } } } fmt.Println("Streaming completed!") sandbox.Delete(ctx) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}/command/{commandId}/logs' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/typescript-sdk/process.md), [Ruby SDK](https://www.daytona.io/docs/ruby-sdk/process.md), [Go SDK](https://www.daytona.io/docs/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references. > [**get_session_command_logs_async (Python SDK)**](https://www.daytona.io/docs/python-sdk/sync/process.md#processget_session_command_logs_async) > > [**getSessionCommandLogs (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/process.md#getsessioncommandlogs) > > [**get_session_command_logs_async (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/process.md#get_session_command_logs_async) > > [**GetSessionCommandLogsStream (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#ProcessService.GetSessionCommandLogsStream) > > [**get session command logs (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/session/{sessionId}/exec) ## Retrieve all existing logs If the command has a predictable duration, or if you don't need to run it in the background but want to periodically check all existing logs, you can use the following example to get the logs up to the current point in time. ```python import time from daytona import Daytona, SessionExecuteRequest daytona = Daytona() sandbox = daytona.create() session_id = "exec-session-1" sandbox.process.create_session(session_id) # Execute a blocking command and wait for the result command = sandbox.process.execute_session_command( session_id, SessionExecuteRequest(command="echo 'Hello from stdout' && echo 'Hello from stderr' >&2") ) print(f"[STDOUT]: {command.stdout}") print(f"[STDERR]: {command.stderr}") print(f"[OUTPUT]: {command.output}") # Or execute command in the background and get the logs later command = sandbox.process.execute_session_command( session_id, SessionExecuteRequest( command='while true; do if (( RANDOM % 2 )); then echo "All good at $(date)"; else echo "Oops, an error at $(date)" >&2; fi; sleep 1; done', run_async=True ) ) time.sleep(5) # Get the logs up to the current point in time logs = sandbox.process.get_session_command_logs(session_id, command.cmd_id) print(f"[STDOUT]: {logs.stdout}") print(f"[STDERR]: {logs.stderr}") print(f"[OUTPUT]: {logs.output}") sandbox.delete() ``` ```typescript import { Daytona, SessionExecuteRequest } from '@daytonaio/sdk' async function main() { const daytona = new Daytona() const sandbox = await daytona.create() const sessionId = "exec-session-1" await sandbox.process.createSession(sessionId) // Execute a blocking command and wait for the result const command = await sandbox.process.executeSessionCommand( sessionId, { command: 'echo "Hello from stdout" && echo "Hello from stderr" >&2', }, ) console.log(`[STDOUT]: ${command.stdout}`) console.log(`[STDERR]: ${command.stderr}`) console.log(`[OUTPUT]: ${command.output}`) // Or execute command in the background and get the logs later const command2 = await sandbox.process.executeSessionCommand( sessionId, { command: 'while true; do if (( RANDOM % 2 )); then echo "All good at $(date)"; else echo "Oops, an error at $(date)" >&2; fi; sleep 1; done', runAsync: true, }, ) await new Promise((resolve) => setTimeout(resolve, 5000)) // Get the logs up to the current point in time const logs = await sandbox.process.getSessionCommandLogs(sessionId, command2.cmdId!) console.log(`[STDOUT]: ${logs.stdout}`) console.log(`[STDERR]: ${logs.stderr}`) console.log(`[OUTPUT]: ${logs.output}`) await sandbox.delete() } main() ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create session_id = 'exec-session-1' sandbox.process.create_session(session_id) # Execute a blocking command and wait for the result command = sandbox.process.execute_session_command( session_id, Daytona::SessionExecuteRequest.new( command: 'echo "Hello from stdout" && echo "Hello from stderr" >&2' ) ) puts "[STDOUT]: #{command.stdout}" puts "[STDERR]: #{command.stderr}" puts "[OUTPUT]: #{command.output}" # Or execute command in the background and get the logs later command = sandbox.process.execute_session_command( session_id, Daytona::SessionExecuteRequest.new( command: 'while true; do if (( RANDOM % 2 )); then echo "All good at $(date)"; else echo "Oops, an error at $(date)" >&2; fi; sleep 1; done', var_async: true ) ) sleep(5) # Get the logs up to the current point in time logs = sandbox.process.get_session_command_logs(session_id, command.cmd_id) puts "[STDOUT]: #{logs.stdout}" puts "[STDERR]: #{logs.stderr}" puts "[OUTPUT]: #{logs.output}" daytona.delete(sandbox) ``` ```go package main import ( "context" "fmt" "log" "time" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) func main() { client, _ := daytona.NewClient() ctx := context.Background() sandbox, _ := client.Create(ctx, nil) sessionID := "exec-session-1" sandbox.Process.CreateSession(ctx, sessionID) // Execute a blocking command and wait for the result cmd1, _ := sandbox.Process.ExecuteSessionCommand(ctx, sessionID, `echo "Hello from stdout" && echo "Hello from stderr" >&2`, false) if stdout, ok := cmd1["stdout"].(string); ok { fmt.Printf("[STDOUT]: %s\n", stdout) } if stderr, ok := cmd1["stderr"].(string); ok { fmt.Printf("[STDERR]: %s\n", stderr) } // Or execute command in the background and get the logs later cmd := `counter=1; while (( counter <= 5 )); do echo "Count: $counter"; ((counter++)); sleep 1; done` cmdResult, _ := sandbox.Process.ExecuteSessionCommand(ctx, sessionID, cmd, true) cmdID, _ := cmdResult["id"].(string) time.Sleep(5 * time.Second) // Get the logs up to the current point in time logs, err := sandbox.Process.GetSessionCommandLogs(ctx, sessionID, cmdID) if err != nil { log.Fatalf("Failed to get logs: %v", err) } if logContent, ok := logs["logs"].(string); ok { fmt.Printf("[LOGS]: %s\n", logContent) } sandbox.Delete(ctx) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}/command/{commandId}/logs' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/typescript-sdk/process.md), [Ruby SDK](https://www.daytona.io/docs/ruby-sdk/process.md), [Go SDK](https://www.daytona.io/docs/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references. > [**get_session_command_logs (Python SDK)**](https://www.daytona.io/docs/python-sdk/sync/process.md#processget_session_command_logs) > > [**getSessionCommandLogs (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/process.md#getsessioncommandlogs) > > [**get_session_command_logs (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/process.md#get_session_command_logs) > > [**GetSessionCommandLogs (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#ProcessService.GetSessionCommandLogs) > > [**get session command logs (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/session/{sessionId}/exec) Daytona Model Context Protocol (MCP) server enables AI agents to interact with [Daytona Sandboxes](https://www.daytona.io/docs/en/sandboxes.md) programmatically. This guide covers how to set up and use the MCP server with various AI agents. ## Install Daytona CLI Install the Daytona CLI to manage the MCP server. ```bash brew install daytonaio/cli/daytona ``` ```bash powershell -Command "irm https://get.daytona.io/windows | iex" ``` For more information, see the [CLI](https://www.daytona.io/docs/en/tools/cli.md) reference. ## Authenticate with Daytona Authenticate with Daytona to enable MCP server access. ```bash daytona login ``` For more information, see the [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-login) reference: > [**login (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-login) ## Initialize MCP server Daytona provides methods to initialize the MCP server with your preferred AI agent. Supported agents include Claude, Cursor, and Windsurf. ```bash # Initialize with Claude daytona mcp init claude # Initialize with Cursor daytona mcp init cursor # Initialize with Windsurf daytona mcp init windsurf ``` After initialization, open your AI agent application to begin using Daytona features. For more information, see the [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-mcp-init) reference: > [**mcp init (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-mcp-init) ## Configure MCP server Daytona provides methods to generate MCP configuration for integration with other AI agents. ```bash daytona mcp config ``` This command outputs a JSON configuration that you can copy into your agent's settings: ```json { "mcpServers": { "daytona-mcp": { "command": "daytona", "args": ["mcp", "start"], "env": { "HOME": "${HOME}", "PATH": "${HOME}:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin" }, "logFile": "${HOME}/Library/Logs/daytona/daytona-mcp-server.log" } } } ``` :::note For Windows users, add the following to the `env` field:
```json "APPDATA": "${APPDATA}" ``` ::: For more information, see the [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-mcp-config) reference: > [**mcp config (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-mcp-config) ## Start MCP server Daytona provides methods to manually start the MCP server. ```bash daytona mcp start ``` For more information, see the [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-mcp-start) reference: > [**mcp start (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-mcp-start) ## Available tools Daytona MCP server provides the following tools for interacting with Daytona Sandboxes: - [Sandbox management](https://www.daytona.io/docs/en/sandboxes.md) - [File system operations](https://www.daytona.io/docs/en/file-system-operations.md) - [Git operations](https://www.daytona.io/docs/en/git-operations.md) - [Process and code execution](https://www.daytona.io/docs/en/process-code-execution.md) - [Computer use](https://www.daytona.io/docs/en/computer-use.md) - [Preview](https://www.daytona.io/docs/en/preview.md) ## Troubleshooting To troubleshoot issues with the Daytona MCP server, try the following: - **Authentication issues**: run `daytona login` to refresh credentials - **Connection errors**: verify MCP server configuration, check server status - **Sandbox errors**: use `daytona list` to check sandbox status If the issue persists, contact [support@daytona.io](mailto:support@daytona.io). Daytona provides network egress limiting for sandboxes to control internet access. This feature can be automatically applied based on your [organization's limits](https://www.daytona.io/docs/en/limits.md) or manually configured for specific sandboxes. ## Tier-based network restrictions Network limits are automatically applied to sandboxes based on your organization's billing tier. This provides secure and controlled internet access for development environments: - **Tier 1 & Tier 2**: Network access is restricted and cannot be overridden at the sandbox level. Organization-level network restrictions take precedence over sandbox-level settings. Even with [`networkAllowList`](#create-sandboxes-with-network-restrictions) specified when creating a sandbox, the organization's network restrictions still apply - **Tier 3 & Tier 4**: Full internet access is available by default, with the ability to configure custom network settings > To learn more about organization tiers and limits, see [limits](https://www.daytona.io/docs/en/limits.md). [Essential services](#essential-services) are available on all tiers and include services essential for development: package registries, container registries, Git repositories, CDN services, platform services, and system package managers. ## Create sandboxes with network restrictions Daytona provides methods to control network access when [creating sandboxes](https://www.daytona.io/docs/en/sandboxes.md#create-sandboxes) by using the `networkAllowList` and `networkBlockAll` parameters: ```python from daytona import CreateSandboxFromSnapshotParams, Daytona daytona = Daytona() # Allow access to specific IP addresses (Wikipedia, X/Twitter, private network) sandbox = daytona.create(CreateSandboxFromSnapshotParams( network_allow_list='208.80.154.232/32,199.16.156.103/32,192.168.1.0/24' )) # Or block all network access sandbox = daytona.create(CreateSandboxFromSnapshotParams( network_block_all=True )) ``` ```typescript import { Daytona } from '@daytonaio/sdk' const daytona = new Daytona() // Allow access to specific IP addresses (Wikipedia, X/Twitter, private network) const sandbox = await daytona.create({ networkAllowList: '208.80.154.232/32,199.16.156.103/32,192.168.1.0/24' }) // Or block all network access const sandbox = await daytona.create({ networkBlockAll: true }) ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new # Allow access to specific IP addresses (Wikipedia, X/Twitter, private network) sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( network_allow_list: '208.80.154.232/32,199.16.156.103/32,192.168.1.0/24' ) ) # Or block all network access sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( network_block_all: true ) ) ``` ```go package main import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) func main() { client, err := daytona.NewClient() if err != nil { log.Fatal(err) } ctx := context.Background() // Allow access to specific IP addresses (Wikipedia, X/Twitter, private network) allowList := "208.80.154.232/32,199.16.156.103/32,192.168.1.0/24" sandbox, err := client.Create(ctx, types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ NetworkAllowList: &allowList, }, }) // Or block all network access sandbox, err = client.Create(ctx, types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ NetworkBlockAll: true, }, }) } ``` ```bash # Allow access to specific IP addresses (Wikipedia, X/Twitter, private network) curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data '{ "networkAllowList": "208.80.154.232/32,199.16.156.103/32,192.168.1.0/24" }' # Or block all network access curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data '{ "networkBlockAll": true }' ``` ```bash # Allow access to specific IP addresses (Wikipedia, X/Twitter, private network) daytona create --network-allow-list '208.80.154.232/32,199.16.156.103/32,192.168.1.0/24' # Or block all network access daytona create --network-block-all ``` :::note If both `networkBlockAll` and `networkAllowList` are specified, `networkBlockAll` takes precedence and all network access will be blocked, ignoring the allow list. ::: For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/daytona.md#createsandboxbaseparams), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#createsandboxbaseparams), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#network_allow_list), [Go SDK](https://www.daytona.io/docs/en/go-sdk/types.md#SandboxBaseParams), [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox), and [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-create) references: > [**network_allow_list (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/daytona.md#createsandboxbaseparams) > > [**network_block_all (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/daytona.md#createsandboxbaseparams) > > [**network_allow_list (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#createsandboxbaseparams) > > [**network_block_all (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#createsandboxbaseparams) > > [**network_allow_list (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#network_allow_list) > > [**network_block_all (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#network_allow_list) > > [**network_allow_list (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/types.md#SandboxBaseParams) > > [**network_block_all (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/types.md#SandboxBaseParams) > > [**networkAllowList (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox) > > [**networkBlockAll (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox) > > [**--network-allow-list (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-create) > > [**--network-block-all (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-create) ## Network allow list format The network allow list is a comma-separated list of IPv4 CIDR blocks. Set your allowed networks using the `networkAllowList` parameter when [creating a sandbox](https://www.daytona.io/docs/en/sandboxes.md#create-sandboxes). - **IPv4 only**: hostnames, domains, and IPv6 are not supported - **CIDR required**: every entry must include a `/` prefix length integer in the range `0` to `32` (inclusive), for example: `/32` - **CIDR format**: use standard CIDR notation (`A.B.C.D/N`). Do not include extra `/` segments - **Max 10 entries**: the list cannot contain more than 10 comma-separated items - **Whitespace is ignored**: entries are trimmed, so spaces around commas are ok The following examples are valid: - **Single IP**: `208.80.154.232/32` (Wikipedia) - **Subnet**: `192.168.1.0/24` (Private network) - **Multiple networks**: `208.80.154.232/32,199.16.156.103/32,10.0.0.0/8` ## Organization configuration The network access policies for your organization are set automatically depending on your organization's limits tier and cannot be modified by organization administrators. These policies determine the default network behavior for all sandboxes in your organization. ## Test network access To test network connectivity from your sandbox: ```bash # Test HTTP connectivity to allowed addresses curl -I https://208.80.154.232 # Test package manager access (allowed on all tiers) apt update # For Ubuntu/Debian npm ping # For Node.js pip install --dry-run requests # For Python ``` ## Security benefits Network limits provide several security advantages: - **Prevents data exfiltration** from sandboxes - **Reduces attack surface** by limiting external connections - **Complies with security policies** for development environments - **Enables fine-grained control** over network access :::caution Enabling unrestricted network access may pose security risks when executing untrusted code. It is recommended to whitelist specific network addresses using `networkAllowList` or block all network access using `networkBlockAll` instead. Test network connectivity before starting critical development work and consider upgrading your tier if you need access to many external services. ::: ## Essential services Daytona provides a list of essential services that are available on all tiers and can be used for development. :::note This list is continuously updated. If you require access to additional essential development services, submit a request in the [sandbox network whitelist](https://github.com/daytonaio/sandbox-network-whitelist) repository or contact [support@daytona.io](mailto:support@daytona.io). ::: ### NPM registry and package managers - **NPM Registry**: `registry.npmjs.org`, `registry.npmjs.com`, `nodejs.org`, `nodesource.com`, `npm.pkg.github.com` - **Yarn Packages**: `yarnpkg.com`, `*.yarnpkg.com`, `yarn.npmjs.org`, `yarnpkg.netlify.com` - **Bun**: `bun.sh`, `*.bun.sh` ### Git hosting and version control - **GitHub**: `github.com`, `*.github.com`, `*.githubusercontent.com`, `ghcr.io` - **GitLab**: `gitlab.com`, `*.gitlab.com` - **Bitbucket**: `bitbucket.org` - **Azure DevOps**: `dev.azure.com`, `*.dev.azure.com`, `login.microsoftonline.com`, `visualstudio.com`, `*.visualstudio.com`, `ssh.dev.azure.com`, `vs-ssh.visualstudio.com` ### Python package managers - **PyPI**: `pypi.org`, `pypi.python.org`, `files.pythonhosted.org`, `bootstrap.pypa.io`, `astral.sh` ### Composer packages - **Composer**: `*.packagist.org`, `packagist.com` ### Ubuntu/Debian package repositories - **Ubuntu Repos**: `*.ubuntu.com` - **Debian Repos**: `*.debian.org`, `cdn-fastly.deb.debian.org` ### CDN and content delivery - **CDN Services**: `fastly.com`, `cloudflare.com`, `r2.cloudflarestorage.com`, `*.r2.cloudflarestorage.com` - **JavaScript CDNs**: `unpkg.com`, `jsdelivr.net` ### AI/ML services - **Anthropic**: `*.anthropic.com`, `claude.ai`, `platform.claude.com` - **OpenAI**: `openai.com`, `*.openai.com`, `chatgpt.com` - **Google AI**: `generativelanguage.googleapis.com`, `gemini.google.com`, `aistudio.google.com`, `ai.google.dev`, `models.dev` - **Perplexity**: `api.perplexity.ai` - **DeepSeek**: `api.deepseek.com` - **Groq**: `api.groq.com` - **Expo**: `api.expo.dev` - **OpenRouter**: `openrouter.ai` - **Qwen**: `chat.qwen.ai`, `dashscope.aliyuncs.com`, `dashscope-intl.aliyuncs.com` - **Cursor**: `*.cursor.com` - **OpenCode**: `opencode.ai`, `*.opencode.ai` - **Other AI Services**: `api.letta.com`, `api.fireworks.ai`, `open.bigmodel.cn`, `*.z.ai`, `*.moonshot.ai`, `ai-gateway.vercel.sh`, `api.featherless.ai` ### Docker registries and container services - **Docker Registries**: `docker.io`, `*.docker.io`, `*.docker.com` - **Microsoft Container Registry**: `mcr.microsoft.com` - **Kubernetes Registry**: `registry.k8s.io` - **Google Container Registry**: `gcr.io`, `*.gcr.io`, `registry.cloud.google.com` - **Quay**: `quay.io`, `quay-registry.s3.amazonaws.com` ### Maven repositories - **Maven Repos**: `repo1.maven.org`, `repo.maven.apache.org` ### Google Fonts - **Google Fonts**: `fonts.googleapis.com`, `fonts.gstatic.com` ### AWS S3 endpoints - **US East**: `s3.us-east-1.amazonaws.com`, `s3.us-east-2.amazonaws.com` - **US West**: `s3.us-west-1.amazonaws.com`, `s3.us-west-2.amazonaws.com` - **EU**: `s3.eu-central-1.amazonaws.com`, `s3.eu-west-1.amazonaws.com`, `s3.eu-west-2.amazonaws.com` ### Google Cloud Storage - **GCS**: `storage.googleapis.com` ### Daytona - **Daytona**: `app.daytona.io` ### Developer tools and services - **Convex**: `convex.dev`, `*.convex.dev`, `*.convex.cloud`, `*.convex.site` - **Heroku**: `herokuapp.com`, `*.herokuapp.com` - **Vercel**: `vercel.com`, `*.vercel.com`, `*.vercel.app` - **Supabase**: `supabase.com`, `*.supabase.com`, `supabase.co`, `*.supabase.co` - **Clerk**: `clerk.com`, `*.clerk.com`, `clerk.dev`, `*.clerk.dev`, `accounts.dev`, `*.accounts.dev`, `clerk.accounts.dev`, `*.clerk.accounts.dev` - **WorkOS**: `workos.com`, `*.workos.com`, `authkit.app`, `*.authkit.app` - **Inngest**: `inngest.com`, `*.inngest.com` - **PostHog**: `posthog.com`, `*.posthog.com` - **Sentry**: `sentry.io`, `*.sentry.io`, `sentry-cdn.com`, `*.sentry-cdn.com` - **Linear**: `linear.app`, `*.linear.app` - **Figma**: `figma.com`, `*.figma.com`, `*.figmafiles.com` - **ClickUp**: `clickup.com`, `*.clickup.com` - **Playwright**: `playwright.dev`, `cdn.playwright.dev` ### Messaging services - **Telegram**: `api.telegram.org` - **WhatsApp**: `web.whatsapp.com`, `*.whatsapp.net` ### LLM observability - **Langfuse**: `*.langfuse.com`, `*.cloud.langfuse.com` ## Troubleshooting If you encounter network access issues or need unrestricted network access: 1. Verify your [organization tier](https://www.daytona.io/docs/en/limits.md#tier-upgrade) in the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/limits) 2. Verify your [network allow list](#network-allow-list-format) configuration 3. Contact [support@daytona.io](mailto:support@daytona.io) for assistance Daytona provides organizations as a way to group resources and enable collaboration. Users can work individually in their personal organization or together in a collaborative organization. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard) to manage your organizations. ## Personal vs Collaborative organizations Every Daytona user starts with a personal organization, ideal for solo use and experimentation. Collaborative organizations are created manually and designed for company-wide collaboration with shared access and controls. | **Feature** | **Personal organization** | **Collaborative organization** | | ------------------ | -------------------------------- | ---------------------------------------------- | | **Creation** | Automatic on signup | Manually by a user | | **Members** | Single user only | Multiple users (invite-based) | | **Access Control** | No roles or permissions | Roles with granular resource-based assignments | | **Billing** | Tied to individual user | Shared across team members | | **Use Case** | Personal testing, small projects | Company/team development and production | | **Quota Scope** | Per user | Shared across all members | | **Deletable** | No | Yes (by Owner) | Users can switch between their personal and collaborative organizations by using the dropdown in the [Daytona Dashboard ↗](https://app.daytona.io/dashboard) sidebar. Each organization has its own sandboxes, API keys, and resource quotas. ## Organization roles Users within an organization can have one of two different roles: 1. **Owners** have full administrative access to the organization and its resources. Organization owners can perform administrative actions. 2. **Members** have no administrative access to the organization, while their access to organization resources is based on [**Assignments**](#available-assignments). ## Administrative actions Organization owners can perform administrative actions such as: - [Invite new users to the organization](#inviting-new-users) - [Manage pending invitations](#managing-invitations) - [Change role](#organization-roles) of a user in the Organization - [Update assignments](#available-assignments) for organization members - Remove user from the organization - Inspect audit logs - [Delete organization](#organization-settings) ## Available assignments The list of available assignments includes: | Assignment | Description | | ----------------------------- | ------------------------------------------------------------------- | | **`Viewer (required)`** | Grants read access to all resources in the organization | | **`Developer`** | Grants the ability to create sandboxes and keys in the organization | | **`Sandboxes Admin`** | Grants admin access to sandboxes in the organization | | **`Snapshots Admin`** | Grants admin access to snapshots in the organization | | **`Registries Admin`** | Grants admin access to registries in the organization | | **`Volumes Admin`** | Grants admin access to volumes in the organization | | **`Super Admin`** | Grants full access to all resources in the organization | | **`Auditor`** | Grants access to audit logs in the organization | | **`Infrastructure Admin`** | Grants admin access to infrastructure in the organization | ## Manage members ### Invite new users As an organization **Owner**, to invite a new user to your organization: 1. Navigate to [Members ↗](https://app.daytona.io/dashboard/members) 2. Click the **Invite Member** button 3. Enter the email address of the user you want to invite 4. [Select a role](#organization-roles) for the new user. If you select the **`Member`** role, define their [assignments](#available-assignments) ### Remove users As an organization **Owner**, to remove a user from your organization: 1. Navigate to [Members ↗](https://app.daytona.io/dashboard/members) 2. Click the **Remove** button next to the user you want to remove 3. Confirm the removal by clicking the **Remove** button ## Manage invitations To view pending invitations to join other organizations, navigate to [Invitations ↗](https://app.daytona.io/dashboard/invitations) page by expanding the dropdown at the bottom of the sidebar. Once a user accepts an invitation to join an organization, they get access to resource quotas assigned to that organization and they may proceed by issuing a new [API key](https://www.daytona.io/docs/en/api-keys.md) and creating sandboxes. ## Organization settings The [Settings](https://app.daytona.io/dashboard/settings) subpage in the Dashboard allows you to view the Organization ID and Name and to delete the Organization if you don't need it anymore. This action is irreversible, so please proceed with caution. Personal Organizations are there by default and cannot be deleted. This guide will walk you through running Daytona Open Source locally using Docker Compose. The compose file can be found in the [docker](https://github.com/daytonaio/daytona/tree/main/docker) folder of the Daytona repository. :::caution - This setup is still in development and is **not safe to use in production** - For a fully licensed stable version, [contact sales](https://www.daytona.io/contact) ::: ## Overview The Docker Compose configuration includes all the necessary services to run Daytona: - **API**: Main Daytona application server - **Proxy**: Request proxy service - **Runner**: Service that hosts the Daytona Runner - **SSH Gateway**: Service that handles sandbox SSH access - **Database**: PostgreSQL database for data persistence - **Redis**: In-memory data store for caching and sessions - **Dex**: OIDC authentication provider - **Registry**: Docker image registry with web UI - **MinIO**: S3-compatible object storage - **MailDev**: Email testing service - **Jaeger**: Distributed tracing - **PgAdmin**: Database administration interface ## Quick Start 1. Clone the [Daytona repository](https://github.com/daytonaio/daytona) 2. [Install Docker and Docker Compose](https://docs.docker.com/get-docker/) 3. Run the following command (from the root of the Daytona repo) to start all services: ```bash docker compose -f docker/docker-compose.yaml up -d ``` 4. Access the services: - Daytona Dashboard: http://localhost:3000 - Access Credentials: dev@daytona.io `password` - Make sure that the default snapshot is active at http://localhost:3000/dashboard/snapshots - PgAdmin: http://localhost:5050 - Registry UI: http://localhost:5100 - MinIO Console: http://localhost:9001 (minioadmin / minioadmin) ## DNS Setup for Proxy URLs For local development, you need to resolve `*.proxy.localhost` domains to `127.0.0.1`: ```bash ./scripts/setup-proxy-dns.sh ``` This configures dnsmasq with `address=/proxy.localhost/127.0.0.1`. **Without this setup**, SDK examples and direct proxy access won't work. ## Development Notes - The setup uses shared networking for simplified service communication - Database and storage data is persisted in Docker volumes - The registry is configured to allow image deletion for testing - Sandbox resource limits are disabled due to inability to partition cgroups in DinD environment where the sock is not mounted ## Additional Network Options ### HTTP Proxy To configurate an outbound HTTP proxy for the Daytona services, you can set the following environment variables in the `docker-compose.yaml` file for each service that requires proxy access (the API service is the only that requires outbound access to pull images): - `HTTP_PROXY`: URL of the HTTP proxy server - `HTTPS_PROXY`: URL of the HTTPS proxy server - `NO_PROXY`: Comma-separated list of hostnames or IP addresses that should bypass the proxy The baseline configuration for the API service should be as follows: ```yaml environment: - HTTP_PROXY= - HTTPS_PROXY= - NO_PROXY=localhost,runner,dex,registry,minio,jaeger,otel-collector, ``` ### Extra CA Certificates To configure extra CA certificates (for example, paired with `DB_TLS` env vars), set the following environment variable in the API service: ```yaml environment: - NODE_EXTRA_CA_CERTS=/path/to/your/cert-bundle.pembundle ``` The provided file is a cert bundle. Meaning it can contain multiple CA certificates in PEM format. ## Environment Variables You can customize the deployment by modifying environment variables in the `docker-compose.yaml` file. Below is a full list of environment variables with their default values: ### API Service | Variable | Type | Default Value | Description | | ------------------------------------------ | ------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | `ENCRYPTION_KEY` | string | `supersecretkey` | Encryption key for sensitive data (User must override outside of Compose) | | `ENCRYPTION_SALT` | string | `supersecretsalt` | Encryption salt for sensitive data (User must override outside of Compose) | | `PORT` | number | `3000` | API service port | | `DB_HOST` | string | `db` | PostgreSQL database hostname | | `DB_PORT` | number | `5432` | PostgreSQL database port | | `DB_USERNAME` | string | `user` | PostgreSQL database username | | `DB_PASSWORD` | string | `pass` | PostgreSQL database password | | `DB_DATABASE` | string | `daytona` | PostgreSQL database name | | `DB_TLS_ENABLED` | boolean | `false` | Enable TLS for database connection | | `DB_TLS_REJECT_UNAUTHORIZED` | boolean | `true` | Reject unauthorized TLS certificates | | `REDIS_HOST` | string | `redis` | Redis server hostname | | `REDIS_PORT` | number | `6379` | Redis server port | | `OIDC_CLIENT_ID` | string | `daytona` | OIDC client identifier | | `OIDC_ISSUER_BASE_URL` | string | `http://dex:5556/dex` | OIDC issuer base URL | | `PUBLIC_OIDC_DOMAIN` | string | `http://localhost:5556/dex` | Public OIDC domain | | `OIDC_AUDIENCE` | string | `daytona` | OIDC audience identifier | | `OIDC_MANAGEMENT_API_ENABLED` | boolean | (empty) | Enable OIDC management API | | `OIDC_MANAGEMENT_API_CLIENT_ID` | string | (empty) | OIDC management API client ID | | `OIDC_MANAGEMENT_API_CLIENT_SECRET` | string | (empty) | OIDC management API client secret | | `OIDC_MANAGEMENT_API_AUDIENCE` | string | (empty) | OIDC management API audience | | `DEFAULT_SNAPSHOT` | string | `daytonaio/sandbox:0.4.3` | Default sandbox snapshot image | | `DASHBOARD_URL` | string | `http://localhost:3000/dashboard` | Dashboard URL | | `DASHBOARD_BASE_API_URL` | string | `http://localhost:3000` | Dashboard base API URL | | `POSTHOG_API_KEY` | string | `phc_bYtEsdMDrNLydXPD4tufkBrHKgfO2zbycM30LOowYNv` | PostHog API key for analytics | | `POSTHOG_HOST` | string | `https://d18ag4dodbta3l.cloudfront.net` | PostHog host URL | | `POSTHOG_ENVIRONMENT` | string | `local` | PostHog environment identifier | | `TRANSIENT_REGISTRY_URL` | string | `http://registry:6000` | Transient registry URL | | `TRANSIENT_REGISTRY_ADMIN` | string | `admin` | Transient registry admin username | | `TRANSIENT_REGISTRY_PASSWORD` | string | `password` | Transient registry admin password | | `TRANSIENT_REGISTRY_PROJECT_ID` | string | `daytona` | Transient registry project ID | | `INTERNAL_REGISTRY_URL` | string | `http://registry:6000` | Internal registry URL | | `INTERNAL_REGISTRY_ADMIN` | string | `admin` | Internal registry admin username | | `INTERNAL_REGISTRY_PASSWORD` | string | `password` | Internal registry admin password | | `INTERNAL_REGISTRY_PROJECT_ID` | string | `daytona` | Internal registry project ID | | `SMTP_HOST` | string | `maildev` | SMTP server hostname | | `SMTP_PORT` | number | `1025` | SMTP server port | | `SMTP_USER` | string | (empty) | SMTP username | | `SMTP_PASSWORD` | string | (empty) | SMTP password | | `SMTP_SECURE` | boolean | (empty) | Enable SMTP secure connection | | `SMTP_EMAIL_FROM` | string | `"Daytona Team "` | SMTP sender email address | | `S3_ENDPOINT` | string | `http://minio:9000` | S3-compatible storage endpoint | | `S3_STS_ENDPOINT` | string | `http://minio:9000/minio/v1/assume-role` | S3 STS endpoint | | `S3_REGION` | string | `us-east-1` | S3 region | | `S3_ACCESS_KEY` | string | `minioadmin` | S3 access key | | `S3_SECRET_KEY` | string | `minioadmin` | S3 secret key | | `S3_DEFAULT_BUCKET` | string | `daytona` | S3 default bucket name | | `S3_ACCOUNT_ID` | string | `/` | S3 account ID | | `S3_ROLE_NAME` | string | `/` | S3 role name | | `ENVIRONMENT` | string | `dev` | Application environment | | `MAX_AUTO_ARCHIVE_INTERVAL` | number | `43200` | Maximum auto-archive interval (seconds) | | `OTEL_ENABLED` | boolean | `true` | Enable OpenTelemetry tracing | | `OTEL_COLLECTOR_URL` | string | `http://jaeger:4318/v1/traces` | OpenTelemetry collector URL | | `MAINTENANCE_MODE` | boolean | `false` | Enable maintenance mode | | `PROXY_DOMAIN` | string | `proxy.localhost:4000` | Proxy domain | | `PROXY_PROTOCOL` | string | `http` | Proxy protocol | | `PROXY_API_KEY` | string | `super_secret_key` | Proxy API key | | `PROXY_TEMPLATE_URL` | string | `http://{{PORT}}-{{sandboxId}}.proxy.localhost:4000` | Proxy template URL pattern | | `PROXY_TOOLBOX_BASE_URL` | string | `{PROXY_PROTOCOL}://{PROXY_DOMAIN}` | Proxy base URL for toolbox requests | | `DEFAULT_RUNNER_DOMAIN` | string | `runner:3003` | Default runner domain | | `DEFAULT_RUNNER_API_URL` | string | `http://runner:3003` | Default runner API URL | | `DEFAULT_RUNNER_PROXY_URL` | string | `http://runner:3003` | Default runner proxy URL | | `DEFAULT_RUNNER_API_KEY` | string | `secret_api_token` | Default runner API key | | `DEFAULT_RUNNER_CPU` | number | `4` | Default runner CPU allocation | | `DEFAULT_RUNNER_MEMORY` | number | `8` | Default runner memory allocation (GB) | | `DEFAULT_RUNNER_DISK` | number | `50` | Default runner disk allocation (GB) | | `DEFAULT_RUNNER_API_VERSION` | string | `0` | Default runner API version | | `DEFAULT_ORG_QUOTA_TOTAL_CPU_QUOTA` | number | `10000` | Default organization total CPU quota | | `DEFAULT_ORG_QUOTA_TOTAL_MEMORY_QUOTA` | number | `10000` | Default organization total memory quota | | `DEFAULT_ORG_QUOTA_TOTAL_DISK_QUOTA` | number | `100000` | Default organization total disk quota | | `DEFAULT_ORG_QUOTA_MAX_CPU_PER_SANDBOX` | number | `100` | Default organization max CPU per sandbox | | `DEFAULT_ORG_QUOTA_MAX_MEMORY_PER_SANDBOX` | number | `100` | Default organization max memory per sandbox | | `DEFAULT_ORG_QUOTA_MAX_DISK_PER_SANDBOX` | number | `1000` | Default organization max disk per sandbox | | `DEFAULT_ORG_QUOTA_SNAPSHOT_QUOTA` | number | `1000` | Default organization snapshot quota | | `DEFAULT_ORG_QUOTA_MAX_SNAPSHOT_SIZE` | number | `1000` | Default organization max snapshot size | | `DEFAULT_ORG_QUOTA_VOLUME_QUOTA` | number | `10000` | Default organization volume quota | | `SSH_GATEWAY_API_KEY` | string | `ssh_secret_api_token` | SSH gateway API key | | `SSH_GATEWAY_COMMAND` | string | `ssh -p 2222 {{TOKEN}}@localhost` | SSH gateway command template | | `SSH_GATEWAY_PUBLIC_KEY` | string | (Base64-encoded OpenSSH public key) | SSH gateway public key for authentication | | `SSH_GATEWAY_URL` | string | `localhost:2222` | SSH gateway URL | | `RUNNER_DECLARATIVE_BUILD_SCORE_THRESHOLD` | number | `10` | Runner declarative build score threshold | | `RUNNER_AVAILABILITY_SCORE_THRESHOLD` | number | `10` | Runner availability score threshold | | `RUNNER_HEALTH_TIMEOUT_SECONDS` | number | `3` | Runner health-check timeout in seconds | | `RUNNER_START_SCORE_THRESHOLD` | number | `3` | Runner start score threshold | | `RUN_MIGRATIONS` | boolean | `true` | Enable database migrations on startup | | `ADMIN_API_KEY` | string | (empty) | Admin API key, auto-generated if empty, used only upon initial setup, not recommended for production | | `ADMIN_TOTAL_CPU_QUOTA` | number | `0` | Admin total CPU quota, used only upon initial setup | | `ADMIN_TOTAL_MEMORY_QUOTA` | number | `0` | Admin total memory quota, used only upon initial setup | | `ADMIN_TOTAL_DISK_QUOTA` | number | `0` | Admin total disk quota, used only upon initial setup | | `ADMIN_MAX_CPU_PER_SANDBOX` | number | `0` | Admin max CPU per sandbox, used only upon initial setup | | `ADMIN_MAX_MEMORY_PER_SANDBOX` | number | `0` | Admin max memory per sandbox, used only upon initial setup | | `ADMIN_MAX_DISK_PER_SANDBOX` | number | `0` | Admin max disk per sandbox, used only upon initial setup | | `ADMIN_SNAPSHOT_QUOTA` | number | `100` | Admin snapshot quota, used only upon initial setup | | `ADMIN_MAX_SNAPSHOT_SIZE` | number | `100` | Admin max snapshot size, used only upon initial setup | | `ADMIN_VOLUME_QUOTA` | number | `0` | Admin volume quota, used only upon initial setup | | `SKIP_USER_EMAIL_VERIFICATION` | boolean | `true` | Skip user email verification process | | `RATE_LIMIT_ANONYMOUS_TTL` | number | (empty) | Anonymous rate limit time-to-live (seconds, empty - rate limit is disabled) | | `RATE_LIMIT_ANONYMOUS_LIMIT` | number | (empty) | Anonymous rate limit (requests per TTL, empty - rate limit is disabled) | | `RATE_LIMIT_AUTHENTICATED_TTL` | number | (empty) | Authenticated rate limit time-to-live (seconds, empty - rate limit is disabled) | | `RATE_LIMIT_AUTHENTICATED_LIMIT` | number | (empty) | Authenticated rate limit (requests per TTL, empty - rate limit is disabled) | | `RATE_LIMIT_SANDBOX_CREATE_TTL` | number | (empty) | Sandbox create rate limit time-to-live (seconds, empty - rate limit is disabled) | | `RATE_LIMIT_SANDBOX_CREATE_LIMIT` | number | (empty) | Sandbox create rate limit (requests per TTL, empty - rate limit is disabled) | | `RATE_LIMIT_SANDBOX_LIFECYCLE_TTL` | number | (empty) | Sandbox lifecycle rate limit time-to-live (seconds, empty - rate limit is disabled) | | `RATE_LIMIT_SANDBOX_LIFECYCLE_LIMIT` | number | (empty) | Sandbox lifecycle rate limit (requests per TTL, empty - rate limit is disabled) | | `RATE_LIMIT_FAILED_AUTH_TTL` | number | (empty) | Failed authentication rate limit time-to-live (seconds, empty - rate limit is disabled) | | `RATE_LIMIT_FAILED_AUTH_LIMIT` | number | (empty) | Failed authentication rate limit (requests per TTL, empty - rate limit is disabled) | | `DEFAULT_REGION_ID` | string | `us` | Default region ID | | `DEFAULT_REGION_NAME` | string | `us` | Default region name | | `DEFAULT_REGION_ENFORCE_QUOTAS` | boolean | `false` | Enable region-based resource limits for default region | | `OTEL_COLLECTOR_API_KEY` | string | `otel_collector_api_key` | OpenTelemetry collector API key for authentication (only needed if otel collector is deployed) | | `CLICKHOUSE_HOST` | string | (empty) | ClickHouse host for querying sandbox otel | | `CLICKHOUSE_DATABASE` | string | `otel` | ClickHouse database for querying sandbox otel | | `CLICKHOUSE_PORT` | number | `8123` | ClickHouse port | | `CLICKHOUSE_USERNAME` | string | (empty) | ClickHouse username | | `CLICKHOUSE_PASSWORD` | string | (empty) | ClickHouse password | | `CLICKHOUSE_PROTOCOL` | string | `https` | ClickHouse protocol (e.g., `http` or `https`) | | `SANDBOX_OTEL_ENDPOINT_URL` | string | (empty) | OpenTelemetry endpoint URL for sandbox traces | | `HEALTH_CHECK_API_KEY` | string | `supersecretkey` | Authentication key for the readiness health-check route. | | `NOTIFICATION_GATEWAY_DISABLED` | boolean | `false` | Disable notification gateway service | ### Runner | Variable | Type | Default Value | Description | | --------------------------------------- | ------- | --------------------------------- | ----------------------------------------------------- | | `DAYTONA_API_URL` | string | `http://api:3000/api` | Daytona API URL | | `DAYTONA_RUNNER_TOKEN` | string | `secret_api_token` | Runner API authentication token | | `VERSION` | string | `0.0.1` | Runner service version | | `OTEL_LOGGING_ENABLED` | boolean | `false` | Runner OpenTelemetry logging enabled | | `OTEL_TRACING_ENABLED` | boolean | `false` | Runner OpenTelemetry tracing enabled | | `OTEL_EXPORTER_OTLP_ENDPOINT` | string | (empty) | Runner OpenTelemetry OTLP exporter endpoint | | `OTEL_EXPORTER_OTLP_HEADERS` | string | (empty) | Runner OpenTelemetry OTLP exporter headers | | `ENVIRONMENT` | string | `development` | Application environment | | `API_PORT` | number | `3003` | Runner API service port | | `LOG_FILE_PATH` | string | `/home/daytona/runner/runner.log` | Path to runner log file | | `RESOURCE_LIMITS_DISABLED` | boolean | `true` | Disable resource limits for sandboxes | | `AWS_ENDPOINT_URL` | string | `http://minio:9000` | AWS S3-compatible storage endpoint | | `AWS_REGION` | string | `us-east-1` | AWS region | | `AWS_ACCESS_KEY_ID` | string | `minioadmin` | AWS access key ID | | `AWS_SECRET_ACCESS_KEY` | string | `minioadmin` | AWS secret access key | | `AWS_DEFAULT_BUCKET` | string | `daytona` | AWS default bucket name | | `DAEMON_START_TIMEOUT_SEC` | number | `60` | Daemon start timeout in seconds | | `SANDBOX_START_TIMEOUT_SEC` | number | `30` | Sandbox start timeout in seconds | | `USE_SNAPSHOT_ENTRYPOINT` | boolean | `false` | Use snapshot entrypoint for sandbox | | `RUNNER_DOMAIN` | string | (none) | Runner domain name (hostname for runner URLs) | | `VOLUME_CLEANUP_INTERVAL` | number | `30s` | Volume cleanup interval in seconds (minimum: 10s) | | `COLLECTOR_WINDOW_SIZE` | number | `60` | Metrics collector window size (number of samples) | | `CPU_USAGE_SNAPSHOT_INTERVAL` | string | `5s` | CPU usage snapshot interval duration (minimum: 1s) | | `ALLOCATED_RESOURCES_SNAPSHOT_INTERVAL` | string | `5s` | Allocated resources snapshot interval (minimum: 1s) | | `POLL_TIMEOUT` | string | `30s` | Poller service timeout duration (e.g., `30s`, `1m`) | | `POLL_LIMIT` | number | `10` | Maximum poll attempts per request (min: 1, max: 100) | | `HEALTHCHECK_INTERVAL` | string | `30s` | Interval between health checks (minimum: 10s) | | `HEALTHCHECK_TIMEOUT` | string | `10s` | Health check timeout duration | | `API_VERSION` | number | `2` | Runner API version (default: 2) | | `SNAPSHOT_ERROR_CACHE_RETENTION` | string | `10m` | Snapshot error cache retention duration (minimum: 5m) | ### SSH Gateway | Variable | Type | Default Value | Description | | ------------------ | ------ | ------------------------------------ | -------------------------- | | `API_URL` | string | `http://api:3000/api` | Daytona API URL | | `API_KEY` | string | `ssh_secret_api_token` | API authentication key | | `SSH_PRIVATE_KEY` | string | (Base64-encoded OpenSSH private key) | SSH private key for auth | | `SSH_HOST_KEY` | string | (Base64-encoded OpenSSH host key) | SSH host key for server | | `SSH_GATEWAY_PORT` | number | `2222` | SSH gateway listening port | ### Proxy | Variable | Type | Default Value | Description | | ------------------------- | ------- | --------------------------- | ------------------------------- | | `DAYTONA_API_URL` | string | `http://api:3000/api` | Daytona API URL | | `PROXY_PORT` | number | `4000` | Proxy service port | | `PROXY_API_KEY` | string | `super_secret_key` | Proxy API authentication key | | `PROXY_PROTOCOL` | string | `http` | Proxy protocol (http or https) | | `COOKIE_DOMAIN` | string | `$PROXY_DOMAIN` | Cookie domain for proxy cookies | | `OIDC_CLIENT_ID` | string | `daytona` | OIDC client identifier | | `OIDC_CLIENT_SECRET` | string | (empty) | OIDC client secret | | `OIDC_DOMAIN` | string | `http://dex:5556/dex` | OIDC domain | | `OIDC_PUBLIC_DOMAIN` | string | `http://localhost:5556/dex` | OIDC public domain | | `OIDC_AUDIENCE` | string | `daytona` | OIDC audience identifier | | `REDIS_HOST` | string | `redis` | Redis server hostname | | `REDIS_PORT` | number | `6379` | Redis server port | | `TOOLBOX_ONLY_MODE` | boolean | `false` | Allow only toolbox requests | | `PREVIEW_WARNING_ENABLED` | boolean | `false` | Enable browser preview warning | | `SHUTDOWN_TIMEOUT_SEC` | number | `3600` | Shutdown timeout in seconds | ## [OPTIONAL] Configure Auth0 for Authentication The default compose setup uses a local Dex OIDC provider for authentication. However, you can configure Auth0 as an alternative OIDC provider by following these steps: ### Step 1: Create Your Auth0 Tenant Begin by navigating to https://auth0.com/signup and start the signup process. Choose your account type based on your use case - select `Company` for business applications or `Personal` for individual projects.\ On the "Let's get setup" page, you'll need to enter your application name such as `My Daytona` and select `Single Page Application (SPA)` as the application type. For authentication methods, you can start with `Email and Password` since additional social providers like Google, GitHub, or Facebook can be added later. Once you've configured these settings, click `Create Application` in the bottom right corner. ### Step 2: Configure Your Single Page Application Navigate to `Applications` > `Applications` in the left sidebar and select the application you just created. Click the `Settings` tab and scroll down to find the `Application URIs` section where you'll configure the callback and origin URLs. In the `Allowed Callback URIs` field, add the following URLs: ``` http://localhost:3000 http://localhost:3000/api/oauth2-redirect.html http://localhost:4000/callback http://proxy.localhost:4000/callback ``` For `Allowed Logout URIs`, add: ``` http://localhost:3000 ``` And for `Allowed Web Origins`, add: ``` http://localhost:3000 ``` Remember to click `Save Changes` at the bottom of the page to apply these configurations. ### Step 3: Create Machine-to-Machine Application You'll need a Machine-to-Machine application to interact with Auth0's Management API. Go to `Applications` > `Applications` and click `Create Application`. Choose `Machine to Machine Applications` as the type and provide a descriptive name like `My Management API M2M`. After creating the application, navigate to the `APIs` tab within your new M2M application. Find and authorize the `Auth0 Management API` by clicking the toggle or authorize button.\ Once authorized, click the dropdown arrow next to the Management API to configure permissions. Grant the following permissions to your M2M application: ``` read:users update:users read:connections create:guardian_enrollment_tickets read:connections_options ``` Click `Save` to apply these permission changes. ### Step 4: Set Up Custom API Your Daytona application will need a custom API to handle authentication and authorization. Navigate to `Applications` > `APIs` in the left sidebar and click `Create API`. Enter a descriptive name such as `My Daytona API` and provide an identifier like `my-daytona-api`. The identifier should be a unique string that will be used in your application configuration.\ After creating the API, go to the `Permissions` tab to define the scopes your application will use. Add each of the following permissions with their corresponding descriptions: | Permission | Description | | --------------------------- | ---------------------------------------- | | `read:node` | Get workspace node info | | `create:node` | Create new workspace node record | | `create:user` | Create user account | | `read:users` | Get all user accounts | | `regenerate-key-pair:users` | Regenerate user SSH key-pair | | `read:workspaces` | Read workspaces (user scope) | | `create:registry` | Create a new docker registry auth record | | `read:registries` | Get all docker registry records | | `read:registry` | Get docker registry record | | `write:registry` | Create or update docker registry record | ### Step 5: Configure Environment Variables Once you've completed all the Auth0 setup steps, you'll need to configure environment variables in your Daytona deployment. These variables connect your application to the Auth0 services you've just configured. #### Finding Your Configuration Values You can find the necessary values in the Auth0 dashboard. For your SPA application settings, go to `Applications` > `Applications`, select your SPA app, and click the `Settings` tab. For your M2M application, follow the same path but select your Machine-to-Machine app instead. Custom API settings are located under `Applications` > `APIs`, then select your custom API and go to `Settings`. #### API Service Configuration Configure the following environment variables for your API service: ```bash OIDC_CLIENT_ID=your_spa_app_client_id OIDC_ISSUER_BASE_URL=your_spa_app_domain OIDC_AUDIENCE=your_custom_api_identifier OIDC_MANAGEMENT_API_ENABLED=true OIDC_MANAGEMENT_API_CLIENT_ID=your_m2m_app_client_id OIDC_MANAGEMENT_API_CLIENT_SECRET=your_m2m_app_client_secret OIDC_MANAGEMENT_API_AUDIENCE=your_auth0_managment_api_identifier ``` #### Proxy Service Configuration For your proxy service, configure these environment variables: ```bash OIDC_CLIENT_ID=your_spa_app_client_id OIDC_CLIENT_SECRET= OIDC_DOMAIN=your_spa_app_domain OIDC_AUDIENCE=your_custom_api_identifier (with trailing slash) ``` Note that `OIDC_CLIENT_SECRET` should remain empty for your proxy environment. Daytona provides an interactive environment ("Playground") for creating sandboxes, running SDK operations, and exploring Daytona features directly from your browser. - **Interactive sandbox creation**: configure and create sandboxes with custom resources - **Code snippet generation**: automatically generate SDK code samples based on the values configured in the [management](#management) section - [Web terminal](https://www.daytona.io/docs/en/web-terminal.md): run commands directly in your sandbox through a built-in web terminal - [VNC access](https://www.daytona.io/docs/en/vnc-access.md): interact with GUI applications using [Computer Use](https://www.daytona.io/docs/en/computer-use.md) features ## Access from Dashboard Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard/playground) to access the playground. Playground consists of three tabs: [Sandbox](#sandbox), [Terminal](#terminal), and [VNC](#vnc). All three tabs operate on the same active sandbox. ## Sandbox The sandbox tab provides an interactive interface to configure sandboxes and perform SDK operations. The left panel contains configurable parameters organized into collapsible sections. The right panel displays auto-generated code snippets that you can inspect, copy, and run. ### Management The management section contains the parameters used to configure a sandbox. You can edit these parameters to customize your sandbox and its resources. - [sandbox language](https://www.daytona.io/docs/en/sandboxes.md#multiple-runtime-support): select a programming language runtime for the sandbox - [sandbox resources](https://www.daytona.io/docs/en/sandboxes.md#resources): configure resources allocated to the sandbox - [sandbox lifecycle](https://www.daytona.io/docs/en/sandboxes.md#sandbox-lifecycle): set the sandbox lifecycle policies :::note In the management section, sandboxes are only created when you explicitly click **Run**, replacing any existing playground sandbox. In the [Terminal](#terminal) or [VNC](#vnc) tabs, if there are no active sandboxes, the playground automatically creates one using the configured parameters. ::: ### File system The file system section provides operations to manage files and directories in the sandbox. You can modify files and directories in the sandbox using the following operations: - **Create a new directory**: set the directory location and its permissions - **List files and directories**: set the directory location - **Delete files**: set the file location and delete directory checkbox For more information, see [file system operations](https://www.daytona.io/docs/en/file-system-operations.md). ### Git operations The Git operations section provides operations to manage Git repositories in the sandbox. You can clone, get repository status, and list branches using the following operations: - **Clone a Git repository**: set the repository URL, destination, branch, commit ID, and credentials - **Get repository status**: retrieve the repository status - **List branches**: retrieve the list of branches in the repository For more information, see [Git operations](https://www.daytona.io/docs/en/git-operations.md). ### Process and code execution The process and code execution section provides operations to run code snippets and shell commands directly in the sandbox. Shell commands are fixed, while code snippets change automatically based on the selected [sandbox language](https://www.daytona.io/docs/en/sandboxes.md#multiple-runtime-support) parameter. For more information, see [process and code execution](https://www.daytona.io/docs/en/process-code-execution.md). ## Terminal The terminal tab provides a web-based terminal connected to the sandbox. This gives you direct command-line access to the sandbox environment for running commands, viewing files, and debugging. The terminal runs on port `22222` and remains active as long as the sandbox is running. If the sandbox stops due to inactivity, start it again to restore terminal access. :::note Terminal access is restricted to authenticated members of your [organization](https://www.daytona.io/docs/en/organizations.md). ::: For more information, see [web terminal](https://www.daytona.io/docs/en/web-terminal.md). ## VNC The VNC tab provides graphical desktop access to the sandbox, enabling you to interact with GUI applications and test [Computer Use](https://www.daytona.io/docs/en/computer-use.md) features. The left panel contains interaction controls organized into sections. The right panel displays the desktop view. For more information, see [VNC access](https://www.daytona.io/docs/en/vnc-access.md). ### Display The display section provides options to inspect the sandbox desktop environment. - **Get display information**: retrieve information about the available displays - **List open windows**: retrieve a list of currently open windows For more information, see [display operations](https://www.daytona.io/docs/en/computer-use.md#display-operations). ### Keyboard The keyboard section provides options to send keyboard input to the sandbox. - **Press a hotkey combination**: send a hotkey combination to the sandbox - **Press a key**: press a key with optional modifiers - **Type text**: type text into the active window For more information, see [keyboard operations](https://www.daytona.io/docs/en/computer-use.md#keyboard-operations). ### Mouse The mouse section provides options to control mouse input in the sandbox. - **Click**: click at a specified position - **Drag**: drag from one position to another - **Move**: move the cursor to a specified position - **Get cursor position**: retrieve the current cursor position For more information, see [mouse operations](https://www.daytona.io/docs/en/computer-use.md#mouse-operations). ### Screenshot The screenshot section provides options to capture screenshots of the sandbox desktop. - **Take a screenshot**: select format, scale, and quality, show cursor, and capture the entire screen or specific regions For more information, see [screenshot operations](https://www.daytona.io/docs/en/computer-use.md#screenshot-operations). ## Related - [Web Terminal](https://www.daytona.io/docs/en/web-terminal.md): browser-based terminal access for sandboxes - [VNC Access](https://www.daytona.io/docs/en/vnc-access.md): graphical desktop access for sandboxes - [Computer Use](https://www.daytona.io/docs/en/computer-use.md): programmatic desktop automation - [File System Operations](https://www.daytona.io/docs/en/file-system-operations.md): manage files and directories in sandboxes - [Git Operations](https://www.daytona.io/docs/en/git-operations.md): manage Git repositories in sandboxes - [Process & Code Execution](https://www.daytona.io/docs/en/process-code-execution.md): execute commands and run code in sandboxes Daytona provides preview URLs for accessing services running in your sandboxes. Any process listening for HTTP traffic on ports `3000` - `9999` can be previewed through a generated URL. Daytona supports two types of preview URLs, each with a different authentication mechanism: - [Standard preview URL](#standard-preview-url) uses the sandbox ID in the URL and requires a token sent via header - [Signed preview URL](#signed-preview-url) embeds the authentication token directly in the URL, requiring no headers ## Authentication If a sandbox has its `public` property set to `true`, preview links are publicly accessible without authentication. Otherwise, authentication is required. The authentication mechanism depends on the preview URL type. :::note Standard and signed preview tokens are not interchangeable. The token from `get_preview_link()` must be sent via the `x-daytona-preview-token` header. The token from `create_signed_preview_url()` is embedded in the URL itself: it cannot be used as a header value, and vice versa. ::: ## Standard preview URL The standard preview URL includes your sandbox ID in the URL and provides a separate token for authentication via the `x-daytona-preview-token` request header. URL structure: `https://{port}-{sandboxId}.{daytonaProxyDomain}` The token resets automatically when the sandbox restarts. Any previously issued standard preview tokens become invalid. Call the `get_preview_link()` method again after starting the sandbox to obtain a fresh token. Use standard preview URLs for programmatic access and API integrations where you control the HTTP headers. ```python preview_info = sandbox.get_preview_link(3000) print(f"URL: {preview_info.url}") print(f"Token: {preview_info.token}") # Use with requests import requests response = requests.get( preview_info.url, headers={"x-daytona-preview-token": preview_info.token} ) ``` ```typescript const previewInfo = await sandbox.getPreviewLink(3000); console.log(`URL: ${previewInfo.url}`); console.log(`Token: ${previewInfo.token}`); // Use with fetch const response = await fetch(previewInfo.url, { headers: { 'x-daytona-preview-token': previewInfo.token } }); ``` ```ruby preview_info = sandbox.preview_url(3000) puts "Preview link url: #{preview_info.url}" puts "Preview link token: #{preview_info.token}" ``` ```go preview, err := sandbox.GetPreviewLink(ctx, 3000) if err != nil { log.Fatal(err) } fmt.Printf("URL: %s\n", preview.URL) fmt.Printf("Token: %s\n", preview.Token) ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxId}/ports/3000/preview-url' \ --header 'Authorization: Bearer ' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**get_preview_link (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxget_preview_link) > > [**getPreviewLink (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#getpreviewlink) > > [**preview_url (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#preview_url) > > [**GetPreviewLink (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.GetPreviewLink) > > [**Get Port Preview URL (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/GET/sandbox/{sandboxIdOrName}/ports/{port}/preview-url) ### Authentication Authenticate by sending the token in the `x-daytona-preview-token` header: ```bash curl -H "x-daytona-preview-token: vg5c0ylmcimr8b_v1ne0u6mdnvit6gc0" \ https://3000-sandbox-123456.proxy.daytona.work ``` ## Signed preview URL The signed preview URL embeds the authentication token directly in the URL, eliminating the need for separate headers. You can set a custom expiry time for the token (defaults to 60 seconds). The token persists across sandbox restarts until it expires. Tokens can be revoked manually before expiry if needed. :::tip Always set the `expires_in_seconds` parameter explicitly. The default of 60 seconds is short due to security considerations. Most use cases should use at least 3600 (1 hour). ::: URL structure: `https://{port}-{token}.{daytonaProxyDomain}` Use signed preview URLs when sharing links with users who cannot set custom headers, embedding previews in iframes or emails, or creating time-limited shareable links. ```python # Create a signed preview URL that expires in 3600 seconds (1 hour) signed_url = sandbox.create_signed_preview_url(3000, expires_in_seconds=3600) print(f"URL: {signed_url.url}") # Token is embedded in the URL print(f"Token: {signed_url.token}") # Can be used to revoke access # Use directly - no headers needed import requests response = requests.get(signed_url.url) # Revoke the token before expiry if needed sandbox.expire_signed_preview_url(3000, signed_url.token) ``` ```typescript // Create a signed preview URL that expires in 3600 seconds (1 hour) const signedUrl = await sandbox.getSignedPreviewUrl(3000, 3600); console.log(`URL: ${signedUrl.url}`); // Token is embedded in the URL console.log(`Token: ${signedUrl.token}`); // Can be used to revoke access // Use directly - no headers needed const response = await fetch(signedUrl.url); // Revoke the token before expiry if needed await sandbox.expireSignedPreviewUrl(3000, signedUrl.token); ``` ```ruby # Create a signed preview URL that expires in 3600 seconds (1 hour) signed_url = sandbox.create_signed_preview_url(3000, 3600) puts "URL: #{signed_url.url}" puts "Token: #{signed_url.token}" ``` ```bash daytona preview-url --port 3000 --expires 3600 ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxId}/ports/3000/signed-preview-url?expiresInSeconds=3600' \ --header 'Authorization: Bearer ' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**create_signed_preview_url (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxcreate_signed_preview_url) > > [**getSignedPreviewUrl (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#getsignedpreviewurl) > > [**create_signed_preview_url (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#create_signed_preview_url) > > [**Get Signed Preview URL (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/GET/sandbox/{sandboxIdOrName}/ports/{port}/signed-preview-url) ### Authentication The token is embedded in the URL itself, so no additional headers are required: ```bash curl https://3000-.proxy.daytona.work ``` :::tip Port `22222` is used by the [web terminal](https://www.daytona.io/docs/en/web-terminal.md) to access the terminal using preview URLs. ::: ## Warning page When opening a preview link in a browser for the first time, Daytona displays a warning page. This warning informs users about potential risks of visiting the preview URL and only appears when loading the link in a browser. To skip the warning page: - Send the `X-Daytona-Skip-Preview-Warning: true` header - Upgrade to [Tier 3](https://www.daytona.io/docs/en/limits.md) - Deploy a [custom preview proxy](https://www.daytona.io/docs/en/custom-domain-authentication.md) Daytona provides process and code execution capabilities through the `process` module in sandboxes. ## Code execution Daytona provides methods to execute code in sandboxes. You can run code snippets in multiple languages with support for both stateless execution and stateful interpretation with persistent contexts. :::note Stateless execution inherits the sandbox language that you choose at [sandbox creation](https://www.daytona.io/docs/en/sandboxes.md#create-sandboxes) time. The stateful interpreter supports only Python. ::: ### Run code (stateless) Daytona provides methods to run code snippets in sandboxes using stateless execution. Each invocation starts from a clean interpreter, making it ideal for independent code snippets. ```python # Run Python code response = sandbox.process.code_run(''' def greet(name): return f"Hello, {name}!" print(greet("Daytona")) ''') print(response.result) ``` ```typescript // Run TypeScript code let response = await sandbox.process.codeRun(` function greet(name: string): string { return \`Hello, \${name}!\`; } console.log(greet("Daytona")); `); console.log(response.result); // Run code with argv and environment variables response = await sandbox.process.codeRun( ` console.log(\`Hello, \${process.argv[2]}!\`); console.log(\`FOO: \${process.env.FOO}\`); `, { argv: ["Daytona"], env: { FOO: "BAR" } } ); console.log(response.result); // Run code with timeout (5 seconds) response = await sandbox.process.codeRun( 'setTimeout(() => console.log("Done"), 2000);', undefined, 5 ); console.log(response.result); ``` ```ruby # Run Python code response = sandbox.process.code_run(code: <<~PYTHON) def greet(name): return f"Hello, {name}!" print(greet("Daytona")) PYTHON puts response.result ``` ```go // Run code using shell command execution // Note: For stateless code execution in Go, use ExecuteCommand with the appropriate interpreter result, err := sandbox.Process.ExecuteCommand(ctx, `python3 -c ' def greet(name): return f"Hello, {name}!" print(greet("Daytona")) '`) if err != nil { log.Fatal(err) } fmt.Println(result.Result) // Run code with environment variables result, err = sandbox.Process.ExecuteCommand(ctx, `python3 -c 'import os; print(f"FOO: {os.environ.get(\"FOO\")}")'`, options.WithCommandEnv(map[string]string{"FOO": "BAR"}), ) if err != nil { log.Fatal(err) } fmt.Println(result.Result) // Run code with timeout result, err = sandbox.Process.ExecuteCommand(ctx, `python3 -c 'import time; time.sleep(2); print("Done")'`, options.WithExecuteTimeout(5*time.Second), ) if err != nil { log.Fatal(err) } fmt.Println(result.Result) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/code-run' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "code": "def greet(name):\n return f\"Hello, {name}!\"\n\nprint(greet(\"Daytona\"))", "env": { "FOO": "BAR" }, "timeout": 5000 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**code_run (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processcode_run) > > [**codeRun (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#coderun) > > [**code_run (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#code_run) > > [**ExecuteCommand (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.ExecuteCommand) > > [**execute command (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/execute) ### Run code (stateful) Daytona provides methods to run code with persistent state using the code interpreter. You can maintain variables and imports between calls, create isolated contexts, and control environment variables. ```python from daytona import Daytona, OutputMessage def handle_stdout(message: OutputMessage): print(f"[STDOUT] {message.output}") daytona = Daytona() sandbox = daytona.create() # Shared default context result = sandbox.code_interpreter.run_code( "counter = 1\nprint(f'Counter initialized at {counter}')", on_stdout=handle_stdout, ) # Isolated context ctx = sandbox.code_interpreter.create_context() try: sandbox.code_interpreter.run_code( "value = 'stored in ctx'", context=ctx, ) sandbox.code_interpreter.run_code( "print(value)", context=ctx, on_stdout=handle_stdout, ) finally: sandbox.code_interpreter.delete_context(ctx) ``` ```typescript import { Daytona } from '@daytonaio/sdk' const daytona = new Daytona() async function main() { const sandbox = await daytona.create() // Shared default context await sandbox.codeInterpreter.runCode( ` counter = 1 print(f'Counter initialized at {counter}') `, { onStdout: (msg) => process.stdout.write(`[STDOUT] ${msg.output}`)}, ) // Isolated context const ctx = await sandbox.codeInterpreter.createContext() try { await sandbox.codeInterpreter.runCode( `value = 'stored in ctx'`, { context: ctx }, ) await sandbox.codeInterpreter.runCode( `print(value)`, { context: ctx, onStdout: (msg) => process.stdout.write(`[STDOUT] ${msg.output}`) }, ) } finally { await sandbox.codeInterpreter.deleteContext(ctx) } } main() ``` ```ruby # Ruby SDK uses process.code_run for code execution # Stateful contexts are managed through the code interpreter API require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create # Run code (stateless in Ruby SDK) response = sandbox.process.code_run(code: <<~PYTHON) counter = 1 print(f'Counter initialized at {counter}') PYTHON puts response.result ``` ```go // Create a code interpreter context ctxInfo, err := sandbox.CodeInterpreter.CreateContext(ctx, nil) if err != nil { log.Fatal(err) } contextID := ctxInfo["id"].(string) // Run code in the context channels, err := sandbox.CodeInterpreter.RunCode(ctx, "counter = 1\nprint(f'Counter initialized at {counter}')", options.WithCustomContext(contextID), ) if err != nil { log.Fatal(err) } // Read output for msg := range channels.Stdout { fmt.Printf("[STDOUT] %s\n", msg.Text) } // Clean up context err = sandbox.CodeInterpreter.DeleteContext(ctx, contextID) if err != nil { log.Fatal(err) } ``` ```bash # Create context curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/interpreter/context' \ --request POST \ --header 'Content-Type: application/json' \ --data '{}' # Run code in context (WebSocket endpoint) # Connect via WebSocket to: # wss://proxy.app.daytona.io/toolbox/{sandboxId}/process/interpreter/execute # Send JSON message: # { # "code": "counter = 1\nprint(f\"Counter initialized at {counter}\")", # "contextId": "your-context-id" # } # Delete context curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/interpreter/context/{contextId}' \ --request DELETE ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**run_code (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/code-interpreter.md#codeinterpreterrun_code) > > [**create_context (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/code-interpreter.md#codeinterpretercreate_context) > > [**delete_context (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/code-interpreter.md#codeinterpreterdelete_context) > > [**runCode (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/code-interpreter.md#runcode) > > [**createContext (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/code-interpreter.md#createcontext) > > [**deleteContext (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/code-interpreter.md#deletecontext) > > [**code_run (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#code_run) > > [**RunCode (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#CodeInterpreterService.RunCode) > > [**CreateContext (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#CodeInterpreterService.CreateContext) > > [**DeleteContext (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#CodeInterpreterService.DeleteContext) > > [**code interpreter (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/interpreter) ## Command execution Daytona provides methods to execute shell commands in sandboxes. You can run commands with working directory, timeout, and environment variable options. The working directory defaults to the sandbox working directory. It uses the WORKDIR specified in the Dockerfile if present, or falls back to the user's home directory if not (e.g., `workspace/repo` implies `/home/daytona/workspace/repo`). You can override it with an absolute path by starting the path with `/`. ### Execute commands Daytona provides methods to execute shell commands in sandboxes by providing the command string and optional parameters for working directory, timeout, and environment variables. You can also use the `daytona exec` CLI command for quick command execution. ```python # Execute any shell command response = sandbox.process.exec("ls -la") print(response.result) # Setting a working directory and a timeout response = sandbox.process.exec("sleep 3", cwd="workspace/src", timeout=5) print(response.result) # Passing environment variables response = sandbox.process.exec("echo $CUSTOM_SECRET", env={ "CUSTOM_SECRET": "DAYTONA" } ) print(response.result) ``` ```typescript // Execute any shell command const response = await sandbox.process.executeCommand("ls -la"); console.log(response.result); // Setting a working directory and a timeout const response2 = await sandbox.process.executeCommand("sleep 3", "workspace/src", undefined, 5); console.log(response2.result); // Passing environment variables const response3 = await sandbox.process.executeCommand("echo $CUSTOM_SECRET", ".", { "CUSTOM_SECRET": "DAYTONA" } ); console.log(response3.result); ``` ```ruby # Execute any shell command response = sandbox.process.exec(command: 'ls -la') puts response.result # Setting a working directory and a timeout response = sandbox.process.exec(command: 'sleep 3', cwd: 'workspace/src', timeout: 5) puts response.result # Passing environment variables response = sandbox.process.exec( command: 'echo $CUSTOM_SECRET', env: { 'CUSTOM_SECRET' => 'DAYTONA' } ) puts response.result ``` ```go // Execute any shell command response, err := sandbox.Process.ExecuteCommand(ctx, "ls -la") if err != nil { log.Fatal(err) } fmt.Println(response.Result) // Setting a working directory and a timeout response, err = sandbox.Process.ExecuteCommand(ctx, "sleep 3", options.WithCwd("workspace/src"), options.WithExecuteTimeout(5*time.Second), ) if err != nil { log.Fatal(err) } fmt.Println(response.Result) // Passing environment variables response, err = sandbox.Process.ExecuteCommand(ctx, "echo $CUSTOM_SECRET", options.WithCommandEnv(map[string]string{"CUSTOM_SECRET": "DAYTONA"}), ) if err != nil { log.Fatal(err) } fmt.Println(response.Result) ``` ```bash # Execute any shell command daytona exec my-sandbox -- ls -la # Setting a working directory and a timeout daytona exec my-sandbox --cwd workspace/src --timeout 5 -- sleep 3 # Passing environment variables (use shell syntax) daytona exec my-sandbox -- sh -c 'CUSTOM_SECRET=DAYTONA echo $CUSTOM_SECRET' ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/execute' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "command": "ls -la", "cwd": "workspace", "timeout": 5 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**exec (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processexec) > > [**executeCommand (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#executecommand) > > [**exec (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#exec) > > [**ExecuteCommand (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.ExecuteCommand) > > [**daytona exec (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-exec) > > [**execute command (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/execute) ## Session operations Daytona provides methods to manage background process sessions in sandboxes. You can create sessions, execute commands, monitor status, and manage long-running processes. ### Get session status Daytona provides methods to get session status and list all sessions in a sandbox by providing the session ID. ```python # Check session's executed commands session = sandbox.process.get_session(session_id) print(f"Session {session_id}:") for command in session.commands: print(f"Command: {command.command}, Exit Code: {command.exit_code}") # List all running sessions sessions = sandbox.process.list_sessions() for session in sessions: print(f"Session: {session.session_id}, Commands: {session.commands}") ``` ```typescript // Check session's executed commands const session = await sandbox.process.getSession(sessionId); console.log(`Session ${sessionId}:`); for (const command of session.commands) { console.log(`Command: ${command.command}, Exit Code: ${command.exitCode}`); } // List all running sessions const sessions = await sandbox.process.listSessions(); for (const session of sessions) { console.log(`Session: ${session.sessionId}, Commands: ${session.commands}`); } ``` ```ruby # Check session's executed commands session = sandbox.process.get_session(session_id) puts "Session #{session_id}:" session.commands.each do |command| puts "Command: #{command.command}, Exit Code: #{command.exit_code}" end # List all running sessions sessions = sandbox.process.list_sessions sessions.each do |session| puts "Session: #{session.session_id}, Commands: #{session.commands}" end ``` ```go // Check session's executed commands session, err := sandbox.Process.GetSession(ctx, sessionID) if err != nil { log.Fatal(err) } fmt.Printf("Session %s:\n", sessionID) commands := session["commands"].([]any) for _, cmd := range commands { cmdMap := cmd.(map[string]any) fmt.Printf("Command: %s, Exit Code: %v\n", cmdMap["command"], cmdMap["exitCode"]) } // List all running sessions sessions, err := sandbox.Process.ListSessions(ctx) if err != nil { log.Fatal(err) } for _, sess := range sessions { fmt.Printf("Session: %s, Commands: %v\n", sess["sessionId"], sess["commands"]) } ``` ```bash # Get session info curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}' # List all sessions curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**get_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processget_session) > > [**list_sessions (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processlist_sessions) > > [**getSession (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#getsession) > > [**listSessions (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#listsessions) > > [**get_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#get_session) > > [**list_sessions (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#list_sessions) > > [**GetSession (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.GetSession) > > [**ListSessions (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.ListSessions) > > [**get session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/GET/process/session/{sessionId}) > > [**list sessions (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/GET/process/session) ### Execute interactive commands Daytona provides methods to execute interactive commands in sessions. You can send input to running commands that expect user interaction, such as confirmations or interactive tools like database CLIs and package managers. ```python session_id = "interactive-session" sandbox.process.create_session(session_id) # Execute command that requires confirmation command = sandbox.process.execute_session_command( session_id, SessionExecuteRequest( command='pip uninstall requests', run_async=True, ), ) # Stream logs asynchronously logs_task = asyncio.create_task( sandbox.process.get_session_command_logs_async( session_id, command.cmd_id, lambda log: print(f"[STDOUT]: {log}"), lambda log: print(f"[STDERR]: {log}"), ) ) await asyncio.sleep(1) # Send input to the command sandbox.process.send_session_command_input(session_id, command.cmd_id, "y") # Wait for logs to complete await logs_task ``` ```typescript const sessionId = 'interactive-session' await sandbox.process.createSession(sessionId) // Execute command that requires confirmation const command = await sandbox.process.executeSessionCommand(sessionId, { command: 'pip uninstall requests', runAsync: true, }) // Stream logs asynchronously const logPromise = sandbox.process.getSessionCommandLogs( sessionId, command.cmdId!, (stdout) => console.log('[STDOUT]:', stdout), (stderr) => console.log('[STDERR]:', stderr), ) await new Promise((resolve) => setTimeout(resolve, 1000)) // Send input to the command await sandbox.process.sendSessionCommandInput(sessionId, command.cmdId!, 'y') // Wait for logs to complete await logPromise ``` ```ruby session_id = "interactive-session" sandbox.process.create_session(session_id) # Execute command that requires confirmation interactive_command = sandbox.process.execute_session_command( session_id: session_id, req: Daytona::SessionExecuteRequest.new( command: 'pip uninstall requests', run_async: true ) ) # Wait a moment for the command to start sleep 1 # Send input to the command sandbox.process.send_session_command_input( session_id: session_id, command_id: interactive_command.cmd_id, data: "y" ) # Get logs for the interactive command asynchronously sandbox.process.get_session_command_logs_async( session_id: session_id, command_id: interactive_command.cmd_id, on_stdout: ->(log) { puts "[STDOUT]: #{log}" }, on_stderr: ->(log) { puts "[STDERR]: #{log}" } ) ``` ```go sessionID := "interactive-session" err := sandbox.Process.CreateSession(ctx, sessionID) if err != nil { log.Fatal(err) } // Execute command that requires confirmation result, err := sandbox.Process.ExecuteSessionCommand(ctx, sessionID, "pip uninstall requests", true) if err != nil { log.Fatal(err) } cmdID := result["cmdId"].(string) // Stream logs asynchronously stdout := make(chan string) stderr := make(chan string) go func() { err := sandbox.Process.GetSessionCommandLogsStream(ctx, sessionID, cmdID, stdout, stderr) if err != nil { log.Println("Log stream error:", err) } }() time.Sleep(1 * time.Second) // Note: SendSessionCommandInput is not available in Go SDK // Use the API endpoint directly for sending input // Read logs for msg := range stdout { fmt.Printf("[STDOUT]: %s\n", msg) } ``` ```bash # Create session curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session' \ --request POST \ --header 'Content-Type: application/json' \ --data '{"sessionId": "interactive-session"}' # Execute session command curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}/exec' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "command": "pip uninstall requests", "runAsync": true }' # Send input to command curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}/command/{commandId}/input' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "data": "y" }' # Get command logs curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}/command/{commandId}/logs' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**create_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processcreate_session) > > [**execute_session_command (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processexecute_session_command) > > [**send_session_command_input (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processsend_session_command_input) > > [**get_session_command_logs_async (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processget_session_command_logs_async) > > [**createSession (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#createsession) > > [**executeSessionCommand (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#executesessioncommand) > > [**sendSessionCommandInput (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#sendsessioncommandinput) > > [**getSessionCommandLogs (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#getsessioncommandlogs) > > [**create_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#create_session) > > [**execute_session_command (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#execute_session_command) > > [**send_session_command_input (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#send_session_command_input) > > [**CreateSession (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.CreateSession) > > [**ExecuteSessionCommand (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.ExecuteSessionCommand) > > [**GetSessionCommandLogsStream (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.GetSessionCommandLogsStream) > > [**create session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/session) > > [**execute session command (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/session/{sessionId}/exec) ## Resource management Daytona provides methods to manage session resources. You should use sessions for long-running operations, clean up sessions after execution, and handle exceptions properly. ```python # Python - Clean up session session_id = "long-running-cmd" try: sandbox.process.create_session(session_id) session = sandbox.process.get_session(session_id) # Do work... finally: sandbox.process.delete_session(session.session_id) ``` ```typescript // TypeScript - Clean up session const sessionId = "long-running-cmd"; try { await sandbox.process.createSession(sessionId); const session = await sandbox.process.getSession(sessionId); // Do work... } finally { await sandbox.process.deleteSession(session.sessionId); } ``` ```ruby # Ruby - Clean up session session_id = 'long-running-cmd' begin sandbox.process.create_session(session_id) session = sandbox.process.get_session(session_id) # Do work... ensure sandbox.process.delete_session(session.session_id) end ``` ```go // Go - Clean up session sessionID := "long-running-cmd" err := sandbox.Process.CreateSession(ctx, sessionID) if err != nil { log.Fatal(err) } defer sandbox.Process.DeleteSession(ctx, sessionID) session, err := sandbox.Process.GetSession(ctx, sessionID) if err != nil { log.Fatal(err) } // Do work... ``` ```bash # Create session curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session' \ --request POST \ --header 'Content-Type: application/json' \ --data '{"sessionId": "long-running-cmd"}' # Delete session when done curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}' \ --request DELETE ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**create_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processcreate_session) > > [**delete_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processdelete_session) > > [**createSession (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#createsession) > > [**deleteSession (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#deletesession) > > [**create_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#create_session) > > [**delete_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#delete_session) > > [**CreateSession (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.CreateSession) > > [**DeleteSession (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.DeleteSession) > > [**create session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/session) > > [**delete session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/DELETE/process/session/{sessionId}) ## Error handling Daytona provides methods to handle errors when executing processes. You should handle process exceptions properly, log error details for debugging, and use try-catch blocks for error handling. ```python from daytona import DaytonaError try: response = sandbox.process.code_run("invalid python code") if response.exit_code != 0: print(f"Exit code: {response.exit_code}") print(f"Error output: {response.result}") except DaytonaError as e: print(f"Execution failed: {e}") ``` ```typescript import { DaytonaError } from '@daytonaio/sdk' try { const response = await sandbox.process.codeRun("invalid typescript code"); if (response.exitCode !== 0) { console.error("Exit code:", response.exitCode); console.error("Error output:", response.result); } } catch (e) { if (e instanceof DaytonaError) { console.error("Execution failed:", e); } } ``` ```ruby begin response = sandbox.process.code_run(code: 'invalid python code') if response.exit_code != 0 puts "Exit code: #{response.exit_code}" puts "Error output: #{response.result}" end rescue StandardError => e puts "Execution failed: #{e}" end ``` ```go result, err := sandbox.Process.ExecuteCommand(ctx, "python3 -c 'invalid python code'") if err != nil { fmt.Println("Execution failed:", err) } if result != nil && result.ExitCode != 0 { fmt.Println("Exit code:", result.ExitCode) fmt.Println("Error output:", result.Result) } ``` ```bash # API responses include exitCode field for error handling curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/execute' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "command": "python3 -c \"invalid python code\"" }' # Response includes: # { # "result": "", # "exitCode": 1 # } ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references. ## Common issues Daytona provides solutions for troubleshooting common issues related to process and code execution. | **Issue** | **Solutions** | | ------------------------ | --------------------------------------------------------------------------------------------------------------- | | Process execution failed | • Check command syntax
• Verify required dependencies
• Ensure sufficient permissions | | Process timeout | • Adjust timeout settings
• Optimize long-running operations
• Consider using background processes | | Resource limits | • Monitor process memory usage
• Handle process cleanup properly
• Use appropriate resource constraints | Daytona provides powerful pseudo terminal (PTY) capabilities through the `process` module in sandboxes. PTY sessions allow you to create interactive terminal sessions that can execute commands, handle user input, and manage terminal operations. A PTY (Pseudo Terminal) is a virtual terminal interface that allows programs to interact with a shell as if they were connected to a real terminal. PTY sessions in Daytona enable: - **Interactive Development**: REPLs, debuggers, and development tools - **Build Processes**: Running and monitoring compilation, testing, or deployment - **System Administration**: Remote server management and configuration - **User Interfaces**: Terminal-based applications requiring user interaction ## Create PTY session Daytona provides methods to create an interactive terminal session that can execute commands and handle user input. ```python from daytona.common.pty import PtySize pty_handle = sandbox.process.create_pty_session( id="my-session", cwd="/workspace", envs={"TERM": "xterm-256color"}, pty_size=PtySize(cols=120, rows=30) ) ``` ```typescript // Create a PTY session with custom configuration const ptyHandle = await sandbox.process.createPty({ id: 'my-interactive-session', cwd: '/workspace', envs: { TERM: 'xterm-256color', LANG: 'en_US.UTF-8' }, cols: 120, rows: 30, onData: (data) => { // Handle terminal output const text = new TextDecoder().decode(data) process.stdout.write(text) }, }) // Wait for connection to be established await ptyHandle.waitForConnection() // Send commands to the terminal await ptyHandle.sendInput('ls -la\n') await ptyHandle.sendInput('echo "Hello, PTY!"\n') await ptyHandle.sendInput('exit\n') // Wait for completion and get result const result = await ptyHandle.wait() console.log(`PTY session completed with exit code: ${result.exitCode}`) // Clean up await ptyHandle.disconnect() ``` ```ruby pty_size = Daytona::PtySize.new(rows: 30, cols: 120) pty_handle = sandbox.process.create_pty_session( id: 'my-interactive-session', cwd: '/workspace', envs: { 'TERM' => 'xterm-256color' }, pty_size: pty_size ) # Use the PTY session pty_handle.send_input("ls -la\n") pty_handle.send_input("echo 'Hello, PTY!'\n") pty_handle.send_input("exit\n") # Handle output pty_handle.each { |data| print data } puts "PTY session completed with exit code: #{pty_handle.exit_code}" ``` ```go // Create a PTY session with custom configuration handle, err := sandbox.Process.CreatePty(ctx, "my-interactive-session", options.WithCreatePtySize(types.PtySize{Cols: 120, Rows: 30}), options.WithCreatePtyEnv(map[string]string{"TERM": "xterm-256color"}), ) if err != nil { log.Fatal(err) } defer handle.Disconnect() // Wait for connection to be established if err := handle.WaitForConnection(ctx); err != nil { log.Fatal(err) } // Send commands to the terminal handle.SendInput([]byte("ls -la\n")) handle.SendInput([]byte("echo 'Hello, PTY!'\n")) handle.SendInput([]byte("exit\n")) // Read output from channel for data := range handle.DataChan() { fmt.Print(string(data)) } // Wait for completion and get result result, err := handle.Wait(ctx) if err != nil { log.Fatal(err) } fmt.Printf("PTY session completed with exit code: %d\n", *result.ExitCode) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/pty' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "cols": 1, "cwd": "", "envs": { "additionalProperty": "" }, "id": "", "lazyStart": true, "rows": 1 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/process.md#createpty), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/process.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references: > [**create_pty_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processcreate_pty_session) > > [**createPty (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#createpty) > > [**create_pty_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#create_pty_session) > > [**CreatePty (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.CreatePty) > > [**Create PTY session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/pty) ## Connect to PTY session Daytona provides methods to establish a connection to an existing PTY session, enabling interaction with a previously created terminal. ```python pty_handle = sandbox.process.connect_pty_session("my-session") ``` ```typescript // Connect to an existing PTY session const handle = await sandbox.process.connectPty('my-session', { onData: (data) => { // Handle terminal output const text = new TextDecoder().decode(data) process.stdout.write(text) }, }) // Wait for connection to be established await handle.waitForConnection() // Send commands to the existing session await handle.sendInput('pwd\n') await handle.sendInput('ls -la\n') await handle.sendInput('exit\n') // Wait for completion const result = await handle.wait() console.log(`Session exited with code: ${result.exitCode}`) // Clean up await handle.disconnect() ``` ```ruby # Connect to an existing PTY session pty_handle = sandbox.process.connect_pty_session('my-session') pty_handle.send_input("echo 'Hello World'\n") pty_handle.send_input("exit\n") # Handle output pty_handle.each { |data| print data } puts "Session exited with code: #{pty_handle.exit_code}" ``` ```go // Connect to an existing PTY session handle, err := sandbox.Process.ConnectPty(ctx, "my-session") if err != nil { log.Fatal(err) } defer handle.Disconnect() // Wait for connection to be established if err := handle.WaitForConnection(ctx); err != nil { log.Fatal(err) } // Send commands to the existing session handle.SendInput([]byte("pwd\n")) handle.SendInput([]byte("ls -la\n")) handle.SendInput([]byte("exit\n")) // Read output for data := range handle.DataChan() { fmt.Print(string(data)) } // Wait for completion result, err := handle.Wait(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Session exited with code: %d\n", *result.ExitCode) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/pty/{sessionId}/connect' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/process.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/process.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references: > [**connect_pty_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processconnect_pty_session) > > [**connectPty (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#connectpty) > > [**connect_pty_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#connect_pty_session) > > [**ConnectPty (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.ConnectPty) > > [**Connect to PTY session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/GET/process/pty/{sessionId}/connect) ## List PTY sessions Daytona provides methods to list PTY sessions, allowing you to retrieve information about all PTY sessions, both active and inactive, that have been created in the sandbox. ```python # List all PTY sessions sessions = sandbox.process.list_pty_sessions() for session in sessions: print(f"Session ID: {session.id}") print(f"Active: {session.active}") print(f"Created: {session.created_at}") ``` ```typescript // List all PTY sessions const sessions = await sandbox.process.listPtySessions() for (const session of sessions) { console.log(`Session ID: ${session.id}`) console.log(`Active: ${session.active}`) console.log(`Created: ${session.createdAt}`) console.log('---') } ``` ```ruby # List all PTY sessions sessions = sandbox.process.list_pty_sessions sessions.each do |session| puts "Session ID: #{session.id}" puts "Active: #{session.active}" puts "Terminal Size: #{session.cols}x#{session.rows}" puts '---' end ``` ```go // List all PTY sessions sessions, err := sandbox.Process.ListPtySessions(ctx) if err != nil { log.Fatal(err) } for _, session := range sessions { fmt.Printf("Session ID: %s\n", session.Id) fmt.Printf("Active: %t\n", session.Active) fmt.Printf("Terminal Size: %dx%d\n", session.Cols, session.Rows) fmt.Println("---") } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/pty' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/process.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/process.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references: > [**list_pty_sessions (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processlist_pty_sessions) > > [**listPtySessions (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#listptysessions) > > [**list_pty_sessions (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#list_pty_sessions) > > [**ListPtySessions (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.ListPtySessions) > > [**List PTY sessions (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/GET/process/pty) ## Get PTY session info Daytona provides methods to get information about a specific PTY session, allowing you to retrieve comprehensive information about a specific PTY session including its current state, configuration, and metadata. ```python # Get details about a specific PTY session session_info = sandbox.process.get_pty_session_info("my-session") print(f"Session ID: {session_info.id}") print(f"Active: {session_info.active}") print(f"Working Directory: {session_info.cwd}") print(f"Terminal Size: {session_info.cols}x{session_info.rows}") ``` ```typescript // Get details about a specific PTY session const session = await sandbox.process.getPtySessionInfo('my-session') console.log(`Session ID: ${session.id}`) console.log(`Active: ${session.active}`) console.log(`Working Directory: ${session.cwd}`) console.log(`Terminal Size: ${session.cols}x${session.rows}`) if (session.processId) { console.log(`Process ID: ${session.processId}`) } ``` ```ruby # Get details about a specific PTY session session_info = sandbox.process.get_pty_session_info('my-session') puts "Session ID: #{session_info.id}" puts "Active: #{session_info.active}" puts "Working Directory: #{session_info.cwd}" puts "Terminal Size: #{session_info.cols}x#{session_info.rows}" ``` ```go // Get details about a specific PTY session session, err := sandbox.Process.GetPtySessionInfo(ctx, "my-session") if err != nil { log.Fatal(err) } fmt.Printf("Session ID: %s\n", session.Id) fmt.Printf("Active: %t\n", session.Active) fmt.Printf("Working Directory: %s\n", session.Cwd) fmt.Printf("Terminal Size: %dx%d\n", session.Cols, session.Rows) if session.ProcessId != nil { fmt.Printf("Process ID: %d\n", *session.ProcessId) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/process.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/process.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references: > [**get_pty_session_info (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processget_pty_session_info) > > [**getPtySessionInfo (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#getptysessioninfo) > > [**get_pty_session_info (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#get_pty_session_info) > > [**GetPtySessionInfo (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.GetPtySessionInfo) > > [**Get PTY session info (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/GET/process/session/{sessionId}) ## Kill PTY session Daytona provides methods to kill a PTY session, allowing you to forcefully terminate a PTY session and cleans up all associated resources. ```python # Kill a specific PTY session sandbox.process.kill_pty_session("my-session") # Verify the session no longer exists pty_sessions = sandbox.process.list_pty_sessions() for pty_session in pty_sessions: print(f"PTY session: {pty_session.id}") ``` ```typescript // Kill a specific PTY session await sandbox.process.killPtySession('my-session') // Verify the session is no longer active try { const info = await sandbox.process.getPtySessionInfo('my-session') console.log(`Session still exists but active: ${info.active}`) } catch (error) { console.log('Session has been completely removed') } ``` ```ruby # Delete a specific PTY session sandbox.process.delete_pty_session('my-session') # Verify the session no longer exists sessions = sandbox.process.list_pty_sessions sessions.each do |session| puts "PTY session: #{session.id}" end ``` ```go // Kill a specific PTY session err := sandbox.Process.KillPtySession(ctx, "my-session") if err != nil { log.Fatal(err) } // Verify the session is no longer active sessions, err := sandbox.Process.ListPtySessions(ctx) if err != nil { log.Fatal(err) } for _, session := range sessions { fmt.Printf("PTY session: %s\n", session.Id) } ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/session/{sessionId}' \ --request DELETE ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/process.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/process.md#delete_pty_session), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references: > [**kill_pty_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processkill_pty_session) > > [**killPtySession (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#killptysession) > > [**delete_pty_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#delete_pty_session) > > [**KillPtySession (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.KillPtySession) > > [**Kill PTY session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/DELETE/process/session/{sessionId}) ## Resize PTY session Daytona provides methods to resize a PTY session, allowing you to change the terminal dimensions of an active PTY session. This sends a SIGWINCH signal to the shell process, allowing terminal applications to adapt to the new size. ```python from daytona.common.pty import PtySize # Resize a PTY session to a larger terminal new_size = PtySize(rows=40, cols=150) updated_info = sandbox.process.resize_pty_session("my-session", new_size) print(f"Terminal resized to {updated_info.cols}x{updated_info.rows}") # You can also use the PtyHandle's resize method pty_handle.resize(new_size) ``` ```typescript // Resize a PTY session to a larger terminal const updatedInfo = await sandbox.process.resizePtySession('my-session', 150, 40) console.log(`Terminal resized to ${updatedInfo.cols}x${updatedInfo.rows}`) // You can also use the PtyHandle's resize method await ptyHandle.resize(150, 40) // cols, rows ``` ```ruby # Resize a PTY session to a larger terminal pty_size = Daytona::PtySize.new(rows: 40, cols: 150) session_info = sandbox.process.resize_pty_session('my-session', pty_size) puts "Terminal resized to #{session_info.cols}x#{session_info.rows}" ``` ```go // Resize a PTY session to a larger terminal updatedInfo, err := sandbox.Process.ResizePtySession(ctx, "my-session", types.PtySize{ Cols: 150, Rows: 40, }) if err != nil { log.Fatal(err) } fmt.Printf("Terminal resized to %dx%d\n", updatedInfo.Cols, updatedInfo.Rows) // You can also use the PtyHandle's Resize method info, err := handle.Resize(ctx, 150, 40) if err != nil { log.Fatal(err) } fmt.Printf("Terminal resized to %dx%d\n", info.Cols, info.Rows) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/process/pty/{sessionId}/resize' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "cols": 1, "rows": 1 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/process.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/process.md#resizeptysession), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/process.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process) references: > [**resize_pty_session (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/process.md#processresize_pty_session) > > [**resizePtySession (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/process.md#resizeptysession) > > [**resize_pty_session (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/process.md#resize_pty_session) > > [**ResizePtySession (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ProcessService.ResizePtySession) > > [**Resize PTY session (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/process/POST/process/pty/{sessionId}/resize) ## Interactive commands Daytona provides methods to handle interactive commands with PTY sessions, allowing you to handle interactive commands that require user input and can be resized during execution. ```python import time from daytona import Daytona, Sandbox from daytona.common.pty import PtySize def handle_pty_data(data: bytes): text = data.decode("utf-8", errors="replace") print(text, end="") # Create PTY session pty_handle = sandbox.process.create_pty_session( id="interactive-session", pty_size=PtySize(cols=300, rows=100) ) # Send interactive command pty_handle.send_input('printf "Are you accepting the terms and conditions? (y/n): " && read confirm && if [ "$confirm" = "y" ]; then echo "You accepted"; else echo "You did not accept"; fi\n') time.sleep(1) pty_handle.send_input("y\n") # Resize terminal pty_session_info = pty_handle.resize(PtySize(cols=210, rows=110)) print(f"PTY session resized to {pty_session_info.cols}x{pty_session_info.rows}") # Exit the session pty_handle.send_input('exit\n') # Handle output using iterator for data in pty_handle: handle_pty_data(data) print(f"Session completed with exit code: {pty_handle.exit_code}") ``` ```typescript import { Daytona, Sandbox } from '@daytonaio/sdk' // Create PTY session const ptyHandle = await sandbox.process.createPty({ id: 'interactive-session', cols: 300, rows: 100, onData: data => { const text = new TextDecoder().decode(data) process.stdout.write(text) }, }) await ptyHandle.waitForConnection() // Send interactive command await ptyHandle.sendInput( 'printf "Are you accepting the terms and conditions? (y/n): " && read confirm && if [ "$confirm" = "y" ]; then echo "You accepted"; else echo "You did not accept"; fi\n' ) await new Promise(resolve => setTimeout(resolve, 1000)) await ptyHandle.sendInput('y\n') // Resize terminal const ptySessionInfo = await sandbox.process.resizePtySession( 'interactive-session', 210, 110 ) console.log( `\nPTY session resized to ${ptySessionInfo.cols}x${ptySessionInfo.rows}` ) // Exit the session await ptyHandle.sendInput('exit\n') // Wait for completion const result = await ptyHandle.wait() console.log(`Session completed with exit code: ${result.exitCode}`) ``` ```ruby require 'daytona' # Create PTY session pty_handle = sandbox.process.create_pty_session( id: 'interactive-session', pty_size: Daytona::PtySize.new(cols: 300, rows: 100) ) # Handle output in a separate thread thread = Thread.new do pty_handle.each { |data| print data } end # Send interactive command pty_handle.send_input('printf "Are you accepting the terms and conditions? (y/n): " && read confirm && if [ "$confirm" = "y" ]; then echo "You accepted"; else echo "You did not accept"; fi' + "\n") sleep(1) pty_handle.send_input("y\n") # Resize terminal pty_handle.resize(Daytona::PtySize.new(cols: 210, rows: 110)) puts "\nPTY session resized" # Exit the session pty_handle.send_input("exit\n") # Wait for the thread to finish thread.join puts "Session completed with exit code: #{pty_handle.exit_code}" ``` ```go // Create PTY session handle, err := sandbox.Process.CreatePty(ctx, "interactive-session", options.WithCreatePtySize(types.PtySize{Cols: 300, Rows: 100}), ) if err != nil { log.Fatal(err) } defer handle.Disconnect() if err := handle.WaitForConnection(ctx); err != nil { log.Fatal(err) } // Handle output in a goroutine go func() { for data := range handle.DataChan() { fmt.Print(string(data)) } }() // Send interactive command handle.SendInput([]byte(`printf "Are you accepting the terms and conditions? (y/n): " && read confirm && if [ "$confirm" = "y" ]; then echo "You accepted"; else echo "You did not accept"; fi` + "\n")) time.Sleep(1 * time.Second) handle.SendInput([]byte("y\n")) // Resize terminal info, err := handle.Resize(ctx, 210, 110) if err != nil { log.Fatal(err) } fmt.Printf("\nPTY session resized to %dx%d\n", info.Cols, info.Rows) // Exit the session handle.SendInput([]byte("exit\n")) // Wait for completion result, err := handle.Wait(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Session completed with exit code: %d\n", *result.ExitCode) ``` ## Long-running processes Daytona provides methods to manage long-running processes with PTY sessions, allowing you to manage long-running processes that need to be monitored or terminated. ```python import time import threading from daytona import Daytona, Sandbox from daytona.common.pty import PtySize def handle_pty_data(data: bytes): text = data.decode("utf-8", errors="replace") print(text, end="") # Create PTY session pty_handle = sandbox.process.create_pty_session( id="long-running-session", pty_size=PtySize(cols=120, rows=30) ) # Start a long-running process pty_handle.send_input('while true; do echo "Running... $(date)"; sleep 1; done\n') # Using thread and wait() method to handle PTY output thread = threading.Thread(target=pty_handle.wait, args=(handle_pty_data, 10)) thread.start() time.sleep(3) # Let it run for a bit print("Killing long-running process...") pty_handle.kill() thread.join() print(f"\nProcess terminated with exit code: {pty_handle.exit_code}") if pty_handle.error: print(f"Termination reason: {pty_handle.error}") ``` ```typescript import { Daytona, Sandbox } from '@daytonaio/sdk' // Create PTY session const ptyHandle = await sandbox.process.createPty({ id: 'long-running-session', cols: 120, rows: 30, onData: (data) => { const text = new TextDecoder().decode(data) process.stdout.write(text) }, }) await ptyHandle.waitForConnection() // Start a long-running process await ptyHandle.sendInput('while true; do echo "Running... $(date)"; sleep 1; done\n') await new Promise(resolve => setTimeout(resolve, 3000)) // Let it run for a bit console.log('Killing long-running process...') await ptyHandle.kill() // Wait for termination const result = await ptyHandle.wait() console.log(`\nProcess terminated with exit code: ${result.exitCode}`) if (result.error) { console.log(`Termination reason: ${result.error}`) } ``` ```ruby require 'daytona' # Create PTY session pty_handle = sandbox.process.create_pty_session( id: 'long-running-session', pty_size: Daytona::PtySize.new(cols: 120, rows: 30) ) # Handle output in a separate thread thread = Thread.new do pty_handle.each { |data| print data } end # Start a long-running process pty_handle.send_input("while true; do echo \"Running... $(date)\"; sleep 1; done\n") sleep(3) # Let it run for a bit puts "Killing long-running process..." pty_handle.kill thread.join puts "\nProcess terminated with exit code: #{pty_handle.exit_code}" puts "Termination reason: #{pty_handle.error}" if pty_handle.error ``` ```go // Create PTY session handle, err := sandbox.Process.CreatePty(ctx, "long-running-session", options.WithCreatePtySize(types.PtySize{Cols: 120, Rows: 30}), ) if err != nil { log.Fatal(err) } defer handle.Disconnect() if err := handle.WaitForConnection(ctx); err != nil { log.Fatal(err) } // Handle output in a goroutine go func() { for data := range handle.DataChan() { fmt.Print(string(data)) } }() // Start a long-running process handle.SendInput([]byte(`while true; do echo "Running... $(date)"; sleep 1; done` + "\n")) time.Sleep(3 * time.Second) // Let it run for a bit fmt.Println("Killing long-running process...") if err := handle.Kill(ctx); err != nil { log.Fatal(err) } // Wait for termination result, err := handle.Wait(ctx) if err != nil { log.Fatal(err) } fmt.Printf("\nProcess terminated with exit code: %d\n", *result.ExitCode) if result.Error != nil { fmt.Printf("Termination reason: %s\n", *result.Error) } ``` ## Resource management Daytona provides methods to manage resource leaks with PTY sessions, allowing you to always clean up PTY sessions to prevent resource leaks. ```python # Python: Use try/finally pty_handle = None try: pty_handle = sandbox.process.create_pty_session(id="session", pty_size=PtySize(cols=120, rows=30)) # Do work... finally: if pty_handle: pty_handle.kill() ``` ```typescript // TypeScript: Use try/finally let ptyHandle try { ptyHandle = await sandbox.process.createPty({ id: 'session', cols: 120, rows: 30, }) // Do work... } finally { if (ptyHandle) await ptyHandle.kill() } ``` ```ruby # Ruby: Use begin/ensure pty_handle = nil begin pty_handle = sandbox.process.create_pty_session( id: 'session', pty_size: Daytona::PtySize.new(cols: 120, rows: 30) ) # Do work... ensure pty_handle&.kill end ``` ```go // Go: Use defer for cleanup handle, err := sandbox.Process.CreatePty(ctx, "session", options.WithCreatePtySize(types.PtySize{Cols: 120, Rows: 30}), ) if err != nil { log.Fatal(err) } defer handle.Disconnect() // Do work... // Or use Kill to terminate the process defer handle.Kill(ctx) ``` ## PtyHandle methods Daytona provides methods to interact with PTY sessions, allowing you to send input, resize the terminal, wait for completion, and manage the WebSocket connection to a PTY session. ### Send input Daytona provides methods to send input to a PTY session, allowing you to send input data (keystrokes or commands) to the PTY session. ```python # Send a command pty_handle.send_input("ls -la\n") # Send user input pty_handle.send_input("y\n") ``` ```typescript // Send a command await ptyHandle.sendInput('ls -la\n') // Send raw bytes await ptyHandle.sendInput(new Uint8Array([3])) // Ctrl+C ``` ```ruby # Send a command pty_handle.send_input("ls -la\n") # Send user input pty_handle.send_input("y\n") ``` ```go // Send a command handle.SendInput([]byte("ls -la\n")) // Send Ctrl+C handle.SendInput([]byte{0x03}) ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**sendInput (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#sendinput) > > [**SendInput (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.SendInput) ### Wait for completion Daytona provides methods to wait for a PTY process to exit and return the result, allowing you to wait for a PTY process to exit and return the result. ```python # Wait with a callback for output data def handle_data(data: bytes): print(data.decode("utf-8", errors="replace"), end="") result = pty_handle.wait(on_data=handle_data, timeout=30) print(f"Exit code: {result.exit_code}") ``` ```typescript // Wait for process to complete const result = await ptyHandle.wait() if (result.exitCode === 0) { console.log('Process completed successfully') } else { console.log(`Process failed with code: ${result.exitCode}`) if (result.error) { console.log(`Error: ${result.error}`) } } ``` ```ruby # Wait by iterating over output (blocks until PTY session ends) pty_handle.each { |data| print data } if pty_handle.exit_code == 0 puts 'Process completed successfully' else puts "Process failed with code: #{pty_handle.exit_code}" puts "Error: #{pty_handle.error}" if pty_handle.error end ``` ```go // Wait for process to complete result, err := handle.Wait(ctx) if err != nil { log.Fatal(err) } if result.ExitCode != nil && *result.ExitCode == 0 { fmt.Println("Process completed successfully") } else { fmt.Printf("Process failed with code: %d\n", *result.ExitCode) if result.Error != nil { fmt.Printf("Error: %s\n", *result.Error) } } ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**wait (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#wait) > > [**Wait (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.Wait) ### Wait for connection Daytona provides methods to wait for the WebSocket connection to be established before sending input, allowing you to wait for the WebSocket connection to be established before sending input. ```python # Python handles connection internally during creation # No explicit wait needed ``` ```typescript // Wait for connection to be established await ptyHandle.waitForConnection() // Now safe to send input await ptyHandle.sendInput('echo "Connected!"\n') ``` ```ruby # Ruby handles connection internally during creation # No explicit wait needed - can send input immediately after creation pty_handle.send_input("echo 'Connected!'\n") ``` ```go // Wait for connection to be established if err := handle.WaitForConnection(ctx); err != nil { log.Fatal(err) } // Now safe to send input handle.SendInput([]byte("echo 'Connected!'\n")) ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**waitForConnection (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#waitforconnection) > > [**WaitForConnection (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.WaitForConnection) ### Kill PTY process Daytona provides methods to kill a PTY process and terminate the session from the handle. ```python pty_handle.kill() ``` ```typescript // Kill a long-running process await ptyHandle.kill() // Wait to confirm termination const result = await ptyHandle.wait() console.log(`Process terminated with exit code: ${result.exitCode}`) ``` ```ruby # Kill a long-running process pty_handle.kill puts "Process terminated with exit code: #{pty_handle.exit_code}" ``` ```go // Kill a long-running process if err := handle.Kill(ctx); err != nil { log.Fatal(err) } // Wait to confirm termination result, err := handle.Wait(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Process terminated with exit code: %d\n", *result.ExitCode) ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**kill (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#kill) > > [**Kill (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.Kill) ### Resize from handle Daytona provides methods to resize the PTY terminal dimensions directly from the handle. ```python from daytona.common.pty import PtySize pty_handle.resize(PtySize(cols=120, rows=30)) ``` ```typescript // Resize to 120x30 await ptyHandle.resize(120, 30) ``` ```ruby # Resize to 120x30 pty_handle.resize(Daytona::PtySize.new(cols: 120, rows: 30)) ``` ```go // Resize to 120x30 info, err := handle.Resize(ctx, 120, 30) if err != nil { log.Fatal(err) } fmt.Printf("Resized to %dx%d\n", info.Cols, info.Rows) ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**resize (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#resize) > > [**Resize (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.Resize) ### Disconnect Daytona provides methods to disconnect from a PTY session and clean up resources without killing the process. ```python # Python: Use kill() to terminate, or let the handle go out of scope ``` ```typescript // Always clean up when done try { // ... use PTY session } finally { await ptyHandle.disconnect() } ``` ```ruby # Ruby: Use begin/ensure or kill the session begin # ... use PTY session ensure pty_handle.kill end ``` ```go // Always clean up when done using defer handle, err := sandbox.Process.CreatePty(ctx, "session") if err != nil { log.Fatal(err) } defer handle.Disconnect() // ... use PTY session ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**disconnect (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#disconnect) > > [**Disconnect (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.Disconnect) ### Check connection status Daytona provides methods to check if a PTY session is still connected. ```python # Python: Check by attempting operations or using session info session_info = sandbox.process.get_pty_session_info("my-session") print(f"Session active: {session_info.active}") ``` ```typescript if (ptyHandle.isConnected()) { console.log('PTY session is active') } ``` ```ruby # Ruby: Check by using session info session_info = sandbox.process.get_pty_session_info('my-session') puts 'PTY session is active' if session_info.active ``` ```go if handle.IsConnected() { fmt.Println("PTY session is active") } ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**isConnected (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#isconnected) > > [**IsConnected (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.IsConnected) ### Exit code and error Daytona provides methods to access the exit code and error message after a PTY process terminates. ```python # After iteration or wait completes print(f"Exit code: {pty_handle.exit_code}") if pty_handle.error: print(f"Error: {pty_handle.error}") ``` ```typescript // Access via getters after process terminates console.log(`Exit code: ${ptyHandle.exitCode}`) if (ptyHandle.error) { console.log(`Error: ${ptyHandle.error}`) } ``` ```ruby # Access after process terminates puts "Exit code: #{pty_handle.exit_code}" puts "Error: #{pty_handle.error}" if pty_handle.error ``` ```go // Access via methods after process terminates if exitCode := handle.ExitCode(); exitCode != nil { fmt.Printf("Exit code: %d\n", *exitCode) } if errMsg := handle.Error(); errMsg != nil { fmt.Printf("Error: %s\n", *errMsg) } ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-processservice) references: > [**exitCode (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#exitcode) > > [**error (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/pty-handle.md#error) > > [**ExitCode (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.ExitCode) > > [**Error (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#PtyHandle.Error) ### Iterate over output (Python) Daytona provides methods to iterate over a PTY handle to receive output data. ```python # Iterate over PTY output for data in pty_handle: text = data.decode("utf-8", errors="replace") print(text, end="") print(f"Session ended with exit code: {pty_handle.exit_code}") ``` ```typescript // TypeScript uses the onData callback instead const ptyHandle = await sandbox.process.createPty({ id: 'my-session', onData: (data) => { const text = new TextDecoder().decode(data) process.stdout.write(text) }, }) ``` ```ruby # Iterate over PTY output pty_handle.each do |data| print data end puts "Session ended with exit code: #{pty_handle.exit_code}" ``` ```go // Go uses a channel to receive output data for data := range handle.DataChan() { fmt.Print(string(data)) } // Or use as io.Reader io.Copy(os.Stdout, handle) fmt.Printf("Session ended with exit code: %d\n", *handle.ExitCode()) ``` ## Error handling Daytona provides methods to monitor exit codes and handle errors appropriately with PTY sessions. ```python # Python: Check exit codes result = pty_handle.wait() if result.exit_code != 0: print(f"Command failed: {result.exit_code}") print(f"Error: {result.error}") ``` ```typescript // TypeScript: Check exit codes const result = await ptyHandle.wait() if (result.exitCode !== 0) { console.log(`Command failed: ${result.exitCode}`) console.log(`Error: ${result.error}`) } ``` ```ruby # Ruby: Check exit codes # The handle blocks until the PTY session completes pty_handle.each { |data| print data } if pty_handle.exit_code != 0 puts "Command failed: #{pty_handle.exit_code}" puts "Error: #{pty_handle.error}" end ``` ```go // Go: Check exit codes result, err := handle.Wait(ctx) if err != nil { log.Fatal(err) } if result.ExitCode != nil && *result.ExitCode != 0 { fmt.Printf("Command failed: %d\n", *result.ExitCode) if result.Error != nil { fmt.Printf("Error: %s\n", *result.Error) } } ``` ## Troubleshooting - **Connection issues**: verify sandbox status, network connectivity, and proper session IDs - **Performance issues**: use appropriate terminal dimensions and efficient data handlers - **Process management**: use explicit `kill()` calls and proper timeout handling for long-running processes ## AsyncCodeInterpreter ```python class AsyncCodeInterpreter() ``` Handles code interpretation and execution within a Sandbox. Currently supports only Python. This class provides methods to execute code in isolated interpreter contexts, manage contexts, and stream execution output via callbacks. If subsequent code executions are performed in the same context, the variables, imports, and functions defined in the previous execution will be available. For other languages, use the `code_run` method from the `AsyncProcess` interface, or execute the appropriate command directly in the sandbox terminal. #### AsyncCodeInterpreter.\_\_init\_\_ ```python def __init__(api_client: InterpreterApi) ``` Initialize a new AsyncCodeInterpreter instance. **Arguments**: - `api_client` - API client for interpreter operations. #### AsyncCodeInterpreter.run\_code ```python @intercept_errors(message_prefix="Failed to run code: ") async def run_code(code: str, *, context: InterpreterContext | None = None, on_stdout: OutputHandler[OutputMessage] | None = None, on_stderr: OutputHandler[OutputMessage] | None = None, on_error: OutputHandler[ExecutionError] | None = None, envs: dict[str, str] | None = None, timeout: int | None = None) -> ExecutionResult ``` Execute Python code in the sandbox. By default, code runs in the default shared context which persists variables, imports, and functions across executions. To run in an isolated context, create a new context with `create_context()` and pass it as `context` argument. **Arguments**: - `code` _str_ - Code to execute. - `context` _InterpreterContext | None_ - Context to run code in. If not provided, uses default context. - `on_stdout` _OutputHandler[OutputMessage] | None_ - Callback for stdout messages. - `on_stderr` _OutputHandler[OutputMessage] | None_ - Callback for stderr messages. - `on_error` _OutputHandler[ExecutionError] | None_ - Callback for execution errors (e.g., syntax errors, runtime errors). - `envs` _dict[str, str] | None_ - Environment variables for this execution. - `timeout` _int | None_ - Timeout in seconds. 0 means no timeout. Default is 10 minutes. **Returns**: - `ExecutionResult` - Result object containing stdout, stderr and error if any. **Raises**: - `DaytonaTimeoutError` - If execution times out. - `DaytonaError` - If execution fails due to communication or other SDK errors. **Examples**: ```python def handle_stdout(msg: OutputMessage): print(f"STDOUT: {msg.output}", end="") def handle_stderr(msg: OutputMessage): print(f"STDERR: {msg.output}", end="") def handle_error(err: ExecutionError): print(f"ERROR: {err.name}: {err.value}") code = ''' import sys import time for i in range(5): print(i) time.sleep(1) sys.stderr.write("Counting done!") ''' result = await sandbox.code_interpreter.run_code( code=code, on_stdout=handle_stdout, on_stderr=handle_stderr, on_error=handle_error, timeout=10 ) ``` #### AsyncCodeInterpreter.create\_context ```python @intercept_errors(message_prefix="Failed to create interpreter context: ") async def create_context(cwd: str | None = None) -> InterpreterContext ``` Create a new isolated interpreter context. Contexts provide isolated execution environments with their own global namespace. Variables, imports, and functions defined in one context don't affect others. **Arguments**: - `cwd` _str | None_ - Working directory for the context. If not specified, uses sandbox working directory. **Returns**: - `InterpreterContext` - The created context with its ID and metadata. **Raises**: - `DaytonaError` - If context creation fails. **Examples**: ```python # Create isolated context ctx = await sandbox.code_interpreter.create_context() # Execute code in this context await sandbox.code_interpreter.run_code("x = 100", context=ctx) # Variable only exists in this context result = await sandbox.code_interpreter.run_code("print(x)", context=ctx) # OK # Won't see the variable in default context result = await sandbox.code_interpreter.run_code("print(x)") # NameError # Clean up await sandbox.code_interpreter.delete_context(ctx) ``` #### AsyncCodeInterpreter.list\_contexts ```python @intercept_errors(message_prefix="Failed to list interpreter contexts: ") async def list_contexts() -> list[InterpreterContext] ``` List all user-created interpreter contexts. The default context is not included in this list. Only contexts created via `create_context()` are returned. **Returns**: - `list[InterpreterContext]` - List of context objects. **Raises**: - `DaytonaError` - If listing fails. **Examples**: ```python contexts = await sandbox.code_interpreter.list_contexts() for ctx in contexts: print(f"Context {ctx.id}: {ctx.language} at {ctx.cwd}") ``` #### AsyncCodeInterpreter.delete\_context ```python @intercept_errors(message_prefix="Failed to delete interpreter context: ") async def delete_context(context: InterpreterContext) -> None ``` Delete an interpreter context and shut down all associated processes. This permanently removes the context and all its state (variables, imports, etc.). The default context cannot be deleted. **Arguments**: - `context` _InterpreterContext_ - Context to delete. **Raises**: - `DaytonaError` - If deletion fails or context not found. **Examples**: ```python ctx = await sandbox.code_interpreter.create_context() # ... use context ... await sandbox.code_interpreter.delete_context(ctx) ``` ## OutputMessage ```python class OutputMessage(BaseModel) ``` Represents stdout or stderr output from code execution. **Attributes**: - `output` - The output content. ## ExecutionError ```python class ExecutionError(BaseModel) ``` Represents an error that occurred during code execution. **Attributes**: - `name` - The error type/class name (e.g., "ValueError", "SyntaxError"). - `value` - The error value. - `traceback` - Full traceback of the error. ## ExecutionResult ```python class ExecutionResult(BaseModel) ``` Result of code execution. **Attributes**: - `stdout` - Standard output from the code execution. - `stderr` - Standard error output from the code execution. - `error` - Error details if execution failed, None otherwise. ## AsyncComputerUse ```python class AsyncComputerUse() ``` Computer Use functionality for interacting with the desktop environment. Provides access to mouse, keyboard, screenshot, display, and recording operations for automating desktop interactions within a sandbox. **Attributes**: - `mouse` _AsyncMouse_ - Mouse operations interface. - `keyboard` _AsyncKeyboard_ - Keyboard operations interface. - `screenshot` _AsyncScreenshot_ - Screenshot operations interface. - `display` _AsyncDisplay_ - Display operations interface. - `recording` _AsyncRecordingService_ - Screen recording operations interface. #### AsyncComputerUse.start ```python @intercept_errors(message_prefix="Failed to start computer use: ") @with_instrumentation() async def start() -> ComputerUseStartResponse ``` Starts all computer use processes (Xvfb, xfce4, x11vnc, novnc). **Returns**: - `ComputerUseStartResponse` - Computer use start response. **Example**: ```python result = await sandbox.computer_use.start() print("Computer use processes started:", result.message) ``` #### AsyncComputerUse.stop ```python @intercept_errors(message_prefix="Failed to stop computer use: ") @with_instrumentation() async def stop() -> ComputerUseStopResponse ``` Stops all computer use processes. **Returns**: - `ComputerUseStopResponse` - Computer use stop response. **Example**: ```python result = await sandbox.computer_use.stop() print("Computer use processes stopped:", result.message) ``` #### AsyncComputerUse.get\_status ```python @intercept_errors(message_prefix="Failed to get computer use status: ") @with_instrumentation() async def get_status() -> ComputerUseStatusResponse ``` Gets the status of all computer use processes. **Returns**: - `ComputerUseStatusResponse` - Status information about all VNC desktop processes. **Example**: ```python response = await sandbox.computer_use.get_status() print("Computer use status:", response.status) ``` #### AsyncComputerUse.get\_process\_status ```python @intercept_errors(message_prefix="Failed to get process status: ") @with_instrumentation() async def get_process_status(process_name: str) -> ProcessStatusResponse ``` Gets the status of a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to check. **Returns**: - `ProcessStatusResponse` - Status information about the specific process. **Example**: ```python xvfb_status = await sandbox.computer_use.get_process_status("xvfb") no_vnc_status = await sandbox.computer_use.get_process_status("novnc") ``` #### AsyncComputerUse.restart\_process ```python @intercept_errors(message_prefix="Failed to restart process: ") @with_instrumentation() async def restart_process(process_name: str) -> ProcessRestartResponse ``` Restarts a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to restart. **Returns**: - `ProcessRestartResponse` - Process restart response. **Example**: ```python result = await sandbox.computer_use.restart_process("xfce4") print("XFCE4 process restarted:", result.message) ``` #### AsyncComputerUse.get\_process\_logs ```python @intercept_errors(message_prefix="Failed to get process logs: ") @with_instrumentation() async def get_process_logs(process_name: str) -> ProcessLogsResponse ``` Gets logs for a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to get logs for. **Returns**: - `ProcessLogsResponse` - Process logs. **Example**: ```python logs = await sandbox.computer_use.get_process_logs("novnc") print("NoVNC logs:", logs) ``` #### AsyncComputerUse.get\_process\_errors ```python @intercept_errors(message_prefix="Failed to get process errors: ") @with_instrumentation() async def get_process_errors(process_name: str) -> ProcessErrorsResponse ``` Gets error logs for a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to get error logs for. **Returns**: - `ProcessErrorsResponse` - Process error logs. **Example**: ```python errors = await sandbox.computer_use.get_process_errors("x11vnc") print("X11VNC errors:", errors) ``` ## AsyncMouse ```python class AsyncMouse() ``` Mouse operations for computer use functionality. #### AsyncMouse.get\_position ```python @intercept_errors(message_prefix="Failed to get mouse position: ") @with_instrumentation() async def get_position() -> MousePositionResponse ``` Gets the current mouse cursor position. **Returns**: - `MousePositionResponse` - Current mouse position with x and y coordinates. **Example**: ```python position = await sandbox.computer_use.mouse.get_position() print(f"Mouse is at: {position.x}, {position.y}") ``` #### AsyncMouse.move ```python @intercept_errors(message_prefix="Failed to move mouse: ") @with_instrumentation() async def move(x: int, y: int) -> MousePositionResponse ``` Moves the mouse cursor to the specified coordinates. **Arguments**: - `x` _int_ - The x coordinate to move to. - `y` _int_ - The y coordinate to move to. **Returns**: - `MousePositionResponse` - Position after move. **Example**: ```python result = await sandbox.computer_use.mouse.move(100, 200) print(f"Mouse moved to: {result.x}, {result.y}") ``` #### AsyncMouse.click ```python @intercept_errors(message_prefix="Failed to click mouse: ") @with_instrumentation() async def click(x: int, y: int, button: str = "left", double: bool = False) -> MouseClickResponse ``` Clicks the mouse at the specified coordinates. **Arguments**: - `x` _int_ - The x coordinate to click at. - `y` _int_ - The y coordinate to click at. - `button` _str_ - The mouse button to click ('left', 'right', 'middle'). - `double` _bool_ - Whether to perform a double-click. **Returns**: - `MouseClickResponse` - Click operation result. **Example**: ```python # Single left click result = await sandbox.computer_use.mouse.click(100, 200) # Double click double_click = await sandbox.computer_use.mouse.click(100, 200, "left", True) # Right click right_click = await sandbox.computer_use.mouse.click(100, 200, "right") ``` #### AsyncMouse.drag ```python @intercept_errors(message_prefix="Failed to drag mouse: ") @with_instrumentation() async def drag(start_x: int, start_y: int, end_x: int, end_y: int, button: str = "left") -> MouseDragResponse ``` Drags the mouse from start coordinates to end coordinates. **Arguments**: - `start_x` _int_ - The starting x coordinate. - `start_y` _int_ - The starting y coordinate. - `end_x` _int_ - The ending x coordinate. - `end_y` _int_ - The ending y coordinate. - `button` _str_ - The mouse button to use for dragging. **Returns**: - `MouseDragResponse` - Drag operation result. **Example**: ```python result = await sandbox.computer_use.mouse.drag(50, 50, 150, 150) print(f"Dragged from {result.from_x},{result.from_y} to {result.to_x},{result.to_y}") ``` #### AsyncMouse.scroll ```python @intercept_errors(message_prefix="Failed to scroll mouse: ") @with_instrumentation() async def scroll(x: int, y: int, direction: str, amount: int = 1) -> bool ``` Scrolls the mouse wheel at the specified coordinates. **Arguments**: - `x` _int_ - The x coordinate to scroll at. - `y` _int_ - The y coordinate to scroll at. - `direction` _str_ - The direction to scroll ('up' or 'down'). - `amount` _int_ - The amount to scroll. **Returns**: - `bool` - Whether the scroll operation was successful. **Example**: ```python # Scroll up scroll_up = await sandbox.computer_use.mouse.scroll(100, 200, "up", 3) # Scroll down scroll_down = await sandbox.computer_use.mouse.scroll(100, 200, "down", 5) ``` ## AsyncKeyboard ```python class AsyncKeyboard() ``` Keyboard operations for computer use functionality. #### AsyncKeyboard.type ```python @intercept_errors(message_prefix="Failed to type text: ") @with_instrumentation() async def type(text: str, delay: int | None = None) -> None ``` Types the specified text. **Arguments**: - `text` _str_ - The text to type. - `delay` _int_ - Delay between characters in milliseconds. **Raises**: - `DaytonaError` - If the type operation fails. **Example**: ```python try: await sandbox.computer_use.keyboard.type("Hello, World!") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # With delay between characters try: await sandbox.computer_use.keyboard.type("Slow typing", 100) print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") ``` #### AsyncKeyboard.press ```python @intercept_errors(message_prefix="Failed to press key: ") @with_instrumentation() async def press(key: str, modifiers: list[str] | None = None) -> None ``` Presses a key with optional modifiers. **Arguments**: - `key` _str_ - The key to press (e.g., 'Enter', 'Escape', 'Tab', 'a', 'A'). - `modifiers` _list[str]_ - Modifier keys ('ctrl', 'alt', 'meta', 'shift'). **Raises**: - `DaytonaError` - If the press operation fails. **Example**: ```python # Press Enter try: await sandbox.computer_use.keyboard.press("Return") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # Press Ctrl+C try: await sandbox.computer_use.keyboard.press("c", ["ctrl"]) print(f"Operation success") # Press Ctrl+Shift+T try: await sandbox.computer_use.keyboard.press("t", ["ctrl", "shift"]) print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") ``` #### AsyncKeyboard.hotkey ```python @intercept_errors(message_prefix="Failed to press hotkey: ") @with_instrumentation() async def hotkey(keys: str) -> None ``` Presses a hotkey combination. **Arguments**: - `keys` _str_ - The hotkey combination (e.g., 'ctrl+c', 'alt+tab', 'cmd+shift+t'). **Raises**: - `DaytonaError` - If the hotkey operation fails. **Example**: ```python # Copy try: await sandbox.computer_use.keyboard.hotkey("ctrl+c") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # Paste try: await sandbox.computer_use.keyboard.hotkey("ctrl+v") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # Alt+Tab try: await sandbox.computer_use.keyboard.hotkey("alt+tab") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") ``` ## AsyncScreenshot ```python class AsyncScreenshot() ``` Screenshot operations for computer use functionality. #### AsyncScreenshot.take\_full\_screen ```python @intercept_errors(message_prefix="Failed to take screenshot: ") @with_instrumentation() async def take_full_screen(show_cursor: bool = False) -> ScreenshotResponse ``` Takes a screenshot of the entire screen. **Arguments**: - `show_cursor` _bool_ - Whether to show the cursor in the screenshot. **Returns**: - `ScreenshotResponse` - Screenshot data with base64 encoded image. **Example**: ```python screenshot = await sandbox.computer_use.screenshot.take_full_screen() print(f"Screenshot size: {screenshot.width}x{screenshot.height}") # With cursor visible with_cursor = await sandbox.computer_use.screenshot.take_full_screen(True) ``` #### AsyncScreenshot.take\_region ```python @intercept_errors(message_prefix="Failed to take region screenshot: ") @with_instrumentation() async def take_region(region: ScreenshotRegion, show_cursor: bool = False) -> ScreenshotResponse ``` Takes a screenshot of a specific region. **Arguments**: - `region` _ScreenshotRegion_ - The region to capture. - `show_cursor` _bool_ - Whether to show the cursor in the screenshot. **Returns**: - `ScreenshotResponse` - Screenshot data with base64 encoded image. **Example**: ```python region = ScreenshotRegion(x=100, y=100, width=300, height=200) screenshot = await sandbox.computer_use.screenshot.take_region(region) print(f"Captured region: {screenshot.region.width}x{screenshot.region.height}") ``` #### AsyncScreenshot.take\_compressed ```python @intercept_errors(message_prefix="Failed to take compressed screenshot: ") @with_instrumentation() async def take_compressed( options: ScreenshotOptions | None = None) -> ScreenshotResponse ``` Takes a compressed screenshot of the entire screen. **Arguments**: - `options` _ScreenshotOptions | None_ - Compression and display options. **Returns**: - `ScreenshotResponse` - Compressed screenshot data. **Example**: ```python # Default compression screenshot = await sandbox.computer_use.screenshot.take_compressed() # High quality JPEG jpeg = await sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="jpeg", quality=95, show_cursor=True) ) # Scaled down PNG scaled = await sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="png", scale=0.5) ) ``` #### AsyncScreenshot.take\_compressed\_region ```python @intercept_errors( message_prefix="Failed to take compressed region screenshot: ") @with_instrumentation() async def take_compressed_region( region: ScreenshotRegion, options: ScreenshotOptions | None = None) -> ScreenshotResponse ``` Takes a compressed screenshot of a specific region. **Arguments**: - `region` _ScreenshotRegion_ - The region to capture. - `options` _ScreenshotOptions | None_ - Compression and display options. **Returns**: - `ScreenshotResponse` - Compressed screenshot data. **Example**: ```python region = ScreenshotRegion(x=0, y=0, width=800, height=600) screenshot = await sandbox.computer_use.screenshot.take_compressed_region( region, ScreenshotOptions(format="webp", quality=80, show_cursor=True) ) print(f"Compressed size: {screenshot.size_bytes} bytes") ``` ## AsyncDisplay ```python class AsyncDisplay() ``` Display operations for computer use functionality. #### AsyncDisplay.get\_info ```python @intercept_errors(message_prefix="Failed to get display info: ") @with_instrumentation() async def get_info() -> DisplayInfoResponse ``` Gets information about the displays. **Returns**: - `DisplayInfoResponse` - Display information including primary display and all available displays. **Example**: ```python info = await sandbox.computer_use.display.get_info() print(f"Primary display: {info.primary_display.width}x{info.primary_display.height}") print(f"Total displays: {info.total_displays}") for i, display in enumerate(info.displays): print(f"Display {i}: {display.width}x{display.height} at {display.x},{display.y}") ``` #### AsyncDisplay.get\_windows ```python @intercept_errors(message_prefix="Failed to get windows: ") @with_instrumentation() async def get_windows() -> WindowsResponse ``` Gets the list of open windows. **Returns**: - `WindowsResponse` - List of open windows with their IDs and titles. **Example**: ```python windows = await sandbox.computer_use.display.get_windows() print(f"Found {windows.count} open windows:") for window in windows.windows: print(f"- {window.title} (ID: {window.id})") ``` ## AsyncRecordingService ```python class AsyncRecordingService() ``` Recording operations for computer use functionality. #### AsyncRecordingService.start ```python @intercept_errors(message_prefix="Failed to start recording: ") @with_instrumentation() async def start(label: str | None = None) -> Recording ``` Starts a new screen recording session. **Arguments**: - `label` _str | None_ - Optional custom label for the recording. **Returns**: - `Recording` - Recording start response. **Example**: ```python # Start a recording with a label recording = await sandbox.computer_use.recording.start("my-test-recording") print(f"Recording started: {recording.id}") print(f"File: {recording.file_path}") ``` #### AsyncRecordingService.stop ```python @intercept_errors(message_prefix="Failed to stop recording: ") @with_instrumentation() async def stop(recording_id: str) -> Recording ``` Stops an active screen recording session. **Arguments**: - `recording_id` _str_ - The ID of the recording to stop. **Returns**: - `Recording` - Recording stop response. **Example**: ```python result = await sandbox.computer_use.recording.stop(recording.id) print(f"Recording stopped: {result.duration_seconds} seconds") print(f"Saved to: {result.file_path}") ``` #### AsyncRecordingService.list ```python @intercept_errors(message_prefix="Failed to list recordings: ") @with_instrumentation() async def list() -> ListRecordingsResponse ``` Lists all recordings (active and completed). **Returns**: - `ListRecordingsResponse` - List of all recordings. **Example**: ```python recordings = await sandbox.computer_use.recording.list() print(f"Found {len(recordings.recordings)} recordings") for rec in recordings.recordings: print(f"- {rec.file_name}: {rec.status}") ``` #### AsyncRecordingService.get ```python @intercept_errors(message_prefix="Failed to get recording: ") @with_instrumentation() async def get(recording_id: str) -> Recording ``` Gets details of a specific recording by ID. **Arguments**: - `recording_id` _str_ - The ID of the recording to retrieve. **Returns**: - `Recording` - Recording details. **Example**: ```python recording = await sandbox.computer_use.recording.get(recording_id) print(f"Recording: {recording.file_name}") print(f"Status: {recording.status}") print(f"Duration: {recording.duration_seconds} seconds") ``` #### AsyncRecordingService.delete ```python @intercept_errors(message_prefix="Failed to delete recording: ") @with_instrumentation() async def delete(recording_id: str) -> None ``` Deletes a recording by ID. **Arguments**: - `recording_id` _str_ - The ID of the recording to delete. **Example**: ```python await sandbox.computer_use.recording.delete(recording_id) print("Recording deleted") ``` #### AsyncRecordingService.download ```python @intercept_errors(message_prefix="Failed to download recording: ") @with_instrumentation() async def download(recording_id: str, local_path: str) -> None ``` Downloads a recording file from the Sandbox and saves it to a local file. The file is streamed directly to disk without loading the entire content into memory. **Arguments**: - `recording_id` _str_ - The ID of the recording to download. - `local_path` _str_ - Path to save the recording file locally. **Example**: ```python # Download recording to file await sandbox.computer_use.recording.download(recording_id, "local_recording.mp4") print("Recording downloaded") ``` ## ScreenshotRegion ```python class ScreenshotRegion(BaseModel) ``` Region coordinates for screenshot operations. **Attributes**: - `x` _int_ - X coordinate of the region. - `y` _int_ - Y coordinate of the region. - `width` _int_ - Width of the region. - `height` _int_ - Height of the region. ## ScreenshotOptions ```python class ScreenshotOptions(BaseModel) ``` Options for screenshot compression and display. **Attributes**: - `show_cursor` _bool | None_ - Whether to show the cursor in the screenshot. - `fmt` _str | None_ - Image format (e.g., 'png', 'jpeg', 'webp'). - `quality` _int | None_ - Compression quality (0-100). - `scale` _float | None_ - Scale factor for the screenshot. ## AsyncDaytona ```python class AsyncDaytona() ``` Main class for interacting with the Daytona API. This class provides asynchronous methods to create, manage, and interact with Daytona Sandboxes. It can be initialized either with explicit configuration or using environment variables. **Attributes**: - `volume` _AsyncVolumeService_ - Service for managing volumes. - `snapshot` _AsyncSnapshotService_ - Service for managing snapshots. **Example**: Using environment variables: ```python async with AsyncDaytona() as daytona: # Uses DAYTONA_API_KEY, DAYTONA_API_URL sandbox = await daytona.create() ``` Using explicit configuration: ```python config = DaytonaConfig( api_key="your-api-key", api_url="https://your-api.com", target="us" ) try: daytona = AsyncDaytona(config) sandbox = await daytona.create() finally: await daytona.close() ``` Using OpenTelemetry tracing: ```python config = DaytonaConfig( api_key="your-api-key", experimental={"otelEnabled": True} ) async with AsyncDaytona(config) as daytona: sandbox = await daytona.create() # All SDK operations will be traced # OpenTelemetry traces are flushed on close ``` #### AsyncDaytona.\_\_init\_\_ ```python def __init__(config: DaytonaConfig | None = None) ``` Initializes Daytona instance with optional configuration. If no config is provided, reads from environment variables: - `DAYTONA_API_KEY`: Required API key for authentication - `DAYTONA_API_URL`: Required api URL - `DAYTONA_TARGET`: Optional target environment (if not provided, default region for the organization is used) **Arguments**: - `config` _DaytonaConfig | None_ - Object containing api_key, api_url, and target. **Raises**: - `DaytonaError` - If API key is not provided either through config or environment variables **Example**: ```python from daytona import Daytona, DaytonaConfig # Using environment variables daytona1 = AsyncDaytona() await daytona1.close() # Using explicit configuration config = DaytonaConfig( api_key="your-api-key", api_url="https://your-api.com", target="us" ) daytona2 = AsyncDaytona(config) await daytona2.close() ``` #### AsyncDaytona.\_\_aenter\_\_ ```python async def __aenter__() ``` Async context manager entry. #### AsyncDaytona.\_\_aexit\_\_ ```python async def __aexit__(exc_type: type[BaseException] | None = None, exc_value: BaseException | None = None, traceback: TracebackType | None = None) ``` Async context manager exit - ensures proper cleanup. #### AsyncDaytona.close ```python async def close() ``` Close the HTTP session and clean up resources. This method should be called when you're done using the AsyncDaytona instance to properly close the underlying HTTP sessions and avoid resource leaks. **Example**: ```python daytona = AsyncDaytona() try: sandbox = await daytona.create() # ... use sandbox ... finally: await daytona.close() ``` Or better yet, use as async context manager: ```python async with AsyncDaytona() as daytona: sandbox = await daytona.create() # ... use sandbox ... # Automatically closed ``` #### AsyncDaytona.create ```python @overload async def create(params: CreateSandboxFromSnapshotParams | None = None, *, timeout: float = 60) -> AsyncSandbox ``` Creates Sandboxes from specified or default snapshot. You can specify various parameters, including language, image, environment variables, and volumes. **Arguments**: - `params` _CreateSandboxFromSnapshotParams | None_ - Parameters for Sandbox creation. If not provided, defaults to default Daytona snapshot and Python language. - `timeout` _float_ - Timeout (in seconds) for sandbox creation. 0 means no timeout. Default is 60 seconds. **Returns**: - `Sandbox` - The created Sandbox instance. **Raises**: - `DaytonaError` - If timeout, auto_stop_interval or auto_archive_interval is negative; If sandbox fails to start or times out **Example**: Create a default Python Sandbox: ```python sandbox = await daytona.create() ``` Create a custom Sandbox: ```python params = CreateSandboxFromSnapshotParams( language="python", snapshot="my-snapshot-id", env_vars={"DEBUG": "true"}, auto_stop_interval=0, auto_archive_interval=60, auto_delete_interval=120 ) sandbox = await daytona.create(params, timeout=40) ``` #### AsyncDaytona.create ```python @overload async def create( params: CreateSandboxFromImageParams | None = None, *, timeout: float = 60, on_snapshot_create_logs: Callable[[str], None] | None = None ) -> AsyncSandbox ``` Creates Sandboxes from specified image available on some registry or declarative Daytona Image. You can specify various parameters, including resources, language, image, environment variables, and volumes. Daytona creates snapshot from provided image and uses it to create Sandbox. **Arguments**: - `params` _CreateSandboxFromImageParams | None_ - Parameters for Sandbox creation from image. - `timeout` _float_ - Timeout (in seconds) for sandbox creation. 0 means no timeout. Default is 60 seconds. - `on_snapshot_create_logs` _Callable[[str], None] | None_ - This callback function handles snapshot creation logs. **Returns**: - `Sandbox` - The created Sandbox instance. **Raises**: - `DaytonaError` - If timeout, auto_stop_interval or auto_archive_interval is negative; If sandbox fails to start or times out **Example**: Create a default Python Sandbox from image: ```python sandbox = await daytona.create(CreateSandboxFromImageParams(image="debian:12.9")) ``` Create a custom Sandbox from declarative Image definition: ```python declarative_image = ( Image.base("alpine:3.18") .pipInstall(["numpy", "pandas"]) .env({"MY_ENV_VAR": "My Environment Variable"}) ) params = CreateSandboxFromImageParams( language="python", image=declarative_image, env_vars={"DEBUG": "true"}, resources=Resources(cpu=2, memory=4), auto_stop_interval=0, auto_archive_interval=60, auto_delete_interval=120 ) sandbox = await daytona.create( params, timeout=40, on_snapshot_create_logs=lambda chunk: print(chunk, end=""), ) ``` #### AsyncDaytona.delete ```python @with_instrumentation() async def delete(sandbox: AsyncSandbox, timeout: float = 60) -> None ``` Deletes a Sandbox. **Arguments**: - `sandbox` _Sandbox_ - The Sandbox instance to delete. - `timeout` _float_ - Timeout (in seconds) for sandbox deletion. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If sandbox fails to delete or times out **Example**: ```python sandbox = await daytona.create() # ... use sandbox ... await daytona.delete(sandbox) # Clean up when done ``` #### AsyncDaytona.get ```python @intercept_errors(message_prefix="Failed to get sandbox: ") @with_instrumentation() async def get(sandbox_id_or_name: str) -> AsyncSandbox ``` Gets a Sandbox by its ID or name. **Arguments**: - `sandbox_id_or_name` _str_ - The ID or name of the Sandbox to retrieve. **Returns**: - `Sandbox` - The Sandbox instance. **Raises**: - `DaytonaError` - If sandbox_id_or_name is not provided. **Example**: ```python sandbox = await daytona.get("my-sandbox-id-or-name") print(sandbox.state) ``` #### AsyncDaytona.list ```python @intercept_errors(message_prefix="Failed to list sandboxes: ") @with_instrumentation() async def list(labels: dict[str, str] | None = None, page: int | None = None, limit: int | None = None) -> AsyncPaginatedSandboxes ``` Returns paginated list of Sandboxes filtered by labels. **Arguments**: - `labels` _dict[str, str] | None_ - Labels to filter Sandboxes. - `page` _int | None_ - Page number for pagination (starting from 1). - `limit` _int | None_ - Maximum number of items per page. **Returns**: - `AsyncPaginatedSandboxes` - Paginated list of Sandbox instances that match the labels. **Example**: ```python result = await daytona.list(labels={"my-label": "my-value"}, page=2, limit=10) for sandbox in result.items: print(f"{sandbox.id}: {sandbox.state}") ``` #### AsyncDaytona.start ```python @with_instrumentation() async def start(sandbox: AsyncSandbox, timeout: float = 60) -> None ``` Starts a Sandbox and waits for it to be ready. **Arguments**: - `sandbox` _Sandbox_ - The Sandbox to start. - `timeout` _float_ - Optional timeout in seconds to wait for the Sandbox to start. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If Sandbox fails to start or times out #### AsyncDaytona.stop ```python @with_instrumentation() async def stop(sandbox: AsyncSandbox, timeout: float = 60) -> None ``` Stops a Sandbox and waits for it to be stopped. **Arguments**: - `sandbox` _Sandbox_ - The sandbox to stop - `timeout` _float_ - Optional timeout (in seconds) for sandbox stop. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If Sandbox fails to stop or times out ## CodeLanguage ```python class CodeLanguage(str, Enum) ``` Programming languages supported by Daytona **Enum Members**: - `PYTHON` ("python") - `TYPESCRIPT` ("typescript") - `JAVASCRIPT` ("javascript") ## DaytonaConfig ```python class DaytonaConfig(BaseModel) ``` Configuration options for initializing the Daytona client. **Attributes**: - `api_key` _str | None_ - API key for authentication with the Daytona API. If not set, it must be provided via the environment variable `DAYTONA_API_KEY`, or a JWT token must be provided instead. - `jwt_token` _str | None_ - JWT token for authentication with the Daytona API. If not set, it must be provided via the environment variable `DAYTONA_JWT_TOKEN`, or an API key must be provided instead. - `organization_id` _str | None_ - Organization ID used for JWT-based authentication. Required if a JWT token is provided, and must be set either here or in the environment variable `DAYTONA_ORGANIZATION_ID`. - `api_url` _str | None_ - URL of the Daytona API. Defaults to `'https://app.daytona.io/api'` if not set here or in the environment variable `DAYTONA_API_URL`. - `server_url` _str | None_ - Deprecated. Use `api_url` instead. This property will be removed in a future version. - `target` _str | None_ - Target runner location for the Sandbox. Default region for the organization is used if not set here or in the environment variable `DAYTONA_TARGET`. - `_experimental` _dict[str, any] | None_ - Configuration for experimental features. **Example**: ```python config = DaytonaConfig(api_key="your-api-key") ``` ```python config = DaytonaConfig(jwt_token="your-jwt-token", organization_id="your-organization-id") ``` ## CreateSandboxBaseParams ```python class CreateSandboxBaseParams(BaseModel) ``` Base parameters for creating a new Sandbox. **Attributes**: - `name` _str | None_ - Name of the Sandbox. - `language` _CodeLanguage | CodeLanguageLiteral | None_ - Programming language for the Sandbox. Defaults to "python". - `os_user` _str | None_ - OS user for the Sandbox. - `env_vars` _dict[str, str] | None_ - Environment variables to set in the Sandbox. - `labels` _dict[str, str] | None_ - Custom labels for the Sandbox. - `public` _bool | None_ - Whether the Sandbox should be public. - `timeout` _float | None_ - Timeout in seconds for Sandbox to be created and started. - `auto_stop_interval` _int | None_ - Interval in minutes after which Sandbox will automatically stop if no Sandbox event occurs during that time. Default is 15 minutes. 0 means no auto-stop. - `auto_archive_interval` _int | None_ - Interval in minutes after which a continuously stopped Sandbox will automatically archive. Default is 7 days. 0 means the maximum interval will be used. - `auto_delete_interval` _int | None_ - Interval in minutes after which a continuously stopped Sandbox will automatically be deleted. By default, auto-delete is disabled. Negative value means disabled, 0 means delete immediately upon stopping. - `volumes` _list[VolumeMount] | None_ - List of volumes mounts to attach to the Sandbox. - `network_block_all` _bool | None_ - Whether to block all network access for the Sandbox. - `network_allow_list` _str | None_ - Comma-separated list of allowed CIDR network addresses for the Sandbox. - `ephemeral` _bool | None_ - Whether the Sandbox should be ephemeral. If True, auto_delete_interval will be set to 0. ## CreateSandboxFromImageParams ```python class CreateSandboxFromImageParams(CreateSandboxBaseParams) ``` Parameters for creating a new Sandbox from an image. **Attributes**: - `image` _str | Image_ - Custom Docker image to use for the Sandbox. If an Image object is provided, the image will be dynamically built. - `resources` _Resources | None_ - Resource configuration for the Sandbox. If not provided, sandbox will have default resources. ## CreateSandboxFromSnapshotParams ```python class CreateSandboxFromSnapshotParams(CreateSandboxBaseParams) ``` Parameters for creating a new Sandbox from a snapshot. **Attributes**: - `snapshot` _str | None_ - Name of the snapshot to use for the Sandbox. ## AsyncFileSystem ```python class AsyncFileSystem() ``` Provides file system operations within a Sandbox. This class implements a high-level interface to file system operations that can be performed within a Daytona Sandbox. #### AsyncFileSystem.\_\_init\_\_ ```python def __init__(api_client: FileSystemApi) ``` Initializes a new FileSystem instance. **Arguments**: - `api_client` _FileSystemApi_ - API client for Sandbox file system operations. #### AsyncFileSystem.create\_folder ```python @intercept_errors(message_prefix="Failed to create folder: ") @with_instrumentation() async def create_folder(path: str, mode: str) -> None ``` Creates a new directory in the Sandbox at the specified path with the given permissions. **Arguments**: - `path` _str_ - Path where the folder should be created. Relative paths are resolved based on the sandbox working directory. - `mode` _str_ - Folder permissions in octal format (e.g., "755" for rwxr-xr-x). **Example**: ```python # Create a directory with standard permissions await sandbox.fs.create_folder("workspace/data", "755") # Create a private directory await sandbox.fs.create_folder("workspace/secrets", "700") ``` #### AsyncFileSystem.delete\_file ```python @intercept_errors(message_prefix="Failed to delete file: ") @with_instrumentation() async def delete_file(path: str, recursive: bool = False) -> None ``` Deletes a file from the Sandbox. **Arguments**: - `path` _str_ - Path to the file to delete. Relative paths are resolved based on the sandbox working directory. - `recursive` _bool_ - If the file is a directory, this must be true to delete it. **Example**: ```python # Delete a file await sandbox.fs.delete_file("workspace/data/old_file.txt") ``` #### AsyncFileSystem.download\_file ```python @overload async def download_file(remote_path: str, timeout: int = 30 * 60) -> bytes ``` Downloads a file from the Sandbox. Returns the file contents as a bytes object. This method is useful when you want to load the file into memory without saving it to disk. It can only be used for smaller files. **Arguments**: - `remote_path` _str_ - Path to the file in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `timeout` _int_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `bytes` - The file contents as a bytes object. **Example**: ```python # Download and save a file locally content = await sandbox.fs.download_file("workspace/data/file.txt") with open("local_copy.txt", "wb") as f: f.write(content) # Download and process text content content = await sandbox.fs.download_file("workspace/data/config.json") config = json.loads(content.decode('utf-8')) ``` #### AsyncFileSystem.download\_file ```python @overload async def download_file(remote_path: str, local_path: str, timeout: int = 30 * 60) -> None ``` Downloads a file from the Sandbox and saves it to a local file using stream. This method is useful when you want to download larger files that may not fit into memory. **Arguments**: - `remote_path` _str_ - Path to the file in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `local_path` _str_ - Path to save the file locally. - `timeout` _int_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python local_path = "local_copy.txt" await sandbox.fs.download_file("tmp/large_file.txt", local_path) size_mb = os.path.getsize(local_path) / 1024 / 1024 print(f"Size of the downloaded file {local_path}: {size_mb} MB") ``` #### AsyncFileSystem.download\_files ```python @intercept_errors(message_prefix="Failed to download files: ") @with_instrumentation() async def download_files(files: list[FileDownloadRequest], timeout: int = 30 * 60) -> list[FileDownloadResponse] ``` Downloads multiple files from the Sandbox. If the files already exist locally, they will be overwritten. **Arguments**: - `files` _list[FileDownloadRequest]_ - List of files to download. - `timeout` _int_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `list[FileDownloadResponse]` - List of download results. **Raises**: - `Exception` - Only if the request itself fails (network issues, invalid request/response, etc.). Individual file download errors are returned in the `FileDownloadResponse.error` field. **Example**: ```python # Download multiple files results = await sandbox.fs.download_files([ FileDownloadRequest(source="tmp/data.json"), FileDownloadRequest(source="tmp/config.json", destination="local_config.json") ]) for result in results: if result.error: print(f"Error downloading {result.source}: {result.error}") elif result.result: print(f"Downloaded {result.source} to {result.result}") ``` #### AsyncFileSystem.find\_files ```python @intercept_errors(message_prefix="Failed to find files: ") @with_instrumentation() async def find_files(path: str, pattern: str) -> list[Match] ``` Searches for files containing a pattern, similar to the grep command. **Arguments**: - `path` _str_ - Path to the file or directory to search. If the path is a directory, the search will be performed recursively. Relative paths are resolved based on the sandbox working directory. - `pattern` _str_ - Search pattern to match against file contents. **Returns**: - `list[Match]` - List of matches found in files. Each Match object includes: - file: Path to the file containing the match - line: The line number where the match was found - content: The matching line content **Example**: ```python # Search for TODOs in Python files matches = await sandbox.fs.find_files("workspace/src", "TODO:") for match in matches: print(f"{match.file}:{match.line}: {match.content.strip()}") ``` #### AsyncFileSystem.get\_file\_info ```python @intercept_errors(message_prefix="Failed to get file info: ") @with_instrumentation() async def get_file_info(path: str) -> FileInfo ``` Gets detailed information about a file or directory, including its size, permissions, and timestamps. **Arguments**: - `path` _str_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `FileInfo` - Detailed file information including: - name: File name - is_dir: Whether the path is a directory - size: File size in bytes - mode: File permissions - mod_time: Last modification timestamp - permissions: File permissions in octal format - owner: File owner - group: File group **Example**: ```python # Get file metadata info = await sandbox.fs.get_file_info("workspace/data/file.txt") print(f"Size: {info.size} bytes") print(f"Modified: {info.mod_time}") print(f"Mode: {info.mode}") # Check if path is a directory info = await sandbox.fs.get_file_info("workspace/data") if info.is_dir: print("Path is a directory") ``` #### AsyncFileSystem.list\_files ```python @intercept_errors(message_prefix="Failed to list files: ") @with_instrumentation() async def list_files(path: str) -> list[FileInfo] ``` Lists files and directories in a given path and returns their information, similar to the ls -l command. **Arguments**: - `path` _str_ - Path to the directory to list contents from. Relative paths are resolved based on the sandbox working directory. **Returns**: - `list[FileInfo]` - List of file and directory information. Each FileInfo object includes the same fields as described in get_file_info(). **Example**: ```python # List directory contents files = await sandbox.fs.list_files("workspace/data") # Print files and their sizes for file in files: if not file.is_dir: print(f"{file.name}: {file.size} bytes") # List only directories dirs = [f for f in files if f.is_dir] print("Subdirectories:", ", ".join(d.name for d in dirs)) ``` #### AsyncFileSystem.move\_files ```python @intercept_errors(message_prefix="Failed to move files: ") @with_instrumentation() async def move_files(source: str, destination: str) -> None ``` Moves or renames a file or directory. The parent directory of the destination must exist. **Arguments**: - `source` _str_ - Path to the source file or directory. Relative paths are resolved based on the sandbox working directory. - `destination` _str_ - Path to the destination. Relative paths are resolved based on the sandbox working directory. **Example**: ```python # Rename a file await sandbox.fs.move_files( "workspace/data/old_name.txt", "workspace/data/new_name.txt" ) # Move a file to a different directory await sandbox.fs.move_files( "workspace/data/file.txt", "workspace/archive/file.txt" ) # Move a directory await sandbox.fs.move_files( "workspace/old_dir", "workspace/new_dir" ) ``` #### AsyncFileSystem.replace\_in\_files ```python @intercept_errors(message_prefix="Failed to replace in files: ") @with_instrumentation() async def replace_in_files(files: list[str], pattern: str, new_value: str) -> list[ReplaceResult] ``` Performs search and replace operations across multiple files. **Arguments**: - `files` _list[str]_ - List of file paths to perform replacements in. Relative paths are resolved based on the sandbox working directory. - `pattern` _str_ - Pattern to search for. - `new_value` _str_ - Text to replace matches with. **Returns**: - `list[ReplaceResult]` - List of results indicating replacements made in each file. Each ReplaceResult includes: - file: Path to the modified file - success: Whether the operation was successful - error: Error message if the operation failed **Example**: ```python # Replace in specific files results = await sandbox.fs.replace_in_files( files=["workspace/src/file1.py", "workspace/src/file2.py"], pattern="old_function", new_value="new_function" ) # Print results for result in results: if result.success: print(f"{result.file}: {result.success}") else: print(f"{result.file}: {result.error}") ``` #### AsyncFileSystem.search\_files ```python @intercept_errors(message_prefix="Failed to search files: ") @with_instrumentation() async def search_files(path: str, pattern: str) -> SearchFilesResponse ``` Searches for files and directories whose names match the specified pattern. The pattern can be a simple string or a glob pattern. **Arguments**: - `path` _str_ - Path to the root directory to start search from. Relative paths are resolved based on the sandbox working directory. - `pattern` _str_ - Pattern to match against file names. Supports glob patterns (e.g., "*.py" for Python files). **Returns**: - `SearchFilesResponse` - Search results containing: - files: List of matching file and directory paths **Example**: ```python # Find all Python files result = await sandbox.fs.search_files("workspace", "*.py") for file in result.files: print(file) # Find files with specific prefix result = await sandbox.fs.search_files("workspace/data", "test_*") print(f"Found {len(result.files)} test files") ``` #### AsyncFileSystem.set\_file\_permissions ```python @intercept_errors(message_prefix="Failed to set file permissions: ") @with_instrumentation() async def set_file_permissions(path: str, mode: str | None = None, owner: str | None = None, group: str | None = None) -> None ``` Sets permissions and ownership for a file or directory. Any of the parameters can be None to leave that attribute unchanged. **Arguments**: - `path` _str_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. - `mode` _str | None_ - File mode/permissions in octal format (e.g., "644" for rw-r--r--). - `owner` _str | None_ - User owner of the file. - `group` _str | None_ - Group owner of the file. **Example**: ```python # Make a file executable await sandbox.fs.set_file_permissions( path="workspace/scripts/run.sh", mode="755" # rwxr-xr-x ) # Change file owner await sandbox.fs.set_file_permissions( path="workspace/data/file.txt", owner="daytona", group="daytona" ) ``` #### AsyncFileSystem.upload\_file ```python @overload async def upload_file(file: bytes, remote_path: str, timeout: int = 30 * 60) -> None ``` Uploads a file to the specified path in the Sandbox. If a file already exists at the destination path, it will be overwritten. This method is useful when you want to upload small files that fit into memory. **Arguments**: - `file` _bytes_ - File contents as a bytes object. - `remote_path` _str_ - Path to the destination file. Relative paths are resolved based on the sandbox working directory. - `timeout` _int_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python # Upload a text file content = b"Hello, World!" await sandbox.fs.upload_file(content, "tmp/hello.txt") # Upload a local file with open("local_file.txt", "rb") as f: content = f.read() await sandbox.fs.upload_file(content, "tmp/file.txt") # Upload binary data import json data = {"key": "value"} content = json.dumps(data).encode('utf-8') await sandbox.fs.upload_file(content, "tmp/config.json") ``` #### AsyncFileSystem.upload\_file ```python @overload async def upload_file(local_path: str, remote_path: str, timeout: int = 30 * 60) -> None ``` Uploads a file from the local file system to the specified path in the Sandbox. If a file already exists at the destination path, it will be overwritten. This method uses streaming to upload the file, so it is useful when you want to upload larger files that may not fit into memory. **Arguments**: - `local_path` _str_ - Path to the local file to upload. - `remote_path` _str_ - Path to the destination file in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `timeout` _int_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python await sandbox.fs.upload_file("local_file.txt", "tmp/large_file.txt") ``` #### AsyncFileSystem.upload\_files ```python @intercept_errors(message_prefix="Failed to upload files: ") @with_instrumentation() async def upload_files(files: list[FileUpload], timeout: int = 30 * 60) -> None ``` Uploads multiple files to the Sandbox. If files already exist at the destination paths, they will be overwritten. **Arguments**: - `files` _list[FileUpload]_ - List of files to upload. - `timeout` _int_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python # Upload multiple text files files = [ FileUpload( source=b"Content of file 1", destination="/tmp/file1.txt" ), FileUpload( source="workspace/data/file2.txt", destination="/tmp/file2.txt" ), FileUpload( source=b'{"key": "value"}', destination="/tmp/config.json" ) ] await sandbox.fs.upload_files(files) ``` ## FileUpload ```python @dataclass class FileUpload() ``` Represents a file to be uploaded to the Sandbox. **Attributes**: - `source` _bytes | str_ - File contents as a bytes object or a local file path. If a bytes object is provided, make sure it fits into memory, otherwise use the local file path which content will be streamed to the Sandbox. - `destination` _str_ - Absolute destination path in the Sandbox. Relative paths are resolved based on the sandbox working directory. ## FileDownloadRequest ```python @dataclass class FileDownloadRequest() ``` Represents a request to download a single file from the Sandbox. **Attributes**: - `source` _str_ - Source path in the Sandbox. Relative paths are resolved based on the user's root directory. - `destination` _str | None_ - Destination path in the local filesystem where the file content will be streamed to. If not provided, the file will be downloaded in the bytes buffer (might cause memory issues if the file is large). ## FileDownloadResponse ```python @dataclass class FileDownloadResponse() ``` Represents the response to a single file download request. **Attributes**: - `source` _str_ - The original source path requested for download. - `result` _str | bytes | None_ - The download result - file path (if destination provided in the request) or bytes content (if no destination in the request), None if failed or no data received. - `error` _str | None_ - Error message if the download failed, None if successful. ## AsyncGit ```python class AsyncGit() ``` Provides Git operations within a Sandbox. **Example**: ```python # Clone a repository await sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo" ) # Check repository status status = await sandbox.git.status("workspace/repo") print(f"Modified files: {status.modified}") # Stage and commit changes await sandbox.git.add("workspace/repo", ["file.txt"]) await sandbox.git.commit( path="workspace/repo", message="Update file", author="John Doe", email="john@example.com" ) ``` #### AsyncGit.\_\_init\_\_ ```python def __init__(api_client: GitApi) ``` Initializes a new Git handler instance. **Arguments**: - `api_client` _GitApi_ - API client for Sandbox Git operations. #### AsyncGit.add ```python @intercept_errors(message_prefix="Failed to add files: ") @with_instrumentation() async def add(path: str, files: list[str]) -> None ``` Stages the specified files for the next commit, similar to running 'git add' on the command line. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `files` _list[str]_ - List of file paths or directories to stage, relative to the repository root. **Example**: ```python # Stage a single file await sandbox.git.add("workspace/repo", ["file.txt"]) # Stage multiple files await sandbox.git.add("workspace/repo", [ "src/main.py", "tests/test_main.py", "README.md" ]) ``` #### AsyncGit.branches ```python @intercept_errors(message_prefix="Failed to list branches: ") @with_instrumentation() async def branches(path: str) -> ListBranchResponse ``` Lists branches in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `ListBranchResponse` - List of branches in the repository. **Example**: ```python response = await sandbox.git.branches("workspace/repo") print(f"Branches: {response.branches}") ``` #### AsyncGit.clone ```python @intercept_errors(message_prefix="Failed to clone repository: ") @with_instrumentation() async def clone(url: str, path: str, branch: str | None = None, commit_id: str | None = None, username: str | None = None, password: str | None = None) -> None ``` Clones a Git repository into the specified path. It supports cloning specific branches or commits, and can authenticate with the remote repository if credentials are provided. **Arguments**: - `url` _str_ - Repository URL to clone from. - `path` _str_ - Path where the repository should be cloned. Relative paths are resolved based on the sandbox working directory. - `branch` _str | None_ - Specific branch to clone. If not specified, clones the default branch. - `commit_id` _str | None_ - Specific commit to clone. If specified, the repository will be left in a detached HEAD state at this commit. - `username` _str | None_ - Git username for authentication. - `password` _str | None_ - Git password or token for authentication. **Example**: ```python # Clone the default branch await sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo" ) # Clone a specific branch with authentication await sandbox.git.clone( url="https://github.com/user/private-repo.git", path="workspace/private", branch="develop", username="user", password="token" ) # Clone a specific commit await sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo-old", commit_id="abc123" ) ``` #### AsyncGit.commit ```python @intercept_errors(message_prefix="Failed to commit changes: ") @with_instrumentation() async def commit(path: str, message: str, author: str, email: str, allow_empty: bool = False) -> GitCommitResponse ``` Creates a new commit with the staged changes. Make sure to stage changes using the add() method before committing. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `message` _str_ - Commit message describing the changes. - `author` _str_ - Name of the commit author. - `email` _str_ - Email address of the commit author. - `allow_empty` _bool_ - Allow creating an empty commit when no changes are staged. Defaults to False. **Example**: ```python # Stage and commit changes await sandbox.git.add("workspace/repo", ["README.md"]) await sandbox.git.commit( path="workspace/repo", message="Update documentation", author="John Doe", email="john@example.com", allow_empty=True ) ``` #### AsyncGit.push ```python @intercept_errors(message_prefix="Failed to push changes: ") @with_instrumentation() async def push(path: str, username: str | None = None, password: str | None = None) -> None ``` Pushes all local commits on the current branch to the remote repository. If the remote repository requires authentication, provide username and password/token. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username` _str | None_ - Git username for authentication. - `password` _str | None_ - Git password or token for authentication. **Example**: ```python # Push without authentication (for public repos or SSH) await sandbox.git.push("workspace/repo") # Push with authentication await sandbox.git.push( path="workspace/repo", username="user", password="github_token" ) ``` #### AsyncGit.pull ```python @intercept_errors(message_prefix="Failed to pull changes: ") @with_instrumentation() async def pull(path: str, username: str | None = None, password: str | None = None) -> None ``` Pulls changes from the remote repository. If the remote repository requires authentication, provide username and password/token. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username` _str | None_ - Git username for authentication. - `password` _str | None_ - Git password or token for authentication. **Example**: ```python # Pull without authentication await sandbox.git.pull("workspace/repo") # Pull with authentication await sandbox.git.pull( path="workspace/repo", username="user", password="github_token" ) ``` #### AsyncGit.status ```python @intercept_errors(message_prefix="Failed to get status: ") @with_instrumentation() async def status(path: str) -> GitStatus ``` Gets the current Git repository status. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `GitStatus` - Repository status information including: - current_branch: Current branch name - file_status: List of file statuses - ahead: Number of local commits not pushed to remote - behind: Number of remote commits not pulled locally - branch_published: Whether the branch has been published to the remote repository **Example**: ```python status = await sandbox.git.status("workspace/repo") print(f"On branch: {status.current_branch}") print(f"Commits ahead: {status.ahead}") print(f"Commits behind: {status.behind}") ``` #### AsyncGit.checkout\_branch ```python @intercept_errors(message_prefix="Failed to checkout branch: ") @with_instrumentation() async def checkout_branch(path: str, branch: str) -> None ``` Checkout branch in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `branch` _str_ - Name of the branch to checkout **Example**: ```python # Checkout a branch await sandbox.git.checkout_branch("workspace/repo", "feature-branch") ``` #### AsyncGit.create\_branch ```python @intercept_errors(message_prefix="Failed to create branch: ") @with_instrumentation() async def create_branch(path: str, name: str) -> None ``` Create branch in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _str_ - Name of the new branch to create **Example**: ```python # Create a new branch await sandbox.git.create_branch("workspace/repo", "new-feature") ``` #### AsyncGit.delete\_branch ```python @intercept_errors(message_prefix="Failed to delete branch: ") @with_instrumentation() async def delete_branch(path: str, name: str) -> None ``` Delete branch in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _str_ - Name of the branch to delete **Example**: ```python # Delete a branch await sandbox.git.delete_branch("workspace/repo", "old-feature") ``` ## GitCommitResponse ```python class GitCommitResponse() ``` Response from the git commit. **Attributes**: - `sha` _str_ - The SHA of the commit ## AsyncLspServer ```python class AsyncLspServer() ``` Provides Language Server Protocol functionality for code intelligence to provide IDE-like features such as code completion, symbol search, and more. #### AsyncLspServer.\_\_init\_\_ ```python def __init__(language_id: LspLanguageId | LspLanguageIdLiteral, path_to_project: str, api_client: LspApi) ``` Initializes a new LSP server instance. **Arguments**: - `language_id` _LspLanguageId | LspLanguageIdLiteral_ - The language server type (e.g., LspLanguageId.TYPESCRIPT). - `path_to_project` _str_ - Absolute path to the project root directory. - `api_client` _LspApi_ - API client for Sandbox operations. #### AsyncLspServer.start ```python @intercept_errors(message_prefix="Failed to start LSP server: ") @with_instrumentation() async def start() -> None ``` Starts the language server. This method must be called before using any other LSP functionality. It initializes the language server for the specified language and project. **Example**: ```python lsp = sandbox.create_lsp_server("typescript", "workspace/project") await lsp.start() # Initialize the server # Now ready for LSP operations ``` #### AsyncLspServer.stop ```python @intercept_errors(message_prefix="Failed to stop LSP server: ") @with_instrumentation() async def stop() -> None ``` Stops the language server. This method should be called when the LSP server is no longer needed to free up system resources. **Example**: ```python # When done with LSP features await lsp.stop() # Clean up resources ``` #### AsyncLspServer.did\_open ```python @intercept_errors(message_prefix="Failed to open file: ") @with_instrumentation() async def did_open(path: str) -> None ``` Notifies the language server that a file has been opened. This method should be called when a file is opened in the editor to enable language features like diagnostics and completions for that file. The server will begin tracking the file's contents and providing language features. **Arguments**: - `path` _str_ - Path to the opened file. Relative paths are resolved based on the project path set in the LSP server constructor. **Example**: ```python # When opening a file for editing await lsp.did_open("workspace/project/src/index.ts") # Now can get completions, symbols, etc. for this file ``` #### AsyncLspServer.did\_close ```python @intercept_errors(message_prefix="Failed to close file: ") @with_instrumentation() async def did_close(path: str) -> None ``` Notify the language server that a file has been closed. This method should be called when a file is closed in the editor to allow the language server to clean up any resources associated with that file. **Arguments**: - `path` _str_ - Path to the closed file. Relative paths are resolved based on the project path set in the LSP server constructor. **Example**: ```python # When done editing a file await lsp.did_close("workspace/project/src/index.ts") ``` #### AsyncLspServer.document\_symbols ```python @intercept_errors(message_prefix="Failed to get symbols from document: ") @with_instrumentation() async def document_symbols(path: str) -> list[LspSymbol] ``` Gets symbol information (functions, classes, variables, etc.) from a document. **Arguments**: - `path` _str_ - Path to the file to get symbols from. Relative paths are resolved based on the project path set in the LSP server constructor. **Returns**: - `list[LspSymbol]` - List of symbols in the document. Each symbol includes: - name: The symbol's name - kind: The symbol's kind (function, class, variable, etc.) - location: The location of the symbol in the file **Example**: ```python # Get all symbols in a file symbols = await lsp.document_symbols("workspace/project/src/index.ts") for symbol in symbols: print(f"{symbol.kind} {symbol.name}: {symbol.location}") ``` #### AsyncLspServer.workspace\_symbols ```python @deprecated( reason= "Method is deprecated. Use `sandbox_symbols` instead. This method will be removed in a future version." ) @with_instrumentation() async def workspace_symbols(query: str) -> list[LspSymbol] ``` Searches for symbols matching the query string across all files in the Sandbox. **Arguments**: - `query` _str_ - Search query to match against symbol names. **Returns**: - `list[LspSymbol]` - List of matching symbols from all files. #### AsyncLspServer.sandbox\_symbols ```python @intercept_errors(message_prefix="Failed to get symbols from sandbox: ") @with_instrumentation() async def sandbox_symbols(query: str) -> list[LspSymbol] ``` Searches for symbols matching the query string across all files in the Sandbox. **Arguments**: - `query` _str_ - Search query to match against symbol names. **Returns**: - `list[LspSymbol]` - List of matching symbols from all files. Each symbol includes: - name: The symbol's name - kind: The symbol's kind (function, class, variable, etc.) - location: The location of the symbol in the file **Example**: ```python # Search for all symbols containing "User" symbols = await lsp.sandbox_symbols("User") for symbol in symbols: print(f"{symbol.name} in {symbol.location}") ``` #### AsyncLspServer.completions ```python @intercept_errors(message_prefix="Failed to get completions: ") @with_instrumentation() async def completions(path: str, position: LspCompletionPosition) -> CompletionList ``` Gets completion suggestions at a position in a file. **Arguments**: - `path` _str_ - Path to the file. Relative paths are resolved based on the project path set in the LSP server constructor. - `position` _LspCompletionPosition_ - Cursor position to get completions for. **Returns**: - `CompletionList` - List of completion suggestions. The list includes: - isIncomplete: Whether more items might be available - items: List of completion items, each containing: - label: The text to insert - kind: The kind of completion - detail: Additional details about the item - documentation: Documentation for the item - sortText: Text used to sort the item in the list - filterText: Text used to filter the item - insertText: The actual text to insert (if different from label) **Example**: ```python # Get completions at a specific position pos = LspCompletionPosition(line=10, character=15) completions = await lsp.completions("workspace/project/src/index.ts", pos) for item in completions.items: print(f"{item.label} ({item.kind}): {item.detail}") ``` ## LspLanguageId ```python class LspLanguageId(str, Enum) ``` Language IDs for Language Server Protocol (LSP). **Enum Members**: - `PYTHON` ("python") - `TYPESCRIPT` ("typescript") - `JAVASCRIPT` ("javascript") ## LspCompletionPosition ```python @dataclass class LspCompletionPosition() ``` Represents a zero-based completion position in a text document, specified by line number and character offset. **Attributes**: - `line` _int_ - Zero-based line number in the document. - `character` _int_ - Zero-based character offset on the line. ## AsyncObjectStorage ```python class AsyncObjectStorage() ``` AsyncObjectStorage class for interacting with object storage services. **Attributes**: - `endpoint_url` _str_ - The endpoint URL for the object storage service. - `aws_access_key_id` _str_ - The access key ID for the object storage service. - `aws_secret_access_key` _str_ - The secret access key for the object storage service. - `aws_session_token` _str_ - The session token for the object storage service. Used for temporary credentials. - `bucket_name` _str_ - The name of the bucket to use. Defaults to "daytona-volume-builds". #### AsyncObjectStorage.upload ```python @with_instrumentation() async def upload(path: str, organization_id: str, archive_base_path: str | None = None) -> str ``` Uploads a file to the object storage service. **Arguments**: - `path` _str_ - The path to the file to upload. - `organization_id` _str_ - The organization ID to use. - `archive_base_path` _str_ - The base path to use for the archive. **Returns**: - `str` - The hash of the uploaded file. ## AsyncProcess ```python class AsyncProcess() ``` Handles process and code execution within a Sandbox. #### AsyncProcess.\_\_init\_\_ ```python def __init__(code_toolbox: SandboxCodeToolbox, api_client: ProcessApi) ``` Initialize a new Process instance. **Arguments**: - `code_toolbox` _SandboxCodeToolbox_ - Language-specific code execution toolbox. - `api_client` _ProcessApi_ - API client for process operations. #### AsyncProcess.exec ```python @intercept_errors(message_prefix="Failed to execute command: ") @with_instrumentation() async def exec(command: str, cwd: str | None = None, env: dict[str, str] | None = None, timeout: int | None = None) -> ExecuteResponse ``` Execute a shell command in the Sandbox. **Arguments**: - `command` _str_ - Shell command to execute. - `cwd` _str | None_ - Working directory for command execution. If not specified, uses the sandbox working directory. - `env` _dict[str, str] | None_ - Environment variables to set for the command. - `timeout` _int | None_ - Maximum time in seconds to wait for the command to complete. 0 means wait indefinitely. **Returns**: - `ExecuteResponse` - Command execution results containing: - exit_code: The command's exit status - result: Standard output from the command - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) **Example**: ```python # Simple command response = await sandbox.process.exec("echo 'Hello'") print(response.artifacts.stdout) # Prints: Hello # Command with working directory result = await sandbox.process.exec("ls", cwd="workspace/src") # Command with timeout result = await sandbox.process.exec("sleep 10", timeout=5) ``` #### AsyncProcess.code\_run ```python @with_instrumentation() async def code_run(code: str, params: CodeRunParams | None = None, timeout: int | None = None) -> ExecuteResponse ``` Executes code in the Sandbox using the appropriate language runtime. **Arguments**: - `code` _str_ - Code to execute. - `params` _CodeRunParams | None_ - Parameters for code execution. - `timeout` _int | None_ - Maximum time in seconds to wait for the code to complete. 0 means wait indefinitely. **Returns**: - `ExecuteResponse` - Code execution result containing: - exit_code: The execution's exit status - result: Standard output from the code - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) **Example**: ```python # Run Python code response = await sandbox.process.code_run(''' x = 10 y = 20 print(f"Sum: {x + y}") ''') print(response.artifacts.stdout) # Prints: Sum: 30 ``` Matplotlib charts are automatically detected and returned in the `charts` field of the `ExecutionArtifacts` object. ```python code = ''' import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 10, 30) y = np.sin(x) plt.figure(figsize=(8, 5)) plt.plot(x, y, 'b-', linewidth=2) plt.title('Line Chart') plt.xlabel('X-axis (seconds)') plt.ylabel('Y-axis (amplitude)') plt.grid(True) plt.show() ''' response = await sandbox.process.code_run(code) chart = response.artifacts.charts[0] print(f"Type: {chart.type}") print(f"Title: {chart.title}") if chart.type == ChartType.LINE and isinstance(chart, LineChart): print(f"X Label: {chart.x_label}") print(f"Y Label: {chart.y_label}") print(f"X Ticks: {chart.x_ticks}") print(f"X Tick Labels: {chart.x_tick_labels}") print(f"X Scale: {chart.x_scale}") print(f"Y Ticks: {chart.y_ticks}") print(f"Y Tick Labels: {chart.y_tick_labels}") print(f"Y Scale: {chart.y_scale}") print("Elements:") for element in chart.elements: print(f"Label: {element.label}") print(f"Points: {element.points}") ``` #### AsyncProcess.create\_session ```python @intercept_errors(message_prefix="Failed to create session: ") @with_instrumentation() async def create_session(session_id: str) -> None ``` Creates a new long-running background session in the Sandbox. Sessions are background processes that maintain state between commands, making them ideal for scenarios requiring multiple related commands or persistent environment setup. You can run long-running commands and monitor process status. **Arguments**: - `session_id` _str_ - Unique identifier for the new session. **Example**: ```python # Create a new session session_id = "my-session" await sandbox.process.create_session(session_id) session = await sandbox.process.get_session(session_id) # Do work... await sandbox.process.delete_session(session_id) ``` #### AsyncProcess.get\_session ```python @intercept_errors(message_prefix="Failed to get session: ") async def get_session(session_id: str) -> Session ``` Gets a session in the Sandbox. **Arguments**: - `session_id` _str_ - Unique identifier of the session to retrieve. **Returns**: - `Session` - Session information including: - session_id: The session's unique identifier - commands: List of commands executed in the session **Example**: ```python session = await sandbox.process.get_session("my-session") for cmd in session.commands: print(f"Command: {cmd.command}") ``` #### AsyncProcess.get\_entrypoint\_session ```python @intercept_errors(message_prefix="Failed to get sandbox entrypoint session: ") async def get_entrypoint_session() -> Session ``` Gets the sandbox entrypoint session. **Returns**: - `Session` - Entrypoint session information including: - session_id: The entrypoint session's unique identifier - commands: List of commands executed in the entrypoint session **Example**: ```python session = await sandbox.process.get_entrypoint_session() for cmd in session.commands: print(f"Command: {cmd.command}") ``` #### AsyncProcess.get\_session\_command ```python @intercept_errors(message_prefix="Failed to get session command: ") @with_instrumentation() async def get_session_command(session_id: str, command_id: str) -> Command ``` Gets information about a specific command executed in a session. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. **Returns**: - `Command` - Command information including: - id: The command's unique identifier - command: The executed command string - exit_code: Command's exit status (if completed) **Example**: ```python cmd = await sandbox.process.get_session_command("my-session", "cmd-123") if cmd.exit_code == 0: print(f"Command {cmd.command} completed successfully") ``` #### AsyncProcess.execute\_session\_command ```python @intercept_errors(message_prefix="Failed to execute session command: ") @with_instrumentation() async def execute_session_command( session_id: str, req: SessionExecuteRequest, timeout: int | None = None) -> SessionExecuteResponse ``` Executes a command in the session. **Arguments**: - `session_id` _str_ - Unique identifier of the session to use. - `req` _SessionExecuteRequest_ - Command execution request containing: - command: The command to execute - run_async: Whether to execute asynchronously **Returns**: - `SessionExecuteResponse` - Command execution results containing: - cmd_id: Unique identifier for the executed command - output: Combined command output (stdout and stderr) (if synchronous execution) - stdout: Standard output from the command - stderr: Standard error from the command - exit_code: Command exit status (if synchronous execution) **Example**: ```python # Execute commands in sequence, maintaining state session_id = "my-session" # Change directory req = SessionExecuteRequest(command="cd /workspace") await sandbox.process.execute_session_command(session_id, req) # Create a file req = SessionExecuteRequest(command="echo 'Hello' > test.txt") await sandbox.process.execute_session_command(session_id, req) # Read the file req = SessionExecuteRequest(command="cat test.txt") result = await sandbox.process.execute_session_command(session_id, req) print(f"Command stdout: {result.stdout}") print(f"Command stderr: {result.stderr}") ``` #### AsyncProcess.get\_session\_command\_logs ```python @intercept_errors(message_prefix="Failed to get session command logs: ") @with_instrumentation() async def get_session_command_logs( session_id: str, command_id: str) -> SessionCommandLogsResponse ``` Get the logs for a command executed in a session. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. **Returns**: - `SessionCommandLogsResponse` - Command logs including: - output: Combined command output (stdout and stderr) - stdout: Standard output from the command - stderr: Standard error from the command **Example**: ```python logs = await sandbox.process.get_session_command_logs( "my-session", "cmd-123" ) print(f"Command stdout: {logs.stdout}") print(f"Command stderr: {logs.stderr}") ``` #### AsyncProcess.get\_session\_command\_logs\_async ```python @intercept_errors(message_prefix="Failed to get session command logs: ") async def get_session_command_logs_async( session_id: str, command_id: str, on_stdout: OutputHandler[str], on_stderr: OutputHandler[str]) -> None ``` Asynchronously retrieves and processes the logs for a command executed in a session as they become available. Accepts both sync and async callbacks. Async callbacks are awaited. Blocking synchronous operations inside callbacks may cause WebSocket disconnections — use async callbacks and async libraries to avoid this. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. - `on_stdout` _OutputHandler[str]_ - Callback function to handle stdout log chunks as they arrive. - `on_stderr` _OutputHandler[str]_ - Callback function to handle stderr log chunks as they arrive. **Example**: ```python await sandbox.process.get_session_command_logs_async( "my-session", "cmd-123", lambda log: print(f"[STDOUT]: {log}"), lambda log: print(f"[STDERR]: {log}"), ) ``` #### AsyncProcess.get\_entrypoint\_logs ```python @intercept_errors(message_prefix="Failed to get entrypoint logs: ") @with_instrumentation() async def get_entrypoint_logs() -> SessionCommandLogsResponse ``` Get the logs for the entrypoint session. **Returns**: - `SessionCommandLogsResponse` - Command logs including: - output: Combined command output (stdout and stderr) - stdout: Standard output from the command - stderr: Standard error from the command **Example**: ```python logs = await sandbox.process.get_entrypoint_logs() print(f"Command stdout: {logs.stdout}") print(f"Command stderr: {logs.stderr}") ``` #### AsyncProcess.get\_entrypoint\_logs\_async ```python @intercept_errors(message_prefix="Failed to get entrypoint logs: ") async def get_entrypoint_logs_async(on_stdout: OutputHandler[str], on_stderr: OutputHandler[str]) -> None ``` Asynchronously retrieves and processes the logs for the entrypoint session as they become available. **Arguments**: on_stdout OutputHandler[str]: Callback function to handle stdout log chunks as they arrive. on_stderr OutputHandler[str]: Callback function to handle stderr log chunks as they arrive. **Example**: ```python await sandbox.process.get_entrypoint_logs_async( lambda log: print(f"[STDOUT]: {log}"), lambda log: print(f"[STDERR]: {log}"), ) ``` #### AsyncProcess.send\_session\_command\_input ```python @intercept_errors(message_prefix="Failed to send session command input: ") async def send_session_command_input(session_id: str, command_id: str, data: str) -> None ``` Sends input data to a command executed in a session. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. - `data` _str_ - Input data to send. #### AsyncProcess.list\_sessions ```python @intercept_errors(message_prefix="Failed to list sessions: ") @with_instrumentation() async def list_sessions() -> list[Session] ``` Lists all sessions in the Sandbox. **Returns**: - `list[Session]` - List of all sessions in the Sandbox. **Example**: ```python sessions = await sandbox.process.list_sessions() for session in sessions: print(f"Session {session.session_id}:") print(f" Commands: {len(session.commands)}") ``` #### AsyncProcess.delete\_session ```python @intercept_errors(message_prefix="Failed to delete session: ") @with_instrumentation() async def delete_session(session_id: str) -> None ``` Terminates and removes a session from the Sandbox, cleaning up any resources associated with it. **Arguments**: - `session_id` _str_ - Unique identifier of the session to delete. **Example**: ```python # Create and use a session await sandbox.process.create_session("temp-session") # ... use the session ... # Clean up when done await sandbox.process.delete_session("temp-session") ``` #### AsyncProcess.create\_pty\_session ```python @intercept_errors(message_prefix="Failed to create PTY session: ") @with_instrumentation() async def create_pty_session( id: str, on_data: Callable[[bytes], None] | Callable[[bytes], Awaitable[None]], cwd: str | None = None, envs: dict[str, str] | None = None, pty_size: PtySize | None = None) -> AsyncPtyHandle ``` Creates a new PTY (pseudo-terminal) session in the Sandbox. Creates an interactive terminal session that can execute commands and handle user input. The PTY session behaves like a real terminal, supporting features like command history. **Arguments**: - `id` - Unique identifier for the PTY session. Must be unique within the Sandbox. on_data (Callable[[bytes], None] | Callable[[bytes], Awaitable[None]]): Callback function to handle PTY output data. - `cwd` - Working directory for the PTY session. Defaults to the sandbox's working directory. - `env` - Environment variables to set in the PTY session. These will be merged with the Sandbox's default environment variables. - `pty_size` - Terminal size configuration. Defaults to 80x24 if not specified. **Returns**: - `AsyncPtyHandle` - Handle for managing the created PTY session. Use this to send input, receive output, resize the terminal, and manage the session lifecycle. **Raises**: - `DaytonaError` - If the PTY session creation fails or the session ID is already in use. #### AsyncProcess.connect\_pty\_session ```python @intercept_errors(message_prefix="Failed to connect PTY session: ") @with_instrumentation() async def connect_pty_session( session_id: str, on_data: Callable[[bytes], None] | Callable[[bytes], Awaitable[None]] ) -> AsyncPtyHandle ``` Connects to an existing PTY session in the Sandbox. Establishes a WebSocket connection to an existing PTY session, allowing you to interact with a previously created terminal session. **Arguments**: - `session_id` - Unique identifier of the PTY session to connect to. **Returns**: - `AsyncPtyHandle` - Handle for managing the connected PTY session. **Raises**: - `DaytonaError` - If the PTY session doesn't exist or connection fails. #### AsyncProcess.list\_pty\_sessions ```python @intercept_errors(message_prefix="Failed to list PTY sessions: ") @with_instrumentation() async def list_pty_sessions() -> list[PtySessionInfo] ``` Lists all PTY sessions in the Sandbox. Retrieves information about all PTY sessions in this Sandbox. **Returns**: - `list[PtySessionInfo]` - List of PTY session information objects containing details about each session's state, creation time, and configuration. **Example**: ```python # List all PTY sessions sessions = await sandbox.process.list_pty_sessions() for session in sessions: print(f"Session ID: {session.id}") print(f"Active: {session.active}") print(f"Created: {session.created_at}") ``` #### AsyncProcess.get\_pty\_session\_info ```python @intercept_errors(message_prefix="Failed to get PTY session info: ") @with_instrumentation() async def get_pty_session_info(session_id: str) -> PtySessionInfo ``` Gets detailed information about a specific PTY session. Retrieves comprehensive information about a PTY session including its current state, configuration, and metadata. **Arguments**: - `session_id` - Unique identifier of the PTY session to retrieve information for. **Returns**: - `PtySessionInfo` - Detailed information about the PTY session including ID, state, creation time, working directory, environment variables, and more. **Raises**: - `DaytonaError` - If the PTY session doesn't exist. **Example**: ```python # Get details about a specific PTY session session_info = await sandbox.process.get_pty_session_info("my-session") print(f"Session ID: {session_info.id}") print(f"Active: {session_info.active}") print(f"Working Directory: {session_info.cwd}") print(f"Terminal Size: {session_info.cols}x{session_info.rows}") ``` #### AsyncProcess.kill\_pty\_session ```python @intercept_errors(message_prefix="Failed to kill PTY session: ") @with_instrumentation() async def kill_pty_session(session_id: str) -> None ``` Kills a PTY session and terminates its associated process. Forcefully terminates the PTY session and cleans up all associated resources. This will close any active connections and kill the underlying shell process. This operation is irreversible. Any unsaved work in the terminal session will be lost. **Arguments**: - `session_id` - Unique identifier of the PTY session to kill. **Raises**: - `DaytonaError` - If the PTY session doesn't exist or cannot be killed. **Example**: ```python # Kill a specific PTY session await sandbox.process.kill_pty_session("my-session") # Verify the session no longer exists pty_sessions = await sandbox.process.list_pty_sessions() for pty_session in pty_sessions: print(f"PTY session: {pty_session.id}") ``` #### AsyncProcess.resize\_pty\_session ```python @intercept_errors(message_prefix="Failed to resize PTY session: ") @with_instrumentation() async def resize_pty_session(session_id: str, pty_size: PtySize) -> PtySessionInfo ``` Resizes a PTY session's terminal dimensions. Changes the terminal size of an active PTY session. This is useful when the client terminal is resized or when you need to adjust the display for different output requirements. **Arguments**: - `session_id` - Unique identifier of the PTY session to resize. - `pty_size` - New terminal dimensions containing the desired columns and rows. **Returns**: - `PtySessionInfo` - Updated session information reflecting the new terminal size. **Raises**: - `DaytonaError` - If the PTY session doesn't exist or resize operation fails. **Example**: ```python from daytona.common.pty import PtySize # Resize a PTY session to a larger terminal new_size = PtySize(rows=40, cols=150) updated_info = await sandbox.process.resize_pty_session("my-session", new_size) print(f"Terminal resized to {updated_info.cols}x{updated_info.rows}") # You can also use the AsyncPtyHandle's resize method await pty_handle.resize(new_size) ``` ## CodeRunParams ```python @dataclass class CodeRunParams() ``` Parameters for code execution. **Attributes**: - `argv` _list[str] | None_ - Command line arguments - `env` _dict[str, str] | None_ - Environment variables ## SessionExecuteRequest ```python class SessionExecuteRequest(ApiSessionExecuteRequest, AsyncApiSessionExecuteRequest) ``` Contains the request for executing a command in a session. **Attributes**: - `command` _str_ - The command to execute. - `run_async` _bool | None_ - Whether to execute the command asynchronously. - `var_async` _bool | None_ - Deprecated. Use `run_async` instead. - `suppress_input_echo` _bool | None_ - Whether to suppress input echo. Default is `False`. ## ExecutionArtifacts ```python @dataclass class ExecutionArtifacts() ``` Artifacts from the command execution. **Attributes**: - `stdout` _str_ - Standard output from the command, same as `result` in `ExecuteResponse` - `charts` _list[Chart] | None_ - List of chart metadata from matplotlib ## ExecuteResponse ```python class ExecuteResponse(BaseModel) ``` Response from the command execution. **Attributes**: - `exit_code` _int_ - The exit code from the command execution - `result` _str_ - The output from the command execution - `artifacts` _ExecutionArtifacts | None_ - Artifacts from the command execution ## SessionExecuteResponse ```python class SessionExecuteResponse(ApiSessionExecuteResponse) ``` Response from the session command execution. **Attributes**: - `cmd_id` _str_ - The ID of the executed command - `stdout` _str | None_ - The stdout from the command execution - `stderr` _str | None_ - The stderr from the command execution - `output` _str_ - The output from the command execution - `exit_code` _int_ - The exit code from the command execution ## SessionCommandLogsResponse ```python @dataclass class SessionCommandLogsResponse() ``` Response from the command logs. **Attributes**: - `output` _str | None_ - The combined output from the command - `stdout` _str | None_ - The stdout from the command - `stderr` _str | None_ - The stderr from the command #### parse\_session\_command\_logs ```python def parse_session_command_logs(data: bytes) -> SessionCommandLogsResponse ``` Parse combined stdout/stderr output into separate streams. **Arguments**: - `data` - Combined log bytes with STDOUT_PREFIX and STDERR_PREFIX markers **Returns**: SessionCommandLogsResponse with separated stdout and stderr #### demux\_log ```python def demux_log(data: bytes) -> tuple[bytes, bytes] ``` Demultiplex combined stdout/stderr log data. **Arguments**: - `data` - Combined log bytes with STDOUT_PREFIX and STDERR_PREFIX markers **Returns**: Tuple of (stdout_bytes, stderr_bytes) ##### OutputHandler ```python OutputHandler = Union[ Callable[[T], None], Callable[[T], Awaitable[None]], ] ``` Callback type that accepts both sync and async handlers. Blocking synchronous operations inside handlers may cause WebSocket disconnections. ## AsyncSandbox ```python class AsyncSandbox(SandboxDto) ``` Represents a Daytona Sandbox. **Attributes**: - `fs` _AsyncFileSystem_ - File system operations interface. - `git` _AsyncGit_ - Git operations interface. - `process` _AsyncProcess_ - Process execution interface. - `computer_use` _AsyncComputerUse_ - Computer use operations interface for desktop automation. - `code_interpreter` _AsyncCodeInterpreter_ - Stateful interpreter interface for executing code. Currently supports only Python. For other languages, use the `process.code_run` interface. - `id` _str_ - Unique identifier for the Sandbox. - `name` _str_ - Name of the Sandbox. - `organization_id` _str_ - Organization ID of the Sandbox. - `snapshot` _str_ - Daytona snapshot used to create the Sandbox. - `user` _str_ - OS user running in the Sandbox. - `env` _dict[str, str]_ - Environment variables set in the Sandbox. - `labels` _dict[str, str]_ - Custom labels attached to the Sandbox. - `public` _bool_ - Whether the Sandbox is publicly accessible. - `target` _str_ - Target location of the runner where the Sandbox runs. - `cpu` _int_ - Number of CPUs allocated to the Sandbox. - `gpu` _int_ - Number of GPUs allocated to the Sandbox. - `memory` _int_ - Amount of memory allocated to the Sandbox in GiB. - `disk` _int_ - Amount of disk space allocated to the Sandbox in GiB. - `state` _SandboxState_ - Current state of the Sandbox (e.g., "started", "stopped"). - `error_reason` _str_ - Error message if Sandbox is in error state. - `recoverable` _bool_ - Whether the Sandbox error is recoverable. - `backup_state` _SandboxBackupStateEnum_ - Current state of Sandbox backup. - `backup_created_at` _str_ - When the backup was created. - `auto_stop_interval` _int_ - Auto-stop interval in minutes. - `auto_archive_interval` _int_ - Auto-archive interval in minutes. - `auto_delete_interval` _int_ - Auto-delete interval in minutes. - `volumes` _list[str]_ - Volumes attached to the Sandbox. - `build_info` _str_ - Build information for the Sandbox if it was created from dynamic build. - `created_at` _str_ - When the Sandbox was created. - `updated_at` _str_ - When the Sandbox was last updated. - `network_block_all` _bool_ - Whether to block all network access for the Sandbox. - `network_allow_list` _str_ - Comma-separated list of allowed CIDR network addresses for the Sandbox. #### AsyncSandbox.\_\_init\_\_ ```python def __init__(sandbox_dto: SandboxDto, toolbox_api: ApiClient, sandbox_api: SandboxApi, code_toolbox: SandboxCodeToolbox) ``` Initialize a new Sandbox instance. **Arguments**: - `sandbox_dto` _SandboxDto_ - The sandbox data from the API. - `toolbox_api` _ApiClient_ - API client for toolbox operations. - `sandbox_api` _SandboxApi_ - API client for Sandbox operations. - `code_toolbox` _SandboxCodeToolbox_ - Language-specific toolbox implementation. #### AsyncSandbox.refresh\_data ```python @intercept_errors(message_prefix="Failed to refresh sandbox data: ") @with_instrumentation() async def refresh_data() -> None ``` Refreshes the Sandbox data from the API. **Example**: ```python await sandbox.refresh_data() print(f"Sandbox {sandbox.id}:") print(f"State: {sandbox.state}") print(f"Resources: {sandbox.cpu} CPU, {sandbox.memory} GiB RAM") ``` #### AsyncSandbox.get\_user\_home\_dir ```python @intercept_errors(message_prefix="Failed to get user home directory: ") @with_instrumentation() async def get_user_home_dir() -> str ``` Gets the user's home directory path inside the Sandbox. **Returns**: - `str` - The absolute path to the user's home directory inside the Sandbox. **Example**: ```python user_home_dir = await sandbox.get_user_home_dir() print(f"Sandbox user home: {user_home_dir}") ``` #### AsyncSandbox.get\_work\_dir ```python @intercept_errors(message_prefix="Failed to get working directory path: ") @with_instrumentation() async def get_work_dir() -> str ``` Gets the working directory path inside the Sandbox. **Returns**: - `str` - The absolute path to the Sandbox working directory. Uses the WORKDIR specified in the Dockerfile if present, or falling back to the user's home directory if not. **Example**: ```python work_dir = await sandbox.get_work_dir() print(f"Sandbox working directory: {work_dir}") ``` #### AsyncSandbox.create\_lsp\_server ```python @with_instrumentation() def create_lsp_server(language_id: LspLanguageId | LspLanguageIdLiteral, path_to_project: str) -> AsyncLspServer ``` Creates a new Language Server Protocol (LSP) server instance. The LSP server provides language-specific features like code completion, diagnostics, and more. **Arguments**: - `language_id` _LspLanguageId | LspLanguageIdLiteral_ - The language server type (e.g., LspLanguageId.PYTHON). - `path_to_project` _str_ - Path to the project root directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `LspServer` - A new LSP server instance configured for the specified language. **Example**: ```python lsp = sandbox.create_lsp_server("python", "workspace/project") ``` #### AsyncSandbox.set\_labels ```python @intercept_errors(message_prefix="Failed to set labels: ") @with_instrumentation() async def set_labels(labels: dict[str, str]) -> dict[str, str] ``` Sets labels for the Sandbox. Labels are key-value pairs that can be used to organize and identify Sandboxes. **Arguments**: - `labels` _dict[str, str]_ - Dictionary of key-value pairs representing Sandbox labels. **Returns**: dict[str, str]: Dictionary containing the updated Sandbox labels. **Example**: ```python new_labels = sandbox.set_labels({ "project": "my-project", "environment": "development", "team": "backend" }) print(f"Updated labels: {new_labels}") ``` #### AsyncSandbox.start ```python @intercept_errors(message_prefix="Failed to start sandbox: ") @with_timeout() @with_instrumentation() async def start(timeout: float | None = 60) ``` Starts the Sandbox and waits for it to be ready. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If sandbox fails to start or times out. **Example**: ```python sandbox = daytona.get("my-sandbox-id") sandbox.start(timeout=40) # Wait up to 40 seconds print("Sandbox started successfully") ``` #### AsyncSandbox.recover ```python @intercept_errors(message_prefix="Failed to recover sandbox: ") @with_timeout() async def recover(timeout: float | None = 60) ``` Recovers the Sandbox from a recoverable error and waits for it to be ready. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If sandbox fails to recover or times out. **Example**: ```python sandbox = daytona.get("my-sandbox-id") await sandbox.recover(timeout=40) # Wait up to 40 seconds print("Sandbox recovered successfully") ``` #### AsyncSandbox.stop ```python @intercept_errors(message_prefix="Failed to stop sandbox: ") @with_timeout() @with_instrumentation() async def stop(timeout: float | None = 60) ``` Stops the Sandbox and waits for it to be fully stopped. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If sandbox fails to stop or times out **Example**: ```python sandbox = daytona.get("my-sandbox-id") sandbox.stop() print("Sandbox stopped successfully") ``` #### AsyncSandbox.delete ```python @intercept_errors(message_prefix="Failed to remove sandbox: ") @with_instrumentation() async def delete(timeout: float | None = 60) -> None ``` Deletes the Sandbox. **Arguments**: - `timeout` _float | None_ - Timeout (in seconds) for sandbox deletion. 0 means no timeout. Default is 60 seconds. #### AsyncSandbox.wait\_for\_sandbox\_start ```python @intercept_errors( message_prefix="Failure during waiting for sandbox to start: ") @with_timeout() @with_instrumentation() async def wait_for_sandbox_start(timeout: float | None = 60) -> None ``` Waits for the Sandbox to reach the 'started' state. Polls the Sandbox status until it reaches the 'started' state, encounters an error or times out. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If Sandbox fails to start or times out #### AsyncSandbox.wait\_for\_sandbox\_stop ```python @intercept_errors( message_prefix="Failure during waiting for sandbox to stop: ") @with_timeout() @with_instrumentation() async def wait_for_sandbox_stop(timeout: float | None = 60) -> None ``` Waits for the Sandbox to reach the 'stopped' state. Polls the Sandbox status until it reaches the 'stopped' state, encounters an error or times out. It will wait up to 60 seconds for the Sandbox to stop. Treats destroyed as stopped to cover ephemeral sandboxes that are automatically deleted after stopping. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If Sandbox fails to stop or times out. #### AsyncSandbox.set\_autostop\_interval ```python @intercept_errors(message_prefix="Failed to set auto-stop interval: ") @with_instrumentation() async def set_autostop_interval(interval: int) -> None ``` Sets the auto-stop interval for the Sandbox. The Sandbox will automatically stop after being idle (no new events) for the specified interval. Events include any state changes or interactions with the Sandbox through the SDK. Interactions using Sandbox Previews are not included. **Arguments**: - `interval` _int_ - Number of minutes of inactivity before auto-stopping. Set to 0 to disable auto-stop. Defaults to 15. **Raises**: - `DaytonaError` - If interval is negative **Example**: ```python # Auto-stop after 1 hour sandbox.set_autostop_interval(60) # Or disable auto-stop sandbox.set_autostop_interval(0) ``` #### AsyncSandbox.set\_auto\_archive\_interval ```python @intercept_errors(message_prefix="Failed to set auto-archive interval: ") @with_instrumentation() async def set_auto_archive_interval(interval: int) -> None ``` Sets the auto-archive interval for the Sandbox. The Sandbox will automatically archive after being continuously stopped for the specified interval. **Arguments**: - `interval` _int_ - Number of minutes after which a continuously stopped Sandbox will be auto-archived. Set to 0 for the maximum interval. Default is 7 days. **Raises**: - `DaytonaError` - If interval is negative **Example**: ```python # Auto-archive after 1 hour sandbox.set_auto_archive_interval(60) # Or use the maximum interval sandbox.set_auto_archive_interval(0) ``` #### AsyncSandbox.set\_auto\_delete\_interval ```python @intercept_errors(message_prefix="Failed to set auto-delete interval: ") @with_instrumentation() async def set_auto_delete_interval(interval: int) -> None ``` Sets the auto-delete interval for the Sandbox. The Sandbox will automatically delete after being continuously stopped for the specified interval. **Arguments**: - `interval` _int_ - Number of minutes after which a continuously stopped Sandbox will be auto-deleted. Set to negative value to disable auto-delete. Set to 0 to delete immediately upon stopping. By default, auto-delete is disabled. **Example**: ```python # Auto-delete after 1 hour sandbox.set_auto_delete_interval(60) # Or delete immediately upon stopping sandbox.set_auto_delete_interval(0) # Or disable auto-delete sandbox.set_auto_delete_interval(-1) ``` #### AsyncSandbox.get\_preview\_link ```python @intercept_errors(message_prefix="Failed to get preview link: ") @with_instrumentation() async def get_preview_link(port: int) -> PortPreviewUrl ``` Retrieves the preview link for the sandbox at the specified port. If the port is closed, it will be opened automatically. For private sandboxes, a token is included to grant access to the URL. **Arguments**: - `port` _int_ - The port to open the preview link on. **Returns**: - `PortPreviewUrl` - The response object for the preview link, which includes the `url` and the `token` (to access private sandboxes). **Example**: ```python preview_link = sandbox.get_preview_link(3000) print(f"Preview URL: {preview_link.url}") print(f"Token: {preview_link.token}") ``` #### AsyncSandbox.create\_signed\_preview\_url ```python @intercept_errors(message_prefix="Failed to create signed preview url: ") async def create_signed_preview_url( port: int, expires_in_seconds: int | None = None) -> SignedPortPreviewUrl ``` Creates a signed preview URL for the sandbox at the specified port. **Arguments**: - `port` _int_ - The port to open the preview link on. - `expires_in_seconds` _int | None_ - The number of seconds the signed preview url will be valid for. Defaults to 60 seconds. **Returns**: - `SignedPortPreviewUrl` - The response object for the signed preview url. #### AsyncSandbox.expire\_signed\_preview\_url ```python @intercept_errors(message_prefix="Failed to expire signed preview url: ") async def expire_signed_preview_url(port: int, token: str) -> None ``` Expires a signed preview URL for the sandbox at the specified port. **Arguments**: - `port` _int_ - The port to expire the signed preview url on. - `token` _str_ - The token to expire the signed preview url on. #### AsyncSandbox.archive ```python @intercept_errors(message_prefix="Failed to archive sandbox: ") @with_instrumentation() async def archive() -> None ``` Archives the sandbox, making it inactive and preserving its state. When sandboxes are archived, the entire filesystem state is moved to cost-effective object storage, making it possible to keep sandboxes available for an extended period. The tradeoff between archived and stopped states is that starting an archived sandbox takes more time, depending on its size. Sandbox must be stopped before archiving. #### AsyncSandbox.resize ```python @intercept_errors(message_prefix="Failed to resize sandbox: ") @with_timeout() @with_instrumentation() async def resize(resources: Resources, timeout: float | None = 60) -> None ``` Resizes the Sandbox resources. Changes the CPU, memory, or disk allocation for the Sandbox. Hot resize (on running sandbox) only allows CPU/memory increases. Disk resize requires a stopped sandbox. **Arguments**: - `resources` _Resources_ - New resource configuration. Only specified fields will be updated. - cpu: Number of CPU cores (minimum: 1). For hot resize, can only be increased. - memory: Memory in GiB (minimum: 1). For hot resize, can only be increased. - disk: Disk space in GiB (can only be increased, requires stopped sandbox). - `timeout` _Optional[float]_ - Timeout (in seconds) for the resize operation. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If hot resize constraints are violated (CPU/memory decrease on running sandbox). - `DaytonaError` - If disk resize attempted on running sandbox. - `DaytonaError` - If disk size decrease is attempted. - `DaytonaError` - If resize operation times out. - `DaytonaError` - If no resource changes are specified. **Example**: ```python # Increase CPU/memory on running sandbox (hot resize) await sandbox.resize(Resources(cpu=4, memory=8)) # Change disk (sandbox must be stopped) await sandbox.stop() await sandbox.resize(Resources(cpu=2, memory=4, disk=30)) ``` #### AsyncSandbox.wait\_for\_resize\_complete ```python @intercept_errors( message_prefix="Failure during waiting for resize to complete: ") @with_timeout() @with_instrumentation() async def wait_for_resize_complete(timeout: float | None = 60) -> None ``` Waits for the Sandbox resize operation to complete. Polls the Sandbox status until the state is no longer 'resizing'. **Arguments**: - `timeout` _Optional[float]_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If resize operation times out. #### AsyncSandbox.create\_ssh\_access ```python @intercept_errors(message_prefix="Failed to create SSH access: ") @with_instrumentation() async def create_ssh_access( expires_in_minutes: int | None = None) -> SshAccessDto ``` Creates an SSH access token for the sandbox. **Arguments**: - `expires_in_minutes` _int | None_ - The number of minutes the SSH access token will be valid for. #### AsyncSandbox.revoke\_ssh\_access ```python @intercept_errors(message_prefix="Failed to revoke SSH access: ") @with_instrumentation() async def revoke_ssh_access(token: str) -> None ``` Revokes an SSH access token for the sandbox. **Arguments**: - `token` _str_ - The token to revoke. #### AsyncSandbox.validate\_ssh\_access ```python @intercept_errors(message_prefix="Failed to validate SSH access: ") @with_instrumentation() async def validate_ssh_access(token: str) -> SshAccessValidationDto ``` Validates an SSH access token for the sandbox. **Arguments**: - `token` _str_ - The token to validate. #### AsyncSandbox.refresh\_activity ```python @intercept_errors(message_prefix="Failed to refresh sandbox activity: ") async def refresh_activity() -> None ``` Refreshes the sandbox activity to reset the timer for automated lifecycle management actions. This method updates the sandbox's last activity timestamp without changing its state. It is useful for keeping long-running sessions alive while there is still user activity. **Example**: ```python await sandbox.refresh_activity() ``` ## AsyncPaginatedSandboxes ```python class AsyncPaginatedSandboxes(PaginatedSandboxesDto) ``` Represents a paginated list of Daytona Sandboxes. **Attributes**: - `items` _list[AsyncSandbox]_ - List of Sandbox instances in the current page. - `total` _int_ - Total number of Sandboxes across all pages. - `page` _int_ - Current page number. - `total_pages` _int_ - Total number of pages available. ##### items: `list[AsyncSandbox]` ```python items = None ``` pyright: ignore[reportIncompatibleVariableOverride] ## Resources ```python @dataclass class Resources() ``` Resources configuration for Sandbox. **Attributes**: - `cpu` _int | None_ - Number of CPU cores to allocate. - `memory` _int | None_ - Amount of memory in GiB to allocate. - `disk` _int | None_ - Amount of disk space in GiB to allocate. - `gpu` _int | None_ - Number of GPUs to allocate. **Example**: ```python resources = Resources( cpu=2, memory=4, # 4GiB RAM disk=20, # 20GiB disk gpu=1 ) params = CreateSandboxFromImageParams( image=Image.debian_slim("3.12"), language="python", resources=resources ) ``` ## Snapshot ```python class Snapshot(SyncSnapshotDto) ``` Represents a Daytona Snapshot which is a pre-configured sandbox. **Attributes**: - `id` _str_ - Unique identifier for the Snapshot. - `organization_id` _str | None_ - Organization ID of the Snapshot. - `general` _bool_ - Whether the Snapshot is general. - `name` _str_ - Name of the Snapshot. - `image_name` _str_ - Name of the Image of the Snapshot. - `state` _str_ - State of the Snapshot. - `size` _float | int | None_ - Size of the Snapshot. - `entrypoint` _list[str] | None_ - Entrypoint of the Snapshot. - `cpu` _float | int_ - CPU of the Snapshot. - `gpu` _float | int_ - GPU of the Snapshot. - `mem` _float | int_ - Memory of the Snapshot in GiB. - `disk` _float | int_ - Disk of the Snapshot in GiB. - `error_reason` _str | None_ - Error reason of the Snapshot. - `created_at` _str_ - Timestamp when the Snapshot was created. - `updated_at` _str_ - Timestamp when the Snapshot was last updated. - `last_used_at` _str_ - Timestamp when the Snapshot was last used. ## AsyncSnapshotService ```python class AsyncSnapshotService() ``` Service for managing Daytona Snapshots. Can be used to list, get, create and delete Snapshots. #### AsyncSnapshotService.list ```python @intercept_errors(message_prefix="Failed to list snapshots: ") @with_instrumentation() async def list(page: int | None = None, limit: int | None = None) -> PaginatedSnapshots ``` Returns paginated list of Snapshots. **Arguments**: - `page` _int | None_ - Page number for pagination (starting from 1). - `limit` _int | None_ - Maximum number of items per page. **Returns**: - `PaginatedSnapshots` - Paginated list of Snapshots. **Example**: ```python async with AsyncDaytona() as daytona: result = await daytona.snapshot.list(page=2, limit=10) for snapshot in result.items: print(f"{snapshot.name} ({snapshot.image_name})") ``` #### AsyncSnapshotService.delete ```python @intercept_errors(message_prefix="Failed to delete snapshot: ") @with_instrumentation() async def delete(snapshot: Snapshot) -> None ``` Delete a Snapshot. **Arguments**: - `snapshot` _Snapshot_ - Snapshot to delete. **Example**: ```python async with AsyncDaytona() as daytona: snapshot = await daytona.snapshot.get("test-snapshot") await daytona.snapshot.delete(snapshot) print("Snapshot deleted") ``` #### AsyncSnapshotService.get ```python @intercept_errors(message_prefix="Failed to get snapshot: ") @with_instrumentation() async def get(name: str) -> Snapshot ``` Get a Snapshot by name. **Arguments**: - `name` _str_ - Name of the Snapshot to get. **Returns**: - `Snapshot` - The Snapshot object. **Example**: ```python async with AsyncDaytona() as daytona: snapshot = await daytona.snapshot.get("test-snapshot-name") print(f"{snapshot.name} ({snapshot.image_name})") ``` #### AsyncSnapshotService.create ```python @intercept_errors(message_prefix="Failed to create snapshot: ") @with_timeout() @with_instrumentation() async def create(params: CreateSnapshotParams, *, on_logs: Callable[[str], None] | None = None, timeout: float | None = 0) -> Snapshot ``` Creates and registers a new snapshot from the given Image definition. **Arguments**: - `params` _CreateSnapshotParams_ - Parameters for snapshot creation. - `on_logs` _Callable[[str], None]_ - This callback function handles snapshot creation logs. - `timeout` _float | None_ - Default is no timeout. Timeout in seconds (0 means no timeout). **Example**: ```python image = Image.debianSlim('3.12').pipInstall('numpy') daytona.snapshot.create( CreateSnapshotParams(name='my-snapshot', image=image), on_logs=lambda chunk: print(chunk, end=""), ) ``` #### AsyncSnapshotService.activate ```python @with_instrumentation() async def activate(snapshot: Snapshot) -> Snapshot ``` Activate a snapshot. **Arguments**: - `snapshot` _Snapshot_ - The Snapshot instance. **Returns**: - `Snapshot` - The activated Snapshot instance. #### AsyncSnapshotService.process\_image\_context ```python @staticmethod @with_instrumentation() async def process_image_context(object_storage_api: ObjectStorageApi, image: Image) -> list[str] ``` Processes the image context by uploading it to object storage. **Arguments**: - `image` _Image_ - The Image instance. **Returns**: - `List[str]` - List of context hashes stored in object storage. ## PaginatedSnapshots ```python class PaginatedSnapshots(PaginatedSnapshotsDto) ``` Represents a paginated list of Daytona Snapshots. **Attributes**: - `items` _list[Snapshot]_ - List of Snapshot instances in the current page. - `total` _int_ - Total number of Snapshots across all pages. - `page` _int_ - Current page number. - `total_pages` _int_ - Total number of pages available. ## CreateSnapshotParams ```python class CreateSnapshotParams(BaseModel) ``` Parameters for creating a new snapshot. **Attributes**: - `name` _str_ - Name of the snapshot. - `image` _str | Image_ - Image of the snapshot. If a string is provided, it should be available on some registry. If an Image instance is provided, it will be used to create a new image in Daytona. - `resources` _Resources | None_ - Resources of the snapshot. - `entrypoint` _list[str] | None_ - Entrypoint of the snapshot. - `region_id` _str | None_ - ID of the region where the snapshot will be available. Defaults to organization default region if not specified. ## Volume ```python class Volume(VolumeDto) ``` Represents a Daytona Volume which is a shared storage volume for Sandboxes. **Attributes**: - `id` _str_ - Unique identifier for the Volume. - `name` _str_ - Name of the Volume. - `organization_id` _str_ - Organization ID of the Volume. - `state` _str_ - State of the Volume. - `created_at` _str_ - Date and time when the Volume was created. - `updated_at` _str_ - Date and time when the Volume was last updated. - `last_used_at` _str_ - Date and time when the Volume was last used. ## AsyncVolumeService ```python class AsyncVolumeService() ``` Service for managing Daytona Volumes. Can be used to list, get, create and delete Volumes. #### AsyncVolumeService.list ```python async def list() -> list[Volume] ``` List all Volumes. **Returns**: - `list[Volume]` - List of all Volumes. **Example**: ```python async with AsyncDaytona() as daytona: volumes = await daytona.volume.list() for volume in volumes: print(f"{volume.name} ({volume.id})") ``` #### AsyncVolumeService.get ```python @with_instrumentation() async def get(name: str, create: bool = False) -> Volume ``` Get a Volume by name. **Arguments**: - `name` _str_ - Name of the Volume to get. - `create` _bool_ - If True, create a new Volume if it doesn't exist. **Returns**: - `Volume` - The Volume object. **Example**: ```python async with AsyncDaytona() as daytona: volume = await daytona.volume.get("test-volume-name", create=True) print(f"{volume.name} ({volume.id})") ``` #### AsyncVolumeService.create ```python @with_instrumentation() async def create(name: str) -> Volume ``` Create a new Volume. **Arguments**: - `name` _str_ - Name of the Volume to create. **Returns**: - `Volume` - The Volume object. **Example**: ```python async with AsyncDaytona() as daytona: volume = await daytona.volume.create("test-volume") print(f"{volume.name} ({volume.id}); state: {volume.state}") ``` #### AsyncVolumeService.delete ```python @with_instrumentation() async def delete(volume: Volume) -> None ``` Delete a Volume. **Arguments**: - `volume` _Volume_ - Volume to delete. **Example**: ```python async with AsyncDaytona() as daytona: volume = await daytona.volume.get("test-volume") await daytona.volume.delete(volume) print("Volume deleted") ``` ## VolumeMount ```python class VolumeMount(ApiVolumeMount, AsyncApiVolumeMount) ``` Represents a Volume mount configuration for a Sandbox. **Attributes**: - `volume_id` _str_ - ID of the volume to mount. - `mount_path` _str_ - Path where the volume will be mounted in the sandbox. - `subpath` _str | None_ - Optional S3 subpath/prefix within the volume to mount. When specified, only this prefix will be accessible. When omitted, the entire volume is mounted. ## Chart ```python class Chart(BaseModel) ``` Represents a chart with metadata from matplotlib. **Attributes**: - `type` _ChartType_ - The type of chart - `title` _str_ - The title of the chart - `elements` _list[Any]_ - The elements of the chart - `png` _str | None_ - The PNG representation of the chart encoded in base64 #### Chart.to\_dict ```python def to_dict() -> dict[str, Any] ``` Return the metadata dictionary used to create the chart. ## ChartType ```python class ChartType(str, Enum) ``` Chart types **Enum Members**: - `LINE` ("line") - `SCATTER` ("scatter") - `BAR` ("bar") - `PIE` ("pie") - `BOX_AND_WHISKER` ("box_and_whisker") - `COMPOSITE_CHART` ("composite_chart") - `UNKNOWN` ("unknown") ## Chart2D ```python class Chart2D(Chart) ``` Represents a 2D chart with metadata. **Attributes**: - `x_label` _str | None_ - The label of the x-axis - `y_label` _str | None_ - The label of the y-axis ## PointData ```python class PointData(BaseModel) ``` Represents a point in a 2D chart. **Attributes**: - `label` _str_ - The label of the point - `points` _list[tuple[str | float, str | float]]_ - The points of the chart ## PointChart ```python class PointChart(Chart2D) ``` Represents a point chart with metadata. **Attributes**: - `x_ticks` _list[str | float]_ - The ticks of the x-axis - `x_tick_labels` _list[str]_ - The labels of the x-axis - `x_scale` _str_ - The scale of the x-axis - `y_ticks` _list[str | float]_ - The ticks of the y-axis - `y_tick_labels` _list[str]_ - The labels of the y-axis - `y_scale` _str_ - The scale of the y-axis - `elements` _list[PointData]_ - The points of the chart ## LineChart ```python class LineChart(PointChart) ``` Represents a line chart with metadata. **Attributes**: - `type` _ChartType_ - The type of chart ## ScatterChart ```python class ScatterChart(PointChart) ``` Represents a scatter chart with metadata. **Attributes**: - `type` _ChartType_ - The type of chart ## BarData ```python class BarData(BaseModel) ``` Represents a bar in a bar chart. **Attributes**: - `label` _str_ - The label of the bar - `group` _str_ - The group of the bar - `value` _str_ - The value of the bar ## BarChart ```python class BarChart(Chart2D) ``` Represents a bar chart with metadata. **Attributes**: - `type` _ChartType_ - The type of chart - `elements` _list[BarData]_ - The bars of the chart ## PieData ```python class PieData(BaseModel) ``` Represents a pie slice in a pie chart. **Attributes**: - `label` _str_ - The label of the pie slice - `angle` _float_ - The angle of the pie slice - `radius` _float_ - The radius of the pie slice - `autopct` _str | float_ - The autopct value of the pie slice ## PieChart ```python class PieChart(Chart) ``` Represents a pie chart with metadata. **Attributes**: - `type` _ChartType_ - The type of chart - `elements` _list[PieData]_ - The pie slices of the chart ## BoxAndWhiskerData ```python class BoxAndWhiskerData(BaseModel) ``` Represents a box and whisker in a box and whisker chart. **Attributes**: - `label` _str_ - The label of the box and whisker - `min` _float_ - The minimum value of the box and whisker - `first_quartile` _float_ - The first quartile of the box and whisker - `median` _float_ - The median of the box and whisker - `third_quartile` _float_ - The third quartile of the box and whisker - `max` _float_ - The maximum value of the box and whisker - `outliers` _list[float]_ - The outliers of the box and whisker ## BoxAndWhiskerChart ```python class BoxAndWhiskerChart(Chart2D) ``` Represents a box and whisker chart with metadata. **Attributes**: - `type` _ChartType_ - The type of chart - `elements` _list[BoxAndWhiskerData]_ - The box and whiskers of the chart ## CompositeChart ```python class CompositeChart(Chart) ``` Represents a composite chart with metadata. A composite chart is a chart that contains multiple charts (subplots). **Attributes**: - `type` _ChartType_ - The type of chart - `elements` _list[Chart]_ - The charts (subplots) of the composite chart ## DaytonaError ```python class DaytonaError(Exception) ``` Base error for Daytona SDK. **Attributes**: - `message` _str_ - Error message - `status_code` _int | None_ - HTTP status code if available - `headers` _dict[str, Any]_ - Response headers #### DaytonaError.\_\_init\_\_ ```python def __init__(message: str, status_code: int | None = None, headers: Mapping[str, Any] | None = None) ``` Initialize Daytona error. **Arguments**: - `message` _str_ - Error message - `status_code` _int | None_ - HTTP status code if available - `headers` _Mapping[str, Any] | None_ - Response headers if available ## DaytonaNotFoundError ```python class DaytonaNotFoundError(DaytonaError) ``` Error for when a resource is not found. ## DaytonaRateLimitError ```python class DaytonaRateLimitError(DaytonaError) ``` Error for when rate limit is exceeded. ## DaytonaTimeoutError ```python class DaytonaTimeoutError(DaytonaError) ``` Error for when a timeout occurs. ## Image ```python class Image(BaseModel) ``` Represents an image definition for a Daytona sandbox. Do not construct this class directly. Instead use one of its static factory methods, such as `Image.base()`, `Image.debian_slim()`, or `Image.from_dockerfile()`. #### Image.dockerfile ```python def dockerfile() -> str ``` Returns a generated Dockerfile for the image. #### Image.pip\_install ```python def pip_install(*packages: str | list[str], find_links: list[str] | None = None, index_url: str | None = None, extra_index_urls: list[str] | None = None, pre: bool = False, extra_options: str = "") -> "Image" ``` Adds commands to install packages using pip. **Arguments**: - `*packages` - The packages to install. - `find_links` - list[str] | None: The find-links to use. - `index_url` - str | None: The index URL to use. - `extra_index_urls` - list[str] | None: The extra index URLs to use. - `pre` - bool = False: Whether to install pre-release packages. - `extra_options` - str = "": Additional options to pass to pip. Given string is passed directly to the pip install command. **Returns**: - `Image` - The image with the pip install commands added. **Example**: ```python image = Image.debian_slim("3.12").pip_install("requests", "pandas") ``` #### Image.pip\_install\_from\_requirements ```python def pip_install_from_requirements(requirements_txt: str, find_links: list[str] | None = None, index_url: str | None = None, extra_index_urls: list[str] | None = None, pre: bool = False, extra_options: str = "") -> "Image" ``` Installs dependencies from a requirements.txt file. **Arguments**: - `requirements_txt` - str: The path to the requirements.txt file. - `find_links` - list[str] | None: The find-links to use. - `index_url` - str | None: The index URL to use. - `extra_index_urls` - list[str] | None: The extra index URLs to use. - `pre` - bool = False: Whether to install pre-release packages. - `extra_options` - str = "": Additional options to pass to pip. **Returns**: - `Image` - The image with the pip install commands added. **Example**: ```python image = Image.debian_slim("3.12").pip_install_from_requirements("requirements.txt") ``` #### Image.pip\_install\_from\_pyproject ```python def pip_install_from_pyproject(pyproject_toml: str, optional_dependencies: list[str], find_links: str | None = None, index_url: str | None = None, extra_index_url: str | None = None, pre: bool = False, extra_options: str = "") -> "Image" ``` Installs dependencies from a pyproject.toml file. **Arguments**: - `pyproject_toml` - str: The path to the pyproject.toml file. - `optional_dependencies` - list[str] = []: The optional dependencies to install from the pyproject.toml file. - `find_links` - str | None = None: The find-links to use. - `index_url` - str | None = None: The index URL to use. - `extra_index_url` - str | None = None: The extra index URL to use. - `pre` - bool = False: Whether to install pre-release packages. - `extra_options` - str = "": Additional options to pass to pip. Given string is passed directly to the pip install command. **Returns**: - `Image` - The image with the pip install commands added. **Example**: ```python image = Image.debian_slim("3.12") .pip_install_from_pyproject("pyproject.toml", optional_dependencies=["dev"]) ``` #### Image.add\_local\_file ```python def add_local_file(local_path: str | Path, remote_path: str) -> "Image" ``` Adds a local file to the image. **Arguments**: - `local_path` - str | Path: The path to the local file. - `remote_path` - str: The path to the file in the image. **Returns**: - `Image` - The image with the local file added. **Example**: ```python image = Image.debian_slim("3.12").add_local_file("package.json", "/home/daytona/package.json") ``` #### Image.add\_local\_dir ```python def add_local_dir(local_path: str | Path, remote_path: str) -> "Image" ``` Adds a local directory to the image. **Arguments**: - `local_path` - str | Path: The path to the local directory. - `remote_path` - str: The path to the directory in the image. **Returns**: - `Image` - The image with the local directory added. **Example**: ```python image = Image.debian_slim("3.12").add_local_dir("src", "/home/daytona/src") ``` #### Image.run\_commands ```python def run_commands(*commands: str | list[str]) -> "Image" ``` Runs commands in the image. **Arguments**: - `*commands` - The commands to run. **Returns**: - `Image` - The image with the commands added. **Example**: ```python image = Image.debian_slim("3.12").run_commands( 'echo "Hello, world!"', ['bash', '-c', 'echo Hello, world, again!'] ) ``` #### Image.env ```python def env(env_vars: dict[str, str]) -> "Image" ``` Sets environment variables in the image. **Arguments**: - `env_vars` - dict[str, str]: The environment variables to set. **Returns**: - `Image` - The image with the environment variables added. **Example**: ```python image = Image.debian_slim("3.12").env({"PROJECT_ROOT": "/home/daytona"}) ``` #### Image.workdir ```python def workdir(path: str | Path) -> "Image" ``` Sets the working directory in the image. **Arguments**: - `path` - str | Path: The path to the working directory. **Returns**: - `Image` - The image with the working directory added. **Example**: ```python image = Image.debian_slim("3.12").workdir("/home/daytona") ``` #### Image.entrypoint ```python def entrypoint(entrypoint_commands: list[str]) -> "Image" ``` Sets the entrypoint for the image. **Arguments**: - `entrypoint_commands` - list[str]: The commands to set as the entrypoint. **Returns**: - `Image` - The image with the entrypoint added. **Example**: ```python image = Image.debian_slim("3.12").entrypoint(["/bin/bash"]) ``` #### Image.cmd ```python def cmd(cmd: list[str]) -> "Image" ``` Sets the default command for the image. **Arguments**: - `cmd` - list[str]: The commands to set as the default command. **Returns**: - `Image` - The image with the default command added. **Example**: ```python image = Image.debian_slim("3.12").cmd(["/bin/bash"]) ``` #### Image.dockerfile\_commands ```python def dockerfile_commands(dockerfile_commands: list[str], context_dir: Path | str | None = None) -> "Image" ``` Adds arbitrary Dockerfile-like commands to the image. **Arguments**: - `*dockerfile_commands` - The commands to add to the Dockerfile. - `context_dir` - Path | str | None: The path to the context directory. **Returns**: - `Image` - The image with the Dockerfile commands added. **Example**: ```python image = Image.debian_slim("3.12").dockerfile_commands(["RUN echo 'Hello, world!'"]) ``` #### Image.from\_dockerfile ```python @staticmethod def from_dockerfile(path: str | Path) -> "Image" ``` Creates an Image from an existing Dockerfile. **Arguments**: - `path` - str | Path: The path to the Dockerfile. **Returns**: - `Image` - The image with the Dockerfile added. **Example**: ```python image = Image.from_dockerfile("Dockerfile") ``` #### Image.base ```python @staticmethod def base(image: str) -> "Image" ``` Creates an Image from an existing base image. **Arguments**: - `image` - str: The base image to use. **Returns**: - `Image` - The image with the base image added. **Example**: ```python image = Image.base("python:3.12-slim-bookworm") ``` #### Image.debian\_slim ```python @staticmethod def debian_slim( python_version: SupportedPythonSeries | None = None) -> "Image" ``` Creates a Debian slim image based on the official Python Docker image. **Arguments**: - `python_version` - SupportedPythonSeries | None: The Python version to use. **Returns**: - `Image` - The image with the Debian slim image added. **Example**: ```python image = Image.debian_slim("3.12") ``` ## Context ```python class Context(BaseModel) ``` Context for an image. **Attributes**: - `source_path` _str_ - The path to the source file or directory. - `archive_path` _str | None_ - The path inside the archive file in object storage. The Daytona Python SDK provides a robust interface for programmatically interacting with Daytona Sandboxes. ## Installation Install the Daytona Python SDK using pip: ```bash pip install daytona ``` Or using poetry: ```bash poetry add daytona ``` ## Getting Started ### Create a Sandbox Create a Daytona Sandbox to run your code securely in an isolated environment. The following snippet is an example "Hello World" program that runs securely inside a Daytona Sandbox. ```python from daytona import Daytona def main(): # Initialize the SDK (uses environment variables by default) daytona = Daytona() # Create a new sandbox sandbox = daytona.create() # Execute a command response = sandbox.process.exec("echo 'Hello, World!'") print(response.result) if __name__ == "__main__": main() ``` ```python import asyncio from daytona import AsyncDaytona async def main(): # Initialize the SDK (uses environment variables by default) async with AsyncDaytona() as daytona: # Create a new sandbox sandbox = await daytona.create() # Execute a command response = await sandbox.process.exec("echo 'Hello, World!'") print(response.result) if __name__ == "__main__": asyncio.run(main()) ``` ## Configuration The Daytona SDK can be configured using environment variables or by passing options to the constructor: ```python from daytona import Daytona, DaytonaConfig # Using environment variables (DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET) daytona = Daytona() # Using explicit configuration config = DaytonaConfig( api_key="YOUR_API_KEY", api_url="https://app.daytona.io/api", target="us" ) daytona = Daytona(config) ``` ```python import asyncio from daytona import AsyncDaytona, DaytonaConfig async def main(): try: # Using environment variables (DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET) daytona = AsyncDaytona() # Your async code here pass finally: await daytona.close() # Using explicit configuration config = DaytonaConfig( api_key="YOUR_API_KEY", api_url="https://app.daytona.io/api", target="us" ) async with AsyncDaytona(config) as daytona: # Your code here pass if __name__ == "__main__": asyncio.run(main()) ``` For more information on configuring the Daytona SDK, see [configuration](https://www.daytona.io/docs/en/configuration.md). ## CodeInterpreter ```python class CodeInterpreter() ``` Handles code interpretation and execution within a Sandbox. Currently supports only Python. This class provides methods to execute code in isolated interpreter contexts, manage contexts, and stream execution output via callbacks. If subsequent code executions are performed in the same context, the variables, imports, and functions defined in the previous execution will be available. For other languages, use the `code_run` method from the `Process` interface, or execute the appropriate command directly in the sandbox terminal. #### CodeInterpreter.\_\_init\_\_ ```python def __init__(api_client: InterpreterApi) ``` Initialize a new CodeInterpreter instance. **Arguments**: - `api_client` - API client for interpreter operations. #### CodeInterpreter.run\_code ```python @intercept_errors(message_prefix="Failed to run code: ") def run_code(code: str, *, context: InterpreterContext | None = None, on_stdout: OutputHandler[OutputMessage] | None = None, on_stderr: OutputHandler[OutputMessage] | None = None, on_error: OutputHandler[ExecutionError] | None = None, envs: dict[str, str] | None = None, timeout: int | None = None) -> ExecutionResult ``` Execute Python code in the sandbox. By default, code runs in the default shared context which persists variables, imports, and functions across executions. To run in an isolated context, create a new context with `create_context()` and pass it as `context` argument. **Arguments**: - `code` _str_ - Code to execute. - `context` _InterpreterContext | None_ - Context to run code in. If not provided, uses default context. - `on_stdout` _OutputHandler[OutputMessage] | None_ - Callback for stdout messages. - `on_stderr` _OutputHandler[OutputMessage] | None_ - Callback for stderr messages. - `on_error` _OutputHandler[ExecutionError] | None_ - Callback for execution errors (e.g., syntax errors, runtime errors). - `envs` _dict[str, str] | None_ - Environment variables for this execution. - `timeout` _int | None_ - Timeout in seconds. 0 means no timeout. Default is 10 minutes. **Returns**: - `ExecutionResult` - Result object containing stdout, stderr and error if any. **Raises**: - `DaytonaTimeoutError` - If execution times out. - `DaytonaError` - If execution fails due to communication or other SDK errors. **Examples**: ```python def handle_stdout(msg: OutputMessage): print(f"STDOUT: {msg.output}", end="") def handle_stderr(msg: OutputMessage): print(f"STDERR: {msg.output}", end="") def handle_error(err: ExecutionError): print(f"ERROR: {err.name}: {err.value}") code = ''' import sys import time for i in range(5): print(i) time.sleep(1) sys.stderr.write("Counting done!") ''' result = sandbox.code_interpreter.run_code( code=code, on_stdout=handle_stdout, on_stderr=handle_stderr, on_error=handle_error, timeout=10 ) ``` #### CodeInterpreter.create\_context ```python @intercept_errors(message_prefix="Failed to create interpreter context: ") def create_context(cwd: str | None = None) -> InterpreterContext ``` Create a new isolated interpreter context. Contexts provide isolated execution environments with their own global namespace. Variables, imports, and functions defined in one context don't affect others. **Arguments**: - `cwd` _str | None_ - Working directory for the context. If not specified, uses sandbox working directory. **Returns**: - `InterpreterContext` - The created context with its ID and metadata. **Raises**: - `DaytonaError` - If context creation fails. **Examples**: ```python # Create isolated context ctx = sandbox.code_interpreter.create_context() # Execute code in this context sandbox.code_interpreter.run_code("x = 100", context=ctx) # Variable only exists in this context result = sandbox.code_interpreter.run_code("print(x)", context=ctx) # OK # Won't see the variable in default context result = sandbox.code_interpreter.run_code("print(x)") # NameError # Clean up sandbox.code_interpreter.delete_context(ctx) ``` #### CodeInterpreter.list\_contexts ```python @intercept_errors(message_prefix="Failed to list interpreter contexts: ") def list_contexts() -> list[InterpreterContext] ``` List all user-created interpreter contexts. The default context is not included in this list. Only contexts created via `create_context()` are returned. **Returns**: - `list[InterpreterContext]` - List of context objects. **Raises**: - `DaytonaError` - If listing fails. **Examples**: ```python contexts = sandbox.code_interpreter.list_contexts() for ctx in contexts: print(f"Context {ctx.id}: {ctx.language} at {ctx.cwd}") ``` #### CodeInterpreter.delete\_context ```python @intercept_errors(message_prefix="Failed to delete interpreter context: ") def delete_context(context: InterpreterContext) -> None ``` Delete an interpreter context and shut down all associated processes. This permanently removes the context and all its state (variables, imports, etc.). The default context cannot be deleted. **Arguments**: - `context` _InterpreterContext_ - Context to delete. **Raises**: - `DaytonaError` - If deletion fails or context not found. **Examples**: ```python ctx = sandbox.code_interpreter.create_context() # ... use context ... sandbox.code_interpreter.delete_context(ctx) ``` ## OutputMessage ```python class OutputMessage(BaseModel) ``` Represents stdout or stderr output from code execution. **Attributes**: - `output` - The output content. ## ExecutionError ```python class ExecutionError(BaseModel) ``` Represents an error that occurred during code execution. **Attributes**: - `name` - The error type/class name (e.g., "ValueError", "SyntaxError"). - `value` - The error value. - `traceback` - Full traceback of the error. ## ExecutionResult ```python class ExecutionResult(BaseModel) ``` Result of code execution. **Attributes**: - `stdout` - Standard output from the code execution. - `stderr` - Standard error output from the code execution. - `error` - Error details if execution failed, None otherwise. ## ComputerUse ```python class ComputerUse() ``` Computer Use functionality for interacting with the desktop environment. Provides access to mouse, keyboard, screenshot, display, and recording operations for automating desktop interactions within a sandbox. **Attributes**: - `mouse` _Mouse_ - Mouse operations interface. - `keyboard` _Keyboard_ - Keyboard operations interface. - `screenshot` _Screenshot_ - Screenshot operations interface. - `display` _Display_ - Display operations interface. - `recording` _RecordingService_ - Screen recording operations interface. #### ComputerUse.start ```python @intercept_errors(message_prefix="Failed to start computer use: ") @with_instrumentation() def start() -> ComputerUseStartResponse ``` Starts all computer use processes (Xvfb, xfce4, x11vnc, novnc). **Returns**: - `ComputerUseStartResponse` - Computer use start response. **Example**: ```python result = sandbox.computer_use.start() print("Computer use processes started:", result.message) ``` #### ComputerUse.stop ```python @intercept_errors(message_prefix="Failed to stop computer use: ") @with_instrumentation() def stop() -> ComputerUseStopResponse ``` Stops all computer use processes. **Returns**: - `ComputerUseStopResponse` - Computer use stop response. **Example**: ```python result = sandbox.computer_use.stop() print("Computer use processes stopped:", result.message) ``` #### ComputerUse.get\_status ```python @intercept_errors(message_prefix="Failed to get computer use status: ") @with_instrumentation() def get_status() -> ComputerUseStatusResponse ``` Gets the status of all computer use processes. **Returns**: - `ComputerUseStatusResponse` - Status information about all VNC desktop processes. **Example**: ```python response = sandbox.computer_use.get_status() print("Computer use status:", response.status) ``` #### ComputerUse.get\_process\_status ```python @intercept_errors(message_prefix="Failed to get process status: ") @with_instrumentation() def get_process_status(process_name: str) -> ProcessStatusResponse ``` Gets the status of a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to check. **Returns**: - `ProcessStatusResponse` - Status information about the specific process. **Example**: ```python xvfb_status = sandbox.computer_use.get_process_status("xvfb") no_vnc_status = sandbox.computer_use.get_process_status("novnc") ``` #### ComputerUse.restart\_process ```python @intercept_errors(message_prefix="Failed to restart process: ") @with_instrumentation() def restart_process(process_name: str) -> ProcessRestartResponse ``` Restarts a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to restart. **Returns**: - `ProcessRestartResponse` - Process restart response. **Example**: ```python result = sandbox.computer_use.restart_process("xfce4") print("XFCE4 process restarted:", result.message) ``` #### ComputerUse.get\_process\_logs ```python @intercept_errors(message_prefix="Failed to get process logs: ") @with_instrumentation() def get_process_logs(process_name: str) -> ProcessLogsResponse ``` Gets logs for a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to get logs for. **Returns**: - `ProcessLogsResponse` - Process logs. **Example**: ```python logs = sandbox.computer_use.get_process_logs("novnc") print("NoVNC logs:", logs) ``` #### ComputerUse.get\_process\_errors ```python @intercept_errors(message_prefix="Failed to get process errors: ") @with_instrumentation() def get_process_errors(process_name: str) -> ProcessErrorsResponse ``` Gets error logs for a specific VNC process. **Arguments**: - `process_name` _str_ - Name of the process to get error logs for. **Returns**: - `ProcessErrorsResponse` - Process error logs. **Example**: ```python errors = sandbox.computer_use.get_process_errors("x11vnc") print("X11VNC errors:", errors) ``` ## Mouse ```python class Mouse() ``` Mouse operations for computer use functionality. #### Mouse.get\_position ```python @intercept_errors(message_prefix="Failed to get mouse position: ") @with_instrumentation() def get_position() -> MousePositionResponse ``` Gets the current mouse cursor position. **Returns**: - `MousePositionResponse` - Current mouse position with x and y coordinates. **Example**: ```python position = sandbox.computer_use.mouse.get_position() print(f"Mouse is at: {position.x}, {position.y}") ``` #### Mouse.move ```python @intercept_errors(message_prefix="Failed to move mouse: ") @with_instrumentation() def move(x: int, y: int) -> MousePositionResponse ``` Moves the mouse cursor to the specified coordinates. **Arguments**: - `x` _int_ - The x coordinate to move to. - `y` _int_ - The y coordinate to move to. **Returns**: - `MousePositionResponse` - Position after move. **Example**: ```python result = sandbox.computer_use.mouse.move(100, 200) print(f"Mouse moved to: {result.x}, {result.y}") ``` #### Mouse.click ```python @intercept_errors(message_prefix="Failed to click mouse: ") @with_instrumentation() def click(x: int, y: int, button: str = "left", double: bool = False) -> MouseClickResponse ``` Clicks the mouse at the specified coordinates. **Arguments**: - `x` _int_ - The x coordinate to click at. - `y` _int_ - The y coordinate to click at. - `button` _str_ - The mouse button to click ('left', 'right', 'middle'). - `double` _bool_ - Whether to perform a double-click. **Returns**: - `MouseClickResponse` - Click operation result. **Example**: ```python # Single left click result = sandbox.computer_use.mouse.click(100, 200) # Double click double_click = sandbox.computer_use.mouse.click(100, 200, "left", True) # Right click right_click = sandbox.computer_use.mouse.click(100, 200, "right") ``` #### Mouse.drag ```python @intercept_errors(message_prefix="Failed to drag mouse: ") @with_instrumentation() def drag(start_x: int, start_y: int, end_x: int, end_y: int, button: str = "left") -> MouseDragResponse ``` Drags the mouse from start coordinates to end coordinates. **Arguments**: - `start_x` _int_ - The starting x coordinate. - `start_y` _int_ - The starting y coordinate. - `end_x` _int_ - The ending x coordinate. - `end_y` _int_ - The ending y coordinate. - `button` _str_ - The mouse button to use for dragging. **Returns**: - `MouseDragResponse` - Drag operation result. **Example**: ```python result = sandbox.computer_use.mouse.drag(50, 50, 150, 150) print(f"Dragged from {result.from_x},{result.from_y} to {result.to_x},{result.to_y}") ``` #### Mouse.scroll ```python @intercept_errors(message_prefix="Failed to scroll mouse: ") @with_instrumentation() def scroll(x: int, y: int, direction: str, amount: int = 1) -> bool ``` Scrolls the mouse wheel at the specified coordinates. **Arguments**: - `x` _int_ - The x coordinate to scroll at. - `y` _int_ - The y coordinate to scroll at. - `direction` _str_ - The direction to scroll ('up' or 'down'). - `amount` _int_ - The amount to scroll. **Returns**: - `bool` - Whether the scroll operation was successful. **Example**: ```python # Scroll up scroll_up = sandbox.computer_use.mouse.scroll(100, 200, "up", 3) # Scroll down scroll_down = sandbox.computer_use.mouse.scroll(100, 200, "down", 5) ``` ## Keyboard ```python class Keyboard() ``` Keyboard operations for computer use functionality. #### Keyboard.type ```python @intercept_errors(message_prefix="Failed to type text: ") @with_instrumentation() def type(text: str, delay: int | None = None) -> None ``` Types the specified text. **Arguments**: - `text` _str_ - The text to type. - `delay` _int_ - Delay between characters in milliseconds. **Raises**: - `DaytonaError` - If the type operation fails. **Example**: ```python try: sandbox.computer_use.keyboard.type("Hello, World!") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # With delay between characters try: sandbox.computer_use.keyboard.type("Slow typing", 100) print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") ``` #### Keyboard.press ```python @intercept_errors(message_prefix="Failed to press key: ") @with_instrumentation() def press(key: str, modifiers: list[str] | None = None) -> None ``` Presses a key with optional modifiers. **Arguments**: - `key` _str_ - The key to press (e.g., 'Enter', 'Escape', 'Tab', 'a', 'A'). - `modifiers` _list[str]_ - Modifier keys ('ctrl', 'alt', 'meta', 'shift'). **Raises**: - `DaytonaError` - If the press operation fails. **Example**: ```python # Press Enter try: sandbox.computer_use.keyboard.press("Return") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # Press Ctrl+C try: sandbox.computer_use.keyboard.press("c", ["ctrl"]) print(f"Operation success") # Press Ctrl+Shift+T try: sandbox.computer_use.keyboard.press("t", ["ctrl", "shift"]) print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") ``` #### Keyboard.hotkey ```python @intercept_errors(message_prefix="Failed to press hotkey: ") @with_instrumentation() def hotkey(keys: str) -> None ``` Presses a hotkey combination. **Arguments**: - `keys` _str_ - The hotkey combination (e.g., 'ctrl+c', 'alt+tab', 'cmd+shift+t'). **Raises**: - `DaytonaError` - If the hotkey operation fails. **Example**: ```python # Copy try: sandbox.computer_use.keyboard.hotkey("ctrl+c") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # Paste try: sandbox.computer_use.keyboard.hotkey("ctrl+v") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") # Alt+Tab try: sandbox.computer_use.keyboard.hotkey("alt+tab") print(f"Operation success") except Exception as e: print(f"Operation failed: {e}") ``` ## Screenshot ```python class Screenshot() ``` Screenshot operations for computer use functionality. #### Screenshot.take\_full\_screen ```python @intercept_errors(message_prefix="Failed to take screenshot: ") @with_instrumentation() def take_full_screen(show_cursor: bool = False) -> ScreenshotResponse ``` Takes a screenshot of the entire screen. **Arguments**: - `show_cursor` _bool_ - Whether to show the cursor in the screenshot. **Returns**: - `ScreenshotResponse` - Screenshot data with base64 encoded image. **Example**: ```python screenshot = sandbox.computer_use.screenshot.take_full_screen() print(f"Screenshot size: {screenshot.width}x{screenshot.height}") # With cursor visible with_cursor = sandbox.computer_use.screenshot.take_full_screen(True) ``` #### Screenshot.take\_region ```python @intercept_errors(message_prefix="Failed to take region screenshot: ") @with_instrumentation() def take_region(region: ScreenshotRegion, show_cursor: bool = False) -> ScreenshotResponse ``` Takes a screenshot of a specific region. **Arguments**: - `region` _ScreenshotRegion_ - The region to capture. - `show_cursor` _bool_ - Whether to show the cursor in the screenshot. **Returns**: - `ScreenshotResponse` - Screenshot data with base64 encoded image. **Example**: ```python region = ScreenshotRegion(x=100, y=100, width=300, height=200) screenshot = sandbox.computer_use.screenshot.take_region(region) print(f"Captured region: {screenshot.region.width}x{screenshot.region.height}") ``` #### Screenshot.take\_compressed ```python @intercept_errors(message_prefix="Failed to take compressed screenshot: ") @with_instrumentation() def take_compressed( options: ScreenshotOptions | None = None) -> ScreenshotResponse ``` Takes a compressed screenshot of the entire screen. **Arguments**: - `options` _ScreenshotOptions | None_ - Compression and display options. **Returns**: - `ScreenshotResponse` - Compressed screenshot data. **Example**: ```python # Default compression screenshot = sandbox.computer_use.screenshot.take_compressed() # High quality JPEG jpeg = sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="jpeg", quality=95, show_cursor=True) ) # Scaled down PNG scaled = sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="png", scale=0.5) ) ``` #### Screenshot.take\_compressed\_region ```python @intercept_errors( message_prefix="Failed to take compressed region screenshot: ") @with_instrumentation() def take_compressed_region( region: ScreenshotRegion, options: ScreenshotOptions | None = None) -> ScreenshotResponse ``` Takes a compressed screenshot of a specific region. **Arguments**: - `region` _ScreenshotRegion_ - The region to capture. - `options` _ScreenshotOptions | None_ - Compression and display options. **Returns**: - `ScreenshotResponse` - Compressed screenshot data. **Example**: ```python region = ScreenshotRegion(x=0, y=0, width=800, height=600) screenshot = sandbox.computer_use.screenshot.take_compressed_region( region, ScreenshotOptions(format="webp", quality=80, show_cursor=True) ) print(f"Compressed size: {screenshot.size_bytes} bytes") ``` ## Display ```python class Display() ``` Display operations for computer use functionality. #### Display.get\_info ```python @intercept_errors(message_prefix="Failed to get display info: ") @with_instrumentation() def get_info() -> DisplayInfoResponse ``` Gets information about the displays. **Returns**: - `DisplayInfoResponse` - Display information including primary display and all available displays. **Example**: ```python info = sandbox.computer_use.display.get_info() print(f"Primary display: {info.primary_display.width}x{info.primary_display.height}") print(f"Total displays: {info.total_displays}") for i, display in enumerate(info.displays): print(f"Display {i}: {display.width}x{display.height} at {display.x},{display.y}") ``` #### Display.get\_windows ```python @intercept_errors(message_prefix="Failed to get windows: ") @with_instrumentation() def get_windows() -> WindowsResponse ``` Gets the list of open windows. **Returns**: - `WindowsResponse` - List of open windows with their IDs and titles. **Example**: ```python windows = sandbox.computer_use.display.get_windows() print(f"Found {windows.count} open windows:") for window in windows.windows: print(f"- {window.title} (ID: {window.id})") ``` ## RecordingService ```python class RecordingService() ``` Recording operations for computer use functionality. #### RecordingService.start ```python @intercept_errors(message_prefix="Failed to start recording: ") @with_instrumentation() def start(label: str | None = None) -> Recording ``` Starts a new screen recording session. **Arguments**: - `label` _str | None_ - Optional custom label for the recording. **Returns**: - `Recording` - Recording start response. **Example**: ```python # Start a recording with a label recording = sandbox.computer_use.recording.start("my-test-recording") print(f"Recording started: {recording.id}") print(f"File: {recording.file_path}") ``` #### RecordingService.stop ```python @intercept_errors(message_prefix="Failed to stop recording: ") @with_instrumentation() def stop(recording_id: str) -> Recording ``` Stops an active screen recording session. **Arguments**: - `recording_id` _str_ - The ID of the recording to stop. **Returns**: - `Recording` - Recording stop response. **Example**: ```python result = sandbox.computer_use.recording.stop(recording.id) print(f"Recording stopped: {result.duration_seconds} seconds") print(f"Saved to: {result.file_path}") ``` #### RecordingService.list ```python @intercept_errors(message_prefix="Failed to list recordings: ") @with_instrumentation() def list() -> ListRecordingsResponse ``` Lists all recordings (active and completed). **Returns**: - `ListRecordingsResponse` - List of all recordings. **Example**: ```python recordings = sandbox.computer_use.recording.list() print(f"Found {len(recordings.recordings)} recordings") for rec in recordings.recordings: print(f"- {rec.file_name}: {rec.status}") ``` #### RecordingService.get ```python @intercept_errors(message_prefix="Failed to get recording: ") @with_instrumentation() def get(recording_id: str) -> Recording ``` Gets details of a specific recording by ID. **Arguments**: - `recording_id` _str_ - The ID of the recording to retrieve. **Returns**: - `Recording` - Recording details. **Example**: ```python recording = sandbox.computer_use.recording.get(recording_id) print(f"Recording: {recording.file_name}") print(f"Status: {recording.status}") print(f"Duration: {recording.duration_seconds} seconds") ``` #### RecordingService.delete ```python @intercept_errors(message_prefix="Failed to delete recording: ") @with_instrumentation() def delete(recording_id: str) -> None ``` Deletes a recording by ID. **Arguments**: - `recording_id` _str_ - The ID of the recording to delete. **Example**: ```python sandbox.computer_use.recording.delete(recording_id) print("Recording deleted") ``` #### RecordingService.download ```python @intercept_errors(message_prefix="Failed to download recording: ") @with_instrumentation() def download(recording_id: str, local_path: str) -> None ``` Downloads a recording file from the Sandbox and saves it to a local file. The file is streamed directly to disk without loading the entire content into memory. **Arguments**: - `recording_id` _str_ - The ID of the recording to download. - `local_path` _str_ - Path to save the recording file locally. **Example**: ```python # Download recording to file sandbox.computer_use.recording.download(recording_id, "local_recording.mp4") print("Recording downloaded") ``` ## ScreenshotRegion ```python class ScreenshotRegion(BaseModel) ``` Region coordinates for screenshot operations. **Attributes**: - `x` _int_ - X coordinate of the region. - `y` _int_ - Y coordinate of the region. - `width` _int_ - Width of the region. - `height` _int_ - Height of the region. ## ScreenshotOptions ```python class ScreenshotOptions(BaseModel) ``` Options for screenshot compression and display. **Attributes**: - `show_cursor` _bool | None_ - Whether to show the cursor in the screenshot. - `fmt` _str | None_ - Image format (e.g., 'png', 'jpeg', 'webp'). - `quality` _int | None_ - Compression quality (0-100). - `scale` _float | None_ - Scale factor for the screenshot. ## Daytona ```python class Daytona() ``` Main class for interacting with the Daytona API. This class provides methods to create, manage, and interact with Daytona Sandboxes. It can be initialized either with explicit configuration or using environment variables. **Attributes**: - `volume` _VolumeService_ - Service for managing volumes. - `snapshot` _SnapshotService_ - Service for managing snapshots. **Example**: Using environment variables: ```python daytona = Daytona() # Uses DAYTONA_API_KEY, DAYTONA_API_URL sandbox = daytona.create() ``` Using explicit configuration: ```python config = DaytonaConfig( api_key="your-api-key", api_url="https://your-api.com", target="us" ) daytona = Daytona(config) sandbox = daytona.create() ``` Using OpenTelemetry tracing: ```python config = DaytonaConfig( api_key="your-api-key", experimental={"otelEnabled": True} # Enable OpenTelemetry tracing through experimental config ) async with Daytona(config) as daytona: sandbox = daytona.create() # All SDK operations will be traced # OpenTelemetry traces are flushed on close ``` #### Daytona.\_\_init\_\_ ```python def __init__(config: DaytonaConfig | None = None) ``` Initializes Daytona instance with optional configuration. If no config is provided, reads from environment variables: - `DAYTONA_API_KEY`: Required API key for authentication - `DAYTONA_API_URL`: Required api URL - `DAYTONA_TARGET`: Optional target environment (if not provided, default region for the organization is used) **Arguments**: - `config` _DaytonaConfig | None_ - Object containing api_key, api_url, and target. **Raises**: - `DaytonaError` - If API key is not provided either through config or environment variables **Example**: ```python from daytona import Daytona, DaytonaConfig # Using environment variables daytona1 = Daytona() # Using explicit configuration config = DaytonaConfig( api_key="your-api-key", api_url="https://your-api.com", target="us" ) daytona2 = Daytona(config) ``` #### Daytona.create ```python @overload def create(params: CreateSandboxFromSnapshotParams | None = None, *, timeout: float = 60) -> Sandbox ``` Creates Sandboxes from specified or default snapshot. You can specify various parameters, including language, image, environment variables, and volumes. **Arguments**: - `params` _CreateSandboxFromSnapshotParams | None_ - Parameters for Sandbox creation. If not provided, defaults to default Daytona snapshot and Python language. - `timeout` _float_ - Timeout (in seconds) for sandbox creation. 0 means no timeout. Default is 60 seconds. **Returns**: - `Sandbox` - The created Sandbox instance. **Raises**: - `DaytonaError` - If timeout, auto_stop_interval or auto_archive_interval is negative; If sandbox fails to start or times out **Example**: Create a default Python Sandbox: ```python sandbox = daytona.create() ``` Create a custom Sandbox: ```python params = CreateSandboxFromSnapshotParams( language="python", snapshot="my-snapshot-id", env_vars={"DEBUG": "true"}, auto_stop_interval=0, auto_archive_interval=60, auto_delete_interval=120 ) sandbox = daytona.create(params, timeout=40) ``` #### Daytona.create ```python @overload def create( params: CreateSandboxFromImageParams | None = None, *, timeout: float = 60, on_snapshot_create_logs: Callable[[str], None] | None = None ) -> Sandbox ``` Creates Sandboxes from specified image available on some registry or declarative Daytona Image. You can specify various parameters, including resources, language, image, environment variables, and volumes. Daytona creates snapshot from provided image and uses it to create Sandbox. **Arguments**: - `params` _CreateSandboxFromImageParams | None_ - Parameters for Sandbox creation from image. - `timeout` _float_ - Timeout (in seconds) for sandbox creation. 0 means no timeout. Default is 60 seconds. - `on_snapshot_create_logs` _Callable[[str], None] | None_ - This callback function handles snapshot creation logs. **Returns**: - `Sandbox` - The created Sandbox instance. **Raises**: - `DaytonaError` - If timeout, auto_stop_interval or auto_archive_interval is negative; If sandbox fails to start or times out **Example**: Create a default Python Sandbox from image: ```python sandbox = daytona.create(CreateSandboxFromImageParams(image="debian:12.9")) ``` Create a custom Sandbox from declarative Image definition: ```python declarative_image = ( Image.base("alpine:3.18") .pipInstall(["numpy", "pandas"]) .env({"MY_ENV_VAR": "My Environment Variable"}) ) params = CreateSandboxFromImageParams( language="python", image=declarative_image, env_vars={"DEBUG": "true"}, resources=Resources(cpu=2, memory=4), auto_stop_interval=0, auto_archive_interval=60, auto_delete_interval=120 ) sandbox = daytona.create( params, timeout=40, on_snapshot_create_logs=lambda chunk: print(chunk, end=""), ) ``` #### Daytona.delete ```python @with_instrumentation() def delete(sandbox: Sandbox, timeout: float = 60) -> None ``` Deletes a Sandbox. **Arguments**: - `sandbox` _Sandbox_ - The Sandbox instance to delete. - `timeout` _float_ - Timeout (in seconds) for sandbox deletion. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If sandbox fails to delete or times out **Example**: ```python sandbox = daytona.create() # ... use sandbox ... daytona.delete(sandbox) # Clean up when done ``` #### Daytona.get ```python @intercept_errors(message_prefix="Failed to get sandbox: ") @with_instrumentation() def get(sandbox_id_or_name: str) -> Sandbox ``` Gets a Sandbox by its ID or name. **Arguments**: - `sandbox_id_or_name` _str_ - The ID or name of the Sandbox to retrieve. **Returns**: - `Sandbox` - The Sandbox instance. **Raises**: - `DaytonaError` - If sandbox_id_or_name is not provided. **Example**: ```python sandbox = daytona.get("my-sandbox-id-or-name") print(sandbox.state) ``` #### Daytona.list ```python @intercept_errors(message_prefix="Failed to list sandboxes: ") @with_instrumentation() def list(labels: dict[str, str] | None = None, page: int | None = None, limit: int | None = None) -> PaginatedSandboxes ``` Returns paginated list of Sandboxes filtered by labels. **Arguments**: - `labels` _dict[str, str] | None_ - Labels to filter Sandboxes. - `page` _int | None_ - Page number for pagination (starting from 1). - `limit` _int | None_ - Maximum number of items per page. **Returns**: - `PaginatedSandboxes` - Paginated list of Sandbox instances that match the labels. **Example**: ```python result = daytona.list(labels={"my-label": "my-value"}, page=2, limit=10) for sandbox in result.items: print(f"{sandbox.id}: {sandbox.state}") ``` #### Daytona.start ```python @with_instrumentation() def start(sandbox: Sandbox, timeout: float = 60) -> None ``` Starts a Sandbox and waits for it to be ready. **Arguments**: - `sandbox` _Sandbox_ - The Sandbox to start. - `timeout` _float_ - Optional timeout in seconds to wait for the Sandbox to start. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If Sandbox fails to start or times out #### Daytona.stop ```python @with_instrumentation() def stop(sandbox: Sandbox, timeout: float = 60) -> None ``` Stops a Sandbox and waits for it to be stopped. **Arguments**: - `sandbox` _Sandbox_ - The sandbox to stop - `timeout` _float_ - Optional timeout (in seconds) for sandbox stop. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If Sandbox fails to stop or times out ## CodeLanguage ```python class CodeLanguage(str, Enum) ``` Programming languages supported by Daytona **Enum Members**: - `PYTHON` ("python") - `TYPESCRIPT` ("typescript") - `JAVASCRIPT` ("javascript") ## DaytonaConfig ```python class DaytonaConfig(BaseModel) ``` Configuration options for initializing the Daytona client. **Attributes**: - `api_key` _str | None_ - API key for authentication with the Daytona API. If not set, it must be provided via the environment variable `DAYTONA_API_KEY`, or a JWT token must be provided instead. - `jwt_token` _str | None_ - JWT token for authentication with the Daytona API. If not set, it must be provided via the environment variable `DAYTONA_JWT_TOKEN`, or an API key must be provided instead. - `organization_id` _str | None_ - Organization ID used for JWT-based authentication. Required if a JWT token is provided, and must be set either here or in the environment variable `DAYTONA_ORGANIZATION_ID`. - `api_url` _str | None_ - URL of the Daytona API. Defaults to `'https://app.daytona.io/api'` if not set here or in the environment variable `DAYTONA_API_URL`. - `server_url` _str | None_ - Deprecated. Use `api_url` instead. This property will be removed in a future version. - `target` _str | None_ - Target runner location for the Sandbox. Default region for the organization is used if not set here or in the environment variable `DAYTONA_TARGET`. - `_experimental` _dict[str, any] | None_ - Configuration for experimental features. **Example**: ```python config = DaytonaConfig(api_key="your-api-key") ``` ```python config = DaytonaConfig(jwt_token="your-jwt-token", organization_id="your-organization-id") ``` ## CreateSandboxBaseParams ```python class CreateSandboxBaseParams(BaseModel) ``` Base parameters for creating a new Sandbox. **Attributes**: - `name` _str | None_ - Name of the Sandbox. - `language` _CodeLanguage | CodeLanguageLiteral | None_ - Programming language for the Sandbox. Defaults to "python". - `os_user` _str | None_ - OS user for the Sandbox. - `env_vars` _dict[str, str] | None_ - Environment variables to set in the Sandbox. - `labels` _dict[str, str] | None_ - Custom labels for the Sandbox. - `public` _bool | None_ - Whether the Sandbox should be public. - `timeout` _float | None_ - Timeout in seconds for Sandbox to be created and started. - `auto_stop_interval` _int | None_ - Interval in minutes after which Sandbox will automatically stop if no Sandbox event occurs during that time. Default is 15 minutes. 0 means no auto-stop. - `auto_archive_interval` _int | None_ - Interval in minutes after which a continuously stopped Sandbox will automatically archive. Default is 7 days. 0 means the maximum interval will be used. - `auto_delete_interval` _int | None_ - Interval in minutes after which a continuously stopped Sandbox will automatically be deleted. By default, auto-delete is disabled. Negative value means disabled, 0 means delete immediately upon stopping. - `volumes` _list[VolumeMount] | None_ - List of volumes mounts to attach to the Sandbox. - `network_block_all` _bool | None_ - Whether to block all network access for the Sandbox. - `network_allow_list` _str | None_ - Comma-separated list of allowed CIDR network addresses for the Sandbox. - `ephemeral` _bool | None_ - Whether the Sandbox should be ephemeral. If True, auto_delete_interval will be set to 0. ## CreateSandboxFromImageParams ```python class CreateSandboxFromImageParams(CreateSandboxBaseParams) ``` Parameters for creating a new Sandbox from an image. **Attributes**: - `image` _str | Image_ - Custom Docker image to use for the Sandbox. If an Image object is provided, the image will be dynamically built. - `resources` _Resources | None_ - Resource configuration for the Sandbox. If not provided, sandbox will have default resources. ## CreateSandboxFromSnapshotParams ```python class CreateSandboxFromSnapshotParams(CreateSandboxBaseParams) ``` Parameters for creating a new Sandbox from a snapshot. **Attributes**: - `snapshot` _str | None_ - Name of the snapshot to use for the Sandbox. ## FileSystem ```python class FileSystem() ``` Provides file system operations within a Sandbox. This class implements a high-level interface to file system operations that can be performed within a Daytona Sandbox. #### FileSystem.\_\_init\_\_ ```python def __init__(api_client: FileSystemApi) ``` Initializes a new FileSystem instance. **Arguments**: - `api_client` _FileSystemApi_ - API client for Sandbox file system operations. #### FileSystem.create\_folder ```python @intercept_errors(message_prefix="Failed to create folder: ") @with_instrumentation() def create_folder(path: str, mode: str) -> None ``` Creates a new directory in the Sandbox at the specified path with the given permissions. **Arguments**: - `path` _str_ - Path where the folder should be created. Relative paths are resolved based on the sandbox working directory. - `mode` _str_ - Folder permissions in octal format (e.g., "755" for rwxr-xr-x). **Example**: ```python # Create a directory with standard permissions sandbox.fs.create_folder("workspace/data", "755") # Create a private directory sandbox.fs.create_folder("workspace/secrets", "700") ``` #### FileSystem.delete\_file ```python @intercept_errors(message_prefix="Failed to delete file: ") @with_instrumentation() def delete_file(path: str, recursive: bool = False) -> None ``` Deletes a file from the Sandbox. **Arguments**: - `path` _str_ - Path to the file to delete. Relative paths are resolved based on the sandbox working directory. - `recursive` _bool_ - If the file is a directory, this must be true to delete it. **Example**: ```python # Delete a file sandbox.fs.delete_file("workspace/data/old_file.txt") ``` #### FileSystem.download\_file ```python @overload def download_file(remote_path: str, timeout: int = 30 * 60) -> bytes ``` Downloads a file from the Sandbox. Returns the file contents as a bytes object. This method is useful when you want to load the file into memory without saving it to disk. It can only be used for smaller files. **Arguments**: - `remote_path` _str_ - Path to the file in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `timeout` _int_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `bytes` - The file contents as a bytes object. **Example**: ```python # Download and save a file locally content = sandbox.fs.download_file("workspace/data/file.txt") with open("local_copy.txt", "wb") as f: f.write(content) # Download and process text content content = sandbox.fs.download_file("workspace/data/config.json") config = json.loads(content.decode('utf-8')) ``` #### FileSystem.download\_file ```python @overload def download_file(remote_path: str, local_path: str, timeout: int = 30 * 60) -> None ``` Downloads a file from the Sandbox and saves it to a local file using stream. This method is useful when you want to download larger files that may not fit into memory. **Arguments**: - `remote_path` _str_ - Path to the file in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `local_path` _str_ - Path to save the file locally. - `timeout` _int_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python local_path = "local_copy.txt" sandbox.fs.download_file("tmp/large_file.txt", local_path) size_mb = os.path.getsize(local_path) / 1024 / 1024 print(f"Size of the downloaded file {local_path}: {size_mb} MB") ``` #### FileSystem.download\_files ```python @intercept_errors(message_prefix="Failed to download files: ") @with_instrumentation() def download_files(files: list[FileDownloadRequest], timeout: int = 30 * 60) -> list[FileDownloadResponse] ``` Downloads multiple files from the Sandbox. If the files already exist locally, they will be overwritten. **Arguments**: - `files` _list[FileDownloadRequest]_ - List of files to download. - `timeout` _int_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `list[FileDownloadResponse]` - List of download results. **Raises**: - `Exception` - Only if the request itself fails (network issues, invalid request/response, etc.). Individual file download errors are returned in the `FileDownloadResponse.error` field. **Example**: ```python # Download multiple files results = sandbox.fs.download_files([ FileDownloadRequest(source="tmp/data.json"), FileDownloadRequest(source="tmp/config.json", destination="local_config.json") ]) for result in results: if result.error: print(f"Error downloading {result.source}: {result.error}") elif result.result: print(f"Downloaded {result.source} to {result.result}") ``` #### FileSystem.find\_files ```python @intercept_errors(message_prefix="Failed to find files: ") @with_instrumentation() def find_files(path: str, pattern: str) -> list[Match] ``` Searches for files containing a pattern, similar to the grep command. **Arguments**: - `path` _str_ - Path to the file or directory to search. If the path is a directory, the search will be performed recursively. Relative paths are resolved based on the sandbox working directory. - `pattern` _str_ - Search pattern to match against file contents. **Returns**: - `list[Match]` - List of matches found in files. Each Match object includes: - file: Path to the file containing the match - line: The line number where the match was found - content: The matching line content **Example**: ```python # Search for TODOs in Python files matches = sandbox.fs.find_files("workspace/src", "TODO:") for match in matches: print(f"{match.file}:{match.line}: {match.content.strip()}") ``` #### FileSystem.get\_file\_info ```python @intercept_errors(message_prefix="Failed to get file info: ") @with_instrumentation() def get_file_info(path: str) -> FileInfo ``` Gets detailed information about a file or directory, including its size, permissions, and timestamps. **Arguments**: - `path` _str_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `FileInfo` - Detailed file information including: - name: File name - is_dir: Whether the path is a directory - size: File size in bytes - mode: File permissions - mod_time: Last modification timestamp - permissions: File permissions in octal format - owner: File owner - group: File group **Example**: ```python # Get file metadata info = sandbox.fs.get_file_info("workspace/data/file.txt") print(f"Size: {info.size} bytes") print(f"Modified: {info.mod_time}") print(f"Mode: {info.mode}") # Check if path is a directory info = sandbox.fs.get_file_info("workspace/data") if info.is_dir: print("Path is a directory") ``` #### FileSystem.list\_files ```python @intercept_errors(message_prefix="Failed to list files: ") @with_instrumentation() def list_files(path: str) -> list[FileInfo] ``` Lists files and directories in a given path and returns their information, similar to the ls -l command. **Arguments**: - `path` _str_ - Path to the directory to list contents from. Relative paths are resolved based on the sandbox working directory. **Returns**: - `list[FileInfo]` - List of file and directory information. Each FileInfo object includes the same fields as described in get_file_info(). **Example**: ```python # List directory contents files = sandbox.fs.list_files("workspace/data") # Print files and their sizes for file in files: if not file.is_dir: print(f"{file.name}: {file.size} bytes") # List only directories dirs = [f for f in files if f.is_dir] print("Subdirectories:", ", ".join(d.name for d in dirs)) ``` #### FileSystem.move\_files ```python @intercept_errors(message_prefix="Failed to move files: ") @with_instrumentation() def move_files(source: str, destination: str) -> None ``` Moves or renames a file or directory. The parent directory of the destination must exist. **Arguments**: - `source` _str_ - Path to the source file or directory. Relative paths are resolved based on the sandbox working directory. - `destination` _str_ - Path to the destination. Relative paths are resolved based on the sandbox working directory. **Example**: ```python # Rename a file sandbox.fs.move_files( "workspace/data/old_name.txt", "workspace/data/new_name.txt" ) # Move a file to a different directory sandbox.fs.move_files( "workspace/data/file.txt", "workspace/archive/file.txt" ) # Move a directory sandbox.fs.move_files( "workspace/old_dir", "workspace/new_dir" ) ``` #### FileSystem.replace\_in\_files ```python @intercept_errors(message_prefix="Failed to replace in files: ") @with_instrumentation() def replace_in_files(files: list[str], pattern: str, new_value: str) -> list[ReplaceResult] ``` Performs search and replace operations across multiple files. **Arguments**: - `files` _list[str]_ - List of file paths to perform replacements in. Relative paths are resolved based on the sandbox working directory. - `pattern` _str_ - Pattern to search for. - `new_value` _str_ - Text to replace matches with. **Returns**: - `list[ReplaceResult]` - List of results indicating replacements made in each file. Each ReplaceResult includes: - file: Path to the modified file - success: Whether the operation was successful - error: Error message if the operation failed **Example**: ```python # Replace in specific files results = sandbox.fs.replace_in_files( files=["workspace/src/file1.py", "workspace/src/file2.py"], pattern="old_function", new_value="new_function" ) # Print results for result in results: if result.success: print(f"{result.file}: {result.success}") else: print(f"{result.file}: {result.error}") ``` #### FileSystem.search\_files ```python @intercept_errors(message_prefix="Failed to search files: ") @with_instrumentation() def search_files(path: str, pattern: str) -> SearchFilesResponse ``` Searches for files and directories whose names match the specified pattern. The pattern can be a simple string or a glob pattern. **Arguments**: - `path` _str_ - Path to the root directory to start search from. Relative paths are resolved based on the sandbox working directory. - `pattern` _str_ - Pattern to match against file names. Supports glob patterns (e.g., "*.py" for Python files). **Returns**: - `SearchFilesResponse` - Search results containing: - files: List of matching file and directory paths **Example**: ```python # Find all Python files result = sandbox.fs.search_files("workspace", "*.py") for file in result.files: print(file) # Find files with specific prefix result = sandbox.fs.search_files("workspace/data", "test_*") print(f"Found {len(result.files)} test files") ``` #### FileSystem.set\_file\_permissions ```python @intercept_errors(message_prefix="Failed to set file permissions: ") @with_instrumentation() def set_file_permissions(path: str, mode: str | None = None, owner: str | None = None, group: str | None = None) -> None ``` Sets permissions and ownership for a file or directory. Any of the parameters can be None to leave that attribute unchanged. **Arguments**: - `path` _str_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. - `mode` _str | None_ - File mode/permissions in octal format (e.g., "644" for rw-r--r--). - `owner` _str | None_ - User owner of the file. - `group` _str | None_ - Group owner of the file. **Example**: ```python # Make a file executable sandbox.fs.set_file_permissions( path="workspace/scripts/run.sh", mode="755" # rwxr-xr-x ) # Change file owner sandbox.fs.set_file_permissions( path="workspace/data/file.txt", owner="daytona", group="daytona" ) ``` #### FileSystem.upload\_file ```python @overload def upload_file(file: bytes, remote_path: str, timeout: int = 30 * 60) -> None ``` Uploads a file to the specified path in the Sandbox. If a file already exists at the destination path, it will be overwritten. This method is useful when you want to upload small files that fit into memory. **Arguments**: - `file` _bytes_ - File contents as a bytes object. - `remote_path` _str_ - Path to the destination file. Relative paths are resolved based on the sandbox working directory. - `timeout` _int_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python # Upload a text file content = b"Hello, World!" sandbox.fs.upload_file(content, "tmp/hello.txt") # Upload a local file with open("local_file.txt", "rb") as f: content = f.read() sandbox.fs.upload_file(content, "tmp/file.txt") # Upload binary data import json data = {"key": "value"} content = json.dumps(data).encode('utf-8') sandbox.fs.upload_file(content, "tmp/config.json") ``` #### FileSystem.upload\_file ```python @overload def upload_file(local_path: str, remote_path: str, timeout: int = 30 * 60) -> None ``` Uploads a file from the local file system to the specified path in the Sandbox. If a file already exists at the destination path, it will be overwritten. This method uses streaming to upload the file, so it is useful when you want to upload larger files that may not fit into memory. **Arguments**: - `local_path` _str_ - Path to the local file to upload. - `remote_path` _str_ - Path to the destination file in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `timeout` _int_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python sandbox.fs.upload_file("local_file.txt", "tmp/large_file.txt") ``` #### FileSystem.upload\_files ```python @intercept_errors(message_prefix="Failed to upload files: ") @with_instrumentation() def upload_files(files: list[FileUpload], timeout: int = 30 * 60) -> None ``` Uploads multiple files to the Sandbox. If files already exist at the destination paths, they will be overwritten. **Arguments**: - `files` _list[FileUpload]_ - List of files to upload. - `timeout` _int_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Example**: ```python # Upload multiple text files files = [ FileUpload( source=b"Content of file 1", destination="/tmp/file1.txt" ), FileUpload( source="workspace/data/file2.txt", destination="/tmp/file2.txt" ), FileUpload( source=b'{"key": "value"}', destination="/tmp/config.json" ) ] sandbox.fs.upload_files(files) ``` ## FileUpload ```python @dataclass class FileUpload() ``` Represents a file to be uploaded to the Sandbox. **Attributes**: - `source` _bytes | str_ - File contents as a bytes object or a local file path. If a bytes object is provided, make sure it fits into memory, otherwise use the local file path which content will be streamed to the Sandbox. - `destination` _str_ - Absolute destination path in the Sandbox. Relative paths are resolved based on the sandbox working directory. ## FileDownloadRequest ```python @dataclass class FileDownloadRequest() ``` Represents a request to download a single file from the Sandbox. **Attributes**: - `source` _str_ - Source path in the Sandbox. Relative paths are resolved based on the user's root directory. - `destination` _str | None_ - Destination path in the local filesystem where the file content will be streamed to. If not provided, the file will be downloaded in the bytes buffer (might cause memory issues if the file is large). ## FileDownloadResponse ```python @dataclass class FileDownloadResponse() ``` Represents the response to a single file download request. **Attributes**: - `source` _str_ - The original source path requested for download. - `result` _str | bytes | None_ - The download result - file path (if destination provided in the request) or bytes content (if no destination in the request), None if failed or no data received. - `error` _str | None_ - Error message if the download failed, None if successful. ## Git ```python class Git() ``` Provides Git operations within a Sandbox. **Example**: ```python # Clone a repository sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo" ) # Check repository status status = sandbox.git.status("workspace/repo") print(f"Modified files: {status.modified}") # Stage and commit changes sandbox.git.add("workspace/repo", ["file.txt"]) sandbox.git.commit( path="workspace/repo", message="Update file", author="John Doe", email="john@example.com" ) ``` #### Git.\_\_init\_\_ ```python def __init__(api_client: GitApi) ``` Initializes a new Git handler instance. **Arguments**: - `api_client` _GitApi_ - API client for Sandbox Git operations. #### Git.add ```python @intercept_errors(message_prefix="Failed to add files: ") @with_instrumentation() def add(path: str, files: list[str]) -> None ``` Stages the specified files for the next commit, similar to running 'git add' on the command line. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `files` _list[str]_ - List of file paths or directories to stage, relative to the repository root. **Example**: ```python # Stage a single file sandbox.git.add("workspace/repo", ["file.txt"]) # Stage multiple files sandbox.git.add("workspace/repo", [ "src/main.py", "tests/test_main.py", "README.md" ]) ``` #### Git.branches ```python @intercept_errors(message_prefix="Failed to list branches: ") @with_instrumentation() def branches(path: str) -> ListBranchResponse ``` Lists branches in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `ListBranchResponse` - List of branches in the repository. **Example**: ```python response = sandbox.git.branches("workspace/repo") print(f"Branches: {response.branches}") ``` #### Git.clone ```python @intercept_errors(message_prefix="Failed to clone repository: ") @with_instrumentation() def clone(url: str, path: str, branch: str | None = None, commit_id: str | None = None, username: str | None = None, password: str | None = None) -> None ``` Clones a Git repository into the specified path. It supports cloning specific branches or commits, and can authenticate with the remote repository if credentials are provided. **Arguments**: - `url` _str_ - Repository URL to clone from. - `path` _str_ - Path where the repository should be cloned. Relative paths are resolved based on the sandbox working directory. - `branch` _str | None_ - Specific branch to clone. If not specified, clones the default branch. - `commit_id` _str | None_ - Specific commit to clone. If specified, the repository will be left in a detached HEAD state at this commit. - `username` _str | None_ - Git username for authentication. - `password` _str | None_ - Git password or token for authentication. **Example**: ```python # Clone the default branch sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo" ) # Clone a specific branch with authentication sandbox.git.clone( url="https://github.com/user/private-repo.git", path="workspace/private", branch="develop", username="user", password="token" ) # Clone a specific commit sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo-old", commit_id="abc123" ) ``` #### Git.commit ```python @intercept_errors(message_prefix="Failed to commit changes: ") @with_instrumentation() def commit(path: str, message: str, author: str, email: str, allow_empty: bool = False) -> GitCommitResponse ``` Creates a new commit with the staged changes. Make sure to stage changes using the add() method before committing. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `message` _str_ - Commit message describing the changes. - `author` _str_ - Name of the commit author. - `email` _str_ - Email address of the commit author. - `allow_empty` _bool, optional_ - Allow creating an empty commit when no changes are staged. Defaults to False. **Example**: ```python # Stage and commit changes sandbox.git.add("workspace/repo", ["README.md"]) sandbox.git.commit( path="workspace/repo", message="Update documentation", author="John Doe", email="john@example.com", allow_empty=True ) ``` #### Git.push ```python @intercept_errors(message_prefix="Failed to push changes: ") @with_instrumentation() def push(path: str, username: str | None = None, password: str | None = None) -> None ``` Pushes all local commits on the current branch to the remote repository. If the remote repository requires authentication, provide username and password/token. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username` _str | None_ - Git username for authentication. - `password` _str | None_ - Git password or token for authentication. **Example**: ```python # Push without authentication (for public repos or SSH) sandbox.git.push("workspace/repo") # Push with authentication sandbox.git.push( path="workspace/repo", username="user", password="github_token" ) ``` #### Git.pull ```python @intercept_errors(message_prefix="Failed to pull changes: ") @with_instrumentation() def pull(path: str, username: str | None = None, password: str | None = None) -> None ``` Pulls changes from the remote repository. If the remote repository requires authentication, provide username and password/token. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username` _str | None_ - Git username for authentication. - `password` _str | None_ - Git password or token for authentication. **Example**: ```python # Pull without authentication sandbox.git.pull("workspace/repo") # Pull with authentication sandbox.git.pull( path="workspace/repo", username="user", password="github_token" ) ``` #### Git.status ```python @intercept_errors(message_prefix="Failed to get status: ") @with_instrumentation() def status(path: str) -> GitStatus ``` Gets the current Git repository status. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `GitStatus` - Repository status information including: - current_branch: Current branch name - file_status: List of file statuses - ahead: Number of local commits not pushed to remote - behind: Number of remote commits not pulled locally - branch_published: Whether the branch has been published to the remote repository **Example**: ```python status = sandbox.git.status("workspace/repo") print(f"On branch: {status.current_branch}") print(f"Commits ahead: {status.ahead}") print(f"Commits behind: {status.behind}") ``` #### Git.checkout\_branch ```python @intercept_errors(message_prefix="Failed to checkout branch: ") @with_instrumentation() def checkout_branch(path: str, branch: str) -> None ``` Checkout branch in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `branch` _str_ - Name of the branch to checkout **Example**: ```python # Checkout a branch sandbox.git.checkout_branch("workspace/repo", "feature-branch") ``` #### Git.create\_branch ```python @intercept_errors(message_prefix="Failed to create branch: ") @with_instrumentation() def create_branch(path: str, name: str) -> None ``` Create branch in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _str_ - Name of the new branch to create **Example**: ```python # Create a new branch sandbox.git.create_branch("workspace/repo", "new-feature") ``` #### Git.delete\_branch ```python @intercept_errors(message_prefix="Failed to delete branch: ") @with_instrumentation() def delete_branch(path: str, name: str) -> None ``` Delete branch in the repository. **Arguments**: - `path` _str_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _str_ - Name of the branch to delete **Example**: ```python # Delete a branch sandbox.git.delete_branch("workspace/repo", "old-feature") ``` ## GitCommitResponse ```python class GitCommitResponse() ``` Response from the git commit. **Attributes**: - `sha` _str_ - The SHA of the commit ## LspServer ```python class LspServer() ``` Provides Language Server Protocol functionality for code intelligence to provide IDE-like features such as code completion, symbol search, and more. #### LspServer.\_\_init\_\_ ```python def __init__(language_id: LspLanguageId | LspLanguageIdLiteral, path_to_project: str, api_client: LspApi) ``` Initializes a new LSP server instance. **Arguments**: - `language_id` _LspLanguageId | LspLanguageIdLiteral_ - The language server type (e.g., LspLanguageId.TYPESCRIPT). - `path_to_project` _str_ - Absolute path to the project root directory. - `api_client` _LspApi_ - API client for Sandbox operations. #### LspServer.start ```python @intercept_errors(message_prefix="Failed to start LSP server: ") @with_instrumentation() def start() -> None ``` Starts the language server. This method must be called before using any other LSP functionality. It initializes the language server for the specified language and project. **Example**: ```python lsp = sandbox.create_lsp_server("typescript", "workspace/project") lsp.start() # Initialize the server # Now ready for LSP operations ``` #### LspServer.stop ```python @intercept_errors(message_prefix="Failed to stop LSP server: ") @with_instrumentation() def stop() -> None ``` Stops the language server. This method should be called when the LSP server is no longer needed to free up system resources. **Example**: ```python # When done with LSP features lsp.stop() # Clean up resources ``` #### LspServer.did\_open ```python @intercept_errors(message_prefix="Failed to open file: ") @with_instrumentation() def did_open(path: str) -> None ``` Notifies the language server that a file has been opened. This method should be called when a file is opened in the editor to enable language features like diagnostics and completions for that file. The server will begin tracking the file's contents and providing language features. **Arguments**: - `path` _str_ - Path to the opened file. Relative paths are resolved based on the project path set in the LSP server constructor. **Example**: ```python # When opening a file for editing lsp.did_open("workspace/project/src/index.ts") # Now can get completions, symbols, etc. for this file ``` #### LspServer.did\_close ```python @intercept_errors(message_prefix="Failed to close file: ") @with_instrumentation() def did_close(path: str) -> None ``` Notify the language server that a file has been closed. This method should be called when a file is closed in the editor to allow the language server to clean up any resources associated with that file. **Arguments**: - `path` _str_ - Path to the closed file. Relative paths are resolved based on the project path set in the LSP server constructor. **Example**: ```python # When done editing a file lsp.did_close("workspace/project/src/index.ts") ``` #### LspServer.document\_symbols ```python @intercept_errors(message_prefix="Failed to get symbols from document: ") @with_instrumentation() def document_symbols(path: str) -> list[LspSymbol] ``` Gets symbol information (functions, classes, variables, etc.) from a document. **Arguments**: - `path` _str_ - Path to the file to get symbols from. Relative paths are resolved based on the project path set in the LSP server constructor. **Returns**: - `list[LspSymbol]` - List of symbols in the document. Each symbol includes: - name: The symbol's name - kind: The symbol's kind (function, class, variable, etc.) - location: The location of the symbol in the file **Example**: ```python # Get all symbols in a file symbols = lsp.document_symbols("workspace/project/src/index.ts") for symbol in symbols: print(f"{symbol.kind} {symbol.name}: {symbol.location}") ``` #### LspServer.workspace\_symbols ```python @deprecated( reason= "Method is deprecated. Use `sandbox_symbols` instead. This method will be removed in a future version." ) @with_instrumentation() def workspace_symbols(query: str) -> list[LspSymbol] ``` Searches for symbols matching the query string across all files in the Sandbox. **Arguments**: - `query` _str_ - Search query to match against symbol names. **Returns**: - `list[LspSymbol]` - List of matching symbols from all files. #### LspServer.sandbox\_symbols ```python @intercept_errors(message_prefix="Failed to get symbols from sandbox: ") @with_instrumentation() def sandbox_symbols(query: str) -> list[LspSymbol] ``` Searches for symbols matching the query string across all files in the Sandbox. **Arguments**: - `query` _str_ - Search query to match against symbol names. **Returns**: - `list[LspSymbol]` - List of matching symbols from all files. Each symbol includes: - name: The symbol's name - kind: The symbol's kind (function, class, variable, etc.) - location: The location of the symbol in the file **Example**: ```python # Search for all symbols containing "User" symbols = lsp.sandbox_symbols("User") for symbol in symbols: print(f"{symbol.name} in {symbol.location}") ``` #### LspServer.completions ```python @intercept_errors(message_prefix="Failed to get completions: ") @with_instrumentation() def completions(path: str, position: LspCompletionPosition) -> CompletionList ``` Gets completion suggestions at a position in a file. **Arguments**: - `path` _str_ - Path to the file. Relative paths are resolved based on the project path set in the LSP server constructor. - `position` _LspCompletionPosition_ - Cursor position to get completions for. **Returns**: - `CompletionList` - List of completion suggestions. The list includes: - isIncomplete: Whether more items might be available - items: List of completion items, each containing: - label: The text to insert - kind: The kind of completion - detail: Additional details about the item - documentation: Documentation for the item - sortText: Text used to sort the item in the list - filterText: Text used to filter the item - insertText: The actual text to insert (if different from label) **Example**: ```python # Get completions at a specific position pos = LspCompletionPosition(line=10, character=15) completions = lsp.completions("workspace/project/src/index.ts", pos) for item in completions.items: print(f"{item.label} ({item.kind}): {item.detail}") ``` ## LspLanguageId ```python class LspLanguageId(str, Enum) ``` Language IDs for Language Server Protocol (LSP). **Enum Members**: - `PYTHON` ("python") - `TYPESCRIPT` ("typescript") - `JAVASCRIPT` ("javascript") ## LspCompletionPosition ```python @dataclass class LspCompletionPosition() ``` Represents a zero-based completion position in a text document, specified by line number and character offset. **Attributes**: - `line` _int_ - Zero-based line number in the document. - `character` _int_ - Zero-based character offset on the line. ## ObjectStorage ```python class ObjectStorage() ``` ObjectStorage class for interacting with object storage services. **Attributes**: - `endpoint_url` _str_ - The endpoint URL for the object storage service. - `aws_access_key_id` _str_ - The access key ID for the object storage service. - `aws_secret_access_key` _str_ - The secret access key for the object storage service. - `aws_session_token` _str_ - The session token for the object storage service. Used for temporary credentials. - `bucket_name` _str_ - The name of the bucket to use. Defaults to "daytona-volume-builds". #### ObjectStorage.upload ```python @with_instrumentation() def upload(path: str, organization_id: str, archive_base_path: str | None = None) -> str ``` Uploads a file to the object storage service. **Arguments**: - `path` _str_ - The path to the file to upload. - `organization_id` _str_ - The organization ID to use. - `archive_base_path` _str_ - The base path to use for the archive. **Returns**: - `str` - The hash of the uploaded file. ## Process ```python class Process() ``` Handles process and code execution within a Sandbox. #### Process.\_\_init\_\_ ```python def __init__(code_toolbox: SandboxCodeToolbox, api_client: ProcessApi) ``` Initialize a new Process instance. **Arguments**: - `code_toolbox` _SandboxCodeToolbox_ - Language-specific code execution toolbox. - `api_client` _ProcessApi_ - API client for process operations. #### Process.exec ```python @intercept_errors(message_prefix="Failed to execute command: ") @with_instrumentation() def exec(command: str, cwd: str | None = None, env: dict[str, str] | None = None, timeout: int | None = None) -> ExecuteResponse ``` Execute a shell command in the Sandbox. **Arguments**: - `command` _str_ - Shell command to execute. - `cwd` _str | None_ - Working directory for command execution. If not specified, uses the sandbox working directory. - `env` _dict[str, str] | None_ - Environment variables to set for the command. - `timeout` _int | None_ - Maximum time in seconds to wait for the command to complete. 0 means wait indefinitely. **Returns**: - `ExecuteResponse` - Command execution results containing: - exit_code: The command's exit status - result: Standard output from the command - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) **Example**: ```python # Simple command response = sandbox.process.exec("echo 'Hello'") print(response.artifacts.stdout) # Prints: Hello # Command with working directory result = sandbox.process.exec("ls", cwd="workspace/src") # Command with timeout result = sandbox.process.exec("sleep 10", timeout=5) ``` #### Process.code\_run ```python @with_instrumentation() def code_run(code: str, params: CodeRunParams | None = None, timeout: int | None = None) -> ExecuteResponse ``` Executes code in the Sandbox using the appropriate language runtime. **Arguments**: - `code` _str_ - Code to execute. - `params` _CodeRunParams | None_ - Parameters for code execution. - `timeout` _int | None_ - Maximum time in seconds to wait for the code to complete. 0 means wait indefinitely. **Returns**: - `ExecuteResponse` - Code execution result containing: - exit_code: The execution's exit status - result: Standard output from the code - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) **Example**: ```python # Run Python code response = sandbox.process.code_run(''' x = 10 y = 20 print(f"Sum: {x + y}") ''') print(response.artifacts.stdout) # Prints: Sum: 30 ``` Matplotlib charts are automatically detected and returned in the `charts` field of the `ExecutionArtifacts` object. ```python code = ''' import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 10, 30) y = np.sin(x) plt.figure(figsize=(8, 5)) plt.plot(x, y, 'b-', linewidth=2) plt.title('Line Chart') plt.xlabel('X-axis (seconds)') plt.ylabel('Y-axis (amplitude)') plt.grid(True) plt.show() ''' response = sandbox.process.code_run(code) chart = response.artifacts.charts[0] print(f"Type: {chart.type}") print(f"Title: {chart.title}") if chart.type == ChartType.LINE and isinstance(chart, LineChart): print(f"X Label: {chart.x_label}") print(f"Y Label: {chart.y_label}") print(f"X Ticks: {chart.x_ticks}") print(f"X Tick Labels: {chart.x_tick_labels}") print(f"X Scale: {chart.x_scale}") print(f"Y Ticks: {chart.y_ticks}") print(f"Y Tick Labels: {chart.y_tick_labels}") print(f"Y Scale: {chart.y_scale}") print("Elements:") for element in chart.elements: print(f"Label: {element.label}") print(f"Points: {element.points}") ``` #### Process.create\_session ```python @intercept_errors(message_prefix="Failed to create session: ") @with_instrumentation() def create_session(session_id: str) -> None ``` Creates a new long-running background session in the Sandbox. Sessions are background processes that maintain state between commands, making them ideal for scenarios requiring multiple related commands or persistent environment setup. You can run long-running commands and monitor process status. **Arguments**: - `session_id` _str_ - Unique identifier for the new session. **Example**: ```python # Create a new session session_id = "my-session" sandbox.process.create_session(session_id) session = sandbox.process.get_session(session_id) # Do work... sandbox.process.delete_session(session_id) ``` #### Process.get\_session ```python @intercept_errors(message_prefix="Failed to get session: ") def get_session(session_id: str) -> Session ``` Gets a session in the Sandbox. **Arguments**: - `session_id` _str_ - Unique identifier of the session to retrieve. **Returns**: - `Session` - Session information including: - session_id: The session's unique identifier - commands: List of commands executed in the session **Example**: ```python session = sandbox.process.get_session("my-session") for cmd in session.commands: print(f"Command: {cmd.command}") ``` #### Process.get\_entrypoint\_session ```python @intercept_errors(message_prefix="Failed to get sandbox entrypoint session: ") def get_entrypoint_session() -> Session ``` Gets the sandbox entrypoint session. **Returns**: - `Session` - Entrypoint session information including: - session_id: The entrypoint session's unique identifier - commands: List of commands executed in the entrypoint session **Example**: ```python session = sandbox.process.get_entrypoint_session() for cmd in session.commands: print(f"Command: {cmd.command}") ``` #### Process.get\_session\_command ```python @intercept_errors(message_prefix="Failed to get session command: ") @with_instrumentation() def get_session_command(session_id: str, command_id: str) -> Command ``` Gets information about a specific command executed in a session. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. **Returns**: - `Command` - Command information including: - id: The command's unique identifier - command: The executed command string - exit_code: Command's exit status (if completed) **Example**: ```python cmd = sandbox.process.get_session_command("my-session", "cmd-123") if cmd.exit_code == 0: print(f"Command {cmd.command} completed successfully") ``` #### Process.execute\_session\_command ```python @intercept_errors(message_prefix="Failed to execute session command: ") @with_instrumentation() def execute_session_command( session_id: str, req: SessionExecuteRequest, timeout: int | None = None) -> SessionExecuteResponse ``` Executes a command in the session. **Arguments**: - `session_id` _str_ - Unique identifier of the session to use. - `req` _SessionExecuteRequest_ - Command execution request containing: - command: The command to execute - run_async: Whether to execute asynchronously **Returns**: - `SessionExecuteResponse` - Command execution results containing: - cmd_id: Unique identifier for the executed command - output: Combined command output (stdout and stderr) (if synchronous execution) - stdout: Standard output from the command - stderr: Standard error from the command - exit_code: Command exit status (if synchronous execution) **Example**: ```python # Execute commands in sequence, maintaining state session_id = "my-session" # Change directory req = SessionExecuteRequest(command="cd /workspace") sandbox.process.execute_session_command(session_id, req) # Create a file req = SessionExecuteRequest(command="echo 'Hello' > test.txt") sandbox.process.execute_session_command(session_id, req) # Read the file req = SessionExecuteRequest(command="cat test.txt") result = sandbox.process.execute_session_command(session_id, req) print(f"Command stdout: {result.stdout}") print(f"Command stderr: {result.stderr}") ``` #### Process.get\_session\_command\_logs ```python @intercept_errors(message_prefix="Failed to get session command logs: ") @with_instrumentation() def get_session_command_logs(session_id: str, command_id: str) -> SessionCommandLogsResponse ``` Get the logs for a command executed in a session. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. **Returns**: - `SessionCommandLogsResponse` - Command logs including: - output: Combined command output (stdout and stderr) - stdout: Standard output from the command - stderr: Standard error from the command **Example**: ```python logs = sandbox.process.get_session_command_logs( "my-session", "cmd-123" ) print(f"Command stdout: {logs.stdout}") print(f"Command stderr: {logs.stderr}") ``` #### Process.get\_session\_command\_logs\_async ```python @intercept_errors(message_prefix="Failed to get session command logs: ") async def get_session_command_logs_async( session_id: str, command_id: str, on_stdout: OutputHandler[str], on_stderr: OutputHandler[str]) -> None ``` Asynchronously retrieves and processes the logs for a command executed in a session as they become available. Accepts both sync and async callbacks. Async callbacks are awaited. Blocking synchronous operations inside callbacks may cause WebSocket disconnections — use async callbacks and async libraries to avoid this. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. - `on_stdout` _OutputHandler[str]_ - Callback function to handle stdout log chunks as they arrive. - `on_stderr` _OutputHandler[str]_ - Callback function to handle stderr log chunks as they arrive. **Example**: ```python await sandbox.process.get_session_command_logs_async( "my-session", "cmd-123", lambda log: print(f"[STDOUT]: {log}"), lambda log: print(f"[STDERR]: {log}"), ) ``` #### Process.get\_entrypoint\_logs ```python @intercept_errors(message_prefix="Failed to get entrypoint logs: ") @with_instrumentation() def get_entrypoint_logs() -> SessionCommandLogsResponse ``` Get the logs for the entrypoint session. **Returns**: - `SessionCommandLogsResponse` - Command logs including: - output: Combined command output (stdout and stderr) - stdout: Standard output from the command - stderr: Standard error from the command **Example**: ```python logs = sandbox.process.get_entrypoint_logs() print(f"Command stdout: {logs.stdout}") print(f"Command stderr: {logs.stderr}") ``` #### Process.get\_entrypoint\_logs\_async ```python @intercept_errors(message_prefix="Failed to get entrypoint logs: ") async def get_entrypoint_logs_async(on_stdout: OutputHandler[str], on_stderr: OutputHandler[str]) -> None ``` Asynchronously retrieves and processes the logs for the entrypoint session as they become available. **Arguments**: on_stdout OutputHandler[str]: Callback function to handle stdout log chunks as they arrive. on_stderr OutputHandler[str]: Callback function to handle stderr log chunks as they arrive. **Example**: ```python await sandbox.process.get_entrypoint_logs_async( lambda log: print(f"[STDOUT]: {log}"), lambda log: print(f"[STDERR]: {log}"), ) ``` #### Process.send\_session\_command\_input ```python @intercept_errors(message_prefix="Failed to send session command input: ") def send_session_command_input(session_id: str, command_id: str, data: str) -> None ``` Sends input data to a command executed in a session. **Arguments**: - `session_id` _str_ - Unique identifier of the session. - `command_id` _str_ - Unique identifier of the command. - `data` _str_ - Input data to send. #### Process.list\_sessions ```python @intercept_errors(message_prefix="Failed to list sessions: ") @with_instrumentation() def list_sessions() -> list[Session] ``` Lists all sessions in the Sandbox. **Returns**: - `list[Session]` - List of all sessions in the Sandbox. **Example**: ```python sessions = sandbox.process.list_sessions() for session in sessions: print(f"Session {session.session_id}:") print(f" Commands: {len(session.commands)}") ``` #### Process.delete\_session ```python @intercept_errors(message_prefix="Failed to delete session: ") @with_instrumentation() def delete_session(session_id: str) -> None ``` Terminates and removes a session from the Sandbox, cleaning up any resources associated with it. **Arguments**: - `session_id` _str_ - Unique identifier of the session to delete. **Example**: ```python # Create and use a session sandbox.process.create_session("temp-session") # ... use the session ... # Clean up when done sandbox.process.delete_session("temp-session") ``` #### Process.create\_pty\_session ```python @intercept_errors(message_prefix="Failed to create PTY session: ") @with_instrumentation() def create_pty_session(id: str, cwd: str | None = None, envs: dict[str, str] | None = None, pty_size: PtySize | None = None) -> PtyHandle ``` Creates a new PTY (pseudo-terminal) session in the Sandbox. Creates an interactive terminal session that can execute commands and handle user input. The PTY session behaves like a real terminal, supporting features like command history. **Arguments**: - `id` - Unique identifier for the PTY session. Must be unique within the Sandbox. - `cwd` - Working directory for the PTY session. Defaults to the sandbox's working directory. - `env` - Environment variables to set in the PTY session. These will be merged with the Sandbox's default environment variables. - `pty_size` - Terminal size configuration. Defaults to 80x24 if not specified. **Returns**: - `PtyHandle` - Handle for managing the created PTY session. Use this to send input, receive output, resize the terminal, and manage the session lifecycle. **Raises**: - `DaytonaError` - If the PTY session creation fails or the session ID is already in use. #### Process.connect\_pty\_session ```python @intercept_errors(message_prefix="Failed to connect PTY session: ") @with_instrumentation() def connect_pty_session(session_id: str) -> PtyHandle ``` Connects to an existing PTY session in the Sandbox. Establishes a WebSocket connection to an existing PTY session, allowing you to interact with a previously created terminal session. **Arguments**: - `session_id` - Unique identifier of the PTY session to connect to. **Returns**: - `PtyHandle` - Handle for managing the connected PTY session. **Raises**: - `DaytonaError` - If the PTY session doesn't exist or connection fails. #### Process.list\_pty\_sessions ```python @intercept_errors(message_prefix="Failed to list PTY sessions: ") @with_instrumentation() def list_pty_sessions() -> list[PtySessionInfo] ``` Lists all PTY sessions in the Sandbox. Retrieves information about all PTY sessions in this Sandbox. **Returns**: - `list[PtySessionInfo]` - List of PTY session information objects containing details about each session's state, creation time, and configuration. **Example**: ```python # List all PTY sessions sessions = sandbox.process.list_pty_sessions() for session in sessions: print(f"Session ID: {session.id}") print(f"Active: {session.active}") print(f"Created: {session.created_at}") ``` #### Process.get\_pty\_session\_info ```python @intercept_errors(message_prefix="Failed to get PTY session info: ") @with_instrumentation() def get_pty_session_info(session_id: str) -> PtySessionInfo ``` Gets detailed information about a specific PTY session. Retrieves comprehensive information about a PTY session including its current state, configuration, and metadata. **Arguments**: - `session_id` - Unique identifier of the PTY session to retrieve information for. **Returns**: - `PtySessionInfo` - Detailed information about the PTY session including ID, state, creation time, working directory, environment variables, and more. **Raises**: - `DaytonaError` - If the PTY session doesn't exist. **Example**: ```python # Get details about a specific PTY session session_info = sandbox.process.get_pty_session_info("my-session") print(f"Session ID: {session_info.id}") print(f"Active: {session_info.active}") print(f"Working Directory: {session_info.cwd}") print(f"Terminal Size: {session_info.cols}x{session_info.rows}") ``` #### Process.kill\_pty\_session ```python @intercept_errors(message_prefix="Failed to kill PTY session: ") @with_instrumentation() def kill_pty_session(session_id: str) -> None ``` Kills a PTY session and terminates its associated process. Forcefully terminates the PTY session and cleans up all associated resources. This will close any active connections and kill the underlying shell process. This operation is irreversible. Any unsaved work in the terminal session will be lost. **Arguments**: - `session_id` - Unique identifier of the PTY session to kill. **Raises**: - `DaytonaError` - If the PTY session doesn't exist or cannot be killed. **Example**: ```python # Kill a specific PTY session sandbox.process.kill_pty_session("my-session") # Verify the session no longer exists pty_sessions = sandbox.process.list_pty_sessions() for pty_session in pty_sessions: print(f"PTY session: {pty_session.id}") ``` #### Process.resize\_pty\_session ```python @intercept_errors(message_prefix="Failed to resize PTY session: ") @with_instrumentation() def resize_pty_session(session_id: str, pty_size: PtySize) -> PtySessionInfo ``` Resizes a PTY session's terminal dimensions. Changes the terminal size of an active PTY session. This is useful when the client terminal is resized or when you need to adjust the display for different output requirements. **Arguments**: - `session_id` - Unique identifier of the PTY session to resize. - `pty_size` - New terminal dimensions containing the desired columns and rows. **Returns**: - `PtySessionInfo` - Updated session information reflecting the new terminal size. **Raises**: - `DaytonaError` - If the PTY session doesn't exist or resize operation fails. **Example**: ```python from daytona.common.pty import PtySize # Resize a PTY session to a larger terminal new_size = PtySize(rows=40, cols=150) updated_info = sandbox.process.resize_pty_session("my-session", new_size) print(f"Terminal resized to {updated_info.cols}x{updated_info.rows}") # You can also use the PtyHandle's resize method pty_handle.resize(new_size) ``` ## CodeRunParams ```python @dataclass class CodeRunParams() ``` Parameters for code execution. **Attributes**: - `argv` _list[str] | None_ - Command line arguments - `env` _dict[str, str] | None_ - Environment variables ## SessionExecuteRequest ```python class SessionExecuteRequest(ApiSessionExecuteRequest, AsyncApiSessionExecuteRequest) ``` Contains the request for executing a command in a session. **Attributes**: - `command` _str_ - The command to execute. - `run_async` _bool | None_ - Whether to execute the command asynchronously. - `var_async` _bool | None_ - Deprecated. Use `run_async` instead. - `suppress_input_echo` _bool | None_ - Whether to suppress input echo. Default is `False`. ## ExecutionArtifacts ```python @dataclass class ExecutionArtifacts() ``` Artifacts from the command execution. **Attributes**: - `stdout` _str_ - Standard output from the command, same as `result` in `ExecuteResponse` - `charts` _list[Chart] | None_ - List of chart metadata from matplotlib ## ExecuteResponse ```python class ExecuteResponse(BaseModel) ``` Response from the command execution. **Attributes**: - `exit_code` _int_ - The exit code from the command execution - `result` _str_ - The output from the command execution - `artifacts` _ExecutionArtifacts | None_ - Artifacts from the command execution ## SessionExecuteResponse ```python class SessionExecuteResponse(ApiSessionExecuteResponse) ``` Response from the session command execution. **Attributes**: - `cmd_id` _str_ - The ID of the executed command - `stdout` _str | None_ - The stdout from the command execution - `stderr` _str | None_ - The stderr from the command execution - `output` _str_ - The output from the command execution - `exit_code` _int_ - The exit code from the command execution ## SessionCommandLogsResponse ```python @dataclass class SessionCommandLogsResponse() ``` Response from the command logs. **Attributes**: - `output` _str | None_ - The combined output from the command - `stdout` _str | None_ - The stdout from the command - `stderr` _str | None_ - The stderr from the command #### parse\_session\_command\_logs ```python def parse_session_command_logs(data: bytes) -> SessionCommandLogsResponse ``` Parse combined stdout/stderr output into separate streams. **Arguments**: - `data` - Combined log bytes with STDOUT_PREFIX and STDERR_PREFIX markers **Returns**: SessionCommandLogsResponse with separated stdout and stderr #### demux\_log ```python def demux_log(data: bytes) -> tuple[bytes, bytes] ``` Demultiplex combined stdout/stderr log data. **Arguments**: - `data` - Combined log bytes with STDOUT_PREFIX and STDERR_PREFIX markers **Returns**: Tuple of (stdout_bytes, stderr_bytes) ##### OutputHandler ```python OutputHandler = Union[ Callable[[T], None], Callable[[T], Awaitable[None]], ] ``` Callback type that accepts both sync and async handlers. Blocking synchronous operations inside handlers may cause WebSocket disconnections. ## Sandbox ```python class Sandbox(SandboxDto) ``` Represents a Daytona Sandbox. **Attributes**: - `fs` _FileSystem_ - File system operations interface. - `git` _Git_ - Git operations interface. - `process` _Process_ - Process execution interface. - `computer_use` _ComputerUse_ - Computer use operations interface for desktop automation. - `code_interpreter` _CodeInterpreter_ - Stateful interpreter interface for executing code. Currently supports only Python. For other languages, use the `process.code_run` interface. - `id` _str_ - Unique identifier for the Sandbox. - `name` _str_ - Name of the Sandbox. - `organization_id` _str_ - Organization ID of the Sandbox. - `snapshot` _str_ - Daytona snapshot used to create the Sandbox. - `user` _str_ - OS user running in the Sandbox. - `env` _dict[str, str]_ - Environment variables set in the Sandbox. - `labels` _dict[str, str]_ - Custom labels attached to the Sandbox. - `public` _bool_ - Whether the Sandbox is publicly accessible. - `target` _str_ - Target location of the runner where the Sandbox runs. - `cpu` _int_ - Number of CPUs allocated to the Sandbox. - `gpu` _int_ - Number of GPUs allocated to the Sandbox. - `memory` _int_ - Amount of memory allocated to the Sandbox in GiB. - `disk` _int_ - Amount of disk space allocated to the Sandbox in GiB. - `state` _SandboxState_ - Current state of the Sandbox (e.g., "started", "stopped"). - `error_reason` _str_ - Error message if Sandbox is in error state. - `recoverable` _bool_ - Whether the Sandbox error is recoverable. - `backup_state` _SandboxBackupStateEnum_ - Current state of Sandbox backup. - `backup_created_at` _str_ - When the backup was created. - `auto_stop_interval` _int_ - Auto-stop interval in minutes. - `auto_archive_interval` _int_ - Auto-archive interval in minutes. - `auto_delete_interval` _int_ - Auto-delete interval in minutes. - `volumes` _list[str]_ - Volumes attached to the Sandbox. - `build_info` _str_ - Build information for the Sandbox if it was created from dynamic build. - `created_at` _str_ - When the Sandbox was created. - `updated_at` _str_ - When the Sandbox was last updated. - `network_block_all` _bool_ - Whether to block all network access for the Sandbox. - `network_allow_list` _str_ - Comma-separated list of allowed CIDR network addresses for the Sandbox. #### Sandbox.\_\_init\_\_ ```python def __init__(sandbox_dto: SandboxDto, toolbox_api: ApiClient, sandbox_api: SandboxApi, code_toolbox: SandboxCodeToolbox) ``` Initialize a new Sandbox instance. **Arguments**: - `sandbox_dto` _SandboxDto_ - The sandbox data from the API. - `toolbox_api` _ApiClient_ - API client for toolbox operations. - `sandbox_api` _SandboxApi_ - API client for Sandbox operations. - `code_toolbox` _SandboxCodeToolbox_ - Language-specific toolbox implementation. #### Sandbox.refresh\_data ```python @intercept_errors(message_prefix="Failed to refresh sandbox data: ") @with_instrumentation() def refresh_data() -> None ``` Refreshes the Sandbox data from the API. **Example**: ```python sandbox.refresh_data() print(f"Sandbox {sandbox.id}:") print(f"State: {sandbox.state}") print(f"Resources: {sandbox.cpu} CPU, {sandbox.memory} GiB RAM") ``` #### Sandbox.get\_user\_home\_dir ```python @intercept_errors(message_prefix="Failed to get user home directory: ") @with_instrumentation() def get_user_home_dir() -> str ``` Gets the user's home directory path inside the Sandbox. **Returns**: - `str` - The absolute path to the user's home directory inside the Sandbox. **Example**: ```python user_home_dir = sandbox.get_user_home_dir() print(f"Sandbox user home: {user_home_dir}") ``` #### Sandbox.get\_work\_dir ```python @intercept_errors(message_prefix="Failed to get working directory path: ") @with_instrumentation() def get_work_dir() -> str ``` Gets the working directory path inside the Sandbox. **Returns**: - `str` - The absolute path to the Sandbox working directory. Uses the WORKDIR specified in the Dockerfile if present, or falling back to the user's home directory if not. **Example**: ```python work_dir = sandbox.get_work_dir() print(f"Sandbox working directory: {work_dir}") ``` #### Sandbox.create\_lsp\_server ```python @with_instrumentation() def create_lsp_server(language_id: LspLanguageId | LspLanguageIdLiteral, path_to_project: str) -> LspServer ``` Creates a new Language Server Protocol (LSP) server instance. The LSP server provides language-specific features like code completion, diagnostics, and more. **Arguments**: - `language_id` _LspLanguageId | LspLanguageIdLiteral_ - The language server type (e.g., LspLanguageId.PYTHON). - `path_to_project` _str_ - Path to the project root directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `LspServer` - A new LSP server instance configured for the specified language. **Example**: ```python lsp = sandbox.create_lsp_server("python", "workspace/project") ``` #### Sandbox.set\_labels ```python @intercept_errors(message_prefix="Failed to set labels: ") @with_instrumentation() def set_labels(labels: dict[str, str]) -> dict[str, str] ``` Sets labels for the Sandbox. Labels are key-value pairs that can be used to organize and identify Sandboxes. **Arguments**: - `labels` _dict[str, str]_ - Dictionary of key-value pairs representing Sandbox labels. **Returns**: dict[str, str]: Dictionary containing the updated Sandbox labels. **Example**: ```python new_labels = sandbox.set_labels({ "project": "my-project", "environment": "development", "team": "backend" }) print(f"Updated labels: {new_labels}") ``` #### Sandbox.start ```python @intercept_errors(message_prefix="Failed to start sandbox: ") @with_timeout() @with_instrumentation() def start(timeout: float | None = 60) ``` Starts the Sandbox and waits for it to be ready. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If sandbox fails to start or times out. **Example**: ```python sandbox = daytona.get("my-sandbox-id") sandbox.start(timeout=40) # Wait up to 40 seconds print("Sandbox started successfully") ``` #### Sandbox.recover ```python @intercept_errors(message_prefix="Failed to recover sandbox: ") @with_timeout() def recover(timeout: float | None = 60) ``` Recovers the Sandbox from a recoverable error and waits for it to be ready. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If sandbox fails to recover or times out. **Example**: ```python sandbox = daytona.get("my-sandbox-id") sandbox.recover(timeout=40) # Wait up to 40 seconds print("Sandbox recovered successfully") ``` #### Sandbox.stop ```python @intercept_errors(message_prefix="Failed to stop sandbox: ") @with_timeout() @with_instrumentation() def stop(timeout: float | None = 60) ``` Stops the Sandbox and waits for it to be fully stopped. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If sandbox fails to stop or times out **Example**: ```python sandbox = daytona.get("my-sandbox-id") sandbox.stop() print("Sandbox stopped successfully") ``` #### Sandbox.delete ```python @intercept_errors(message_prefix="Failed to remove sandbox: ") @with_instrumentation() def delete(timeout: float | None = 60) -> None ``` Deletes the Sandbox. **Arguments**: - `timeout` _float | None_ - Timeout (in seconds) for sandbox deletion. 0 means no timeout. Default is 60 seconds. #### Sandbox.wait\_for\_sandbox\_start ```python @intercept_errors( message_prefix="Failure during waiting for sandbox to start: ") @with_timeout() @with_instrumentation() def wait_for_sandbox_start(timeout: float | None = 60) -> None ``` Waits for the Sandbox to reach the 'started' state. Polls the Sandbox status until it reaches the 'started' state, encounters an error or times out. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative; If Sandbox fails to start or times out #### Sandbox.wait\_for\_sandbox\_stop ```python @intercept_errors( message_prefix="Failure during waiting for sandbox to stop: ") @with_timeout() @with_instrumentation() def wait_for_sandbox_stop(timeout: float | None = 60) -> None ``` Waits for the Sandbox to reach the 'stopped' state. Polls the Sandbox status until it reaches the 'stopped' state, encounters an error or times out. It will wait up to 60 seconds for the Sandbox to stop. Treats destroyed as stopped to cover ephemeral sandboxes that are automatically deleted after stopping. **Arguments**: - `timeout` _float | None_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If Sandbox fails to stop or times out. #### Sandbox.set\_autostop\_interval ```python @intercept_errors(message_prefix="Failed to set auto-stop interval: ") @with_instrumentation() def set_autostop_interval(interval: int) -> None ``` Sets the auto-stop interval for the Sandbox. The Sandbox will automatically stop after being idle (no new events) for the specified interval. Events include any state changes or interactions with the Sandbox through the SDK. Interactions using Sandbox Previews are not included. **Arguments**: - `interval` _int_ - Number of minutes of inactivity before auto-stopping. Set to 0 to disable auto-stop. Defaults to 15. **Raises**: - `DaytonaError` - If interval is negative **Example**: ```python # Auto-stop after 1 hour sandbox.set_autostop_interval(60) # Or disable auto-stop sandbox.set_autostop_interval(0) ``` #### Sandbox.set\_auto\_archive\_interval ```python @intercept_errors(message_prefix="Failed to set auto-archive interval: ") @with_instrumentation() def set_auto_archive_interval(interval: int) -> None ``` Sets the auto-archive interval for the Sandbox. The Sandbox will automatically archive after being continuously stopped for the specified interval. **Arguments**: - `interval` _int_ - Number of minutes after which a continuously stopped Sandbox will be auto-archived. Set to 0 for the maximum interval. Default is 7 days. **Raises**: - `DaytonaError` - If interval is negative **Example**: ```python # Auto-archive after 1 hour sandbox.set_auto_archive_interval(60) # Or use the maximum interval sandbox.set_auto_archive_interval(0) ``` #### Sandbox.set\_auto\_delete\_interval ```python @intercept_errors(message_prefix="Failed to set auto-delete interval: ") @with_instrumentation() def set_auto_delete_interval(interval: int) -> None ``` Sets the auto-delete interval for the Sandbox. The Sandbox will automatically delete after being continuously stopped for the specified interval. **Arguments**: - `interval` _int_ - Number of minutes after which a continuously stopped Sandbox will be auto-deleted. Set to negative value to disable auto-delete. Set to 0 to delete immediately upon stopping. By default, auto-delete is disabled. **Example**: ```python # Auto-delete after 1 hour sandbox.set_auto_delete_interval(60) # Or delete immediately upon stopping sandbox.set_auto_delete_interval(0) # Or disable auto-delete sandbox.set_auto_delete_interval(-1) ``` #### Sandbox.get\_preview\_link ```python @intercept_errors(message_prefix="Failed to get preview link: ") @with_instrumentation() def get_preview_link(port: int) -> PortPreviewUrl ``` Retrieves the preview link for the sandbox at the specified port. If the port is closed, it will be opened automatically. For private sandboxes, a token is included to grant access to the URL. **Arguments**: - `port` _int_ - The port to open the preview link on. **Returns**: - `PortPreviewUrl` - The response object for the preview link, which includes the `url` and the `token` (to access private sandboxes). **Example**: ```python preview_link = sandbox.get_preview_link(3000) print(f"Preview URL: {preview_link.url}") print(f"Token: {preview_link.token}") ``` #### Sandbox.create\_signed\_preview\_url ```python @intercept_errors(message_prefix="Failed to create signed preview url: ") def create_signed_preview_url( port: int, expires_in_seconds: int | None = None) -> SignedPortPreviewUrl ``` Creates a signed preview URL for the sandbox at the specified port. **Arguments**: - `port` _int_ - The port to open the preview link on. - `expires_in_seconds` _int | None_ - The number of seconds the signed preview url will be valid for. Defaults to 60 seconds. **Returns**: - `SignedPortPreviewUrl` - The response object for the signed preview url. #### Sandbox.expire\_signed\_preview\_url ```python @intercept_errors(message_prefix="Failed to expire signed preview url: ") def expire_signed_preview_url(port: int, token: str) -> None ``` Expires a signed preview URL for the sandbox at the specified port. **Arguments**: - `port` _int_ - The port to expire the signed preview url on. - `token` _str_ - The token to expire the signed preview url on. #### Sandbox.archive ```python @intercept_errors(message_prefix="Failed to archive sandbox: ") @with_instrumentation() def archive() -> None ``` Archives the sandbox, making it inactive and preserving its state. When sandboxes are archived, the entire filesystem state is moved to cost-effective object storage, making it possible to keep sandboxes available for an extended period. The tradeoff between archived and stopped states is that starting an archived sandbox takes more time, depending on its size. Sandbox must be stopped before archiving. #### Sandbox.resize ```python @intercept_errors(message_prefix="Failed to resize sandbox: ") @with_timeout() @with_instrumentation() def resize(resources: Resources, timeout: float | None = 60) -> None ``` Resizes the Sandbox resources. Changes the CPU, memory, or disk allocation for the Sandbox. Hot resize (on running sandbox) only allows CPU/memory increases. Disk resize requires a stopped sandbox. **Arguments**: - `resources` _Resources_ - New resource configuration. Only specified fields will be updated. - cpu: Number of CPU cores (minimum: 1). For hot resize, can only be increased. - memory: Memory in GiB (minimum: 1). For hot resize, can only be increased. - disk: Disk space in GiB (can only be increased, requires stopped sandbox). - `timeout` _Optional[float]_ - Timeout (in seconds) for the resize operation. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If hot resize constraints are violated (CPU/memory decrease on running sandbox). - `DaytonaError` - If disk resize attempted on running sandbox. - `DaytonaError` - If disk size decrease is attempted. - `DaytonaError` - If resize operation times out. - `DaytonaError` - If no resource changes are specified. **Example**: ```python # Increase CPU/memory on running sandbox (hot resize) sandbox.resize(Resources(cpu=4, memory=8)) # Change disk (sandbox must be stopped) sandbox.stop() sandbox.resize(Resources(cpu=2, memory=4, disk=30)) ``` #### Sandbox.wait\_for\_resize\_complete ```python @intercept_errors( message_prefix="Failure during waiting for resize to complete: ") @with_timeout() @with_instrumentation() def wait_for_resize_complete(timeout: float | None = 60) -> None ``` Waits for the Sandbox resize operation to complete. Polls the Sandbox status until the state is no longer 'resizing'. **Arguments**: - `timeout` _Optional[float]_ - Maximum time to wait in seconds. 0 means no timeout. Default is 60 seconds. **Raises**: - `DaytonaError` - If timeout is negative. If resize operation times out. #### Sandbox.create\_ssh\_access ```python @intercept_errors(message_prefix="Failed to create SSH access: ") @with_instrumentation() def create_ssh_access(expires_in_minutes: int | None = None) -> SshAccessDto ``` Creates an SSH access token for the sandbox. **Arguments**: - `expires_in_minutes` _int | None_ - The number of minutes the SSH access token will be valid for. #### Sandbox.revoke\_ssh\_access ```python @intercept_errors(message_prefix="Failed to revoke SSH access: ") @with_instrumentation() def revoke_ssh_access(token: str) -> None ``` Revokes an SSH access token for the sandbox. **Arguments**: - `token` _str_ - The token to revoke. #### Sandbox.validate\_ssh\_access ```python @intercept_errors(message_prefix="Failed to validate SSH access: ") @with_instrumentation() def validate_ssh_access(token: str) -> SshAccessValidationDto ``` Validates an SSH access token for the sandbox. **Arguments**: - `token` _str_ - The token to validate. #### Sandbox.refresh\_activity ```python @intercept_errors(message_prefix="Failed to refresh sandbox activity: ") def refresh_activity() -> None ``` Refreshes the sandbox activity to reset the timer for automated lifecycle management actions. This method updates the sandbox's last activity timestamp without changing its state. It is useful for keeping long-running sessions alive while there is still user activity. **Example**: ```python sandbox.refresh_activity() ``` ## PaginatedSandboxes ```python class PaginatedSandboxes(PaginatedSandboxesDto) ``` Represents a paginated list of Daytona Sandboxes. **Attributes**: - `items` _list[Sandbox]_ - List of Sandbox instances in the current page. - `total` _int_ - Total number of Sandboxes across all pages. - `page` _int_ - Current page number. - `total_pages` _int_ - Total number of pages available. ##### items: `list[Sandbox]` ```python items = None ``` pyright: ignore[reportIncompatibleVariableOverride] ## Resources ```python @dataclass class Resources() ``` Resources configuration for Sandbox. **Attributes**: - `cpu` _int | None_ - Number of CPU cores to allocate. - `memory` _int | None_ - Amount of memory in GiB to allocate. - `disk` _int | None_ - Amount of disk space in GiB to allocate. - `gpu` _int | None_ - Number of GPUs to allocate. **Example**: ```python resources = Resources( cpu=2, memory=4, # 4GiB RAM disk=20, # 20GiB disk gpu=1 ) params = CreateSandboxFromImageParams( image=Image.debian_slim("3.12"), language="python", resources=resources ) ``` ## Snapshot ```python class Snapshot(SyncSnapshotDto) ``` Represents a Daytona Snapshot which is a pre-configured sandbox. **Attributes**: - `id` _str_ - Unique identifier for the Snapshot. - `organization_id` _str | None_ - Organization ID of the Snapshot. - `general` _bool_ - Whether the Snapshot is general. - `name` _str_ - Name of the Snapshot. - `image_name` _str_ - Name of the Image of the Snapshot. - `state` _str_ - State of the Snapshot. - `size` _float | int | None_ - Size of the Snapshot. - `entrypoint` _list[str] | None_ - Entrypoint of the Snapshot. - `cpu` _float | int_ - CPU of the Snapshot. - `gpu` _float | int_ - GPU of the Snapshot. - `mem` _float | int_ - Memory of the Snapshot in GiB. - `disk` _float | int_ - Disk of the Snapshot in GiB. - `error_reason` _str | None_ - Error reason of the Snapshot. - `created_at` _str_ - Timestamp when the Snapshot was created. - `updated_at` _str_ - Timestamp when the Snapshot was last updated. - `last_used_at` _str_ - Timestamp when the Snapshot was last used. ## SnapshotService ```python class SnapshotService() ``` Service for managing Daytona Snapshots. Can be used to list, get, create and delete Snapshots. #### SnapshotService.list ```python @intercept_errors(message_prefix="Failed to list snapshots: ") @with_instrumentation() def list(page: int | None = None, limit: int | None = None) -> PaginatedSnapshots ``` Returns paginated list of Snapshots. **Arguments**: - `page` _int | None_ - Page number for pagination (starting from 1). - `limit` _int | None_ - Maximum number of items per page. **Returns**: - `PaginatedSnapshots` - Paginated list of Snapshots. **Example**: ```python daytona = Daytona() result = daytona.snapshot.list(page=2, limit=10) for snapshot in result.items: print(f"{snapshot.name} ({snapshot.image_name})") ``` #### SnapshotService.delete ```python @intercept_errors(message_prefix="Failed to delete snapshot: ") @with_instrumentation() def delete(snapshot: Snapshot) -> None ``` Delete a Snapshot. **Arguments**: - `snapshot` _Snapshot_ - Snapshot to delete. **Example**: ```python daytona = Daytona() snapshot = daytona.snapshot.get("test-snapshot") daytona.snapshot.delete(snapshot) print("Snapshot deleted") ``` #### SnapshotService.get ```python @intercept_errors(message_prefix="Failed to get snapshot: ") @with_instrumentation() def get(name: str) -> Snapshot ``` Get a Snapshot by name. **Arguments**: - `name` _str_ - Name of the Snapshot to get. **Returns**: - `Snapshot` - The Snapshot object. **Example**: ```python daytona = Daytona() snapshot = daytona.snapshot.get("test-snapshot-name") print(f"{snapshot.name} ({snapshot.image_name})") ``` #### SnapshotService.create ```python @intercept_errors(message_prefix="Failed to create snapshot: ") @with_timeout() @with_instrumentation() def create(params: CreateSnapshotParams, *, on_logs: Callable[[str], None] | None = None, timeout: float | None = 0) -> Snapshot ``` Creates and registers a new snapshot from the given Image definition. **Arguments**: - `params` _CreateSnapshotParams_ - Parameters for snapshot creation. - `on_logs` _Callable[[str], None]_ - This callback function handles snapshot creation logs. - `timeout` _float | None_ - Default is no timeout. Timeout in seconds (0 means no timeout). **Example**: ```python image = Image.debianSlim('3.12').pipInstall('numpy') daytona.snapshot.create( CreateSnapshotParams(name='my-snapshot', image=image), on_logs=lambda chunk: print(chunk, end=""), ) ``` #### SnapshotService.activate ```python @with_instrumentation() def activate(snapshot: Snapshot) -> Snapshot ``` Activate a snapshot. **Arguments**: - `snapshot` _Snapshot_ - The Snapshot instance. **Returns**: - `Snapshot` - The activated Snapshot instance. #### SnapshotService.process\_image\_context ```python @staticmethod @with_instrumentation() def process_image_context(object_storage_api: ObjectStorageApi, image: Image) -> list[str] ``` Processes the image context by uploading it to object storage. **Arguments**: - `image` _Image_ - The Image instance. **Returns**: - `list[str]` - List of context hashes stored in object storage. ## PaginatedSnapshots ```python class PaginatedSnapshots(PaginatedSnapshotsDto) ``` Represents a paginated list of Daytona Snapshots. **Attributes**: - `items` _list[Snapshot]_ - List of Snapshot instances in the current page. - `total` _int_ - Total number of Snapshots across all pages. - `page` _int_ - Current page number. - `total_pages` _int_ - Total number of pages available. ## CreateSnapshotParams ```python class CreateSnapshotParams(BaseModel) ``` Parameters for creating a new snapshot. **Attributes**: - `name` _str_ - Name of the snapshot. - `image` _str | Image_ - Image of the snapshot. If a string is provided, it should be available on some registry. If an Image instance is provided, it will be used to create a new image in Daytona. - `resources` _Resources | None_ - Resources of the snapshot. - `entrypoint` _list[str] | None_ - Entrypoint of the snapshot. - `region_id` _str | None_ - ID of the region where the snapshot will be available. Defaults to organization default region if not specified. ## Volume ```python class Volume(VolumeDto) ``` Represents a Daytona Volume which is a shared storage volume for Sandboxes. **Attributes**: - `id` _str_ - Unique identifier for the Volume. - `name` _str_ - Name of the Volume. - `organization_id` _str_ - Organization ID of the Volume. - `state` _str_ - State of the Volume. - `created_at` _str_ - Date and time when the Volume was created. - `updated_at` _str_ - Date and time when the Volume was last updated. - `last_used_at` _str_ - Date and time when the Volume was last used. ## VolumeService ```python class VolumeService() ``` Service for managing Daytona Volumes. Can be used to list, get, create and delete Volumes. #### VolumeService.list ```python def list() -> list[Volume] ``` List all Volumes. **Returns**: - `list[Volume]` - List of all Volumes. **Example**: ```python daytona = Daytona() volumes = daytona.volume.list() for volume in volumes: print(f"{volume.name} ({volume.id})") ``` #### VolumeService.get ```python @with_instrumentation() def get(name: str, create: bool = False) -> Volume ``` Get a Volume by name. **Arguments**: - `name` _str_ - Name of the Volume to get. - `create` _bool_ - If True, create a new Volume if it doesn't exist. **Returns**: - `Volume` - The Volume object. **Example**: ```python daytona = Daytona() volume = daytona.volume.get("test-volume-name", create=True) print(f"{volume.name} ({volume.id})") ``` #### VolumeService.create ```python @with_instrumentation() def create(name: str) -> Volume ``` Create a new Volume. **Arguments**: - `name` _str_ - Name of the Volume to create. **Returns**: - `Volume` - The Volume object. **Example**: ```python daytona = Daytona() volume = daytona.volume.create("test-volume") print(f"{volume.name} ({volume.id}); state: {volume.state}") ``` #### VolumeService.delete ```python @with_instrumentation() def delete(volume: Volume) -> None ``` Delete a Volume. **Arguments**: - `volume` _Volume_ - Volume to delete. **Example**: ```python daytona = Daytona() volume = daytona.volume.get("test-volume") daytona.volume.delete(volume) print("Volume deleted") ``` ## VolumeMount ```python class VolumeMount(ApiVolumeMount, AsyncApiVolumeMount) ``` Represents a Volume mount configuration for a Sandbox. **Attributes**: - `volume_id` _str_ - ID of the volume to mount. - `mount_path` _str_ - Path where the volume will be mounted in the sandbox. - `subpath` _str | None_ - Optional S3 subpath/prefix within the volume to mount. When specified, only this prefix will be accessible. When omitted, the entire volume is mounted. Sandboxes are isolated runtime environments that run on [runners](https://www.daytona.io/docs/en/runners.md) — machines that form Daytona's compute plane. Runners are organized into **regions**, which are geographic or logical groupings of compute infrastructure. When creating a sandbox, you can target a specific region, and Daytona will schedule your workload on an available runner within that region. As a result, you're able to: - Choose specific geographic locations for reduced latency - Comply with data residency requirements - Use your own runner machines for custom regions - Scale compute resources independently within each custom region Regions are geographic or logical groupings of runners that execute sandbox workloads. The sandbox region is specified by setting the `target` parameter on initialization: ```python from daytona import Daytona, DaytonaConfig # Configure Daytona to use the US region config = DaytonaConfig( target="us" ) # Initialize the Daytona client with the specified configuration daytona = Daytona(config) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; // Configure Daytona to use the EU region const daytona: Daytona = new Daytona({ target: "eu" }); ``` ```go package main import ( "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) // Configure Daytona to use the US region client, _ := daytona.NewClientWithConfig(&types.DaytonaConfig{ Target: "us", }) ``` ```ruby require 'daytona' # Configure Daytona to use the EU region config = Daytona::Config.new( target: "eu" ) # Initialize the Daytona client with the specified configuration daytona = Daytona::Daytona.new(config) ``` ### Shared regions Shared regions are managed by Daytona and available to all organizations. These regions provide immediate access to Daytona's infrastructure without any setup required. Limits are applied to your organization's default region. For access to a different shared region, contact [sales@daytona.io](mailto:sales@daytona.io). | Region | Target | | ------------- | -------- | | United States | **`us`** | | Europe | **`eu`** | ### Dedicated regions Dedicated regions are managed by Daytona and provisioned exclusively for individual organizations. These regions deliver dedicated infrastructure with the operational simplicity of a managed service. :::note Contact [sales@daytona.io](mailto:sales@daytona.io) to set up a dedicated region for your organization. ::: ### Custom regions Custom regions are created and managed by your organization, allowing you to use your own runner machines and scale compute resources independently within each region. This provides maximum control over data locality, compliance, and infrastructure configuration. Additionally, custom regions have no limits applied for concurrent resource usage, giving you full control over capacity and performance. For more information, see the [runners](https://www.daytona.io/docs/en/runners.md) guide. ## ComputerUse Initialize a new ComputerUse instance. ### Constructors #### new ComputerUse() ```ruby def initialize(sandbox_id:, toolbox_api:, otel_state:) ``` Initialize a new ComputerUse instance. **Parameters**: - `sandbox_id` _String_ - The ID of the sandbox - `toolbox_api` _DaytonaApiClient:ToolboxApi_ - API client for sandbox operations - `otel_state` _Daytona:OtelState, nil_ - **Returns**: - `ComputerUse` - a new instance of ComputerUse ### Methods #### sandbox_id() ```ruby def sandbox_id() ``` **Returns**: - `String` - The ID of the sandbox #### toolbox_api() ```ruby def toolbox_api() ``` **Returns**: - `DaytonaApiClient:ToolboxApi` - API client for sandbox operations #### mouse() ```ruby def mouse() ``` **Returns**: - `Mouse` - Mouse operations interface #### keyboard() ```ruby def keyboard() ``` **Returns**: - `Keyboard` - Keyboard operations interface #### screenshot() ```ruby def screenshot() ``` **Returns**: - `Screenshot` - Screenshot operations interface #### display() ```ruby def display() ``` **Returns**: - `Display` - Display operations interface #### recording() ```ruby def recording() ``` **Returns**: - `Recording` - Screen recording operations interface #### start() ```ruby def start() ``` Starts all computer use processes (Xvfb, xfce4, x11vnc, novnc). **Returns**: - `DaytonaApiClient:ComputerUseStartResponse` - Computer use start response **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby result = sandbox.computer_use.start puts "Computer use processes started: #{result.message}" ``` #### stop() ```ruby def stop() ``` Stops all computer use processes. **Returns**: - `DaytonaApiClient:ComputerUseStopResponse` - Computer use stop response **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby result = sandbox.computer_use.stop puts "Computer use processes stopped: #{result.message}" ``` #### status() ```ruby def status() ``` Gets the status of all computer use processes. **Returns**: - `DaytonaApiClient:ComputerUseStatusResponse` - Status information about all VNC desktop processes **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby response = sandbox.computer_use.get_status puts "Computer use status: #{response.status}" ``` #### get_process_status() ```ruby def get_process_status(process_name:) ``` Gets the status of a specific VNC process. **Parameters**: - `process_name` _String_ - Name of the process to check **Returns**: - `DaytonaApiClient:ProcessStatusResponse` - Status information about the specific process **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby xvfb_status = sandbox.computer_use.get_process_status("xvfb") no_vnc_status = sandbox.computer_use.get_process_status("novnc") ``` #### restart_process() ```ruby def restart_process(process_name:) ``` Restarts a specific VNC process. **Parameters**: - `process_name` _String_ - Name of the process to restart **Returns**: - `DaytonaApiClient:ProcessRestartResponse` - Process restart response **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby result = sandbox.computer_use.restart_process("xfce4") puts "XFCE4 process restarted: #{result.message}" ``` #### get_process_logs() ```ruby def get_process_logs(process_name:) ``` Gets logs for a specific VNC process. **Parameters**: - `process_name` _String_ - Name of the process to get logs for **Returns**: - `DaytonaApiClient:ProcessLogsResponse` - Process logs **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby logs = sandbox.computer_use.get_process_logs("novnc") puts "NoVNC logs: #{logs}" ``` #### get_process_errors() ```ruby def get_process_errors(process_name:) ``` Gets error logs for a specific VNC process. **Parameters**: - `process_name` _String_ - Name of the process to get error logs for **Returns**: - `DaytonaApiClient:ProcessErrorsResponse` - Process error logs **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby errors = sandbox.computer_use.get_process_errors("x11vnc") puts "X11VNC errors: #{errors}" ``` ## Config Main class for a new Daytona::Config object. ### Constructors #### new Config() ```ruby def initialize(api_key:, jwt_token:, api_url:, organization_id:, target:, _experimental:) ``` Initializes a new Daytona::Config object. **Parameters**: - `api_key` _String, nil_ - Daytona API key. Defaults to ENV['DAYTONA_API_KEY']. - `jwt_token` _String, nil_ - Daytona JWT token. Defaults to ENV['DAYTONA_JWT_TOKEN']. - `api_url` _String, nil_ - Daytona API URL. Defaults to ENV['DAYTONA_API_URL'] or Daytona::Config::API_URL. - `organization_id` _String, nil_ - Daytona organization ID. Defaults to ENV['DAYTONA_ORGANIZATION_ID']. - `target` _String, nil_ - Daytona target. Defaults to ENV['DAYTONA_TARGET']. - `_experimental` _Hash, nil_ - Experimental configuration options. **Returns**: - `Config` - a new instance of Config ### Methods #### api_key() ```ruby def api_key() ``` API key for authentication with the Daytona API **Returns**: - `String, nil` - Daytona API key #### api_key=() ```ruby def api_key=(value) ``` API key for authentication with the Daytona API **Returns**: - `String, nil` - Daytona API key #### jwt_token() ```ruby def jwt_token() ``` JWT token for authentication with the Daytona API **Returns**: - `String, nil` - Daytona JWT token #### jwt_token=() ```ruby def jwt_token=(value) ``` JWT token for authentication with the Daytona API **Returns**: - `String, nil` - Daytona JWT token #### api_url() ```ruby def api_url() ``` URL of the Daytona API **Returns**: - `String, nil` - Daytona API URL #### api_url=() ```ruby def api_url=(value) ``` URL of the Daytona API **Returns**: - `String, nil` - Daytona API URL #### organization_id() ```ruby def organization_id() ``` Organization ID for authentication with the Daytona API **Returns**: - `String, nil` - Daytona API URL #### organization_id=() ```ruby def organization_id=(value) ``` Organization ID for authentication with the Daytona API **Returns**: - `String, nil` - Daytona API URL #### target() ```ruby def target() ``` Target environment for sandboxes **Returns**: - `String, nil` - Daytona target #### target=() ```ruby def target=(value) ``` Target environment for sandboxes **Returns**: - `String, nil` - Daytona target #### _experimental() ```ruby def _experimental() ``` Experimental configuration options **Returns**: - `Hash, nil` - Experimental configuration hash #### _experimental=() ```ruby def _experimental=(value) ``` Experimental configuration options **Returns**: - `Hash, nil` - Experimental configuration hash ## Daytona Daytona class for Daytona SDK. ### Constructors #### new Daytona() ```ruby def initialize(config) ``` **Parameters**: - `config` _Daytona:Config_ - Configuration options. Defaults to Daytona::Config.new **Returns**: - `Daytona` - a new instance of Daytona ### Methods #### config() ```ruby def config() ``` **Returns**: - `Daytona:Config` #### api_client() ```ruby def api_client() ``` **Returns**: - `DaytonaApiClient` #### sandbox_api() ```ruby def sandbox_api() ``` **Returns**: - `DaytonaApiClient:SandboxApi` #### volume() ```ruby def volume() ``` **Returns**: - `Daytona:VolumeService` #### object_storage_api() ```ruby def object_storage_api() ``` **Returns**: - `DaytonaApiClient:ObjectStorageApi` #### snapshots_api() ```ruby def snapshots_api() ``` **Returns**: - `DaytonaApiClient:SnapshotsApi` #### snapshot() ```ruby def snapshot() ``` **Returns**: - `Daytona:SnapshotService` #### close() ```ruby def close() ``` Shuts down OTel providers, flushing any pending telemetry data. **Returns**: - `void` #### create() ```ruby def create(params, on_snapshot_create_logs:) ``` Creates a sandbox with the specified parameters **Parameters**: - `params` _Daytona:CreateSandboxFromSnapshotParams, Daytona:CreateSandboxFromImageParams, Nil_ - Sandbox creation parameters **Returns**: - `Daytona:Sandbox` - The created sandbox **Raises**: - `Daytona:Sdk:Error` - If auto_stop_interval or auto_archive_interval is negative #### delete() ```ruby def delete(sandbox) ``` Deletes a Sandbox. **Parameters**: - `sandbox` _Daytona:Sandbox_ - **Returns**: - `void` #### get() ```ruby def get(id) ``` Gets a Sandbox by its ID. **Parameters**: - `id` _String_ - **Returns**: - `Daytona:Sandbox` #### list() ```ruby def list(labels, page:, limit:) ``` Lists Sandboxes filtered by labels. **Parameters**: - `labels` _Hash\_ - - `page` _Integer, Nil_ - - `limit` _Integer, Nil_ - **Returns**: - `Daytona:PaginatedResource` **Raises**: - `Daytona:Sdk:Error` - #### start() ```ruby def start(sandbox, timeout) ``` Starts a Sandbox and waits for it to be ready. **Parameters**: - `sandbox` _Daytona:Sandbox_ - - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s). **Returns**: - `void` #### stop() ```ruby def stop(sandbox, timeout) ``` Stops a Sandbox and waits for it to be stopped. **Parameters**: - `sandbox` _Daytona:Sandbox_ - - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s). **Returns**: - `void` ## FileSystem Main class for a new FileSystem instance. ### Constructors #### new FileSystem() ```ruby def initialize(sandbox_id:, toolbox_api:, otel_state:) ``` Initializes a new FileSystem instance. **Parameters**: - `sandbox_id` _String_ - The Sandbox ID - `toolbox_api` _DaytonaToolboxApiClient:FileSystemApi_ - API client for Sandbox operations - `otel_state` _Daytona:OtelState, nil_ - **Returns**: - `FileSystem` - a new instance of FileSystem ### Methods #### sandbox_id() ```ruby def sandbox_id() ``` **Returns**: - `String` - The Sandbox ID #### toolbox_api() ```ruby def toolbox_api() ``` **Returns**: - `DaytonaToolboxApiClient:FileSystemApi` - API client for Sandbox operations #### create_folder() ```ruby def create_folder(path, mode) ``` Creates a new directory in the Sandbox at the specified path with the given permissions. **Parameters**: - `path` _String_ - Path where the folder should be created. Relative paths are resolved based on the sandbox working directory. - `mode` _String_ - Folder permissions in octal format (e.g., "755" for rwxr-xr-x). **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Create a directory with standard permissions sandbox.fs.create_folder("workspace/data", "755") # Create a private directory sandbox.fs.create_folder("workspace/secrets", "700") ``` #### delete_file() ```ruby def delete_file(path, recursive:) ``` Deletes a file from the Sandbox. **Parameters**: - `path` _String_ - Path to the file to delete. Relative paths are resolved based on the sandbox working directory. - `recursive` _Boolean_ - If the file is a directory, this must be true to delete it. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Delete a file sandbox.fs.delete_file("workspace/data/old_file.txt") # Delete a directory recursively sandbox.fs.delete_file("workspace/old_dir", recursive: true) ``` #### get_file_info() ```ruby def get_file_info(path) ``` Gets detailed information about a file or directory, including its size, permissions, and timestamps. **Parameters**: - `path` _String_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `DaytonaApiClient:FileInfo` - Detailed file information **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Get file metadata info = sandbox.fs.get_file_info("workspace/data/file.txt") puts "Size: #{info.size} bytes" puts "Modified: #{info.mod_time}" puts "Mode: #{info.mode}" # Check if path is a directory info = sandbox.fs.get_file_info("workspace/data") puts "Path is a directory" if info.is_dir ``` #### list_files() ```ruby def list_files(path) ``` Lists files and directories in a given path and returns their information, similar to the ls -l command. **Parameters**: - `path` _String_ - Path to the directory to list contents from. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Array\` - List of file and directory information **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # List directory contents files = sandbox.fs.list_files("workspace/data") # Print files and their sizes files.each do |file| puts "#{file.name}: #{file.size} bytes" unless file.is_dir end # List only directories dirs = files.select(&:is_dir) puts "Subdirectories: #{dirs.map(&:name).join(', ')}" ``` #### download_file() ```ruby def download_file(remote_path, local_path) ``` Downloads a file from the Sandbox. Returns the file contents as a string. This method is useful when you want to load the file into memory without saving it to disk. It can only be used for smaller files. **Parameters**: - `remote_path` _String_ - Path to the file in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `local_path` _String, nil_ - Optional path to save the file locally. If provided, the file will be saved to disk. **Returns**: - `File, nil` - The file if local_path is nil, otherwise nil **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Download and get file content content = sandbox.fs.download_file("workspace/data/file.txt") puts content # Download and save a file locally sandbox.fs.download_file("workspace/data/file.txt", "local_copy.txt") size_mb = File.size("local_copy.txt") / 1024.0 / 1024.0 puts "Size of the downloaded file: #{size_mb} MB" ``` #### upload_file() ```ruby def upload_file(source, remote_path) ``` Uploads a file to the specified path in the Sandbox. If a file already exists at the destination path, it will be overwritten. **Parameters**: - `source` _String, IO_ - File contents as a string/bytes or a local file path or IO object. - `remote_path` _String_ - Path to the destination file. Relative paths are resolved based on the sandbox working directory. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Upload a text file from string content content = "Hello, World!" sandbox.fs.upload_file(content, "tmp/hello.txt") # Upload a local file sandbox.fs.upload_file("local_file.txt", "tmp/file.txt") # Upload binary data data = { key: "value" }.to_json sandbox.fs.upload_file(data, "tmp/config.json") ``` #### upload_files() ```ruby def upload_files(files) ``` Uploads multiple files to the Sandbox. If files already exist at the destination paths, they will be overwritten. **Parameters**: - `files` _Array\_ - List of files to upload. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Upload multiple files files = [ FileUpload.new("Content of file 1", "/tmp/file1.txt"), FileUpload.new("workspace/data/file2.txt", "/tmp/file2.txt"), FileUpload.new('{"key": "value"}', "/tmp/config.json") ] sandbox.fs.upload_files(files) ``` #### find_files() ```ruby def find_files(path, pattern) ``` Searches for files containing a pattern, similar to the grep command. **Parameters**: - `path` _String_ - Path to the file or directory to search. If the path is a directory, the search will be performed recursively. Relative paths are resolved based on the sandbox working directory. - `pattern` _String_ - Search pattern to match against file contents. **Returns**: - `Array\` - List of matches found in files **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Search for TODOs in Ruby files matches = sandbox.fs.find_files("workspace/src", "TODO:") matches.each do |match| puts "#{match.file}:#{match.line}: #{match.content.strip}" end ``` #### search_files() ```ruby def search_files(path, pattern) ``` Searches for files and directories whose names match the specified pattern. The pattern can be a simple string or a glob pattern. **Parameters**: - `path` _String_ - Path to the root directory to start search from. Relative paths are resolved based on the sandbox working directory. - `pattern` _String_ - Pattern to match against file names. Supports glob patterns (e.g., "*.rb" for Ruby files). **Returns**: - `DaytonaApiClient:SearchFilesResponse` **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Find all Ruby files result = sandbox.fs.search_files("workspace", "*.rb") result.files.each { |file| puts file } # Find files with specific prefix result = sandbox.fs.search_files("workspace/data", "test_*") puts "Found #{result.files.length} test files" ``` #### move_files() ```ruby def move_files(source, destination) ``` Moves or renames a file or directory. The parent directory of the destination must exist. **Parameters**: - `source` _String_ - Path to the source file or directory. Relative paths are resolved based on the sandbox working directory. - `destination` _String_ - Path to the destination. Relative paths are resolved based on the sandbox working directory. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Rename a file sandbox.fs.move_files( "workspace/data/old_name.txt", "workspace/data/new_name.txt" ) # Move a file to a different directory sandbox.fs.move_files( "workspace/data/file.txt", "workspace/archive/file.txt" ) # Move a directory sandbox.fs.move_files( "workspace/old_dir", "workspace/new_dir" ) ``` #### replace_in_files() ```ruby def replace_in_files(files:, pattern:, new_value:) ``` Performs search and replace operations across multiple files. **Parameters**: - `files` _Array\_ - List of file paths to perform replacements in. Relative paths are resolved based on the sandbox working directory. - `pattern` _String_ - Pattern to search for. - `new_value` _String_ - Text to replace matches with. **Returns**: - `Array\` - List of results indicating replacements made in each file **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Replace in specific files results = sandbox.fs.replace_in_files( files: ["workspace/src/file1.rb", "workspace/src/file2.rb"], pattern: "old_function", new_value: "new_function" ) # Print results results.each do |result| if result.success puts "#{result.file}: #{result.success}" else puts "#{result.file}: #{result.error}" end end ``` #### set_file_permissions() ```ruby def set_file_permissions(path:, mode:, owner:, group:) ``` Sets permissions and ownership for a file or directory. Any of the parameters can be nil to leave that attribute unchanged. **Parameters**: - `path` _String_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. - `mode` _String, nil_ - File mode/permissions in octal format (e.g., "644" for rw-r--r--). - `owner` _String, nil_ - User owner of the file. - `group` _String, nil_ - Group owner of the file. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - If the operation fails **Examples:** ```ruby # Make a file executable sandbox.fs.set_file_permissions( path: "workspace/scripts/run.sh", mode: "755" # rwxr-xr-x ) # Change file owner sandbox.fs.set_file_permissions( path: "workspace/data/file.txt", owner: "daytona", group: "daytona" ) ``` ## Git Main class for a new Git handler instance. ### Constructors #### new Git() ```ruby def initialize(sandbox_id:, toolbox_api:, otel_state:) ``` Initializes a new Git handler instance. **Parameters**: - `sandbox_id` _String_ - The Sandbox ID. - `toolbox_api` _DaytonaToolboxApiClient:GitApi_ - API client for Sandbox operations. - `otel_state` _Daytona:OtelState, nil_ - **Returns**: - `Git` - a new instance of Git ### Methods #### sandbox_id() ```ruby def sandbox_id() ``` **Returns**: - `String` - The Sandbox ID #### toolbox_api() ```ruby def toolbox_api() ``` **Returns**: - `DaytonaToolboxApiClient:GitApi` - API client for Sandbox operations #### add() ```ruby def add(path, files) ``` Stages the specified files for the next commit, similar to running 'git add' on the command line. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `files` _Array\_ - List of file paths or directories to stage, relative to the repository root. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - if adding files fails **Examples:** ```ruby # Stage a single file sandbox.git.add("workspace/repo", ["file.txt"]) # Stage multiple files sandbox.git.add("workspace/repo", [ "src/main.rb", "spec/main_spec.rb", "README.md" ]) ``` #### branches() ```ruby def branches(path) ``` Lists branches in the repository. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `DaytonaApiClient:ListBranchResponse` - List of branches in the repository. **Raises**: - `Daytona:Sdk:Error` - if listing branches fails **Examples:** ```ruby response = sandbox.git.branches("workspace/repo") puts "Branches: #{response.branches}" ``` #### clone() ```ruby def clone(url:, path:, branch:, commit_id:, username:, password:) ``` Clones a Git repository into the specified path. It supports cloning specific branches or commits, and can authenticate with the remote repository if credentials are provided. **Parameters**: - `url` _String_ - Repository URL to clone from. - `path` _String_ - Path where the repository should be cloned. Relative paths are resolved based on the sandbox working directory. - `branch` _String, nil_ - Specific branch to clone. If not specified, clones the default branch. - `commit_id` _String, nil_ - Specific commit to clone. If specified, the repository will be left in a detached HEAD state at this commit. - `username` _String, nil_ - Git username for authentication. - `password` _String, nil_ - Git password or token for authentication. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - if cloning repository fails **Examples:** ```ruby # Clone the default branch sandbox.git.clone( url: "https://github.com/user/repo.git", path: "workspace/repo" ) # Clone a specific branch with authentication sandbox.git.clone( url: "https://github.com/user/private-repo.git", path: "workspace/private", branch: "develop", username: "user", password: "token" ) # Clone a specific commit sandbox.git.clone( url: "https://github.com/user/repo.git", path: "workspace/repo-old", commit_id: "abc123" ) ``` #### commit() ```ruby def commit(path:, message:, author:, email:, allow_empty:) ``` Creates a new commit with the staged changes. Make sure to stage changes using the add() method before committing. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `message` _String_ - Commit message describing the changes. - `author` _String_ - Name of the commit author. - `email` _String_ - Email address of the commit author. - `allow_empty` _Boolean_ - Allow creating an empty commit when no changes are staged. Defaults to false. **Returns**: - `GitCommitResponse` - Response containing the commit SHA. **Raises**: - `Daytona:Sdk:Error` - if committing changes fails **Examples:** ```ruby # Stage and commit changes sandbox.git.add("workspace/repo", ["README.md"]) commit_response = sandbox.git.commit( path: "workspace/repo", message: "Update documentation", author: "John Doe", email: "john@example.com", allow_empty: true ) puts "Commit SHA: #{commit_response.sha}" ``` #### push() ```ruby def push(path:, username:, password:) ``` Pushes all local commits on the current branch to the remote repository. If the remote repository requires authentication, provide username and password/token. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username` _String, nil_ - Git username for authentication. - `password` _String, nil_ - Git password or token for authentication. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - if pushing changes fails **Examples:** ```ruby # Push without authentication (for public repos or SSH) sandbox.git.push("workspace/repo") # Push with authentication sandbox.git.push( path: "workspace/repo", username: "user", password: "github_token" ) ``` #### pull() ```ruby def pull(path:, username:, password:) ``` Pulls changes from the remote repository. If the remote repository requires authentication, provide username and password/token. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username` _String, nil_ - Git username for authentication. - `password` _String, nil_ - Git password or token for authentication. **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - if pulling changes fails **Examples:** ```ruby # Pull without authentication sandbox.git.pull("workspace/repo") # Pull with authentication sandbox.git.pull( path: "workspace/repo", username: "user", password: "github_token" ) ``` #### status() ```ruby def status(path) ``` Gets the current Git repository status. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `DaytonaToolboxApiClient:GitStatus` - Repository status information including: **Raises**: - `Daytona:Sdk:Error` - if getting status fails **Examples:** ```ruby status = sandbox.git.status("workspace/repo") puts "On branch: #{status.current_branch}" puts "Commits ahead: #{status.ahead}" puts "Commits behind: #{status.behind}" ``` #### checkout_branch() ```ruby def checkout_branch(path, branch) ``` Checkout branch in the repository. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `branch` _String_ - Name of the branch to checkout **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - if checking out branch fails **Examples:** ```ruby # Checkout a branch sandbox.git.checkout_branch("workspace/repo", "feature-branch") ``` #### create_branch() ```ruby def create_branch(path, name) ``` Create branch in the repository. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _String_ - Name of the new branch to create **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - if creating branch fails **Examples:** ```ruby # Create a new branch sandbox.git.create_branch("workspace/repo", "new-feature") ``` #### delete_branch() ```ruby def delete_branch(path, name) ``` Delete branch in the repository. **Parameters**: - `path` _String_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _String_ - Name of the branch to delete **Returns**: - `void` **Raises**: - `Daytona:Sdk:Error` - if deleting branch fails **Examples:** ```ruby # Delete a branch sandbox.git.delete_branch("workspace/repo", "old-feature") ``` ## Image Represents an image definition for a Daytona sandbox. Do not construct this class directly. Instead use one of its static factory methods, such as `Image.base()`, `Image.debian_slim()`, or `Image.from_dockerfile()`. ### Constructors #### new Image() ```ruby def initialize(dockerfile:, context_list:) ``` **Parameters**: - `dockerfile` _String, nil_ - The Dockerfile content - `context_list` _Array\_ - List of context files **Returns**: - `Image` - a new instance of Image ### Methods #### dockerfile() ```ruby def dockerfile() ``` **Returns**: - `String, nil` - The generated Dockerfile for the image #### context_list() ```ruby def context_list() ``` **Returns**: - `Array\` - List of context files for the image #### pip_install() ```ruby def pip_install(*packages, find_links:, index_url:, extra_index_urls:, pre:, extra_options:) ``` Adds commands to install packages using pip **Parameters**: - `packages` _Array\_ - The packages to install - `find_links` _Array\, nil_ - The find-links to use - `index_url` _String, nil_ - The index URL to use - `extra_index_urls` _Array\, nil_ - The extra index URLs to use - `pre` _Boolean_ - Whether to install pre-release packages - `extra_options` _String_ - Additional options to pass to pip **Returns**: - `Image` - The image with the pip install commands added **Examples:** ```ruby image = Image.debian_slim("3.12").pip_install("requests", "pandas") ``` #### pip_install_from_requirements() ```ruby def pip_install_from_requirements(requirements_txt, find_links:, index_url:, extra_index_urls:, pre:, extra_options:) ``` Installs dependencies from a requirements.txt file **Parameters**: - `requirements_txt` _String_ - The path to the requirements.txt file - `find_links` _Array\, nil_ - The find-links to use - `index_url` _String, nil_ - The index URL to use - `extra_index_urls` _Array\, nil_ - The extra index URLs to use - `pre` _Boolean_ - Whether to install pre-release packages - `extra_options` _String_ - Additional options to pass to pip **Returns**: - `Image` - The image with the pip install commands added **Raises**: - `Sdk:Error` - If the requirements file does not exist **Examples:** ```ruby image = Image.debian_slim("3.12").pip_install_from_requirements("requirements.txt") ``` #### pip_install_from_pyproject() ```ruby def pip_install_from_pyproject(pyproject_toml, optional_dependencies:, find_links:, index_url:, extra_index_url:, pre:, extra_options:) ``` Installs dependencies from a pyproject.toml file **Parameters**: - `pyproject_toml` _String_ - The path to the pyproject.toml file - `optional_dependencies` _Array\_ - The optional dependencies to install - `find_links` _String, nil_ - The find-links to use - `index_url` _String, nil_ - The index URL to use - `extra_index_url` _String, nil_ - The extra index URL to use - `pre` _Boolean_ - Whether to install pre-release packages - `extra_options` _String_ - Additional options to pass to pip **Returns**: - `Image` - The image with the pip install commands added **Raises**: - `Sdk:Error` - If pyproject.toml parsing is not supported **Examples:** ```ruby image = Image.debian_slim("3.12").pip_install_from_pyproject("pyproject.toml", optional_dependencies: ["dev"]) ``` #### add_local_file() ```ruby def add_local_file(local_path, remote_path) ``` Adds a local file to the image **Parameters**: - `local_path` _String_ - The path to the local file - `remote_path` _String_ - The path to the file in the image **Returns**: - `Image` - The image with the local file added **Examples:** ```ruby image = Image.debian_slim("3.12").add_local_file("package.json", "/home/daytona/package.json") ``` #### add_local_dir() ```ruby def add_local_dir(local_path, remote_path) ``` Adds a local directory to the image **Parameters**: - `local_path` _String_ - The path to the local directory - `remote_path` _String_ - The path to the directory in the image **Returns**: - `Image` - The image with the local directory added **Examples:** ```ruby image = Image.debian_slim("3.12").add_local_dir("src", "/home/daytona/src") ``` #### run_commands() ```ruby def run_commands(*commands) ``` Runs commands in the image **Parameters**: - `commands` _Array\_ - The commands to run **Returns**: - `Image` - The image with the commands added **Examples:** ```ruby image = Image.debian_slim("3.12").run_commands('echo "Hello, world!"', 'echo "Hello again!"') ``` #### env() ```ruby def env(env_vars) ``` Sets environment variables in the image **Parameters**: - `env_vars` _Hash\_ - The environment variables to set **Returns**: - `Image` - The image with the environment variables added **Raises**: - `Sdk:Error` - **Examples:** ```ruby image = Image.debian_slim("3.12").env({"PROJECT_ROOT" => "/home/daytona"}) ``` #### workdir() ```ruby def workdir(path) ``` Sets the working directory in the image **Parameters**: - `path` _String_ - The path to the working directory **Returns**: - `Image` - The image with the working directory added **Examples:** ```ruby image = Image.debian_slim("3.12").workdir("/home/daytona") ``` #### entrypoint() ```ruby def entrypoint(entrypoint_commands) ``` Sets the entrypoint for the image **Parameters**: - `entrypoint_commands` _Array\_ - The commands to set as the entrypoint **Returns**: - `Image` - The image with the entrypoint added **Examples:** ```ruby image = Image.debian_slim("3.12").entrypoint(["/bin/bash"]) ``` #### cmd() ```ruby def cmd(cmd) ``` Sets the default command for the image **Parameters**: - `cmd` _Array\_ - The commands to set as the default command **Returns**: - `Image` - The image with the default command added **Examples:** ```ruby image = Image.debian_slim("3.12").cmd(["/bin/bash"]) ``` #### dockerfile_commands() ```ruby def dockerfile_commands(dockerfile_commands, context_dir:) ``` Adds arbitrary Dockerfile-like commands to the image **Parameters**: - `dockerfile_commands` _Array\_ - The commands to add to the Dockerfile - `context_dir` _String, nil_ - The path to the context directory **Returns**: - `Image` - The image with the Dockerfile commands added **Examples:** ```ruby image = Image.debian_slim("3.12").dockerfile_commands(["RUN echo 'Hello, world!'"]) ``` The Daytona Ruby SDK provides a robust interface for programmatically interacting with Daytona Sandboxes. ## Installation Install the Daytona Ruby SDK using Bundler by adding it to your Gemfile: ```ruby gem 'daytona' ``` Then run: ```bash bundle install ``` Or install it directly: ```bash gem install daytona ``` ## Getting Started Here's a simple example to help you get started with the Daytona Ruby SDK: ```ruby require 'daytona' # Initialize the SDK (uses environment variables by default) daytona = Daytona::Daytona.new # Create a new sandbox sandbox = daytona.create # Execute a command response = sandbox.process.exec(command: "echo 'Hello, World!'") puts response.result # Clean up daytona.delete(sandbox) ``` ## Configuration The SDK can be configured using environment variables or by passing options to the constructor: ```ruby require 'daytona' # Using environment variables (DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET) daytona = Daytona::Daytona.new # Using explicit configuration config = Daytona::Config.new( api_key: 'your-api-key', api_url: 'https://app.daytona.io/api', target: 'us' ) daytona = Daytona::Daytona.new(config) ``` ## Environment Variables The SDK supports the following environment variables: | Variable | Description | |----------|-------------| | `DAYTONA_API_KEY` | API key for authentication | | `DAYTONA_API_URL` | URL of the Daytona API (defaults to `https://app.daytona.io/api`) | | `DAYTONA_TARGET` | Target location for Sandboxes | | `DAYTONA_JWT_TOKEN` | JWT token for authentication (alternative to API key) | | `DAYTONA_ORGANIZATION_ID` | Organization ID (required when using JWT token) | ## LspServer LspServer class for Daytona SDK. ### Constructors #### new LspServer() ```ruby def initialize(language_id:, path_to_project:, toolbox_api:, sandbox_id:, otel_state:) ``` **Parameters**: - `language_id` _Symbol_ - - `path_to_project` _String_ - - `toolbox_api` _DaytonaToolboxApiClient:LspApi_ - - `sandbox_id` _String_ - - `otel_state` _Daytona:OtelState, nil_ - **Returns**: - `LspServer` - a new instance of LspServer ### Methods #### language_id() ```ruby def language_id() ``` **Returns**: - `Symbol` #### path_to_project() ```ruby def path_to_project() ``` **Returns**: - `String` #### toolbox_api() ```ruby def toolbox_api() ``` **Returns**: - `DaytonaToolboxApiClient:LspApi` #### sandbox_id() ```ruby def sandbox_id() ``` **Returns**: - `String` #### completions() ```ruby def completions(path:, position:) ``` Gets completion suggestions at a position in a file **Parameters**: - `path` _String_ - - `position` _Daytona:LspServer:Position_ - **Returns**: - `DaytonaApiClient:CompletionList` #### did_close() ```ruby def did_close(path) ``` Notify the language server that a file has been closed. This method should be called when a file is closed in the editor to allow the language server to clean up any resources associated with that file. **Parameters**: - `path` _String_ - **Returns**: - `void` #### did_open() ```ruby def did_open(path) ``` Notifies the language server that a file has been opened. This method should be called when a file is opened in the editor to enable language features like diagnostics and completions for that file. The server will begin tracking the file's contents and providing language features. **Parameters**: - `path` _String_ - **Returns**: - `void` #### document_symbols() ```ruby def document_symbols(path) ``` Gets symbol information (functions, classes, variables, etc.) from a document. **Parameters**: - `path` _String_ - **Returns**: - `Array\, nil_ - Environment variables to set for the command - `timeout` _Integer, nil_ - Maximum time in seconds to wait for the command to complete. 0 means wait indefinitely **Returns**: - `ExecuteResponse` - Command execution results containing exit_code, result, and artifacts **Examples:** ```ruby # Simple command response = sandbox.process.exec("echo 'Hello'") puts response.artifacts.stdout => "Hello\n" # Command with working directory result = sandbox.process.exec("ls", cwd: "workspace/src") # Command with timeout result = sandbox.process.exec("sleep 10", timeout: 5) ``` #### code_run() ```ruby def code_run(code:, params:, timeout:) ``` Execute code in the Sandbox using the appropriate language runtime **Parameters**: - `code` _String_ - Code to execute - `params` _CodeRunParams, nil_ - Parameters for code execution - `timeout` _Integer, nil_ - Maximum time in seconds to wait for the code to complete. 0 means wait indefinitely **Returns**: - `ExecuteResponse` - Code execution result containing exit_code, result, and artifacts **Examples:** ```ruby # Run Python code response = sandbox.process.code_run(<<~CODE) x = 10 y = 20 print(f"Sum: {x + y}") CODE puts response.artifacts.stdout # Prints: Sum: 30 ``` #### create_session() ```ruby def create_session(session_id) ``` Creates a new long-running background session in the Sandbox Sessions are background processes that maintain state between commands, making them ideal for scenarios requiring multiple related commands or persistent environment setup. **Parameters**: - `session_id` _String_ - Unique identifier for the new session **Returns**: - `void` **Examples:** ```ruby # Create a new session session_id = "my-session" sandbox.process.create_session(session_id) session = sandbox.process.get_session(session_id) # Do work... sandbox.process.delete_session(session_id) ``` #### get_session() ```ruby def get_session(session_id) ``` Gets a session in the Sandbox **Parameters**: - `session_id` _String_ - Unique identifier of the session to retrieve **Returns**: - `DaytonaApiClient:Session` - Session information including session_id and commands **Examples:** ```ruby session = sandbox.process.get_session("my-session") session.commands.each do |cmd| puts "Command: #{cmd.command}" end ``` #### get_entrypoint_session() ```ruby def get_entrypoint_session() ``` Gets the Sandbox entrypoint session **Returns**: - `DaytonaApiClient:Session` - Entrypoint session information including session_id and commands **Examples:** ```ruby session = sandbox.process.get_entrypoint_session() session.commands.each do |cmd| puts "Command: #{cmd.command}" end ``` #### get_session_command() ```ruby def get_session_command(session_id:, command_id:) ``` Gets information about a specific command executed in a session **Parameters**: - `session_id` _String_ - Unique identifier of the session - `command_id` _String_ - Unique identifier of the command **Returns**: - `DaytonaApiClient:Command` - Command information including id, command, and exit_code **Examples:** ```ruby cmd = sandbox.process.get_session_command(session_id: "my-session", command_id: "cmd-123") if cmd.exit_code == 0 puts "Command #{cmd.command} completed successfully" end ``` #### execute_session_command() ```ruby def execute_session_command(session_id:, req:) ``` Executes a command in the session **Parameters**: - `session_id` _String_ - Unique identifier of the session to use - `req` _Daytona:SessionExecuteRequest_ - Command execution request containing command and run_async **Returns**: - `Daytona:SessionExecuteResponse` - Command execution results containing cmd_id, output, stdout, stderr, and exit_code **Examples:** ```ruby # Execute commands in sequence, maintaining state session_id = "my-session" # Change directory req = Daytona::SessionExecuteRequest.new(command: "cd /workspace") sandbox.process.execute_session_command(session_id:, req:) # Create a file req = Daytona::SessionExecuteRequest.new(command: "echo 'Hello' > test.txt") sandbox.process.execute_session_command(session_id:, req:) # Read the file req = Daytona::SessionExecuteRequest.new(command: "cat test.txt") result = sandbox.process.execute_session_command(session_id:, req:) puts "Command stdout: #{result.stdout}" puts "Command stderr: #{result.stderr}" ``` #### get_session_command_logs() ```ruby def get_session_command_logs(session_id:, command_id:) ``` Get the logs for a command executed in a session **Parameters**: - `session_id` _String_ - Unique identifier of the session - `command_id` _String_ - Unique identifier of the command **Returns**: - `Daytona:SessionCommandLogsResponse` - Command logs including output, stdout, and stderr **Examples:** ```ruby logs = sandbox.process.get_session_command_logs(session_id: "my-session", command_id: "cmd-123") puts "Command stdout: #{logs.stdout}" puts "Command stderr: #{logs.stderr}" ``` #### get_session_command_logs_async() ```ruby def get_session_command_logs_async(session_id:, command_id:, on_stdout:, on_stderr:) ``` Asynchronously retrieves and processes the logs for a command executed in a session as they become available **Parameters**: - `session_id` _String_ - Unique identifier of the session - `command_id` _String_ - Unique identifier of the command - `on_stdout` _Proc_ - Callback function to handle stdout log chunks as they arrive - `on_stderr` _Proc_ - Callback function to handle stderr log chunks as they arrive **Returns**: - `WebSocket:Client:Simple:Client` **Examples:** ```ruby sandbox.process.get_session_command_logs_async( session_id: "my-session", command_id: "cmd-123", on_stdout: ->(log) { puts "[STDOUT]: #{log}" }, on_stderr: ->(log) { puts "[STDERR]: #{log}" } ) ``` #### get_entrypoint_logs() ```ruby def get_entrypoint_logs() ``` Get the sandbox entrypoint logs **Returns**: - `Daytona:SessionCommandLogsResponse` - Entrypoint logs including output, stdout, and stderr **Examples:** ```ruby logs = sandbox.process.get_entrypoint_logs() puts "Command stdout: #{logs.stdout}" puts "Command stderr: #{logs.stderr}" ``` #### get_entrypoint_logs_async() ```ruby def get_entrypoint_logs_async(on_stdout:, on_stderr:) ``` Asynchronously retrieves and processes the sandbox entrypoint logs as they become available **Parameters**: - `on_stdout` _Proc_ - Callback function to handle stdout log chunks as they arrive - `on_stderr` _Proc_ - Callback function to handle stderr log chunks as they arrive **Returns**: - `WebSocket:Client:Simple:Client` **Examples:** ```ruby sandbox.process.get_entrypoint_logs_async( on_stdout: ->(log) { puts "[STDOUT]: #{log}" }, on_stderr: ->(log) { puts "[STDERR]: #{log}" } ) ``` #### send_session_command_input() ```ruby def send_session_command_input(session_id:, command_id:, data:) ``` Sends input data to a command executed in a session This method allows you to send input to an interactive command running in a session, such as responding to prompts or providing data to stdin. **Parameters**: - `session_id` _String_ - Unique identifier of the session - `command_id` _String_ - Unique identifier of the command - `data` _String_ - Input data to send to the command **Returns**: - `void` #### list_sessions() ```ruby def list_sessions() ``` **Returns**: - `Array\` - List of all sessions in the Sandbox **Examples:** ```ruby sessions = sandbox.process.list_sessions sessions.each do |session| puts "Session #{session.session_id}:" puts " Commands: #{session.commands.length}" end ``` #### delete_session() ```ruby def delete_session(session_id) ``` Terminates and removes a session from the Sandbox, cleaning up any resources associated with it **Parameters**: - `session_id` _String_ - Unique identifier of the session to delete **Examples:** ```ruby # Create and use a session sandbox.process.create_session("temp-session") # ... use the session ... # Clean up when done sandbox.process.delete_session("temp-session") ``` #### create_pty_session() ```ruby def create_pty_session(id:, cwd:, envs:, pty_size:) ``` Creates a new PTY (pseudo-terminal) session in the Sandbox. Creates an interactive terminal session that can execute commands and handle user input. The PTY session behaves like a real terminal, supporting features like command history. **Parameters**: - `id` _String_ - Unique identifier for the PTY session. Must be unique within the Sandbox. - `cwd` _String, nil_ - Working directory for the PTY session. Defaults to the sandbox's working directory. - `envs` _Hash\, nil_ - Environment variables to set in the PTY session. These will be merged with the Sandbox's default environment variables. - `pty_size` _PtySize, nil_ - Terminal size configuration. Defaults to 80x24 if not specified. **Returns**: - `PtyHandle` - Handle for managing the created PTY session. Use this to send input, receive output, resize the terminal, and manage the session lifecycle. **Raises**: - `Daytona:Sdk:Error` - If the PTY session creation fails or the session ID is already in use. **Examples:** ```ruby # Create a basic PTY session pty_handle = sandbox.process.create_pty_session(id: "my-pty") # Create a PTY session with specific size and environment pty_size = Daytona::PtySize.new(rows: 30, cols: 120) pty_handle = sandbox.process.create_pty_session( id: "my-pty", cwd: "/workspace", envs: {"NODE_ENV" => "development"}, pty_size: pty_size ) # Use the PTY session pty_handle.wait_for_connection pty_handle.send_input("ls -la\n") result = pty_handle.wait pty_handle.disconnect ``` #### connect_pty_session() ```ruby def connect_pty_session(session_id) ``` Connects to an existing PTY session in the Sandbox. Establishes a WebSocket connection to an existing PTY session, allowing you to interact with a previously created terminal session. **Parameters**: - `session_id` _String_ - Unique identifier of the PTY session to connect to. **Returns**: - `PtyHandle` - Handle for managing the connected PTY session. **Raises**: - `Daytona:Sdk:Error` - If the PTY session doesn't exist or connection fails. **Examples:** ```ruby # Connect to an existing PTY session pty_handle = sandbox.process.connect_pty_session("my-pty-session") pty_handle.wait_for_connection pty_handle.send_input("echo 'Hello World'\n") result = pty_handle.wait pty_handle.disconnect ``` #### resize_pty_session() ```ruby def resize_pty_session(session_id, pty_size) ``` Resizes a PTY session to the specified dimensions **Parameters**: - `session_id` _String_ - Unique identifier of the PTY session - `pty_size` _PtySize_ - New terminal size **Returns**: - `DaytonaApiClient:PtySessionInfo` - Updated PTY session information **Examples:** ```ruby pty_size = Daytona::PtySize.new(rows: 30, cols: 120) session_info = sandbox.process.resize_pty_session("my-pty", pty_size) puts "PTY resized to #{session_info.cols}x#{session_info.rows}" ``` #### delete_pty_session() ```ruby def delete_pty_session(session_id) ``` Deletes a PTY session, terminating the associated process **Parameters**: - `session_id` _String_ - Unique identifier of the PTY session to delete **Returns**: - `void` **Examples:** ```ruby sandbox.process.delete_pty_session("my-pty") ``` #### list_pty_sessions() ```ruby def list_pty_sessions() ``` Lists all PTY sessions in the Sandbox **Returns**: - `Array\` - List of PTY session information **Examples:** ```ruby sessions = sandbox.process.list_pty_sessions sessions.each do |session| puts "PTY Session #{session.id}: #{session.cols}x#{session.rows}" end ``` #### get_pty_session_info() ```ruby def get_pty_session_info(session_id) ``` Gets detailed information about a specific PTY session Retrieves comprehensive information about a PTY session including its current state, configuration, and metadata. **Parameters**: - `session_id` _String_ - Unique identifier of the PTY session to retrieve information for **Returns**: - `DaytonaApiClient:PtySessionInfo` - Detailed information about the PTY session including ID, state, creation time, working directory, environment variables, and more **Examples:** ```ruby # Get details about a specific PTY session session_info = sandbox.process.get_pty_session_info("my-session") puts "Session ID: #{session_info.id}" puts "Active: #{session_info.active}" puts "Working Directory: #{session_info.cwd}" puts "Terminal Size: #{session_info.cols}x#{session_info.rows}" ``` ## Sandbox Sandbox class for Daytona SDK. ### Constructors #### new Sandbox() ```ruby def initialize(code_toolbox:, sandbox_dto:, config:, sandbox_api:, otel_state:) ``` **Returns**: - `Sandbox` - a new instance of Sandbox ### Methods #### id() ```ruby def id() ``` **Returns**: - `String` - The ID of the sandbox #### organization_id() ```ruby def organization_id() ``` **Returns**: - `String` - The organization ID of the sandbox #### snapshot() ```ruby def snapshot() ``` **Returns**: - `String` - The snapshot used for the sandbox #### user() ```ruby def user() ``` **Returns**: - `String` - The user associated with the project #### env() ```ruby def env() ``` **Returns**: - `Hash\` - Environment variables for the sandbox #### labels() ```ruby def labels() ``` **Returns**: - `Hash\` - Labels for the sandbox #### public() ```ruby def public() ``` **Returns**: - `Boolean` - Whether the sandbox http preview is public #### network_block_all() ```ruby def network_block_all() ``` **Returns**: - `Boolean` - Whether to block all network access for the sandbox #### network_allow_list() ```ruby def network_allow_list() ``` **Returns**: - `String` - Comma-separated list of allowed CIDR network addresses for the sandbox #### target() ```ruby def target() ``` **Returns**: - `String` - The target environment for the sandbox #### cpu() ```ruby def cpu() ``` **Returns**: - `Float` - The CPU quota for the sandbox #### gpu() ```ruby def gpu() ``` **Returns**: - `Float` - The GPU quota for the sandbox #### memory() ```ruby def memory() ``` **Returns**: - `Float` - The memory quota for the sandbox #### disk() ```ruby def disk() ``` **Returns**: - `Float` - The disk quota for the sandbox #### state() ```ruby def state() ``` **Returns**: - `DaytonaApiClient:SandboxState` - The state of the sandbox #### desired_state() ```ruby def desired_state() ``` **Returns**: - `DaytonaApiClient:SandboxDesiredState` - The desired state of the sandbox #### error_reason() ```ruby def error_reason() ``` **Returns**: - `String` - The error reason of the sandbox #### backup_state() ```ruby def backup_state() ``` **Returns**: - `String` - The state of the backup #### backup_created_at() ```ruby def backup_created_at() ``` **Returns**: - `String` - The creation timestamp of the last backup #### auto_stop_interval() ```ruby def auto_stop_interval() ``` **Returns**: - `Float` - Auto-stop interval in minutes (0 means disabled) #### auto_archive_interval() ```ruby def auto_archive_interval() ``` **Returns**: - `Float` - Auto-archive interval in minutes #### auto_delete_interval() ```ruby def auto_delete_interval() ``` (negative value means disabled, 0 means delete immediately upon stopping) **Returns**: - `Float` - Auto-delete interval in minutes #### volumes() ```ruby def volumes() ``` **Returns**: - `Array\` - Array of volumes attached to the sandbox #### build_info() ```ruby def build_info() ``` **Returns**: - `DaytonaApiClient:BuildInfo` - Build information for the sandbox #### created_at() ```ruby def created_at() ``` **Returns**: - `String` - The creation timestamp of the sandbox #### updated_at() ```ruby def updated_at() ``` **Returns**: - `String` - The last update timestamp of the sandbox #### daemon_version() ```ruby def daemon_version() ``` **Returns**: - `String` - The version of the daemon running in the sandbox #### code_toolbox() ```ruby def code_toolbox() ``` **Returns**: - `Daytona:SandboxPythonCodeToolbox, Daytona:SandboxTsCodeToolbox` #### config() ```ruby def config() ``` **Returns**: - `Daytona:Config` #### sandbox_api() ```ruby def sandbox_api() ``` **Returns**: - `DaytonaApiClient:SandboxApi` #### process() ```ruby def process() ``` **Returns**: - `Daytona:Process` #### fs() ```ruby def fs() ``` **Returns**: - `Daytona:FileSystem` #### git() ```ruby def git() ``` **Returns**: - `Daytona:Git` #### computer_use() ```ruby def computer_use() ``` **Returns**: - `Daytona:ComputerUse` #### code_interpreter() ```ruby def code_interpreter() ``` **Returns**: - `Daytona:CodeInterpreter` #### archive() ```ruby def archive() ``` Archives the sandbox, making it inactive and preserving its state. When sandboxes are archived, the entire filesystem state is moved to cost-effective object storage, making it possible to keep sandboxes available for an extended period. The tradeoff between archived and stopped states is that starting an archived sandbox takes more time, depending on its size. Sandbox must be stopped before archiving. **Returns**: - `void` #### auto_archive_interval=() ```ruby def auto_archive_interval=(interval) ``` Sets the auto-archive interval for the Sandbox. The Sandbox will automatically archive after being continuously stopped for the specified interval. **Parameters**: - `interval` _Integer_ - **Returns**: - `Integer` **Raises**: - `Daytona:Sdk:Error` - #### auto_delete_interval=() ```ruby def auto_delete_interval=(interval) ``` Sets the auto-delete interval for the Sandbox. The Sandbox will automatically delete after being continuously stopped for the specified interval. **Parameters**: - `interval` _Integer_ - **Returns**: - `Integer` **Raises**: - `Daytona:Sdk:Error` - #### auto_stop_interval=() ```ruby def auto_stop_interval=(interval) ``` Sets the auto-stop interval for the Sandbox. The Sandbox will automatically stop after being idle (no new events) for the specified interval. Events include any state changes or interactions with the Sandbox through the SDK. Interactions using Sandbox Previews are not included. **Parameters**: - `interval` _Integer_ - **Returns**: - `Integer` **Raises**: - `Daytona:Sdk:Error` - #### create_ssh_access() ```ruby def create_ssh_access(expires_in_minutes) ``` Creates an SSH access token for the sandbox. **Parameters**: - `expires_in_minutes` _Integer_ - TThe number of minutes the SSH access token will be valid for **Returns**: - `DaytonaApiClient:SshAccessDto` #### delete() ```ruby def delete() ``` **Returns**: - `void` #### get_user_home_dir() ```ruby def get_user_home_dir() ``` Gets the user's home directory path for the logged in user inside the Sandbox. **Returns**: - `String` - The absolute path to the Sandbox user's home directory for the logged in user **Examples:** ```ruby user_home_dir = sandbox.get_user_home_dir puts "Sandbox user home: #{user_home_dir}" ``` #### get_work_dir() ```ruby def get_work_dir() ``` Gets the working directory path inside the Sandbox. **Returns**: - `String` - The absolute path to the Sandbox working directory. Uses the WORKDIR specified in the Dockerfile if present, or falling back to the user's home directory if not. **Examples:** ```ruby work_dir = sandbox.get_work_dir puts "Sandbox working directory: #{work_dir}" ``` #### labels=() ```ruby def labels=(labels) ``` Sets labels for the Sandbox. **Parameters**: - `labels` _Hash\_ - **Returns**: - `Hash\` #### preview_url() ```ruby def preview_url(port) ``` Retrieves the preview link for the sandbox at the specified port. If the port is closed, it will be opened automatically. For private sandboxes, a token is included to grant access to the URL. **Parameters**: - `port` _Integer_ - **Returns**: - `DaytonaApiClient:PortPreviewUrl` #### create_signed_preview_url() ```ruby def create_signed_preview_url(port, expires_in_seconds) ``` Creates a signed preview URL for the sandbox at the specified port. **Parameters**: - `port` _Integer_ - The port to open the preview link on - `expires_in_seconds` _Integer, nil_ - The number of seconds the signed preview URL will be valid for. Defaults to 60 seconds. **Returns**: - `DaytonaApiClient:SignedPortPreviewUrl` - The signed preview URL response object **Examples:** ```ruby signed_url = sandbox.create_signed_preview_url(3000, 120) puts "Signed URL: #{signed_url.url}" puts "Token: #{signed_url.token}" ``` #### expire_signed_preview_url() ```ruby def expire_signed_preview_url(port, token) ``` Expires a signed preview URL for the sandbox at the specified port. **Parameters**: - `port` _Integer_ - The port to expire the signed preview URL on - `token` _String_ - The token to expire **Returns**: - `void` **Examples:** ```ruby sandbox.expire_signed_preview_url(3000, "token-value") ``` #### refresh() ```ruby def refresh() ``` Refresh the Sandbox data from the API. **Returns**: - `void` #### refresh_activity() ```ruby def refresh_activity() ``` Refreshes the sandbox activity to reset the timer for automated lifecycle management actions. This method updates the sandbox's last activity timestamp without changing its state. It is useful for keeping long-running sessions alive while there is still user activity. **Returns**: - `void` **Examples:** ```ruby sandbox.refresh_activity ``` #### revoke_ssh_access() ```ruby def revoke_ssh_access(token) ``` Revokes an SSH access token for the sandbox. **Parameters**: - `token` _String_ - **Returns**: - `void` #### start() ```ruby def start(timeout) ``` Starts the Sandbox and waits for it to be ready. **Parameters**: - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s). **Returns**: - `void` #### recover() ```ruby def recover(timeout) ``` Recovers the Sandbox from a recoverable error and waits for it to be ready. **Parameters**: - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s). **Returns**: - `void` **Examples:** ```ruby sandbox = daytona.get('my-sandbox-id') sandbox.recover(timeout: 40) # Wait up to 40 seconds puts 'Sandbox recovered successfully' ``` #### stop() ```ruby def stop(timeout) ``` Stops the Sandbox and waits for it to be stopped. **Parameters**: - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s). **Returns**: - `void` #### resize() ```ruby def resize(resources, timeout) ``` Resizes the Sandbox resources. Changes the CPU, memory, or disk allocation for the Sandbox. Resizing a started sandbox allows increasing CPU and memory. To resize disk or decrease resources, the sandbox must be stopped first. **Parameters**: - `resources` _Daytona:Resources_ - New resource configuration - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s) **Returns**: - `void` **Raises**: - `Sdk:Error` - **Examples:** ```ruby sandbox.resize(Daytona::Resources.new(cpu: 4, memory: 8)) ``` ```ruby sandbox.stop sandbox.resize(Daytona::Resources.new(cpu: 2, memory: 4, disk: 30)) ``` #### wait_for_resize_complete() ```ruby def wait_for_resize_complete(_timeout) ``` Waits for the Sandbox resize operation to complete. Polls the Sandbox status until the state is no longer 'resizing'. **Parameters**: - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s) **Returns**: - `void` #### create_lsp_server() ```ruby def create_lsp_server(language_id:, path_to_project:) ``` Creates a new Language Server Protocol (LSP) server instance. The LSP server provides language-specific features like code completion, diagnostics, and more. **Parameters**: - `language_id` _Symbol_ - The language server type (e.g., Daytona::LspServer::Language::PYTHON) - `path_to_project` _String_ - Path to the project root directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Daytona:LspServer` #### validate_ssh_access() ```ruby def validate_ssh_access(token) ``` Validates an SSH access token for the sandbox. **Parameters**: - `token` _String_ - **Returns**: - `DaytonaApiClient:SshAccessValidationDto` #### wait_for_sandbox_start() ```ruby def wait_for_sandbox_start(_timeout) ``` Waits for the Sandbox to reach the 'started' state. Polls the Sandbox status until it reaches the 'started' state or encounters an error. **Parameters**: - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s). **Returns**: - `void` #### wait_for_sandbox_stop() ```ruby def wait_for_sandbox_stop(_timeout) ``` Waits for the Sandbox to reach the 'stopped' state. Polls the Sandbox status until it reaches the 'stopped' state or encounters an error. Treats destroyed as stopped to cover ephemeral sandboxes that are automatically deleted after stopping. **Parameters**: - `timeout` _Numeric_ - Maximum wait time in seconds (defaults to 60 s). **Returns**: - `void` ## SnapshotService SnapshotService class for Daytona SDK. ### Constructors #### new SnapshotService() ```ruby def initialize(snapshots_api:, object_storage_api:, default_region_id:, otel_state:) ``` **Parameters**: - `snapshots_api` _DaytonaApiClient:SnapshotsApi_ - The snapshots API client - `object_storage_api` _DaytonaApiClient:ObjectStorageApi_ - The object storage API client - `default_region_id` _String, nil_ - Default region ID for snapshot creation - `otel_state` _Daytona:OtelState, nil_ - **Returns**: - `SnapshotService` - a new instance of SnapshotService ### Methods #### list() ```ruby def list(page:, limit:) ``` List all Snapshots. **Parameters**: - `page` _Integer, Nil_ - - `limit` _Integer, Nil_ - **Returns**: - `Daytona:PaginatedResource` - Paginated list of all Snapshots **Raises**: - `Daytona:Sdk:Error` - **Examples:** ```ruby daytona = Daytona::Daytona.new response = daytona.snapshot.list(page: 1, limit: 10) snapshots.items.each { |snapshot| puts "#{snapshot.name} (#{snapshot.image_name})" } ``` #### delete() ```ruby def delete(snapshot) ``` Delete a Snapshot. **Parameters**: - `snapshot` _Daytona:Snapshot_ - Snapshot to delete **Returns**: - `void` **Examples:** ```ruby daytona = Daytona::Daytona.new snapshot = daytona.snapshot.get("demo") daytona.snapshot.delete(snapshot) puts "Snapshot deleted" ``` #### get() ```ruby def get(name) ``` Get a Snapshot by name. **Parameters**: - `name` _String_ - Name of the Snapshot to get **Returns**: - `Daytona:Snapshot` - The Snapshot object **Examples:** ```ruby daytona = Daytona::Daytona.new snapshot = daytona.snapshot.get("demo") puts "#{snapshot.name} (#{snapshot.image_name})" ``` #### create() ```ruby def create(params, on_logs:) ``` Creates and registers a new snapshot from the given Image definition. **Parameters**: - `params` _Daytona:CreateSnapshotParams_ - Parameters for snapshot creation - `on_logs` _Proc, Nil_ - Callback proc handling snapshot creation logs **Returns**: - `Daytona:Snapshot` - The created snapshot **Examples:** ```ruby image = Image.debianSlim('3.12').pipInstall('numpy') params = CreateSnapshotParams.new(name: 'my-snapshot', image: image) snapshot = daytona.snapshot.create(params) do |chunk| print chunk end ``` #### activate() ```ruby def activate(snapshot) ``` Activate a snapshot **Parameters**: - `snapshot` _Daytona:Snapshot_ - The snapshot instance **Returns**: - `Daytona:Snapshot` ## VolumeService Service for managing Daytona Volumes. Can be used to list, get, create and delete Volumes. ### Constructors #### new VolumeService() ```ruby def initialize(volumes_api, otel_state:) ``` Service for managing Daytona Volumes. Can be used to list, get, create and delete Volumes. **Parameters**: - `volumes_api` _DaytonaApiClient:VolumesApi_ - - `otel_state` _Daytona:OtelState, nil_ - **Returns**: - `VolumeService` - a new instance of VolumeService ### Methods #### create() ```ruby def create(name) ``` Create new Volume. **Parameters**: - `name` _String_ - **Returns**: - `Daytona:Volume` #### delete() ```ruby def delete(volume) ``` Delete a Volume. **Parameters**: - `volume` _Daytona:Volume_ - **Returns**: - `void` #### get() ```ruby def get(name, create:) ``` Get a Volume by name. **Parameters**: - `name` _String_ - - `create` _Boolean_ - **Returns**: - `Daytona:Volume` #### list() ```ruby def list() ``` List all Volumes. **Returns**: - `Array\` ## Volume Initialize volume from DTO ### Constructors #### new Volume() ```ruby def initialize(volume_dto) ``` Initialize volume from DTO **Parameters**: - `volume_dto` _DaytonaApiClient:SandboxVolume_ - **Returns**: - `Volume` - a new instance of Volume ### Methods #### id() ```ruby def id() ``` **Returns**: - `String` #### name() ```ruby def name() ``` **Returns**: - `String` #### organization_id() ```ruby def organization_id() ``` **Returns**: - `String` #### state() ```ruby def state() ``` **Returns**: - `String` #### created_at() ```ruby def created_at() ``` **Returns**: - `String` #### updated_at() ```ruby def updated_at() ``` **Returns**: - `String` #### last_used_at() ```ruby def last_used_at() ``` **Returns**: - `String` #### error_reason() ```ruby def error_reason() ``` **Returns**: - `String, nil` Runners are machines that power Daytona's compute plane, providing the underlying infrastructure for running sandbox workloads. Each runner is responsible for: - **Workload execution**: running sandbox workloads - **Resource management**: allocating and monitoring CPU, memory, and disk resources - **Health reporting**: continuously reporting metrics and health status to the Daytona control plane - **Network connectivity**: managing networking, proxy connections, and SSH access for sandboxes Runners in [shared](https://www.daytona.io/docs/en/regions.md#shared-regions) and [dedicated](https://www.daytona.io/docs/en/regions.md#dedicated-regions) regions are fully managed by Daytona — from provisioning and maintenance to monitoring and scaling. For custom regions, you bring your own runner machines and are responsible for their management and operation. :::caution Custom runners are currently an experimental feature and may change in future releases. To request access, please contact [support@daytona.io](mailto:support@daytona.io). ::: ## Custom regions Custom regions are created and managed by your organization, allowing you to use your own runner machines and scale compute resources independently within each region. This provides maximum control over data locality, compliance, and infrastructure configuration. Additionally, custom regions have no limits applied for concurrent resource usage, giving you full control over capacity and performance. ### Custom region configuration **name** (required) - A unique identifier for your region - Must contain only letters, numbers, underscores, periods, and hyphens - Used for targeting this region when creating a sandbox **proxyUrl** (optional) - The URL of the proxy service that routes traffic to sandboxes in this region - Required if the runner machines in this region are deployed in a private network **sshGatewayUrl** (optional) - The URL of the SSH gateway that handles SSH connections to sandboxes in this region - Required if the runner machines in this region are deployed in a private network **snapshotManagerUrl** (optional) - The URL of the snapshot manager that handles storage and retrieval of snapshots in this region - Required if the runner machines in this region are deployed in a private network ### Custom region credentials When you create a custom region, Daytona will provide credentials for any optional services you configure: - An API key that should be used by your proxy service to authenticate with Daytona - An API key that should be used by your SSH gateway service to authenticate with Daytona - Basic authentication credentials that Daytona uses to access your snapshot manager service :::note If needed, these credentials can always be regenerated, but you will need to redeploy the corresponding services with the updated credentials. ::: ## Custom runners Custom runners are created and managed by your organization, allowing you to use your own runner machines and scale compute resources independently within each custom region. ### Custom runner configuration **name** (required) - A unique identifier for the runner - Must contain only letters, numbers, underscores, periods, and hyphens - Helps distinguish between multiple runners in the same region **regionId** (required) - The ID of the region this runner is assigned to - Must be a custom region owned by your organization - All runners in a region share the region's proxy and SSH gateway configuration ### Custom runner token When you create a custom runner, Daytona will provide you with a **token** that should be used by your runner to authenticate with Daytona. :::note Save this token securely. You won't be able to see it again. ::: ### Installing the custom runner After registering a custom runner and obtaining its secure token, you need to install and configure the Daytona runner application on your infrastructure. :::note Detailed installation instructions for the runner application will be provided in a future update. For assistance with runner installation, please contact [support@daytona.io](mailto:support@daytona.io). ::: Daytona provides **full composable computers** — **sandboxes** — for AI agents. Sandboxes are isolated runtime environments you can manage programmatically to run code. Each sandbox runs in isolation, giving it a dedicated kernel, filesystem, network stack, and allocated vCPU, RAM, and disk. Agents get access to a full composable computer environment where they can install packages, run servers, compile code, and manage processes. Sandboxes have **1 vCPU**, **1GB RAM**, and **3GiB disk** by default. [Organizations](https://www.daytona.io/docs/en/organizations.md) get a maximum sandbox resource limit of **4 vCPUs**, **8GB RAM**, and **10GB disk**. For more power, see [resources](#resources) or contact [support@daytona.io](mailto:support@daytona.io). Sandboxes are built from OCI-compliant images. A [snapshot](https://www.daytona.io/docs/en/snapshots.md) captures a fully configured environment: base OS, installed packages, dependencies, and configuration to create new sandboxes. Each sandbox has its own network stack with per-sandbox firewall rules. By default, sandboxes follow standard network policies, but you can restrict egress to a specific set of allowed destinations or block all outbound traffic entirely. For details on configuring network access, see [network settings](https://www.daytona.io/docs/en/network-limits.md). For a detailed overview of the Daytona platform, see [architecture](https://www.daytona.io/docs/en/architecture.md). ## Sandbox lifecycle Throughout its lifecycle, a Daytona Sandbox can have several different states. The diagram below shows the states and possible transitions between them. ## Multiple runtime support Daytona Sandboxes support Python, TypeScript, and JavaScript programming language runtimes for direct code execution inside the sandbox. The `language` parameter controls which programming language runtime is used for the sandbox: - **`python`** - **`typescript`** - **`javascript`** If omitted, the Daytona SDK will default to `python`. To override this, explicitly set the `language` value when creating the sandbox. :::note **Sandbox Names**: You can specify a custom name for your sandbox using the `name` parameter. If not provided, the sandbox ID will be used as the name. Sandbox names are reusable - once a sandbox with a specific name is destroyed, that name becomes available for use again. ::: ## Create Sandboxes Daytona provides methods to create sandboxes using the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) or programatically using the Daytona [Python](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), [Go](https://www.daytona.io/docs/en/go-sdk/daytona.md#type-sandbox) **SDKs**, [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-create), or [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox). You can specify [programming language runtime](https://www.daytona.io/docs/en/sandboxes.md#multiple-runtime-support), [snapshots](https://www.daytona.io/docs/en/snapshots.md), [resources](https://www.daytona.io/docs/en/sandboxes.md#resources), [regions](https://www.daytona.io/docs/en/regions.md), [environment variables](https://www.daytona.io/docs/en/configuration.md#environment-variables), and [volumes](https://www.daytona.io/docs/en/volumes.md) for each sandbox. Running sandboxes utilize CPU, memory, and disk storage. Every resource is charged per second of usage. 1. Navigate to [Daytona Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Click the **Create Sandbox** button 3. Enter the name of the sandbox 4. Select a source for the sandbox: - [Snapshot](https://www.daytona.io/docs/en/snapshots.md): a pre-configured sandbox template - **Image**: OCI-compliant container image ([public](https://www.daytona.io/docs/en/snapshots.md#using-public-images), [local](https://www.daytona.io/docs/en/snapshots.md#using-local-images), [private registries](https://www.daytona.io/docs/en/snapshots.md#using-images-from-private-registries)). Images require setting [sandbox resources](https://www.daytona.io/docs/en/sandboxes.md#resources). Default: **1 vCPU**, **1GB RAM**, **3GiB disk**. 5. Select a [region](https://www.daytona.io/docs/en/regions.md): if not specified, your organization's default region will be used 6. Define [sandbox lifecycle management](#automated-lifecycle-management) options or set as an [ephemeral sandbox](#ephemeral-sandboxes) 7. Add environment variables in key-value pairs or import them from a **`.env`** file 8. Add labels in key-value pairs 9. Select network settings: - **Public HTTP preview**: allow public access to HTTP [preview URLs](https://www.daytona.io/docs/en/preview.md) - **Block all network access**: block all outbound network access 10. Click the **Create** button to create the sandbox ```python from daytona import Daytona, CreateSandboxFromSnapshotParams daytona = Daytona() # Create a sandbox sandbox = daytona.create() # Create a sandbox with python params = CreateSandboxFromSnapshotParams(language="python") sandbox = daytona.create(params) # Create a sandbox with a custom name params = CreateSandboxFromSnapshotParams(name="my_awesome_sandbox") sandbox = daytona.create(params) # Create a sandbox with custom labels params = CreateSandboxFromSnapshotParams(labels={"LABEL": "label"}) sandbox = daytona.create(params) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); // Create a sandbox const sandbox = await daytona.create(); // Create a sandbox with typescript const sandbox = await daytona.create({ language: 'typescript' }); // Create a sandbox with a custom name const sandbox = await daytona.create({ name: 'my_awesome_sandbox' }); // Create a sandbox with custom labels const sandbox = await daytona.create({ labels: { LABEL: 'label' } }); ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new # Create a sandbox sandbox = daytona.create # Create a sandbox with python params = Daytona::CreateSandboxFromSnapshotParams.new(language: Daytona::CodeLanguage::PYTHON) sandbox = daytona.create(params) # Create a sandbox with custom labels params = Daytona::CreateSandboxFromSnapshotParams.new(labels: { 'LABEL' => 'label' }) sandbox = daytona.create(params) ``` ```go // Create a sandbox params := types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ Language: types.CodeLanguagePython, }, } sandbox, err := client.Create(ctx, params) ``` ```bash daytona create [flags] ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{}' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), [API](https://www.daytona.io/docs/en/tools/api.md#daytona/), and [CLI](https://www.daytona.io/docs/en/tools/cli.md) references: > [**create (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/daytona.md#daytonacreate) > > [**create (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#create) > > [**create (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/daytona.md#create) > > [**Create (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Client.Create) > > [**create (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-create) > > [**create (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox) ### Resources Sandboxes have **1 vCPU**, **1GB RAM**, and **3GiB disk** by default. Organizations get a maximum sandbox resource limit of **4 vCPUs**, **8GB RAM**, and **10GB disk**. To set custom sandbox resources (CPU, memory, and disk space), use the `Resources` class: ```python from daytona import Daytona, Resources, CreateSandboxFromImageParams, Image daytona = Daytona() # Create a sandbox with custom resources resources = Resources( cpu=2, # 2 CPU cores memory=4, # 4GB RAM disk=8, # 8GB disk space ) params = CreateSandboxFromImageParams( image=Image.debian_slim("3.12"), resources=resources ) sandbox = daytona.create(params) ``` ```typescript import { Daytona, Image } from "@daytonaio/sdk"; async function main() { const daytona = new Daytona(); // Create a sandbox with custom resources const sandbox = await daytona.create({ image: Image.debianSlim("3.12"), resources: { cpu: 2, // 2 CPU cores memory: 4, // 4GB RAM disk: 8, // 8GB disk space }, }); } main(); ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new # Create a sandbox with custom resources sandbox = daytona.create( Daytona::CreateSandboxFromImageParams.new( image: Daytona::Image.debian_slim('3.12'), resources: Daytona::Resources.new( cpu: 2, # 2 CPU cores memory: 4, # 4GB RAM disk: 8 # 8GB disk space ) ) ) ``` ```go // Create a sandbox with custom resources sandbox, err := client.Create(ctx, types.ImageParams{ Image: "python:3.11", Resources: &types.Resources{ CPU: 2, // 2 CPU cores Memory: 4, // 4GiB RAM Disk: 8, // 8GiB disk space }, }) ``` ```bash # --memory is in MB; --disk is in GB daytona create --cpu 2 --memory 4096 --disk 8 ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "cpu": 2, "memory": 4, "disk": 8 }' ``` All resource parameters are optional and must be integers. If not specified, Daytona will use the default values listed below. | **Resource** | **Unit** | **Default** | **Minimum** | **Maximum** | | ------------ | -------- | ----------- | ----------- | ----------- | | CPU | vCPU | **`1`** | **`1`** | **`4`** | | Memory | GiB | **`1`** | **`1`** | **`8`** | | Disk | GiB | **`3`** | **`1`** | **`10`** | Maximum values are per-sandbox limits set at the [organization](https://www.daytona.io/docs/en/organizations.md) level. Contact [support@daytona.io](mailto:support@daytona.io) to increase limits. For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#resources), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md) references: > [**Resources (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#resources) > > [**Resources (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#resources) > > [**Resources (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/daytona.md) > > [**Resources (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox) > > [**Resources (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-create) ### Ephemeral Sandboxes Ephemeral Sandboxes are automatically deleted once they are stopped. They are useful for short-lived tasks or for testing purposes. To create an ephemeral Sandbox, set the `ephemeral` parameter to `True` when creating a sandbox: ```python from daytona import Daytona, CreateSandboxFromSnapshotParams daytona = Daytona() # Create an ephemeral sandbox params = CreateSandboxFromSnapshotParams( ephemeral=True, auto_stop_interval=5 # The ephemeral sandbox will be deleted after 5 minutes of inactivity ) sandbox = daytona.create(params) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); // Create an ephemeral sandbox const sandbox = await daytona.create({ ephemeral: true, autoStopInterval: 5 // The ephemeral sandbox will be deleted after 5 minutes of inactivity }); ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new # Create an ephemeral Sandbox params = Daytona::CreateSandboxFromSnapshotParams.new( ephemeral: true, auto_stop_interval: 5 # The ephemeral sandbox will be deleted after 5 minutes of inactivity ) sandbox = daytona.create(params) ``` ```go // Create an ephemeral sandbox autoStopInterval := 5 params := types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ Language: types.CodeLanguagePython, Ephemeral: true, AutoStopInterval: &autoStopInterval, }, } sandbox, err := client.Create(ctx, params) ``` :::note Setting ["autoDeleteInterval: 0"](#auto-delete-interval) has the same effect as setting "ephemeral" to `true`. ::: ### Network settings (Firewall) Daytona Sandboxes provide configurable network firewall controls to enhance security and manage connectivity. By default, network access follows standard security policies, but you can [customize network settings](https://www.daytona.io/docs/en/network-limits.md) when creating a sandbox. ## Start Sandboxes Daytona provides options to start sandboxes in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) or programmatically using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/) references. 1. Navigate to [Daytona Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Click the start icon (**▶**) next to the sandbox you want to start. ```text Starting sandbox with ID: ``` ```python sandbox = daytona.create(CreateSandboxFromSnapshotParams(language="python")) # Start Sandbox sandbox.start() ``` ```typescript const sandbox = await daytona.create({ language: 'typescript' }); // Start Sandbox await sandbox.start(); ``` ```ruby sandbox = daytona.create(Daytona::CreateSandboxFromSnapshotParams.new(language: Daytona::CodeLanguage::PYTHON)) # Start Sandbox sandbox.start ``` ```go // Start sandbox err = sandbox.Start(ctx) ``` ```bash daytona start [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/start' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**start (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxstart) > > [**start (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#start) > > [**start (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#start) > > [**Start (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.Start) > > [**start (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-start) > > [**start (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/start) ## List Sandboxes Daytona provides options to view information about sandboxes in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) via the [sandbox details page](#sandbox-details-page) or programmatically using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references. ```python # List all sandboxes result = daytona.list() # Iterate through results for sandbox in result.items: print(f"Sandbox: {sandbox.id} (state: {sandbox.state})") # List sandboxes with labels filter result = daytona.list(labels={"env": "dev"}) ``` ```typescript // List all sandboxes const result = await daytona.list(); // Iterate through results for (const sandbox of result.items) { console.log(`Sandbox: ${sandbox.id} (state: ${sandbox.state})`); } // List sandboxes with labels filter const filtered = await daytona.list({ 'env': 'dev' }); ``` ```ruby # List all sandboxes result = daytona.list # Iterate through results result.items.each do |sandbox| puts "Sandbox: #{sandbox.id} (state: #{sandbox.state})" end # List sandboxes with labels filter result = daytona.list({ 'env' => 'dev' }) ``` ```go // List all sandboxes result, err := client.List(ctx, nil, nil, nil) // Iterate through results for _, sandbox := range result.Items { fmt.Printf("Sandbox: %s (state: %s)\n", sandbox.Name, sandbox.State) } ``` ```bash daytona list [flags] ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**list (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/daytona.md#daytonalist) > > [**list (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/daytona.md#list) > > [**list (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/daytona.md#list) > > [**List (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Client.List) > > [**list (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-list) > > [**list (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/GET/sandbox) ### Sandbox details page [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) provides a sandbox details page to view detailed information about a sandbox and interact with it directly. 1. Navigate to [Daytona Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Click on a sandbox to open its details page The sandbox details page provides a summary of the sandbox information and actions to perform on the sandbox: - **Name**: the name of the sandbox - **UUID**: the unique identifier of the sandbox - **State**: the sandbox state with a visual indicator - **Actions**: [start](#start-sandboxes), [stop](#stop-sandboxes), [recover](#recover-sandboxes), [archive](#archive-sandboxes), [delete](#delete-sandboxes), refresh, [SSH access](https://www.daytona.io/docs/en/ssh-access.md), [screen recordings](https://www.daytona.io/docs/en/computer-use.md#screen-recording) - [**Region**](https://www.daytona.io/docs/en/regions.md): the target region where the sandbox is running - [**Snapshot**](https://www.daytona.io/docs/en/snapshots.md): the snapshot used to create the sandbox - [**Resources**](#resources): allocated sandbox CPU, memory, and disk - [**Lifecycle**](#sandbox-lifecycle): [auto-stop](#auto-stop-interval), [auto-archive](#auto-archive-interval), and [auto-delete](#auto-delete-interval) intervals - **Labels**: key-value pairs assigned to the sandbox - **Timestamps**: when the sandbox was created and when the last event occurred - [**Web terminal**](https://www.daytona.io/docs/en/web-terminal.md): an embedded web terminal session directly in the browser - [**VNC**](https://www.daytona.io/docs/en/vnc-access.md): a graphical desktop session for sandboxes that have a desktop environment - [**Logs**](https://www.daytona.io/docs/en/experimental/otel-collection.md): a detailed record of user and system activity for the sandbox - **Metrics**: sandbox metrics data displayed as charts - **Traces**: distributed traces and spans collected from the sandbox - **Spending**: usage and cost over time ## Stop Sandboxes Daytona provides methods to stop sandboxes in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) or programmatically using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md). 1. Navigate to [Daytona Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Click the stop icon (**⏹**) next to the sandbox you want to stop. ```text Stopping sandbox with ID: ``` Stopped sandboxes maintain filesystem persistence while their memory state is cleared. They incur only disk usage costs and can be started again when needed. The stopped state should be used when a sandbox is expected to be started again soon. Otherwise, it is recommended to stop and then archive the sandbox to eliminate disk usage costs. ```python sandbox = daytona.create(CreateSandboxFromSnapshotParams(language="python")) # Stop sandbox sandbox.stop() print(sandbox.id) # 7cd11133-96c1-4cc8-9baa-c757b8f8c916 # The sandbox ID can later be used to get the sandbox and start it sandbox = daytona.get("7cd11133-96c1-4cc8-9baa-c757b8f8c916") # Start sandbox sandbox.start() ``` ```typescript const sandbox = await daytona.create({ language: 'typescript' }); // Stop sandbox await sandbox.stop(); console.log(sandbox.id) // 7cd11133-96c1-4cc8-9baa-c757b8f8c916 // The sandbox ID can later be used to get the sandbox and start it const found = await daytona.get('7cd11133-96c1-4cc8-9baa-c757b8f8c916'); // Start sandbox await found.start(); ``` ```ruby sandbox = daytona.create(Daytona::CreateSandboxFromSnapshotParams.new(language: Daytona::CodeLanguage::PYTHON)) # Stop sandbox sandbox.stop puts sandbox.id # 7cd11133-96c1-4cc8-9baa-c757b8f8c916 # The sandbox ID can later be used to find the sandbox and start it sandbox = daytona.get('7cd11133-96c1-4cc8-9baa-c757b8f8c916') # Start sandbox sandbox.start ``` ```go // Stop sandbox err = sandbox.Stop(ctx) fmt.Println(sandbox.ID) // 7cd11133-96c1-4cc8-9baa-c757b8f8c916 // The sandbox ID can later be used to find the sandbox and start it sandbox, err = client.Get(ctx, sandbox.ID) // Start sandbox err = sandbox.Start(ctx) ``` ```bash daytona stop [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/stop' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**stop (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxstop) > > [**stop (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#stop) > > [**stop (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#stop) > > [**Stop (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.Stop) > > [**stop (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-stop) > > [**stop (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/stop) ## Archive Sandboxes Daytona provides methods to archive sandboxes in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) or programmatically using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md). When sandboxes are archived, the entire filesystem state is moved to a cost-effective object storage, making it possible to keep sandboxes available for an extended period. Starting an archived sandbox takes more time than starting a stopped sandbox, depending on its size. A sandbox must be stopped before it can be archived and can be started again in the same way as a stopped sandbox. ```python # Archive Sandbox sandbox.archive() ``` ```typescript // Archive Sandbox await sandbox.archive(); ``` ```ruby # Archive Sandbox sandbox.archive ``` ```go // Archive sandbox err = sandbox.Archive(ctx) ``` ```bash daytona archive [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/archive' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**archive (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxarchive) > > [**archive (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#archive) > > [**archive (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#archive) > > [**Archive (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.Archive) > > [**archive (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-archive) > > [**archive (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/archive) ## Recover Sandboxes Daytona provides methods to recover sandboxes in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) or programmatically using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md). ```python # Recover sandbox sandbox.recover() ``` ```typescript // Recover sandbox await sandbox.recover(); ``` ```ruby # Recover sandbox sandbox.recover ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/recover' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**recover (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxrecover) > > [**recover (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#recover) > > [**recover (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#recover) > > [**recover (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/recover) ### Recover from error state When a sandbox enters an error state, it can sometimes be recovered using the `recover` method, depending on the underlying error reason. The `recoverable` flag indicates whether the error state can be resolved through an automated recovery procedure. :::note Recovery actions are not performed automatically because they address errors that require **further user intervention**, such as freeing up storage space. ::: ```python # Check if the Sandbox is recoverable if sandbox.recoverable: sandbox.recover() print("Sandbox recovered successfully") ``` ```typescript // Check if the Sandbox is recoverable if (sandbox.recoverable) { await sandbox.recover(); console.log('Sandbox recovered successfully'); } ``` ```ruby # Check if the Sandbox is in an error state before recovering if sandbox.state == 'error' sandbox.recover puts 'Sandbox recovered successfully' end ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/recover' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**recover (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxrecover) > > [**recover (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#recover) > > [**recover (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#recover) > > [**recover (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/recover) ## Resize Sandboxes Daytona provides methods to resize sandbox resources (CPU, memory, and disk) after creation. Resizing a started sandbox allows you to `increase CPU and memory` without interruption. To `increase disk capacity` or `decrease CPU and memory`, the sandbox must be stopped first. ```python from daytona import Daytona, Resources daytona = Daytona() sandbox = daytona.create() # Resize a started sandbox (CPU and memory can be increased) sandbox.resize(Resources(cpu=2, memory=4)) # Resize a stopped sandbox (CPU, memory, and disk can be changed) sandbox.stop() sandbox.resize(Resources(cpu=4, memory=8, disk=20)) sandbox.start() ``` ```typescript import { Daytona } from '@daytonaio/sdk'; const daytona = new Daytona(); const sandbox = await daytona.create(); // Resize a started sandbox (CPU and memory can be increased) await sandbox.resize({ cpu: 2, memory: 4 }); // Resize a stopped sandbox (CPU, memory, and disk can be changed) await sandbox.stop(); await sandbox.resize({ cpu: 4, memory: 8, disk: 20 }); await sandbox.start(); ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.create # Resize a started sandbox (CPU and memory can be increased) sandbox.resize(Daytona::Resources.new(cpu: 2, memory: 4)) # Resize a stopped sandbox (CPU, memory, and disk can be changed) sandbox.stop sandbox.resize(Daytona::Resources.new(cpu: 4, memory: 8, disk: 20)) sandbox.start ``` ```go // Resize a started sandbox (CPU and memory can be increased) err := sandbox.Resize(ctx, &types.Resources{CPU: 2, Memory: 4}) // Resize a stopped sandbox (CPU, memory, and disk can be changed) err = sandbox.Stop(ctx) err = sandbox.Resize(ctx, &types.Resources{CPU: 4, Memory: 8, Disk: 20}) err = sandbox.Start(ctx) ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/resize' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "cpu": 2, "memory": 4, "disk": 20 }' ``` :::note - **started** sandboxes: CPU and memory can only be increased, not decreased. Disk cannot be changed. - **stopped** sandboxes: CPU, memory, and disk can be changed. Disk can only be increased. ::: For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxresize), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#resize), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.Resize), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#resize) references: > [**resize (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxresize) > > [**resize (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#resize) > > [**Resize (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.Resize) > > [**resize (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#resize) ## Delete Sandboxes Daytona provides methods to delete sandboxes in [Daytona Dashboard ↗](https://app.daytona.io/dashboard/) or programmatically using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md). 1. Navigate to [Daytona Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Click the **Delete** button next to the sandbox you want to delete. ```text Deleting sandbox with ID: ``` ```python # Delete sandbox sandbox.delete() ``` ```typescript // Delete sandbox await sandbox.delete(); ``` ```ruby # Delete sandbox sandbox.delete ``` ```go // Delete sandbox err = sandbox.Delete(ctx) ``` ```bash daytona delete [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}' \ --request DELETE \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**delete (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxdelete) > > [**delete (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#delete) > > [**delete (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#delete) > > [**Delete (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.Delete) > > [**delete (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-delete) > > [**delete (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/DELETE/sandbox/{sandboxIdOrName}) ## Automated lifecycle management Daytona Sandboxes can be automatically stopped, archived, and deleted based on user-defined intervals. ### Auto-stop interval The auto-stop interval parameter sets the amount of time after which a running sandbox will be automatically stopped. The auto-stop interval will trigger even if there are internal processes running in the sandbox. The system differentiates between "internal processes" and "active user interaction". Merely having a script or background task running is not sufficient to keep the sandbox alive. The parameter can either be set to: - a time interval in minutes - `0`: disables the auto-stop functionality, allowing the sandbox to run indefinitely If the parameter is not set, the default interval of `15 minutes` will be used. ```python sandbox = daytona.create(CreateSandboxFromSnapshotParams( snapshot="my-snapshot-name", # Disables the auto-stop feature - default is 15 minutes auto_stop_interval=0, )) ``` ```typescript const sandbox = await daytona.create({ snapshot: "my-snapshot-name", // Disables the auto-stop feature - default is 15 minutes autoStopInterval: 0, }); ``` ```ruby sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( snapshot: 'my-snapshot-name', # Disables the auto-stop feature - default is 15 minutes auto_stop_interval: 0 ) ) ``` ```go // Create a sandbox with auto-stop disabled autoStopInterval := 0 params := types.SnapshotParams{ Snapshot: "my-snapshot-name", SandboxBaseParams: types.SandboxBaseParams{ AutoStopInterval: &autoStopInterval, }, } sandbox, err := client.Create(ctx, params) ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/autostop/{interval}' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**set_autostop_interval (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxset_autostop_interval) > > [**setAutostopInterval (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#setautostopinterval) > > [**auto_stop_interval (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#auto_stop_interval) > > [**set_auto_stop_interval (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/autostop/1) #### What resets the timer The inactivity timer resets only for specific external interactions: - Accessing [sandbox previews](https://www.daytona.io/docs/en/preview.md) (network requests through preview URLs) - Active [SSH connections](https://www.daytona.io/docs/en/ssh-access.md) - [Daytona Toolbox SDK API](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox) calls #### What does not reset the timer The following do not reset the timer: - SDK calls that are not toolbox actions - Background scripts (e.g., `npm run dev` run as a fire-and-forget command) - Long-running tasks without external interaction - Processes that don't involve active monitoring If you run a long-running task like LLM inference that takes more than 15 minutes without any external interaction, the sandbox may auto-stop mid-process because the process itself doesn't count as "activity". ### Auto-archive interval Daytona provides methods to set the auto-archive interval using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md). The auto-archive interval parameter sets the amount of time after which a continuously stopped sandbox will be automatically archived. The parameter can either be set to: - a time interval in minutes - `0`: the maximum interval of `30 days` will be used If the parameter is not set, the default interval of `7 days` will be used. ```python sandbox = daytona.create(CreateSandboxFromSnapshotParams( snapshot="my-snapshot-name", # Auto-archive after a sandbox has been stopped for 1 hour auto_archive_interval=60, )) ``` ```typescript const sandbox = await daytona.create({ snapshot: "my-snapshot-name", // Auto-archive after a sandbox has been stopped for 1 hour autoArchiveInterval: 60, }); ``` ```ruby sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( snapshot: 'my-snapshot-name', # Auto-archive after a sandbox has been stopped for 1 hour auto_archive_interval: 60 ) ) ``` ```go // Create a sandbox with auto-archive after 1 hour autoArchiveInterval := 60 params := types.SnapshotParams{ Snapshot: "my-snapshot-name", SandboxBaseParams: types.SandboxBaseParams{ AutoArchiveInterval: &autoArchiveInterval, }, } sandbox, err := client.Create(ctx, params) ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/autoarchive/{interval}' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**set_auto_archive_interval (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxset_auto_archive_interval) > > [**setAutoArchiveInterval (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#setautoarchiveinterval) > > [**auto_archive_interval (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#auto_archive_interval) > > [**SetAutoArchiveInterval (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.SetAutoArchiveInterval) > > [**set_auto_archive_interval (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/autoarchive/{interval}) ### Auto-delete interval Daytona provides methods to set the auto-delete interval using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md). The auto-delete interval parameter sets the amount of time after which a continuously stopped sandbox will be automatically deleted. By default, sandboxes will never be automatically deleted. The parameter can either be set to: - a time interval in minutes - `-1`: disables the auto-delete functionality - `0`: the sandbox will be deleted immediately after stopping If the parameter is not set, the sandbox will not be deleted automatically. ```python sandbox = daytona.create(CreateSandboxFromSnapshotParams( snapshot="my-snapshot-name", # Auto-delete after a sandbox has been stopped for 1 hour auto_delete_interval=60, )) # Delete the sandbox immediately after it has been stopped sandbox.set_auto_delete_interval(0) # Disable auto-deletion sandbox.set_auto_delete_interval(-1) ``` ```typescript const sandbox = await daytona.create({ snapshot: "my-snapshot-name", // Auto-delete after a sandbox has been stopped for 1 hour autoDeleteInterval: 60, }); // Delete the sandbox immediately after it has been stopped await sandbox.setAutoDeleteInterval(0) // Disable auto-deletion await sandbox.setAutoDeleteInterval(-1) ``` ```ruby sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( snapshot: 'my-snapshot-name', # Auto-delete after a sandbox has been stopped for 1 hour auto_delete_interval: 60 ) ) # Delete the sandbox immediately after it has been stopped sandbox.auto_delete_interval = 0 # Disable auto-deletion sandbox.auto_delete_interval = -1 ``` ```go // Create a sandbox with auto-delete after 1 hour autoDeleteInterval := 60 params := types.SnapshotParams{ Snapshot: "my-snapshot-name", SandboxBaseParams: types.SandboxBaseParams{ AutoDeleteInterval: &autoDeleteInterval, }, } sandbox, err := client.Create(ctx, params) // Delete the sandbox immediately after it has been stopped zeroInterval := 0 err = sandbox.SetAutoDeleteInterval(ctx, &zeroInterval) // Disable auto-deletion disableInterval := -1 err = sandbox.SetAutoDeleteInterval(ctx, &disableInterval) ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxIdOrName}/autodelete/{interval}' \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox) references: > [**set_auto_delete_interval (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/sandbox.md#sandboxset_auto_delete_interval) > > [**setAutoDeleteInterval (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/sandbox.md#setautodeleteinterval) > > [**auto_delete_interval (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/sandbox.md#auto_delete_interval) > > [**SetAutoDeleteInterval (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Sandbox.SetAutoDeleteInterval) > > [**set_auto_delete_interval (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox/{sandboxIdOrName}/autodelete/{interval}) ### Running indefinitely Daytona provides methods to run sandboxes indefinitely using the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), and [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md). By default, Daytona Sandboxes auto-stop after 15 minutes of inactivity. To keep a sandbox running without interruption, set the auto-stop interval to `0` when creating a new sandbox: ```python sandbox = daytona.create(CreateSandboxFromSnapshotParams( snapshot="my_awesome_snapshot", # Disables the auto-stop feature - default is 15 minutes auto_stop_interval=0, )) ``` ```typescript const sandbox = await daytona.create({ snapshot: "my_awesome_snapshot", // Disables the auto-stop feature - default is 15 minutes autoStopInterval: 0, }); ``` ```ruby sandbox = daytona.create( Daytona::CreateSandboxFromSnapshotParams.new( snapshot: 'my_awesome_snapshot', # Disables the auto-stop feature - default is 15 minutes auto_stop_interval: 0 ) ) ``` ```go // Disables the auto-stop feature - default is 15 minutes autoStopInterval := 0 params := types.SnapshotParams{ Snapshot: "my_awesome_snapshot", SandboxBaseParams: types.SandboxBaseParams{ AutoStopInterval: &autoStopInterval, }, } sandbox, err := client.Create(ctx, params) ``` The security exhibit outlines the technical and organizational security measures Daytona maintains to protect customer data processed through its platform. It covers Daytona's information security program, compliance posture, incident management procedures, and business continuity practices. :::note This security exhibit supplements the Daytona [Terms of Service](https://www.daytona.io/terms-of-service) and [Data Processing Agreement](https://www.daytona.io/dpa), collectively the "Agreement", between Daytona Platforms, Inc. ("Daytona") and Customer ("Customer"). In the event of any conflict between this exhibit and the agreement, the agreement shall control. ::: ## Information security program Daytona maintains a comprehensive information security program designed to protect Customer data processed through its secure runtime platform. The program is aligned with industry-standard frameworks including SOC 2, ISO 27001, and incorporates controls specific to AI agent infrastructure and ephemeral compute environments. ### Security policies Daytona maintains a suite of information security policies that are reviewed at least annually and updated as needed by the Chief Trust Officer. These policies are approved by executive leadership and are made available to all Daytona personnel. Policies cover, at minimum: acceptable use, access control, data classification, incident response, vulnerability management, change management, and business continuity. ### Security training All Daytona personnel with access to Customer data or production systems complete mandatory security awareness training during onboarding and annually thereafter. Training covers phishing recognition, secure coding practices, data handling procedures, incident reporting, and compliance obligations. Completion is tracked and verified. ### Personnel security Background checks are conducted on all Daytona personnel who have access to Customer data or production systems, in accordance with applicable law. All such personnel are bound by confidentiality agreements. Offboarding procedures include timely revocation of all access credentials and return of company assets. ### Access control Access to Customer data and production systems is governed by the principle of least privilege and role-based access control (RBAC). Access is granted only upon documented business need and approved by management. Access reviews are conducted quarterly. Multi-factor authentication (MFA) is enforced for all Daytona personnel with access to production infrastructure, administrative consoles, and source code repositories. ### Data storage and classification Daytona classifies data according to sensitivity levels: Public, Internal, Confidential, and Restricted. Customer data is classified as Confidential at minimum. Data retention and destruction follow documented policies. Customer data is stored in the geographic region specified by the Customer's configuration where supported. Daytona does not use Customer Content to train models or improve services. ### Sandbox isolation Daytona's core architecture isolates each sandbox using container and/or microVM technology, ensuring that one Customer's runtime environment cannot interact with another's. Isolation controls include: dedicated namespaces per sandbox, network segmentation preventing lateral movement between sandboxes, resource quotas (CPU, memory, storage, network bandwidth), read-only root filesystems where applicable, and configurable network allow-lists with network-level firewall rules. ### Ephemeral sandbox supported Daytona sandboxes can be configured as ephemeral, meaning they are automatically deleted once stopped. When ephemeral mode is enabled, all associated compute, memory, and local storage are reclaimed upon sandbox termination, and any session-scoped credentials or tokens are revoked. This reduces the attack surface by ensuring no persistent runtime state accumulates between sessions. For non-ephemeral sandboxes, Daytona provides configurable auto-stop and auto-delete intervals to manage sandbox lifecycle and minimize exposure of idle environments. ### Encryption **Encryption Standards** - **In transit**: TLS 1.2+ for all external and internal communications - **At rest**: AES-256 or equivalent across all storage systems - **Key management**: Infrastructure provider KMS with automatic rotation ### Authentication and access Daytona provides identity and access management through Auth0, supporting authentication via Google and GitHub identity providers. Multi-factor authentication (MFA) is enforced for all Daytona personnel with administrative access. Daytona implements session management controls including configurable session timeouts and token revocation capabilities. Enterprise customers requiring SAML 2.0 or OIDC-based Single Sign-On (SSO) integration should contact Daytona to discuss available options. ### Backup and recovery Critical Daytona platform data (control plane, configuration, metadata) is backed up regularly with a defined recovery point objective (RPO) and recovery time objective (RTO). Backups are encrypted at rest and stored in a geographically separate location from the primary infrastructure. Backup restoration procedures are tested at least annually. ### Vulnerability management Daytona performs automated vulnerability scanning of its infrastructure and applications on at least a monthly basis. Identified vulnerabilities are triaged and remediated according to the following target timelines: | **Severity** | **Target** | **Example** | | ------------ | ---------- | -------------------------- | | Critical | 24 hours | RCE, privilege escalation | | High | 7 days | Auth bypass, data exposure | | Medium | 30 days | XSS, misconfigurations | | Low | 90 days | Informational findings | ### Network security Daytona implements defense-in-depth network security controls including: network segmentation between sandbox traffic, control plane, and management interfaces; firewall rules reviewed at least annually; DDoS mitigation at the infrastructure edge; and intrusion detection and monitoring for anomalous network activity. Sandbox network access can be restricted using configurable allow-lists and network block policies. ### Secure development lifecycle Daytona follows a secure software development lifecycle (SDLC) that includes: security requirements analysis during design, peer code review for all changes, automated static analysis and dependency scanning in CI/CD, container image scanning that blocks critical and high vulnerabilities, and separation of development, staging, and production environments. ### Change management All changes to production systems follow a documented change management process that includes: description and risk assessment of the change, peer review and approval, testing in non-production environments, and rollback procedures. Emergency changes follow an expedited process with retroactive documentation and review. ### Third-party risk management Daytona evaluates the security posture of third-party vendors and sub-processors before engagement and on an ongoing basis. Evaluation criteria include: security certifications, data handling practices, incident response capabilities, and contractual security obligations. Sub-processors are contractually required to maintain security controls substantially similar to those described in this Exhibit and the DPA. ### Patch management Daytona applies security patches to operating systems, libraries, and application dependencies in accordance with its vulnerability management SLAs. Critical patches are tested and deployed within 24 hours. Automated dependency monitoring tracks new CVEs affecting the Daytona stack. ### Audit logging and monitoring Daytona maintains comprehensive audit logs of administrative actions, authentication events, access to Customer data, and system-level events. Logs are stored securely, protected against tampering, and retained for a minimum of 12 months. Security events are monitored and alerted upon in real time. Log access is restricted to authorized security personnel. ### Container and runtime security :::note Daytona uses Sysbox as its container runtime to provide VM-level isolation without hardware virtualization overhead. ::: Sysbox enforces Linux user-namespaces on all sandboxes, ensuring that the root user inside a sandbox maps to a fully unprivileged user on the host. Each sandbox receives exclusive user-ID and group-ID mappings, so a process escaping one sandbox has no permissions to access other sandboxes or host resources. Additional Sysbox security controls include: partial virtualization of procfs and sysfs to hide host information and prevent modification of system-wide kernel settings, immutable initial mounts that prevent sandbox processes from weakening container isolation even with root capabilities, and selective syscall interception that blocks dangerous operations while preserving compatibility with system-level workloads such as Docker-in-Docker. Container images are built from minimal base images and scanned for vulnerabilities in CI/CD pipelines, and runtime threat detection monitors for anomalous process behavior. ### Penetration testing Daytona completes penetration testing at least annually, conducted by a recognized independent third party. Testing scope includes the Daytona platform, APIs, sandbox isolation mechanisms, and control plane. A summary of test results and remediation status is available to Customers upon request. ### Vulnerability disclosure program Daytona welcomes contributions from the security community to identify and responsibly disclose vulnerabilities in its platform. Daytona maintains a public Vulnerability Disclosure Policy with defined scope, exclusions, safe harbor protections, and coordinated disclosure timelines. Rewards ranging from $100 to $1,000 are offered for valid, original findings based on severity, exploitability, and report quality. Reports should be submitted to [security@daytona.io](mailto:security@daytona.io). Full program details are published in Daytona's [Security Policy](https://github.com/daytonaio/daytona/blob/main/SECURITY.md). ## Compliance and certifications Daytona pursues and maintains industry-recognized compliance certifications to demonstrate its commitment to security and data protection. | **Framework** | **Status** | **Details** | | ------------- | ----------- | ---------------------------------------------------------------- | | SOC 2 Type I | Achieved | Completed; report available under NDA via Trust Center. | | SOC 2 Type II | In progress | Audit period underway | | ISO 27001 | In progress | Certification in progress | | HIPAA BAA | Available | Business Associate Agreements available for qualifying customers | Copies of current certifications and audit reports are available to Customers upon written request, subject to reasonable confidentiality obligations, consistent with the DPA (Section 10). ## Assessments, audits, and remediation ### Assessment obligations Daytona shall maintain its security program and submit to independent third-party audits at least annually to verify compliance with this Exhibit and applicable security standards. Daytona will provide copies of audit reports and certifications upon reasonable written request, subject to confidentiality obligations as set forth in the Agreement. ### Remediation Where assessments or audits identify material deficiencies, Daytona shall prepare a remediation plan and address findings within timeframes consistent with the vulnerability severity levels defined in Section 1.11. ### Secure disposal Upon termination of the Agreement or at Customer's request, Daytona shall securely delete or return Customer data in accordance with the DPA (Section 8). Deletion is performed using methods that render data unrecoverable, including cryptographic erasure of encrypted storage volumes. Daytona will certify deletion upon request. ## Security incident management ### Incident response procedures Daytona maintains a documented incident response plan that defines roles, responsibilities, escalation procedures, and communication protocols. The plan is tested at least annually through tabletop exercises. Incidents are classified by severity and handled by a dedicated incident response team. ### Notification In the event of a Security Incident involving Customer data, Daytona shall notify the affected Customer without undue delay, consistent with the DPA (Section 15). Notification shall include, to the extent known: the nature and scope of the incident, the types of data affected, steps taken to contain and remediate, recommended Customer actions, and a point of contact for further communication. Notification may be delayed at the request of law enforcement or where delay is reasonably necessary to investigate and remediate. ### Incident remediation Daytona shall cooperate fully to investigate and remedy any harm or potential harm caused by a Security Incident. The Customer shall be informed of the response plan. Any liability arising from a Security Incident shall be subject to the limitation of liability provisions set forth in the Agreement ([Terms of Service](https://www.daytona.io/terms-of-service), section 15), including the aggregate liability cap and exclusion of indirect, incidental, special, consequential, or punitive damages. Each Party is solely responsible for any regulatory fines imposed directly on it by a supervisory authority, subject to the provisions of the [Data Processing Agreement](https://www.daytona.io/dpa) (section 12). ## Business continuity Daytona maintains a Business Continuity Plan (BCP) and Disaster Recovery Plan (DRP) that are reviewed and tested at least annually. The plans address: critical system recovery priorities and RTOs, data backup and restoration procedures, communication protocols during disruptions, alternative processing capabilities, and lessons-learned reviews following any activation of the BCP/DRP. ## Termination obligations Upon termination or expiration of the Agreement, Daytona shall: cease all processing of Customer data except as required to complete termination; return or delete Customer data at Customer's election, in accordance with the DPA (Section 8); certify deletion upon written request; and continue to protect any Customer data lawfully retained in accordance with this Exhibit and the Agreement. ## Contact and sub-processors ### Security contacts | **Team** | **Email** | | ------------------------- | ------------------------------------------------- | | Security | [security@daytona.io](mailto:security@daytona.io) | | Privacy contact | [privacy@daytona.io](mailto:privacy@daytona.io) | | Trust center | [trust.daytona.io](https://trust.daytona.io) | | Data Processing Agreement | [daytona.io/dpa](https://www.daytona.io/dpa) | | General Support | [support@daytona.io](mailto:support@daytona.io) | ### Sub-processors Daytona maintains and updates a record of sub-processors that process Customer data. The current sub-processor list is published as Exhibit C of Daytona's [Data Processing Agreement](https://www.daytona.io/dpa). Daytona will notify Customer of any material changes to its sub-processor list. If Customer reasonably objects to the appointment of a new sub-processor based on data protection concerns, the parties will discuss such concerns in good faith. If no resolution is reached, Customer may terminate the Agreement for convenience as its sole and exclusive remedy, consistent with the [Data Processing Agreement](https://www.daytona.io/dpa) (section 14). Snapshots are sandbox templates created from [Docker](https://www.docker.com/) or [OCI](https://opencontainers.org/) compatible images. Sandboxes can use a [default snapshot](#default-snapshots) or custom snapshots to provide a consistent and reproducible sandbox environments for your dependencies, settings, and resources. Daytona supports running [Docker](#run-docker-in-a-sandbox) and [Kubernetes](#run-kubernetes-in-a-sandbox) workloads inside sandboxes using snapshots. ## Snapshot lifecycle Throughout the snapshot lifecycle, a snapshot can have the following states: | **State** | **Description** | | ------------------ | ----------------------------------------------- | | **`pending`** | Snapshot creation requested | | **`building`** | Snapshot is being built | | **`pulling`** | Snapshot image is being pulled from a registry | | **`active`** | Snapshot is ready to use for creating sandboxes | | **`inactive`** | Snapshot is deactivated | | **`error`** | Snapshot creation failed | | **`build_failed`** | Snapshot build process failed | | **`removing`** | Snapshot is being deleted | :::note Inactive snapshots cannot be used to create sandboxes. They must be explicitly [re-activated](#activate-snapshots) before use. When activated, the snapshot returns to `pending` state and is re-processed before becoming `active` again. ::: ## Create Snapshots Daytona provides methods to create snapshots using the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/snapshots) or programmatically using the Daytona [Python](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md), [TypeScript](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md), [Ruby](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md), [Go](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService) **SDKs**, [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot), or [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots). Snapshots can be created using: - [public images](#using-public-images) - [local images](#using-local-images) - [images from private registries](#using-images-from-private-registries) - [the declarative builder](#using-the-declarative-builder) 1. Navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 2. Click the **Create Snapshot** button 3. Enter the **snapshot name**, **image** (tag or digest), **entrypoint**, and **resources** - **Snapshot name**: Identifier used to reference the snapshot in the SDK or CLI. - **Image**: Base image for the snapshot. Must include either a tag or a digest (e.g., **`ubuntu:22.04`**). The **`latest`** tag is not allowed. Since images tagged `latest` get frequent updates, only specific tags are supported. Same applies to tags such as `lts` or `stable`, and we recommend avoiding those when defining an image to prevent unexpected behavior. - **Entrypoint** (optional): The entrypoint command for the snapshot. Ensure that the entrypoint is a long-running command. If not provided, or if the snapshot does not have an entrypoint, `sleep infinity` will be used as the default. - [**Resources**](https://www.daytona.io/docs/en/sandboxes.md#resources) (optional): The resources you want the underlying Sandboxes to have. By default, Daytona Sandboxes use **1 vCPU**, **1GiB memory**, and **3GiB storage**. ```python image = Image.debian_slim('3.12').pip_install('numpy') daytona.snapshot.create( CreateSnapshotParams(name='my-awesome-snapshot', image=image), on_logs=lambda chunk: print(chunk, end=""), ) ``` ```typescript const image = Image.debianSlim('3.12').pipInstall('numpy'); await daytona.snapshot.create({ name: 'my-awesome-snapshot', image: image }, { onLogs: console.log }); ``` ```ruby image = Image.debian_slim('3.12').pip_install('numpy') params = CreateSnapshotParams.new(name: 'my-awesome-snapshot', image: image) snapshot = daytona.snapshot.create(params) do |chunk| print chunk end ``` ```go // Create from Docker Hub image snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "my-awesome-snapshot", Image: "python:3.11-slim", }) if err != nil { return err } // Stream build logs for log := range logChan { fmt.Println(log) } // Create with custom image and resources image := daytona.Base("python:3.11").PipInstall([]string{"numpy"}) snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "my-awesome-snapshot", Image: image, Resources: &types.Resources{CPU: 2, Memory: 4096}, }) ``` ```bash daytona snapshot create my-awesome-snapshot --image python:3.11-slim --cpu 2 --memory 4 ``` ```bash curl https://app.daytona.io/api/snapshots \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "name": "my-awesome-snapshot", "imageName": "python:3.11-slim", "cpu": 2, "memory": 4 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Create), [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references: > [**create (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotservicecreate) > > [**create (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#create) > > [**create (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#create) > > [**create (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Create) > > [**create (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-create) > > [**create (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/POST/snapshots) ### Using public images Daytona supports creating snapshots from any publicly accessible image or container registry. 1. Navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 2. Click the **Create Snapshot** button 3. Enter the **snapshot name** and **image** (tag or digest) of any publicly accessible image or container registry Once the snapshot is pulled, validated, and has an `Active` state, it is ready to be used. ```python daytona.snapshot.create( CreateSnapshotParams(name='my-awesome-snapshot', image='python:3.11-slim'), on_logs=lambda chunk: print(chunk, end=""), ) ``` ```typescript await daytona.snapshot.create({ name: 'my-awesome-snapshot', image: 'python:3.11-slim' }, { onLogs: console.log }); ``` ```ruby params = CreateSnapshotParams.new(name: 'my-awesome-snapshot', image: 'python:3.11-slim') snapshot = daytona.snapshot.create(params) do |chunk| print chunk end ``` ```go snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "my-awesome-snapshot", Image: "python:3.11-slim", }) if err != nil { return err } // Stream build logs for log := range logChan { fmt.Println(log) } ``` ```bash daytona snapshot create my-awesome-snapshot --image python:3.11-slim ``` ```bash curl https://app.daytona.io/api/snapshots \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "name": "my-awesome-snapshot", "imageName": "python:3.11-slim" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Create), [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references. > [**create (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotservicecreate) > > [**create (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#create) > > [**create (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#create) > > [**create (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Create) > > [**create (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-create) > > [**create (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/POST/snapshots) ### Using local images Daytona supports creating snapshots from local images or from local Dockerfiles. To create a snapshot from a local image or from a local Dockerfile, use the [Daytona CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot). Daytona expects the local image to be built for AMD64 architecture. Therefore, the `--platform=linux/amd64` flag is required when building the Docker image if your machine is running on a different architecture. 1. Ensure the image and tag you want to use is available ```bash docker images ``` 2. Create a snapshot and push it to Daytona: ```bash daytona snapshot push custom-alpine:3.21 --name alpine-minimal ``` :::tip Use the flags `--cpu`, `--memory` and `--disk` to specify the [resources](https://www.daytona.io/docs/en/sandboxes.md#resources) you want the underlying sandboxes to have. Example:
```bash daytona snapshot push custom-alpine:3.21 --name alpine-minimal --cpu 2 --memory 4 --disk 8 ``` ::: Alternatively, use the `--dockerfile` flag under `create` to pass the path to the Dockerfile you want to use and Daytona will build the snapshot for you. The `COPY`/`ADD` commands will be automatically parsed and added to the context. To manually add files to the context, use the `--context` flag. ```bash daytona snapshot create my-awesome-snapshot --dockerfile ./Dockerfile ``` ```text Building image from /Users/user/docs/Dockerfile Step 1/5 : FROM alpine:latest ... ⡿ Waiting for the Snapshot to be validated ... ... ✓ Use 'harbor-transient.internal.daytona.app/daytona/trying-daytona:0.0.1' to create a new sandbox using this Snapshot ``` ### Using images from private registries Daytona supports creating snapshots from images from [Docker Hub](#docker-hub), [Google Artifact Registry](#google-artifact-registry), [GitHub Container Registry](#github-container-registry) or other private container registries. 1. Navigate to [Daytona Registries ↗](https://app.daytona.io/dashboard/registries) 2. Click the **Add Registry** button 3. Enter the **registry name**, **registry URL**, **username**, **password**, and **project** (if applicable) 4. After the container registry is successfully created, navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 5. Click the **Create Snapshot** button 6. Enter the **snapshot name** and private **image** (tag or digest). When creating the snapshot, make sure to input the entire private image name, including the registry location and project name (e.g. **`my-private-registry.com//custom-alpine:3.21`**) Optionally, set the **`CreateSandboxFromSnapshotParams`** field to use the custom snapshot. #### Docker Hub Daytona supports creating snapshots from Docker Hub images. 1. Navigate to [Daytona Registries ↗](https://app.daytona.io/dashboard/registries) 2. Click the **Add Registry** button 3. Enter the **registry name**, **registry URL**, **username**, **password**, and **project** (if applicable) - **Registry URL**: `docker.io` - **Username**: Docker Hub username (the account with access to the image) - **Password**: [Docker Hub Personal Access Token](https://docs.docker.com/docker-hub/access-tokens/) (not your account password) - **Create the Snapshot**: `docker.io//:` 4. After the container registry is successfully created, navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 5. Click the **Create Snapshot** button 6. Enter the **snapshot name** and **image** (tag or digest). When creating the snapshot, input the entire image name, including the registry location and project name (e.g. **`docker.io//:`**) #### Google Artifact Registry Daytona supports creating snapshots from images from Google Artifact Registry. To use an image from Google Artifact Registry, configure the registry using a [service account key](https://cloud.google.com/iam/docs/keys-create-delete) in JSON format. 1. Navigate to [Daytona Registries ↗](https://app.daytona.io/dashboard/registries) 2. Click the **Add Registry** button 3. Enter the **registry name**, **registry URL**, **username**, **password**, and **project** (if applicable) - **Registry URL**: base URL for your region (e.g., `https://us-central1-docker.pkg.dev` or `https://us-central1-docker.pkg.dev/your-org`). - **Username**: `_json_key` - **Password**: Paste the full contents of your Service Account JSON key file - **Project**: Google Cloud Project ID - **Create the Snapshot**: `us-central1-docker.pkg.dev///:` 4. After the container registry is successfully created, navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 5. Click the **Create Snapshot** button 6. Enter the **snapshot name** and **image** (tag or digest). When creating the snapshot, make sure to input the entire image name, including the registry location and project name (e.g. **`us-central1-docker.pkg.dev///:`**) #### GitHub Container Registry (GHCR) Daytona supports creating snapshots from images from GitHub Container Registry (GHCR). 1. Navigate to [Daytona Registries ↗](https://app.daytona.io/dashboard/registries) 2. Click the **Add Registry** button 3. Enter the **registry name**, **registry URL**, **username**, **password**, and **project** (if applicable) - **Registry URL**: `ghcr.io` - **Username**: GitHub username (the account with access to the image) - **Password**: [GitHub Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) (not your account password). Personal access token (PAT) requires **`write:packages`**, **`read:packages`**, and **`delete:packages`** scopes. 4. After the container registry is successfully created, navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 5. Click the **Create Snapshot** button 6. Enter the **snapshot name** and **image** (tag or digest). When creating the snapshot, make sure to input the entire image name, including the registry location and project name (e.g. **`ghcr.io//custom-alpine:3.21`**) #### Amazon Elastic Container Registry (ECR) Daytona supports creating snapshots from images from Amazon Elastic Container Registry. 1. Navigate to [Daytona Registries ↗](https://app.daytona.io/dashboard/registries) 2. Click the **Add Registry** button 3. Enter the **registry name**, **registry URL**, **username**, **password**, and **project** (if applicable) - **Registry URL**: `.dkr.ecr..amazonaws.com` - **Username**: `AWS` - **Password**: [Authorization token](https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html) 4. After the container registry is successfully created, navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 5. Click the **Create Snapshot** button 6. Enter the **snapshot name** and **image** (tag or digest). When creating the snapshot, make sure to input the entire image name, including the registry location and repository name (e.g. **`123456789012.dkr.ecr.us-east-1.amazonaws.com/my-repo/custom-alpine:3.21`**) :::caution Amazon ECR authorization tokens expire after **12 hours**. Update the registry password in Daytona each time the token expires. Support for automatic renewal is coming soon. ::: ### Using the declarative builder [Declarative Builder](https://www.daytona.io/docs/en/declarative-builder.md) provides a powerful, code-first approach to defining dependencies for Daytona Sandboxes. Instead of importing images from a container registry, you can programmatically define them using the Daytona [SDKs](https://www.daytona.io/docs/en/getting-started.md#sdks). ### Resources Snapshots can be customized with specific resource requirements. By default, Daytona Sandboxes use **1 vCPU**, **1GB RAM**, and **3GiB disk**. For more information, see [sandbox resources](https://www.daytona.io/docs/en/sandboxes.md#resources). To view your available resources and limits, see [limits](https://www.daytona.io/docs/en/limits.md) or navigate to [Daytona Limits ↗](https://app.daytona.io/dashboard/limits). Snapshot resources can be customized using the `Resources` class. ```python from daytona import ( Daytona, CreateSnapshotParams, Image, Resources, ) daytona = Daytona() # Create a snapshot with custom resources daytona.snapshot.create( CreateSnapshotParams( name="my-awesome-snapshot", image=Image.debian_slim("3.12"), resources=Resources( cpu=2, memory=4, disk=8, ), ), on_logs=print, ) ``` ```typescript import { Daytona, Image } from '@daytonaio/sdk' const daytona = new Daytona() // Create a snapshot with custom resources await daytona.snapshot.create( { name: 'my-awesome-snapshot', image: Image.debianSlim('3.13'), resources: { cpu: 2, memory: 4, disk: 8, }, }, { onLogs: console.log } ) ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new # Create a snapshot with custom resources daytona.snapshot.create( Daytona::CreateSnapshotParams.new( name: 'my-awesome-snapshot', image: Daytona::Image.debian_slim('3.12'), resources: Daytona::Resources.new( cpu: 2, memory: 4, disk: 8 ) ), on_logs: proc { |chunk| puts chunk } ) ``` ```go // Create a snapshot with custom resources image := daytona.Base("python:3.11").PipInstall([]string{"numpy"}) snapshot, logChan, err := client.Snapshots.Create(ctx, &types.CreateSnapshotParams{ Name: "my-awesome-snapshot", Image: image, Resources: &types.Resources{CPU: 2, Memory: 4, Disk: 8}, }) if err != nil { return err } // Stream build logs for log := range logChan { fmt.Println(log) } ``` ```bash daytona snapshot create my-awesome-snapshot --image python:3.11-slim --cpu 2 --memory 4 --disk 8 ``` ```bash curl https://app.daytona.io/api/snapshots \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "name": "my-awesome-snapshot", "imageName": "python:3.11-slim", "cpu": 2, "memory": 4, "disk": 8 }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Create), [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-create), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references: > [**CreateSnapshotParams (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#createsnapshotparams) > > [**CreateSnapshotParams (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#createsnapshotparams) > > [**CreateSnapshotParams (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#create) > > [**CreateSnapshotParams (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/types.md#CreateSnapshotParams) > > [**create (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-create) > > [**create (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/POST/snapshots) ### Regions When creating a snapshot, you can specify the [region](https://www.daytona.io/docs/en/regions.md) in which it will be available. If not specified, the snapshot will be created in your organization's default region. When you later create a sandbox from this snapshot, you can use the snapshot's region as the target region for the sandbox. ```python from daytona import ( Daytona, CreateSnapshotParams, Image, ) daytona = Daytona() # Create a Snapshot in a specific region daytona.snapshot.create( CreateSnapshotParams( name="my-awesome-snapshot", image=Image.debian_slim("3.12"), region_id="us", ), on_logs=print, ) ``` ```typescript import { Daytona, Image } from "@daytonaio/sdk"; const daytona = new Daytona(); // Create a Snapshot in a specific region await daytona.snapshot.create( { name: "my-awesome-snapshot", image: Image.debianSlim("3.13"), regionId: "us", }, { onLogs: console.log } ); ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new # Create a Snapshot in a specific region daytona.snapshot.create( Daytona::CreateSnapshotParams.new( name: 'my-awesome-snapshot', image: Daytona::Image.debian_slim('3.12'), region_id: 'us' ), on_logs: proc { |chunk| puts chunk } ) ``` ```bash daytona snapshot create my-awesome-snapshot --image python:3.11-slim --region us ``` ```bash curl https://app.daytona.io/api/snapshots \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "name": "my-awesome-snapshot", "imageName": "python:3.11-slim", "regionId": "us" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md), [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-create), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references: > [**create (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotservicecreate) > > [**create (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#create) > > [**create (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#create) > > [**create (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-create) > > [**create (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/POST/snapshots) ## Get a Snapshot by name Daytona provides an option to get a snapshot by name. The following snippet returns the snapshot with the specified name: ```python daytona = Daytona() snapshot = daytona.snapshot.get("my-awesome-snapshot") print(f"{snapshot.name} ({snapshot.image_name})") ``` ```typescript const daytona = new Daytona() const snapshot = await daytona.snapshot.get('my-awesome-snapshot') console.log(`Snapshot ${snapshot.name} is in state ${snapshot.state}`) ``` ```ruby daytona = Daytona::Daytona.new snapshot = daytona.snapshot.get('my-awesome-snapshot') puts "#{snapshot.name} (#{snapshot.image_name})" ``` ```go snapshot, err := client.Snapshots.Get(ctx, "my-awesome-snapshot") if err != nil { return err } fmt.Printf("%s (%s)\n", snapshot.Name, snapshot.ImageName) ``` ```bash curl https://app.daytona.io/api/snapshots/my-awesome-snapshot \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotserviceget), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#get), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#get), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Get), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references: > [**get (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotserviceget) > > [**get (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#get) > > [**get (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#get) > > [**get (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Get) > > [**get (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/GET/snapshots/{snapshotName}) ## List Snapshots Daytona provides options to list snapshots and view their details. The following snippet lists all snapshots on the first page with a limit of 10 snapshots per page. ```python daytona = Daytona() result = daytona.snapshot.list(page=2, limit=10) for snapshot in result.items: print(f"{snapshot.name} ({snapshot.image_name})") ``` ```typescript const daytona = new Daytona() const result = await daytona.snapshot.list(1, 10) console.log(`Found ${result.total} snapshots`) result.items.forEach(snapshot => console.log(`${snapshot.name} (${snapshot.imageName})`) ) ``` ```ruby daytona = Daytona::Daytona.new result = daytona.snapshot.list(page: 2, limit: 10) result.items.each do |snapshot| puts "#{snapshot.name} (#{snapshot.image_name})" end ``` ```go // List first page with default limit result, err := client.Snapshots.List(ctx, nil, nil) if err != nil { return err } // List with pagination page, limit := 2, 10 result, err := client.Snapshots.List(ctx, &page, &limit) fmt.Printf("Page %d of %d, total: %d\n", result.Page, result.TotalPages, result.Total) ``` ```bash # List snapshots with pagination daytona snapshot list --page 2 --limit 10 ``` ```bash curl 'https://app.daytona.io/api/snapshots?page=2&limit=10' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.List), [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-list), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references. > [**list (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotservicelist) > > [**list (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#list) > > [**list (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#list) > > [**list (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.List) > > [**list (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-list) > > [**list (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/GET/snapshots) ## Activate Snapshots Snapshots automatically become inactive after 2 weeks of not being used. To activate an inactive snapshot: 1. Navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 2. Click the three dots at the end of the row for the snapshot you want to activate 3. Click the **Activate** button ```python daytona = Daytona() snapshot = daytona.snapshot.get("my-inactive-snapshot") activated_snapshot = daytona.snapshot.activate(snapshot) print(f"Snapshot {activated_snapshot.name} activated") ``` ```typescript const daytona = new Daytona() const snapshot = await daytona.snapshot.get("my-inactive-snapshot") const activatedSnapshot = await daytona.snapshot.activate(snapshot) console.log(`Snapshot ${activatedSnapshot.name} activated`) ``` ```ruby daytona = Daytona::Daytona.new snapshot = daytona.snapshot.get('my-inactive-snapshot') activated_snapshot = daytona.snapshot.activate(snapshot) puts "Snapshot #{activated_snapshot.name} activated" ``` ```bash curl https://app.daytona.io/api/snapshots/my-inactive-snapshot/activate \ --request POST \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotserviceactivate), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#activate), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#activate), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references: > [**activate (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotserviceactivate) > > [**activate (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#activate) > > [**activate (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#activate) > > [**activate (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/POST/snapshots/{snapshotName}/activate) ## Deactivate Snapshots Daytona provides an option to deactivate snapshots. Deactivated snapshots are not available for new sandboxes. 1. Navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 2. Click the three dots at the end of the row for the snapshot you want to deactivate 3. Click the **Deactivate** button ## Delete Snapshots Daytona provides options to delete snapshots. Deleted snapshots cannot be recovered. 1. Navigate to [Daytona Snapshots ↗](https://app.daytona.io/dashboard/snapshots) 2. Click the three dots at the end of the row for the snapshot you want to delete 3. Click the **Delete** button ```python daytona = Daytona() snapshot = daytona.snapshot.get("my-awesome-snapshot") daytona.snapshot.delete(snapshot) print("Snapshot deleted") ``` ```typescript const daytona = new Daytona() const snapshot = await daytona.snapshot.get("my-awesome-snapshot") await daytona.snapshot.delete(snapshot) console.log("Snapshot deleted") ``` ```ruby daytona = Daytona::Daytona.new snapshot = daytona.snapshot.get('my-awesome-snapshot') daytona.snapshot.delete(snapshot) puts 'Snapshot deleted' ``` ```go snapshot, err := client.Snapshots.Get(ctx, "my-awesome-snapshot") if err != nil { return err } err = client.Snapshots.Delete(ctx, snapshot) if err != nil { return err } fmt.Println("Snapshot deleted") ``` ```bash daytona snapshot delete my-awesome-snapshot ``` ```bash curl https://app.daytona.io/api/snapshots/my-awesome-snapshot \ --request DELETE \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotservicedelete), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#delete), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#delete), [Go SDK](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Delete), [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-delete), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots) references: > [**delete (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/snapshot.md#snapshotservicedelete) > > [**delete (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/snapshot.md#delete) > > [**delete (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/snapshot.md#delete) > > [**delete (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#SnapshotService.Delete) > > [**delete (CLI)**](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-delete) > > [**delete (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/snapshots/DELETE/snapshots/{snapshotName}) ## Run Docker in a Sandbox Daytona Sandboxes can run Docker containers inside them (**Docker-in-Docker**), enabling you to build, test, and deploy containerized applications. This is particularly useful when your projects have dependencies on external services like databases, message queues, or other microservices. Agents can seamlessly interact with these services since they run within the same sandbox environment, providing better isolation and security compared to external service dependencies. The following use cases are supported: - Run databases (PostgreSQL, Redis, MySQL) and other services - Build and test containerized applications - Deploy microservices and their dependencies - Create isolated development environments with full container orchestration :::note Docker-in-Docker Sandboxes require additional resources due to the Docker daemon overhead. Consider allocating at least 2 vCPU and 4GiB of memory for optimal performance. ::: ### Create a Docker-in-Docker Snapshot Daytona provides an option to create a snapshot with Docker support using pre-built Docker-in-Docker images as a base or by manually installing Docker in a custom image. #### Using pre-built images The following base images are widely used for creating Docker-in-Docker snapshots or can be used as a base for a custom Dockerfile: - `docker:28.3.3-dind`: official Docker-in-Docker image (Alpine-based, lightweight) - `docker:28.3.3-dind-rootless`: rootless Docker-in-Docker for enhanced security - `docker:28.3.2-dind-alpine3.22`: Docker-in-Docker image with Alpine 3.22 #### Using manual installation Alternatively, install Docker manually in a custom Dockerfile: ```dockerfile FROM ubuntu:22.04 # Install Docker using the official install script RUN curl -fsSL https://get.docker.com | VERSION=28.3.3 sh - ``` ### Run Docker Compose in a Sandbox Docker Compose allows you to define and run multi-container applications. With Docker-in-Docker enabled in a Daytona Sandbox, you can use Docker Compose to orchestrate services like databases, caches, and application containers. First, create a Docker-in-Docker snapshot using the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/snapshots) or [CLI](https://www.daytona.io/docs/en/tools/cli.md#daytona-snapshot-create) with one of the [pre-built images](#using-pre-built-images) (e.g., `docker:28.3.3-dind`). Then use the following snippet to run Docker Compose services inside a sandbox: ```python from daytona import Daytona, CreateSandboxFromSnapshotParams # Initialize the Daytona client daytona = Daytona() # Create a sandbox from a Docker-in-Docker snapshot sandbox = daytona.create(CreateSandboxFromSnapshotParams(snapshot='docker-dind')) # Create a docker-compose.yml file compose_content = ''' services: web: image: nginx:alpine ports: - "8080:80" ''' sandbox.fs.upload_file(compose_content.encode(), 'docker-compose.yml') # Start Docker Compose services result = sandbox.process.exec('docker compose -p demo up -d') print(result.result) # Check running services result = sandbox.process.exec('docker compose -p demo ps') print(result.result) # Clean up sandbox.process.exec('docker compose -p demo down') ``` ```typescript import { Daytona } from '@daytonaio/sdk' // Initialize the Daytona client const daytona = new Daytona() // Create a sandbox from a Docker-in-Docker snapshot const sandbox = await daytona.create({ snapshot: 'docker-dind' }) // Create a docker-compose.yml file const composeContent = ` services: web: image: nginx:alpine ports: - "8080:80" ` await sandbox.fs.uploadFile(Buffer.from(composeContent), 'docker-compose.yml') // Start Docker Compose services let result = await sandbox.process.executeCommand('docker compose -p demo up -d') console.log(result.result) // Check running services result = await sandbox.process.executeCommand('docker compose -p demo ps') console.log(result.result) // Clean up await sandbox.process.executeCommand('docker compose -p demo down') ``` ```ruby require 'daytona' # Initialize the Daytona client daytona = Daytona::Daytona.new # Create a sandbox from a Docker-in-Docker snapshot sandbox = daytona.create(Daytona::CreateSandboxFromSnapshotParams.new(snapshot: 'docker-dind')) # Create a docker-compose.yml file compose_content = <<~YAML services: web: image: nginx:alpine ports: - "8080:80" YAML sandbox.fs.upload_file(compose_content, 'docker-compose.yml') # Start Docker Compose services result = sandbox.process.exec(command: 'docker compose -p demo up -d') puts result.result # Check running services result = sandbox.process.exec(command: 'docker compose -p demo ps') puts result.result # Clean up sandbox.process.exec(command: 'docker compose -p demo down') ``` ```go package main import ( "context" "fmt" "github.com/daytonaio/sdk-go/daytona" "github.com/daytonaio/sdk-go/types" ) func main() { ctx := context.Background() // Initialize the Daytona client client, _ := daytona.NewDaytona(nil) // Create a sandbox from a Docker-in-Docker snapshot sandbox, _ := client.Create(ctx, &types.CreateSandboxFromSnapshotParams{ Snapshot: daytona.Ptr("docker-dind"), }, nil) // Create a docker-compose.yml file composeContent := ` services: web: image: nginx:alpine ports: - "8080:80" ` sandbox.Fs.UploadFile(ctx, []byte(composeContent), "docker-compose.yml") // Start Docker Compose services result, _ := sandbox.Process.ExecuteCommand(ctx, "docker compose -p demo up -d", nil) fmt.Println(result.Result) // Check running services result, _ = sandbox.Process.ExecuteCommand(ctx, "docker compose -p demo ps", nil) fmt.Println(result.Result) // Clean up sandbox.Process.ExecuteCommand(ctx, "docker compose -p demo down", nil) } ``` ## Run Kubernetes in a Sandbox Daytona Sandboxes can run a Kubernetes cluster inside the sandbox. Kubernetes runs entirely inside the sandbox and is removed when the sandbox is deleted, keeping environments secure and reproducible. ### Run k3s in a Sandbox The following snippet installs and starts a k3s cluster inside a sandbox and lists all running pods. ```typescript import { Daytona } from '@daytonaio/sdk' import { setTimeout } from 'timers/promises' // Initialize the Daytona client const daytona = new Daytona() // Create the sandbox instance const sandbox = await daytona.create() // Run the k3s installation script const response = await sandbox.process.executeCommand( 'curl -sfL https://get.k3s.io | sh -' ) // Run k3s const sessionName = 'k3s-server' await sandbox.process.createSession(sessionName) const k3s = await sandbox.process.executeSessionCommand(sessionName, { command: 'sudo /usr/local/bin/k3s server', async: true, }) // Give time to k3s to fully start await setTimeout(30000) // Get all pods const pods = await sandbox.process.executeCommand( 'sudo /usr/local/bin/kubectl get pod -A' ) console.log(pods.result) ``` ## Default Snapshots When a sandbox is created with no snapshot specified, Daytona uses a default snapshot that includes `python`, `node`, their language servers, and several common pip packages. Daytona provides three default snapshot sizes: | **Snapshot** | **vCPU** | **Memory** | **Storage** | | -------------------- | -------- | ---------- | ----------- | | **`daytona-small`** | 1 | 1GiB | 3GiB | | **`daytona-medium`** | 2 | 4GiB | 8GiB | | **`daytona-large`** | 4 | 8GiB | 10GiB | All default snapshots are based on the `daytonaio/sandbox:` image. For more information, see the [Dockerfile](https://github.com/daytonaio/daytona/blob/main/images/sandbox/Dockerfile). ### Python packages (pip) - `anthropic` (v0.76.0) - `beautifulsoup4` (v4.14.3) - `claude-agent-sdk` (v0.1.22) - `daytona` (v0.134.0) - `django` (v6.0.1) - `flask` (v3.1.2) - `huggingface-hub` (v0.36.0) - `instructor` (v1.14.4) - `keras` (v3.13.0) - `langchain` (v1.2.7) - `llama-index` (v0.14.13) - `matplotlib` (v3.10.8) - `numpy` (v2.4.1) - `ollama` (v0.6.1) - `openai` (v2.15.0) - `opencv-python` (v4.13.0.90) - `pandas` (v2.3.3) - `pillow` (v12.1.0) - `pydantic-ai` (v1.47.0) - `requests` (v2.32.5) - `scikit-learn` (v1.8.0) - `scipy` (v1.17.0) - `seaborn` (v0.13.2) - `sqlalchemy` (v2.0.46) - `torch` (v2.10.0) - `transformers` (v4.57.6) ### Node.js packages (npm) - `@anthropic-ai/claude-code` (v2.1.19) - `bun` (v1.3.6) - `openclaw` (v2026.2.1) - `opencode-ai` (v1.1.35) - `ts-node` (v10.9.2) - `typescript` (v5.9.3) - `typescript-language-server` (v5.1.3) Daytona provides SSH access to your sandboxes using token-based authentication. This allows you to connect from local terminals, IDEs, and development tools without installing additional software. ## Access from Dashboard Create an SSH access token directly from the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/sandboxes). 1. Navigate to [Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Locate the sandbox you want to create an SSH access token for 3. Click the sandbox options menu (**⋮**) 4. Select **Create SSH Access** 5. Set the expiration time (defaults to 60 minutes) 6. Click **Create** Daytona generates a token and displays it in the modal. Copy the token and use it to connect to your sandbox. ## Access via CLI Daytona provides a CLI command to create an SSH access token for a sandbox: ```shell daytona create ``` When you create a sandbox, Daytona displays the SSH command automatically in the output: ```text Sandbox '' created successfully Connect via SSH: daytona ssh Open the Web Terminal: https://22222-.proxy.daytona.work ``` To SSH into an existing sandbox, use the following command: ```bash daytona ssh --expires 60 ``` ## Access via token You can create SSH access tokens programmatically. The token can then be used to connect manually: ```python from daytona import Daytona daytona = Daytona() sandbox = daytona.get("sandbox-abc123") # Create SSH access token ssh_access = sandbox.create_ssh_access(expires_in_minutes=60) print(f"SSH Token: {ssh_access.token}") ``` ```typescript import { Daytona } from '@daytonaio/sdk' const daytona = new Daytona() const sandbox = await daytona.get('sandbox-abc123') // Create SSH access token const sshAccess = await sandbox.createSshAccess(60) console.log(`SSH Token: ${sshAccess.token}`) ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new sandbox = daytona.get('sandbox-abc123') # Create SSH access token ssh_access = sandbox.create_ssh_access(expires_in_minutes: 60) puts "SSH Token: #{ssh_access.token}" ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxId}/ssh-access?expiresInMinutes=60' \ --request POST \ --header 'Authorization: Bearer ' ``` To connect to your sandbox, use the following command: ```bash ssh @ssh.app.daytona.io ``` ## Connect with VS Code You can connect VS Code directly to your sandbox using the Remote SSH extension. 1. Install the [Remote Explorer extension ↗](https://marketplace.visualstudio.com/items?itemName=ms-vscode.remote-explorer) 2. Add a new SSH connection 3. When prompted for the SSH connection URL, paste the SSH command from above For more information, see the [VS Code Remote SSH documentation ↗](https://code.visualstudio.com/docs/remote/ssh). ## Connect with JetBrains IDEs JetBrains Gateway provides remote development support for connecting to your sandbox. 1. Download [JetBrains Gateway ↗](https://www.jetbrains.com/remote-development/gateway/) 2. Add a new connection 3. When prompted for the SSH connection URL, paste the SSH command from above 4. Select the IDE to install in your sandbox ## Token management ### Expiration SSH access tokens expire automatically after 60 minutes. You can specify a custom expiration time when creating the token using the `expires_in_minutes` parameter. ### Revoke token Revoke SSH access tokens before expiry: ```python # Revoke specific SSH access token for the sandbox sandbox.revoke_ssh_access(token="specific-token") ``` ```typescript // Revoke specific SSH access token for the sandbox await sandbox.revokeSshAccess('specific-token') ``` ```ruby # Revoke specific SSH access token for the sandbox sandbox.revoke_ssh_access(token: 'specific-token') ``` ```bash # Revoke specific SSH access token curl 'https://app.daytona.io/api/sandbox/{sandboxId}/ssh-access?token=specific-token' \ --request DELETE \ --header 'Authorization: Bearer ' # Revoke all SSH access for the sandbox curl 'https://app.daytona.io/api/sandbox/{sandboxId}/ssh-access' \ --request DELETE \ --header 'Authorization: Bearer ' ``` ## Related - [Web Terminal](https://www.daytona.io/docs/en/web-terminal.md): browser-based terminal access to sandboxes - [Preview](https://www.daytona.io/docs/en/preview.md): generate preview URLs for accessing sandbox services The `daytona` command-line tool provides access to Daytona's core features including managing Snapshots and the lifecycle of Daytona Sandboxes. View the installation instructions by clicking [here](https://www.daytona.io/docs/getting-started.md#cli). This reference lists all commands supported by the `daytona` command-line tool complete with a description of their behaviour, and any supported flags. You can access this documentation on a per-command basis by appending the `--help`/`-h` flag when invoking `daytona`. ## daytona Daytona CLI ```shell daytona [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | | `--version` | `-v` | Display the version of Daytona | ## daytona archive Archive a sandbox ```shell daytona archive [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona autocomplete Adds a completion script for your shell environment ```shell daytona autocomplete [bash|zsh|fish|powershell] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona create Create a new sandbox ```shell daytona create [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--auto-archive` | | Auto-archive interval in minutes (0 means the maximum interval will be used) | | `--auto-delete` | | Auto-delete interval in minutes (negative value means disabled, 0 means delete immediately upon stopping) | | `--auto-stop` | | Auto-stop interval in minutes (0 means disabled) | | `--class` | | Sandbox class type (small, medium, large) | | `--context` | `-c` | Files or directories to include in the build context (can be specified multiple times) | | `--cpu` | | CPU cores allocated to the sandbox | | `--disk` | | Disk space allocated to the sandbox in GB | | `--dockerfile` | `-f` | Path to Dockerfile for Sandbox snapshot | | `--env` | `-e` | Environment variables (format: KEY=VALUE) | | `--gpu` | | GPU units allocated to the sandbox | | `--label` | `-l` | Labels (format: KEY=VALUE) | | `--memory` | | Memory allocated to the sandbox in MB | | `--name` | | Name of the sandbox | | `--network-allow-list` | | Comma-separated list of allowed CIDR network addresses for the sandbox | | `--network-block-all` | | Whether to block all network access for the sandbox | | `--public` | | Make sandbox publicly accessible | | `--snapshot` | | Snapshot to use for the sandbox | | `--target` | | Target region (eu, us) | | `--user` | | User associated with the sandbox | | `--volume` | `-v` | Volumes to mount (format: VOLUME_NAME:MOUNT_PATH) | | `--help` | | help for daytona | ## daytona delete Delete a sandbox ```shell daytona delete [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--all` | `-a` | Delete all sandboxes | | `--help` | | help for daytona | ## daytona docs Opens the Daytona documentation in your default browser. ```shell daytona docs [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona exec Execute a command in a sandbox ```shell daytona exec [SANDBOX_ID | SANDBOX_NAME] -- [COMMAND] [ARGS...] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--cwd` | | Working directory for command execution | | `--timeout` | | Command timeout in seconds (0 for no timeout) | | `--help` | | help for daytona | ## daytona info Get sandbox info ```shell daytona info [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--format` | `-f` | Output format. Must be one of (yaml, json) | | `--help` | | help for daytona | ## daytona list List sandboxes ```shell daytona list [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--format` | `-f` | Output format. Must be one of (yaml, json) | | `--limit` | `-l` | Maximum number of items per page | | `--page` | `-p` | Page number for pagination (starting from 1) | | `--help` | | help for daytona | ## daytona login Log in to Daytona ```shell daytona login [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--api-key` | | API key to use for authentication | | `--help` | | help for daytona | ## daytona logout Logout from Daytona ```shell daytona logout [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona mcp Manage Daytona MCP Server ```shell daytona mcp [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona mcp config Outputs JSON configuration for Daytona MCP Server ```shell daytona mcp config [AGENT_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona mcp init Initialize Daytona MCP Server with an agent (currently supported: claude, windsurf, cursor) ```shell daytona mcp init [AGENT_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona mcp start Start Daytona MCP Server ```shell daytona mcp start [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona organization Manage Daytona organizations ```shell daytona organization [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona organization create Create a new organization and set it as active ```shell daytona organization create [ORGANIZATION_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona organization delete Delete an organization ```shell daytona organization delete [ORGANIZATION] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona organization list List all organizations ```shell daytona organization list [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--format` | `-f` | Output format. Must be one of (yaml, json) | | `--help` | | help for daytona | ## daytona organization use Set active organization ```shell daytona organization use [ORGANIZATION] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona preview-url Get signed preview URL for a sandbox port ```shell daytona preview-url [SANDBOX_ID | SANDBOX_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--expires` | | URL expiration time in seconds | | `--port` | `-p` | Port number to get preview URL for (required) | | `--help` | | help for daytona | ## daytona snapshot Manage Daytona snapshots ```shell daytona snapshot [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona snapshot create Create a snapshot ```shell daytona snapshot create [SNAPSHOT] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--context` | `-c` | Files or directories to include in the build context (can be specified multiple times). If not provided, context will be automatically determined from COPY/ADD commands in the Dockerfile | | `--cpu` | | CPU cores that will be allocated to the underlying sandboxes (default: 1) | | `--disk` | | Disk space that will be allocated to the underlying sandboxes in GB (default: 3) | | `--dockerfile` | `-f` | Path to Dockerfile to build | | `--entrypoint` | `-e` | The entrypoint command for the snapshot | | `--image` | `-i` | The image name for the snapshot | | `--memory` | | Memory that will be allocated to the underlying sandboxes in GB (default: 1) | | `--region` | | ID of the region where the snapshot will be available (defaults to organization default region) | | `--help` | | help for daytona | ## daytona snapshot delete Delete a snapshot ```shell daytona snapshot delete [SNAPSHOT_ID] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--all` | `-a` | Delete all snapshots | | `--help` | | help for daytona | ## daytona snapshot list List all snapshots ```shell daytona snapshot list [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--format` | `-f` | Output format. Must be one of (yaml, json) | | `--limit` | `-l` | Maximum number of items per page | | `--page` | `-p` | Page number for pagination (starting from 1) | | `--help` | | help for daytona | ## daytona snapshot push Push local snapshot ```shell daytona snapshot push [SNAPSHOT] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--cpu` | | CPU cores that will be allocated to the underlying sandboxes (default: 1) | | `--disk` | | Disk space that will be allocated to the underlying sandboxes in GB (default: 3) | | `--entrypoint` | `-e` | The entrypoint command for the image | | `--memory` | | Memory that will be allocated to the underlying sandboxes in GB (default: 1) | | `--name` | `-n` | Specify the Snapshot name | | `--region` | | ID of the region where the snapshot will be available (defaults to organization default region) | | `--help` | | help for daytona | ## daytona ssh SSH into a sandbox ```shell daytona ssh [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--expires` | | SSH access token expiration time in minutes (defaults to 24 hours) | | `--help` | | help for daytona | ## daytona start Start a sandbox ```shell daytona start [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona stop Stop a sandbox ```shell daytona stop [SANDBOX_ID] | [SANDBOX_NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona version Print the version number ```shell daytona version [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona volume Manage Daytona volumes ```shell daytona volume [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona volume create Create a volume ```shell daytona volume create [NAME] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--size` | `-s` | Size of the volume in GB | | `--help` | | help for daytona | ## daytona volume delete Delete a volume ```shell daytona volume delete [VOLUME_ID] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--help` | | help for daytona | ## daytona volume get Get volume details ```shell daytona volume get [VOLUME_ID] [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--format` | `-f` | Output format. Must be one of (yaml, json) | | `--help` | | help for daytona | ## daytona volume list List all volumes ```shell daytona volume list [flags] ``` __Flags__ | Long | Short | Description | | :--- | :---- | :---------- | | `--format` | `-f` | Output format. Must be one of (yaml, json) | | `--help` | | help for daytona | ## ChartType Chart types **Enum Members**: - `BAR` ("bar") - `LINE` ("line") - `PIE` ("pie") - `SCATTER` ("scatter") - `UNKNOWN` ("unknown") ## parseChart() ```ts function parseChart(data: any): Chart ``` **Parameters**: - `data` _any_ **Returns**: - `Chart` *** ## BarChart ```ts type BarChart = Chart2D & { elements: BarData[]; type: BAR; }; ``` Represents a bar chart with metadata. **Type declaration**: - `elements` _BarData\[\]_ - The bars of the chart - `type` _BAR_ - The type of chart ## BarData ```ts type BarData = { group: string; label: string; value: string; }; ``` Represents a bar in a bar chart. **Type declaration**: - `group` _string_ - The group of the bar - `label` _string_ - The label of the bar - `value` _string_ - The value of the bar ## BoxAndWhiskerChart ```ts type BoxAndWhiskerChart = Chart2D & { elements: BoxAndWhiskerData[]; type: BOX_AND_WHISKER; }; ``` Represents a box and whisker chart with metadata. **Type declaration**: - `elements` _BoxAndWhiskerData\[\]_ - The box and whiskers of the chart - `type` _BOX\_AND\_WHISKER_ - The type of chart ## BoxAndWhiskerData ```ts type BoxAndWhiskerData = { first_quartile: number; label: string; max: number; median: number; min: number; outliers: number[]; }; ``` Represents a box and whisker in a box and whisker chart. **Type declaration**: - `first\_quartile` _number_ - The first quartile of the box and whisker - `label` _string_ - The label of the box and whisker - `max` _number_ - The third quartile of the box and whisker - `median` _number_ - The median of the box and whisker - `min` _number_ - The minimum value of the box and whisker - `outliers` _number\[\]_ ## Chart ```ts type Chart = { elements: any[]; png: string; title: string; type: ChartType; }; ``` Represents a chart with metadata from matplotlib. **Type declaration**: - `elements` _any\[\]_ - The elements of the chart - `png?` _string_ - The PNG representation of the chart encoded in base64 - `title` _string_ - The title of the chart - `type` _ChartType_ - The type of chart ## Chart2D ```ts type Chart2D = Chart & { x_label: string; y_label: string; }; ``` Represents a 2D chart with metadata. **Type declaration**: - `x\_label?` _string_ - The label of the x-axis - `y\_label?` _string_ - The label of the y-axis ## CompositeChart ```ts type CompositeChart = Chart & { elements: Chart[]; type: COMPOSITE_CHART; }; ``` Represents a composite chart with metadata. **Type declaration**: - `elements` _Chart\[\]_ - The charts of the composite chart - `type` _COMPOSITE\_CHART_ - The type of chart ## LineChart ```ts type LineChart = PointChart & { type: LINE; }; ``` Represents a line chart with metadata. **Type declaration**: - `type` _LINE_ - The type of chart ## PieChart ```ts type PieChart = Chart & { elements: PieData[]; type: PIE; }; ``` Represents a pie chart with metadata. **Type declaration**: - `elements` _PieData\[\]_ - The pie slices of the chart - `type` _PIE_ - The type of chart ## PieData ```ts type PieData = { angle: number; label: string; radius: number; }; ``` Represents a pie slice in a pie chart. **Type declaration**: - `angle` _number_ - The angle of the pie slice - `label` _string_ - The label of the pie slice - `radius` _number_ - The radius of the pie slice ## PointChart ```ts type PointChart = Chart2D & { elements: PointData[]; x_scale: string; x_tick_labels: string[]; x_ticks: (number | string)[]; y_scale: string; y_tick_labels: string[]; y_ticks: (number | string)[]; }; ``` Represents a point chart with metadata. **Type declaration**: - `elements` _PointData\[\]_ - The points of the chart - `x\_scale` _string_ - The scale of the x-axis - `x\_tick\_labels` _string\[\]_ - The labels of the x-axis - `x\_ticks` _\(number \| string\)\[\]_ - The ticks of the x-axis - `y\_scale` _string_ - The scale of the y-axis - `y\_tick\_labels` _string\[\]_ - The labels of the y-axis - `y\_ticks` _\(number \| string\)\[\]_ - The ticks of the y-axis ## PointData ```ts type PointData = { label: string; points: [number | string, number | string][]; }; ``` Represents a point in a 2D chart. **Type declaration**: - `label` _string_ - The label of the point - `points` _\[number \| string, number \| string\]\[\]_ - The points of the chart ## ScatterChart ```ts type ScatterChart = PointChart & { type: SCATTER; }; ``` Represents a scatter chart with metadata. **Type declaration**: - `type` _SCATTER_ - The type of chart ## CodeInterpreter Handles Python code interpretation and execution within a Sandbox. Provides methods to execute code (currently only Python) in isolated interpreter contexts, manage contexts, and stream execution output via callbacks. For other languages, use the `codeRun` method from the `Process` interface, or execute the appropriate command directly in the sandbox terminal. ### Constructors #### new CodeInterpreter() ```ts new CodeInterpreter( clientConfig: Configuration, apiClient: InterpreterApi, getPreviewToken: () => Promise): CodeInterpreter ``` **Parameters**: - `clientConfig` _Configuration_ - `apiClient` _InterpreterApi_ - `getPreviewToken` _\(\) =\> Promise\_ **Returns**: - `CodeInterpreter` ### Methods #### createContext() ```ts createContext(cwd?: string): Promise ``` Create a new isolated interpreter context. **Parameters**: - `cwd?` _string_ - Working directory for the context. Uses sandbox working directory if omitted. **Returns**: - `Promise` - The created context. **Example:** ```ts const ctx = await sandbox.codeInterpreter.createContext() await sandbox.codeInterpreter.runCode('x = 10', { context: ctx }) await sandbox.codeInterpreter.deleteContext(ctx.id!) ``` *** #### deleteContext() ```ts deleteContext(context: InterpreterContext): Promise ``` Delete an interpreter context and shut down its worker process. **Parameters**: - `context` _InterpreterContext_ - Context to delete. **Returns**: - `Promise` **Example:** ```ts const ctx = await sandbox.codeInterpreter.createContext() // ... use context ... await sandbox.codeInterpreter.deleteContext(ctx) ``` *** #### listContexts() ```ts listContexts(): Promise ``` List all user-created interpreter contexts (default context is excluded). **Returns**: - `Promise` - List of contexts. **Example:** ```ts const contexts = await sandbox.codeInterpreter.listContexts() for (const ctx of contexts) { console.log(ctx.id, ctx.language, ctx.cwd) } ``` *** #### runCode() ```ts runCode(code: string, options: RunCodeOptions): Promise ``` Run Python code in the sandbox. **Parameters**: - `code` _string_ - Code to run. - `options` _RunCodeOptions = {}_ - Execution options (context, envs, callbacks, timeout). **Returns**: - `Promise` - ExecutionResult containing stdout, stderr and optional error info. **Example:** ```ts const handleStdout = (msg: OutputMessage) => process.stdout.write(`STDOUT: ${msg.output}`) const handleStderr = (msg: OutputMessage) => process.stdout.write(`STDERR: ${msg.output}`) const handleError = (err: ExecutionError) => console.error(`ERROR: ${err.name}: ${err.value}\n${err.traceback ?? ''}`) const code = ` import sys import time for i in range(5): print(i) time.sleep(1) sys.stderr.write("Counting done!") ` const result = await codeInterpreter.runCode(code, { onStdout: handleStdout, onStderr: handleStderr, onError: handleError, timeout: 10, }) ``` *** ## ExecutionError Represents an error that occurred during code execution. **Properties**: - `name` _string_ - Error type/class name (e.g., "ValueError", "SyntaxError"). - `traceback?` _string_ - Full traceback for the error, if available. - `value` _string_ - Error value/message. ## ExecutionResult Result of code execution. **Properties**: - `error?` _ExecutionError_ - Details about an execution error, if one occurred. - `stderr` _string_ - Standard error captured during execution. - `stdout` _string_ - Standard output captured during execution. ## OutputMessage Represents stdout or stderr output from code execution. **Properties**: - `output` _string_ - Output content. ## RunCodeOptions Options for executing code in the interpreter. **Properties**: - `context?` _InterpreterContext_ - Interpreter context to run code in. - `envs?` _Record\_ - Environment variables for this execution. - `onError()?` _\(error: ExecutionError\) =\> any_ - Callback for execution errors (e.g., runtime exceptions). **Parameters**: - `error` _ExecutionError_ **Returns**: - `any` - `onStderr()?` _\(message: OutputMessage\) =\> any_ - Callback for stderr messages. **Parameters**: - `message` _OutputMessage_ **Returns**: - `any` - `onStdout()?` _\(message: OutputMessage\) =\> any_ - Callback for stdout messages. **Parameters**: - `message` _OutputMessage_ **Returns**: - `any` - `timeout?` _number_ - Timeout in seconds. Set to 0 for no timeout. Default is 10 minutes. ## ComputerUse Computer Use functionality for interacting with the desktop environment. **Properties**: - `display` _Display_ - Display operations interface - `keyboard` _Keyboard_ - Keyboard operations interface - `mouse` _Mouse_ - Mouse operations interface - `recording` _RecordingService_ - Screen recording operations interface - `screenshot` _Screenshot_ - Screenshot operations interface Provides access to mouse, keyboard, screenshot, display, and recording operations for automating desktop interactions within a sandbox. ### Constructors #### new ComputerUse() ```ts new ComputerUse(apiClient: ComputerUseApi): ComputerUse ``` **Parameters**: - `apiClient` _ComputerUseApi_ **Returns**: - `ComputerUse` ### Methods #### getProcessErrors() ```ts getProcessErrors(processName: string): Promise ``` Gets error logs for a specific VNC process **Parameters**: - `processName` _string_ - Name of the process to get error logs for **Returns**: - `Promise` - Process error logs **Example:** ```typescript const errorsResp = await sandbox.computerUse.getProcessErrors('x11vnc'); console.log('X11VNC errors:', errorsResp.errors); ``` *** #### getProcessLogs() ```ts getProcessLogs(processName: string): Promise ``` Gets logs for a specific VNC process **Parameters**: - `processName` _string_ - Name of the process to get logs for **Returns**: - `Promise` - Process logs **Example:** ```typescript const logsResp = await sandbox.computerUse.getProcessLogs('novnc'); console.log('NoVNC logs:', logsResp.logs); ``` *** #### getProcessStatus() ```ts getProcessStatus(processName: string): Promise ``` Gets the status of a specific VNC process **Parameters**: - `processName` _string_ - Name of the process to check **Returns**: - `Promise` - Status information about the specific process **Example:** ```typescript const xvfbStatus = await sandbox.computerUse.getProcessStatus('xvfb'); const noVncStatus = await sandbox.computerUse.getProcessStatus('novnc'); ``` *** #### getStatus() ```ts getStatus(): Promise ``` Gets the status of all computer use processes **Returns**: - `Promise` - Status information about all VNC desktop processes **Example:** ```typescript const status = await sandbox.computerUse.getStatus(); console.log('Computer use status:', status.status); ``` *** #### restartProcess() ```ts restartProcess(processName: string): Promise ``` Restarts a specific VNC process **Parameters**: - `processName` _string_ - Name of the process to restart **Returns**: - `Promise` - Process restart response **Example:** ```typescript const result = await sandbox.computerUse.restartProcess('xfce4'); console.log('XFCE4 process restarted:', result.message); ``` *** #### start() ```ts start(): Promise ``` Starts all computer use processes (Xvfb, xfce4, x11vnc, novnc) **Returns**: - `Promise` - Computer use start response **Example:** ```typescript const result = await sandbox.computerUse.start(); console.log('Computer use processes started:', result.message); ``` *** #### stop() ```ts stop(): Promise ``` Stops all computer use processes **Returns**: - `Promise` - Computer use stop response **Example:** ```typescript const result = await sandbox.computerUse.stop(); console.log('Computer use processes stopped:', result.message); ``` ## Display Display operations for computer use functionality ### Constructors #### new Display() ```ts new Display(apiClient: ComputerUseApi): Display ``` **Parameters**: - `apiClient` _ComputerUseApi_ **Returns**: - `Display` ### Methods #### getInfo() ```ts getInfo(): Promise ``` Gets information about the displays **Returns**: - `Promise` - Display information including primary display and all available displays **Example:** ```typescript const info = await sandbox.computerUse.display.getInfo(); console.log(`Primary display: ${info.primary_display.width}x${info.primary_display.height}`); console.log(`Total displays: ${info.total_displays}`); info.displays.forEach((display, index) => { console.log(`Display ${index}: ${display.width}x${display.height} at ${display.x},${display.y}`); }); ``` *** #### getWindows() ```ts getWindows(): Promise ``` Gets the list of open windows **Returns**: - `Promise` - List of open windows with their IDs and titles **Example:** ```typescript const windows = await sandbox.computerUse.display.getWindows(); console.log(`Found ${windows.count} open windows:`); windows.windows.forEach(window => { console.log(`- ${window.title} (ID: ${window.id})`); }); ``` *** ## Keyboard Keyboard operations for computer use functionality ### Constructors #### new Keyboard() ```ts new Keyboard(apiClient: ComputerUseApi): Keyboard ``` **Parameters**: - `apiClient` _ComputerUseApi_ **Returns**: - `Keyboard` ### Methods #### hotkey() ```ts hotkey(keys: string): Promise ``` Presses a hotkey combination **Parameters**: - `keys` _string_ - The hotkey combination (e.g., 'ctrl+c', 'alt+tab', 'cmd+shift+t') **Returns**: - `Promise` **Throws**: If the hotkey operation fails **Example:** ```typescript // Copy try { await sandbox.computerUse.keyboard.hotkey('ctrl+c'); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } // Paste try { await sandbox.computerUse.keyboard.hotkey('ctrl+v'); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } // Alt+Tab try { await sandbox.computerUse.keyboard.hotkey('alt+tab'); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } ``` *** #### press() ```ts press(key: string, modifiers?: string[]): Promise ``` Presses a key with optional modifiers **Parameters**: - `key` _string_ - The key to press (e.g., 'Enter', 'Escape', 'Tab', 'a', 'A') - `modifiers?` _string\[\] = \[\]_ - Modifier keys ('ctrl', 'alt', 'meta', 'shift') **Returns**: - `Promise` **Throws**: If the press operation fails **Example:** ```typescript // Press Enter try { await sandbox.computerUse.keyboard.press('Return'); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } // Press Ctrl+C try { await sandbox.computerUse.keyboard.press('c', ['ctrl']); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } // Press Ctrl+Shift+T try { await sandbox.computerUse.keyboard.press('t', ['ctrl', 'shift']); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } ``` *** #### type() ```ts type(text: string, delay?: number): Promise ``` Types the specified text **Parameters**: - `text` _string_ - The text to type - `delay?` _number_ - Delay between characters in milliseconds **Returns**: - `Promise` **Throws**: If the type operation fails **Example:** ```typescript try { await sandbox.computerUse.keyboard.type('Hello, World!'); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } // With delay between characters try { await sandbox.computerUse.keyboard.type('Slow typing', 100); console.log('Operation success'); } catch (e) { console.log('Operation failed:', e); } ``` *** ## Mouse Mouse operations for computer use functionality ### Constructors #### new Mouse() ```ts new Mouse(apiClient: ComputerUseApi): Mouse ``` **Parameters**: - `apiClient` _ComputerUseApi_ **Returns**: - `Mouse` ### Methods #### click() ```ts click( x: number, y: number, button?: string, double?: boolean): Promise ``` Clicks the mouse at the specified coordinates **Parameters**: - `x` _number_ - The x coordinate to click at - `y` _number_ - The y coordinate to click at - `button?` _string = 'left'_ - The mouse button to click ('left', 'right', 'middle') - `double?` _boolean = false_ - Whether to perform a double-click **Returns**: - `Promise` - Click operation result **Example:** ```typescript // Single left click const result = await sandbox.computerUse.mouse.click(100, 200); // Double click const doubleClick = await sandbox.computerUse.mouse.click(100, 200, 'left', true); // Right click const rightClick = await sandbox.computerUse.mouse.click(100, 200, 'right'); ``` *** #### drag() ```ts drag( startX: number, startY: number, endX: number, endY: number, button?: string): Promise ``` Drags the mouse from start coordinates to end coordinates **Parameters**: - `startX` _number_ - The starting x coordinate - `startY` _number_ - The starting y coordinate - `endX` _number_ - The ending x coordinate - `endY` _number_ - The ending y coordinate - `button?` _string = 'left'_ - The mouse button to use for dragging **Returns**: - `Promise` - Drag operation result **Example:** ```typescript const result = await sandbox.computerUse.mouse.drag(50, 50, 150, 150); console.log(`Dragged from ${result.from.x},${result.from.y} to ${result.to.x},${result.to.y}`); ``` *** #### getPosition() ```ts getPosition(): Promise ``` Gets the current mouse cursor position **Returns**: - `Promise` - Current mouse position with x and y coordinates **Example:** ```typescript const position = await sandbox.computerUse.mouse.getPosition(); console.log(`Mouse is at: ${position.x}, ${position.y}`); ``` *** #### move() ```ts move(x: number, y: number): Promise ``` Moves the mouse cursor to the specified coordinates **Parameters**: - `x` _number_ - The x coordinate to move to - `y` _number_ - The y coordinate to move to **Returns**: - `Promise` - Position after move **Example:** ```typescript const result = await sandbox.computerUse.mouse.move(100, 200); console.log(`Mouse moved to: ${result.x}, ${result.y}`); ``` *** #### scroll() ```ts scroll( x: number, y: number, direction: "up" | "down", amount?: number): Promise ``` Scrolls the mouse wheel at the specified coordinates **Parameters**: - `x` _number_ - The x coordinate to scroll at - `y` _number_ - The y coordinate to scroll at - `direction` _The direction to scroll_ - `"up"` | `"down"` - `amount?` _number = 1_ - The amount to scroll **Returns**: - `Promise` - Whether the scroll operation was successful **Example:** ```typescript // Scroll up const scrollUp = await sandbox.computerUse.mouse.scroll(100, 200, 'up', 3); // Scroll down const scrollDown = await sandbox.computerUse.mouse.scroll(100, 200, 'down', 5); ``` *** ## RecordingService Recording operations for computer use functionality. ### Constructors #### new RecordingService() ```ts new RecordingService(apiClient: ComputerUseApi): RecordingService ``` **Parameters**: - `apiClient` _ComputerUseApi_ **Returns**: - `RecordingService` ### Methods #### delete() ```ts delete(id: string): Promise ``` Deletes a recording by ID **Parameters**: - `id` _string_ - The ID of the recording to delete **Returns**: - `Promise` **Example:** ```typescript await sandbox.computerUse.recording.delete(recordingId); console.log('Recording deleted'); ``` *** #### download() ```ts download(id: string, localPath: string): Promise ``` Downloads a recording file and saves it to a local path The file is streamed directly to disk without loading the entire content into memory. **Parameters**: - `id` _string_ - The ID of the recording to download - `localPath` _string_ - Path to save the recording file locally **Returns**: - `Promise` **Example:** ```typescript // Download recording to file await sandbox.computerUse.recording.download(recordingId, 'local_recording.mp4'); console.log('Recording downloaded'); ``` *** #### get() ```ts get(id: string): Promise ``` Gets details of a specific recording by ID **Parameters**: - `id` _string_ - The ID of the recording to retrieve **Returns**: - `Promise` - Recording details **Example:** ```typescript const recording = await sandbox.computerUse.recording.get(recordingId); console.log(`Recording: ${recording.fileName}`); console.log(`Status: ${recording.status}`); console.log(`Duration: ${recording.durationSeconds} seconds`); ``` *** #### list() ```ts list(): Promise ``` Lists all recordings (active and completed) **Returns**: - `Promise` - List of all recordings **Example:** ```typescript const recordings = await sandbox.computerUse.recording.list(); console.log(`Found ${recordings.recordings.length} recordings`); recordings.recordings.forEach(rec => { console.log(`- ${rec.fileName}: ${rec.status}`); }); ``` *** #### start() ```ts start(label?: string): Promise ``` Starts a new screen recording session **Parameters**: - `label?` _string_ - Optional custom label for the recording **Returns**: - `Promise` - Started recording details **Example:** ```typescript // Start a recording with a label const recording = await sandbox.computerUse.recording.start('my-test-recording'); console.log(`Recording started: ${recording.id}`); console.log(`File: ${recording.filePath}`); ``` *** #### stop() ```ts stop(id: string): Promise ``` Stops an active screen recording session **Parameters**: - `id` _string_ - The ID of the recording to stop **Returns**: - `Promise` - Stopped recording details **Example:** ```typescript const result = await sandbox.computerUse.recording.stop(recording.id); console.log(`Recording stopped: ${result.durationSeconds} seconds`); console.log(`Saved to: ${result.filePath}`); ``` *** ## Screenshot Screenshot operations for computer use functionality ### Constructors #### new Screenshot() ```ts new Screenshot(apiClient: ComputerUseApi): Screenshot ``` **Parameters**: - `apiClient` _ComputerUseApi_ **Returns**: - `Screenshot` ### Methods #### takeCompressed() ```ts takeCompressed(options?: ScreenshotOptions): Promise ``` Takes a compressed screenshot of the entire screen **Parameters**: - `options?` _ScreenshotOptions = {}_ - Compression and display options **Returns**: - `Promise` - Compressed screenshot data **Example:** ```typescript // Default compression const screenshot = await sandbox.computerUse.screenshot.takeCompressed(); // High quality JPEG const jpeg = await sandbox.computerUse.screenshot.takeCompressed({ format: 'jpeg', quality: 95, showCursor: true }); // Scaled down PNG const scaled = await sandbox.computerUse.screenshot.takeCompressed({ format: 'png', scale: 0.5 }); ``` *** #### takeCompressedRegion() ```ts takeCompressedRegion(region: ScreenshotRegion, options?: ScreenshotOptions): Promise ``` Takes a compressed screenshot of a specific region **Parameters**: - `region` _ScreenshotRegion_ - The region to capture - `options?` _ScreenshotOptions = {}_ - Compression and display options **Returns**: - `Promise` - Compressed screenshot data **Example:** ```typescript const region = { x: 0, y: 0, width: 800, height: 600 }; const screenshot = await sandbox.computerUse.screenshot.takeCompressedRegion(region, { format: 'webp', quality: 80, showCursor: true }); console.log(`Compressed size: ${screenshot.size_bytes} bytes`); ``` *** #### takeFullScreen() ```ts takeFullScreen(showCursor?: boolean): Promise ``` Takes a screenshot of the entire screen **Parameters**: - `showCursor?` _boolean = false_ - Whether to show the cursor in the screenshot **Returns**: - `Promise` - Screenshot data with base64 encoded image **Example:** ```typescript const screenshot = await sandbox.computerUse.screenshot.takeFullScreen(); console.log(`Screenshot size: ${screenshot.width}x${screenshot.height}`); // With cursor visible const withCursor = await sandbox.computerUse.screenshot.takeFullScreen(true); ``` *** #### takeRegion() ```ts takeRegion(region: ScreenshotRegion, showCursor?: boolean): Promise ``` Takes a screenshot of a specific region **Parameters**: - `region` _ScreenshotRegion_ - The region to capture - `showCursor?` _boolean = false_ - Whether to show the cursor in the screenshot **Returns**: - `Promise` - Screenshot data with base64 encoded image **Example:** ```typescript const region = { x: 100, y: 100, width: 300, height: 200 }; const screenshot = await sandbox.computerUse.screenshot.takeRegion(region); console.log(`Captured region: ${screenshot.region.width}x${screenshot.region.height}`); ``` *** ## ScreenshotOptions Interface for screenshot compression options **Properties**: - `format?` _string_ - `quality?` _number_ - `scale?` _number_ - `showCursor?` _boolean_ ## ScreenshotRegion Interface for region coordinates used in screenshot operations **Properties**: - `height` _number_ - `width` _number_ - `x` _number_ - `y` _number_ ## Daytona Main class for interacting with the Daytona API. Provides methods for creating, managing, and interacting with Daytona Sandboxes. Can be initialized either with explicit configuration or using environment variables. **Properties**: - `snapshot` _SnapshotService_ - Service for managing Daytona Snapshots - `volume` _VolumeService_ - Service for managing Daytona Volumes **Examples:** ```ts // Using environment variables // Uses DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET const daytona = new Daytona(); const sandbox = await daytona.create(); ``` ```ts // Using explicit configuration const config: DaytonaConfig = { apiKey: "your-api-key", apiUrl: "https://your-api.com", target: "us" }; const daytona = new Daytona(config); ``` ```ts // Disposes daytona and flushes traces when done await using daytona = new Daytona({ otelEnabled: true, }); @class ``` ### Implements - `AsyncDisposable` ### Constructors #### new Daytona() ```ts new Daytona(config?: DaytonaConfig): Daytona ``` Creates a new Daytona client instance. **Parameters**: - `config?` _DaytonaConfig_ - Configuration options **Returns**: - `Daytona` **Throws**: - `DaytonaError` - When API key is missing ### Methods #### \[asyncDispose\]() ```ts asyncDispose: Promise ``` **Returns**: - `Promise` ##### Implementation of ```ts AsyncDisposable.[asyncDispose] ``` *** #### create() ##### Call Signature ```ts create(params?: CreateSandboxFromSnapshotParams, options?: { timeout: number; }): Promise ``` Creates Sandboxes from specified or default snapshot. You can specify various parameters, including language, image, environment variables, and volumes. **Parameters**: - `params?` _CreateSandboxFromSnapshotParams_ - Parameters for Sandbox creation from snapshot - `options?` _Options for the create operation_ - `timeout?` _number_ - Timeout in seconds (0 means no timeout, default is 60) **Returns**: - `Promise` - The created Sandbox instance **Examples:** ```ts const sandbox = await daytona.create(); ``` ```ts // Create a custom sandbox const params: CreateSandboxFromSnapshotParams = { language: 'typescript', snapshot: 'my-snapshot-id', envVars: { NODE_ENV: 'development', DEBUG: 'true' }, autoStopInterval: 60, autoArchiveInterval: 60, autoDeleteInterval: 120 }; const sandbox = await daytona.create(params, { timeout: 100 }); ``` ##### Call Signature ```ts create(params?: CreateSandboxFromImageParams, options?: { onSnapshotCreateLogs: (chunk: string) => void; timeout: number; }): Promise ``` Creates Sandboxes from specified image available on some registry or declarative Daytona Image. You can specify various parameters, including resources, language, image, environment variables, and volumes. Daytona creates snapshot from provided image and uses it to create Sandbox. **Parameters**: - `params?` _CreateSandboxFromImageParams_ - Parameters for Sandbox creation from image - `options?` _Options for the create operation_ - `onSnapshotCreateLogs?` _\(chunk: string\) =\> void_ - Callback function to handle snapshot creation logs. - `timeout?` _number_ - Timeout in seconds (0 means no timeout, default is 60) **Returns**: - `Promise` - The created Sandbox instance **Examples:** ```ts const sandbox = await daytona.create({ image: 'debian:12.9' }, { timeout: 90, onSnapshotCreateLogs: console.log }); ``` ```ts // Create a custom sandbox const image = Image.base('alpine:3.18').pipInstall('numpy'); const params: CreateSandboxFromImageParams = { language: 'typescript', image, envVars: { NODE_ENV: 'development', DEBUG: 'true' }, resources: { cpu: 2, memory: 4 // 4GB RAM }, autoStopInterval: 60, autoArchiveInterval: 60, autoDeleteInterval: 120 }; const sandbox = await daytona.create(params, { timeout: 100, onSnapshotCreateLogs: console.log }); ``` *** #### delete() ```ts delete(sandbox: Sandbox, timeout: number): Promise ``` Deletes a Sandbox. **Parameters**: - `sandbox` _Sandbox_ - The Sandbox to delete - `timeout` _number = 60_ - Timeout in seconds (0 means no timeout, default is 60) **Returns**: - `Promise` **Example:** ```ts const sandbox = await daytona.get('my-sandbox-id'); await daytona.delete(sandbox); ``` *** #### get() ```ts get(sandboxIdOrName: string): Promise ``` Gets a Sandbox by its ID or name. **Parameters**: - `sandboxIdOrName` _string_ - The ID or name of the Sandbox to retrieve **Returns**: - `Promise` - The Sandbox **Example:** ```ts const sandbox = await daytona.get('my-sandbox-id-or-name'); console.log(`Sandbox state: ${sandbox.state}`); ``` *** #### list() ```ts list( labels?: Record, page?: number, limit?: number): Promise ``` Returns paginated list of Sandboxes filtered by labels. **Parameters**: - `labels?` _Record\_ - Labels to filter Sandboxes - `page?` _number_ - Page number for pagination (starting from 1) - `limit?` _number_ - Maximum number of items per page **Returns**: - `Promise` - Paginated list of Sandboxes that match the labels. **Example:** ```ts const result = await daytona.list({ 'my-label': 'my-value' }, 2, 10); for (const sandbox of result.items) { console.log(`${sandbox.id}: ${sandbox.state}`); } ``` *** #### start() ```ts start(sandbox: Sandbox, timeout?: number): Promise ``` Starts a Sandbox and waits for it to be ready. **Parameters**: - `sandbox` _Sandbox_ - The Sandbox to start - `timeout?` _number_ - Optional timeout in seconds (0 means no timeout) **Returns**: - `Promise` **Example:** ```ts const sandbox = await daytona.get('my-sandbox-id'); // Wait up to 60 seconds for the sandbox to start await daytona.start(sandbox, 60); ``` *** #### stop() ```ts stop(sandbox: Sandbox): Promise ``` Stops a Sandbox. **Parameters**: - `sandbox` _Sandbox_ - The Sandbox to stop **Returns**: - `Promise` **Example:** ```ts const sandbox = await daytona.get('my-sandbox-id'); await daytona.stop(sandbox); ``` ## CodeLanguage Supported programming languages for code execution Python is used as the default sandbox language when no language is explicitly specified. **Enum Members**: - `JAVASCRIPT` ("javascript") - `PYTHON` ("python") - `TYPESCRIPT` ("typescript") ## CreateSandboxBaseParams Base parameters for creating a new Sandbox. **Properties**: - `autoArchiveInterval?` _number_ - Auto-archive interval in minutes (0 means the maximum interval will be used). Default is 7 days. - `autoDeleteInterval?` _number_ - Auto-delete interval in minutes (negative value means disabled, 0 means delete immediately upon stopping). By default, auto-delete is disabled. - `autoStopInterval?` _number_ - Auto-stop interval in minutes (0 means disabled). Default is 15 minutes. - `envVars?` _Record\_ - Optional environment variables to set in the Sandbox - `ephemeral?` _boolean_ - Whether the Sandbox should be ephemeral. If true, autoDeleteInterval will be set to 0. - `labels?` _Record\_ - Sandbox labels - `language?` _string_ - Programming language for direct code execution. Defaults to "python" if not specified. - `name?` _string_ - `networkAllowList?` _string_ - Comma-separated list of allowed CIDR network addresses for the Sandbox - `networkBlockAll?` _boolean_ - Whether to block all network access for the Sandbox - `public?` _boolean_ - Is the Sandbox port preview public - `user?` _string_ - Optional os user to use for the Sandbox - `volumes?` _VolumeMount\[\]_ - Optional array of volumes to mount to the Sandbox ## CreateSandboxFromImageParams Parameters for creating a new Sandbox. **Properties**: - `autoArchiveInterval?` _number_ - `autoDeleteInterval?` _number_ - `autoStopInterval?` _number_ - `envVars?` _Record\_ - `ephemeral?` _boolean_ - `image` _string \| Image_ - Custom Docker image to use for the Sandbox. If an Image object is provided, the image will be dynamically built. - `labels?` _Record\_ - `language?` _string_ - `name?` _string_ - `networkAllowList?` _string_ - `networkBlockAll?` _boolean_ - `public?` _boolean_ - `resources?` _Resources_ - Resource allocation for the Sandbox. If not provided, sandbox will have default resources. - `user?` _string_ - `volumes?` _VolumeMount\[\]_ ## CreateSandboxFromSnapshotParams Parameters for creating a new Sandbox from a snapshot. **Properties**: - `autoArchiveInterval?` _number_ - `autoDeleteInterval?` _number_ - `autoStopInterval?` _number_ - `envVars?` _Record\_ - `ephemeral?` _boolean_ - `labels?` _Record\_ - `language?` _string_ - `name?` _string_ - `networkAllowList?` _string_ - `networkBlockAll?` _boolean_ - `public?` _boolean_ - `snapshot?` _string_ - Name of the snapshot to use for the Sandbox. - `user?` _string_ - `volumes?` _VolumeMount\[\]_ ## DaytonaConfig Configuration options for initializing the Daytona client. **Properties**: - `\_experimental?` _Record\_ - Configuration for experimental features - `apiKey?` _string_ - API key for authentication with the Daytona API - `apiUrl?` _string_ - URL of the Daytona API. Defaults to 'https://app.daytona.io/api' if not set here and not set in environment variable DAYTONA_API_URL. - `jwtToken?` _string_ - JWT token for authentication with the Daytona API. If not set, it must be provided via the environment variable `DAYTONA_JWT_TOKEN`, or an API key must be provided instead. - `organizationId?` _string_ - Organization ID used for JWT-based authentication. Required if a JWT token is provided, and must be set either here or in the environment variable `DAYTONA_ORGANIZATION_ID`. - ~~`serverUrl?`~~ _string_ - **_Deprecated_** - Use `apiUrl` instead. This property will be removed in future versions. - `target?` _string_ - Target location for Sandboxes **Example:** ```ts const config: DaytonaConfig = { apiKey: "your-api-key", apiUrl: "https://your-api.com", target: "us" }; const daytona = new Daytona(config); ``` ## Resources Resource allocation for a Sandbox. **Properties**: - `cpu?` _number_ - CPU allocation for the Sandbox in cores - `disk?` _number_ - Disk space allocation for the Sandbox in GiB - `gpu?` _number_ - GPU allocation for the Sandbox in units - `memory?` _number_ - Memory allocation for the Sandbox in GiB **Example:** ```ts const resources: SandboxResources = { cpu: 2, memory: 4, // 4GiB RAM disk: 20 // 20GiB disk }; ``` ## VolumeMount Represents a volume mount for a Sandbox. **Properties**: - `mountPath` _string_ - Path on the Sandbox to mount the Volume - `subpath?` _string_ - Optional subpath within the volume to mount. When specified, only this S3 prefix will be accessible. When omitted, the entire volume is mounted. - _Inherited from_: `SandboxVolume.subpath` - `volumeId` _string_ - ID of the Volume to mount **Extends:** - `SandboxVolume` ## DaytonaError Base error for Daytona SDK. **Properties**: - `headers?` _AxiosHeaders_ - Response headers if available - `statusCode?` _number_ - HTTP status code if available **Extends:** - `Error` ### Extended by - `DaytonaNotFoundError` - `DaytonaRateLimitError` - `DaytonaTimeoutError` ### Constructors #### new DaytonaError() ```ts new DaytonaError( message: string, statusCode?: number, headers?: AxiosHeaders): DaytonaError ``` **Parameters**: - `message` _string_ - `statusCode?` _number_ - `headers?` _AxiosHeaders_ **Returns**: - `DaytonaError` ##### Overrides ```ts Error.constructor ``` ## DaytonaNotFoundError Base error for Daytona SDK. **Properties**: - `headers?` _AxiosHeaders_ - Response headers if available - _Inherited from_: `DaytonaError.headers` - `statusCode?` _number_ - HTTP status code if available - _Inherited from_: `DaytonaError.statusCode` **Extends:** - `DaytonaError` ### Constructors #### new DaytonaNotFoundError() ```ts new DaytonaNotFoundError( message: string, statusCode?: number, headers?: AxiosHeaders): DaytonaNotFoundError ``` **Parameters**: - `message` _string_ - `statusCode?` _number_ - `headers?` _AxiosHeaders_ **Returns**: - `DaytonaNotFoundError` ##### Overrides `DaytonaError`.`constructor` ## DaytonaRateLimitError Error thrown when rate limit is exceeded. **Properties**: - `headers?` _AxiosHeaders_ - Response headers if available - _Inherited from_: `DaytonaError.headers` - `statusCode?` _number_ - HTTP status code if available - _Inherited from_: `DaytonaError.statusCode` **Extends:** - `DaytonaError` ### Constructors #### new DaytonaRateLimitError() ```ts new DaytonaRateLimitError( message: string, statusCode?: number, headers?: AxiosHeaders): DaytonaRateLimitError ``` **Parameters**: - `message` _string_ - `statusCode?` _number_ - `headers?` _AxiosHeaders_ **Returns**: - `DaytonaRateLimitError` ##### Overrides `DaytonaError`.`constructor` ## DaytonaTimeoutError Error thrown when a timeout occurs. **Properties**: - `headers?` _AxiosHeaders_ - Response headers if available - _Inherited from_: `DaytonaError.headers` - `statusCode?` _number_ - HTTP status code if available - _Inherited from_: `DaytonaError.statusCode` **Extends:** - `DaytonaError` ### Constructors #### new DaytonaTimeoutError() ```ts new DaytonaTimeoutError( message: string, statusCode?: number, headers?: AxiosHeaders): DaytonaTimeoutError ``` **Parameters**: - `message` _string_ - `statusCode?` _number_ - `headers?` _AxiosHeaders_ **Returns**: - `DaytonaTimeoutError` ##### Overrides `DaytonaError`.`constructor` ## ExecuteResponse Response from the command execution. **Properties**: - `artifacts?` _ExecutionArtifacts_ - Artifacts from the command execution - `exitCode` _number_ - The exit code from the command execution - `result` _string_ - The output from the command execution ## ExecutionArtifacts Artifacts from the command execution. **Properties**: - `charts?` _Chart\[\]_ - List of chart metadata from matplotlib - `stdout` _string_ - Standard output from the command, same as `result` in `ExecuteResponse` ## FileSystem Provides file system operations within a Sandbox. ### Constructors #### new FileSystem() ```ts new FileSystem(clientConfig: Configuration, apiClient: FileSystemApi): FileSystem ``` **Parameters**: - `clientConfig` _Configuration_ - `apiClient` _FileSystemApi_ **Returns**: - `FileSystem` ### Methods #### createFolder() ```ts createFolder(path: string, mode: string): Promise ``` Create a new directory in the Sandbox with specified permissions. **Parameters**: - `path` _string_ - Path where the directory should be created. Relative paths are resolved based on the sandbox working directory. - `mode` _string_ - Directory permissions in octal format (e.g. "755") **Returns**: - `Promise` **Example:** ```ts // Create a directory with standard permissions await fs.createFolder('app/data', '755'); ``` *** #### deleteFile() ```ts deleteFile(path: string, recursive?: boolean): Promise ``` Deletes a file or directory from the Sandbox. **Parameters**: - `path` _string_ - Path to the file or directory to delete. Relative paths are resolved based on the sandbox working directory. - `recursive?` _boolean_ - If the file is a directory, this must be true to delete it. **Returns**: - `Promise` **Example:** ```ts // Delete a file await fs.deleteFile('app/temp.log'); ``` *** #### downloadFile() ##### Call Signature ```ts downloadFile(remotePath: string, timeout?: number): Promise> ``` Downloads a file from the Sandbox. This method loads the entire file into memory, so it is not recommended for downloading large files. **Parameters**: - `remotePath` _string_ - Path to the file to download. Relative paths are resolved based on the sandbox working directory. - `timeout?` _number_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `Promise>` - The file contents as a Buffer. **Example:** ```ts // Download and process a file const fileBuffer = await fs.downloadFile('tmp/data.json'); console.log('File content:', fileBuffer.toString()); ``` ##### Call Signature ```ts downloadFile( remotePath: string, localPath: string, timeout?: number): Promise ``` Downloads a file from the Sandbox and saves it to a local file. This method uses streaming to download the file, so it is recommended for downloading larger files. **Parameters**: - `remotePath` _string_ - Path to the file to download in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `localPath` _string_ - Path to save the downloaded file. - `timeout?` _number_ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `Promise` **Example:** ```ts // Download and save a file await fs.downloadFile('tmp/data.json', 'local_file.json'); ``` *** #### downloadFiles() ```ts downloadFiles(files: FileDownloadRequest[], timeoutSec?: number): Promise ``` Downloads multiple files from the Sandbox. If the files already exist locally, they will be overwritten. **Parameters**: - `files` _FileDownloadRequest\[\]_ - Array of file download requests. - `timeoutSec?` _number = ..._ - Timeout for the download operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `Promise` - Array of download results. **Throws**: If the request itself fails (network issues, invalid request/response, etc.). Individual file download errors are returned in the `FileDownloadResponse.error` field. **Example:** ```ts // Download multiple files const results = await fs.downloadFiles([ { source: 'tmp/data.json' }, { source: 'tmp/config.json', destination: 'local_config.json' } ]); results.forEach(result => { if (result.error) { console.error(`Error downloading ${result.source}: ${result.error}`); } else if (result.result) { console.log(`Downloaded ${result.source} to ${result.result}`); } }); ``` *** #### findFiles() ```ts findFiles(path: string, pattern: string): Promise ``` Searches for text patterns within files in the Sandbox. **Parameters**: - `path` _string_ - Directory to search in. Relative paths are resolved based on the sandbox working directory. - `pattern` _string_ - Search pattern **Returns**: - `Promise` - Array of matches with file and line information **Example:** ```ts // Find all TODO comments in TypeScript files const matches = await fs.findFiles('app/src', 'TODO:'); matches.forEach(match => { console.log(`${match.file}:${match.line}: ${match.content}`); }); ``` *** #### getFileDetails() ```ts getFileDetails(path: string): Promise ``` Retrieves detailed information about a file or directory. **Parameters**: - `path` _string_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Promise` - Detailed file information including size, permissions, modification time **Example:** ```ts // Get file details const info = await fs.getFileDetails('app/config.json'); console.log(`Size: ${info.size}, Modified: ${info.modTime}`); ``` *** #### listFiles() ```ts listFiles(path: string): Promise ``` Lists contents of a directory in the Sandbox. **Parameters**: - `path` _string_ - Directory path to list. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Promise` - Array of file and directory information **Example:** ```ts // List directory contents const files = await fs.listFiles('app/src'); files.forEach(file => { console.log(`${file.name} (${file.size} bytes)`); }); ``` *** #### moveFiles() ```ts moveFiles(source: string, destination: string): Promise ``` Moves or renames a file or directory. **Parameters**: - `source` _string_ - Source path. Relative paths are resolved based on the sandbox working directory. - `destination` _string_ - Destination path. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Promise` **Example:** ```ts // Move a file to a new location await fs.moveFiles('app/temp/data.json', 'app/data/data.json'); ``` *** #### replaceInFiles() ```ts replaceInFiles( files: string[], pattern: string, newValue: string): Promise ``` Replaces text content in multiple files. **Parameters**: - `files` _string\[\]_ - Array of file paths to process. Relative paths are resolved based on the sandbox working directory. - `pattern` _string_ - Pattern to replace - `newValue` _string_ - Replacement text **Returns**: - `Promise` - Results of the replace operation for each file **Example:** ```ts // Update version number across multiple files const results = await fs.replaceInFiles( ['app/package.json', 'app/version.ts'], '"version": "1.0.0"', '"version": "1.1.0"' ); ``` *** #### searchFiles() ```ts searchFiles(path: string, pattern: string): Promise ``` Searches for files and directories by name pattern in the Sandbox. **Parameters**: - `path` _string_ - Directory to search in. Relative paths are resolved based on the sandbox working directory. - `pattern` _string_ - File name pattern (supports globs) **Returns**: - `Promise` - Search results with matching files **Example:** ```ts // Find all TypeScript files const result = await fs.searchFiles('app', '*.ts'); result.files.forEach(file => console.log(file)); ``` *** #### setFilePermissions() ```ts setFilePermissions(path: string, permissions: FilePermissionsParams): Promise ``` Sets permissions and ownership for a file or directory. **Parameters**: - `path` _string_ - Path to the file or directory. Relative paths are resolved based on the sandbox working directory. - `permissions` _FilePermissionsParams_ - Permission settings **Returns**: - `Promise` **Example:** ```ts // Set file permissions and ownership await fs.setFilePermissions('app/script.sh', { owner: 'daytona', group: 'users', mode: '755' // Execute permission for shell script }); ``` *** #### uploadFile() ##### Call Signature ```ts uploadFile( file: Buffer, remotePath: string, timeout?: number): Promise ``` Uploads a file to the Sandbox. This method loads the entire file into memory, so it is not recommended for uploading large files. **Parameters**: - `file` _Buffer_ - Buffer of the file to upload. - `remotePath` _string_ - Destination path in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `timeout?` _number_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `Promise` **Example:** ```ts // Upload a configuration file await fs.uploadFile(Buffer.from('{"setting": "value"}'), 'tmp/config.json'); ``` ##### Call Signature ```ts uploadFile( localPath: string, remotePath: string, timeout?: number): Promise ``` Uploads a file from the local file system to the Sandbox. This method uses streaming to upload the file, so it is recommended for uploading larger files. **Parameters**: - `localPath` _string_ - Path to the local file to upload. - `remotePath` _string_ - Destination path in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `timeout?` _number_ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `Promise` **Example:** ```ts // Upload a local file await fs.uploadFile('local_file.txt', 'tmp/file.txt'); ``` *** #### uploadFiles() ```ts uploadFiles(files: FileUpload[], timeout?: number): Promise ``` Uploads multiple files to the Sandbox. If files already exist at the destination paths, they will be overwritten. **Parameters**: - `files` _FileUpload\[\]_ - Array of files to upload. - `timeout?` _number = ..._ - Timeout for the upload operation in seconds. 0 means no timeout. Default is 30 minutes. **Returns**: - `Promise` **Example:** ```ts // Upload multiple text files const files = [ { source: Buffer.from('Content of file 1'), destination: '/tmp/file1.txt' }, { source: 'app/data/file2.txt', destination: '/tmp/file2.txt' }, { source: Buffer.from('{"key": "value"}'), destination: '/tmp/config.json' } ]; await fs.uploadFiles(files); ``` *** ## DownloadMetadata Represents metadata for a file download operation. **Properties**: - `destination?` _string_ - Destination path in the local filesystem where the file content will be streamed to. - `error?` _string_ - Error message if the download failed, undefined if successful. - `result?` _string \| Buffer\ \| Uint8Array\_ - The download result - file path (if destination provided in the request) or bytes content (if no destination in the request), undefined if failed or no data received. ## FileDownloadRequest Represents a request to download a single file from the Sandbox. **Properties**: - `destination?` _string_ - Destination path in the local filesystem where the file content will be streamed to. If not provided, the file will be downloaded in the bytes buffer (might cause memory issues if the file is large). - `source` _string_ - Source path in the Sandbox. Relative paths are resolved based on the user's root directory. ## FileDownloadResponse Represents the response to a single file download request. **Properties**: - `error?` _string_ - Error message if the download failed, undefined if successful. - `result?` _string \| Buffer\_ - The download result - file path (if destination provided in the request) or bytes content (if no destination in the request), undefined if failed or no data received. - `source` _string_ - The original source path requested for download. ## FilePermissionsParams Parameters for setting file permissions in the Sandbox. **Properties**: - `group?` _string_ - Group owner of the file - `mode?` _string_ - File mode/permissions in octal format (e.g. "644") - `owner?` _string_ - User owner of the file **Example:** ```ts const permissions: FilePermissionsParams = { mode: '644', owner: 'daytona', group: 'users' }; ``` ## FileUpload Represents a file to be uploaded to the Sandbox. **Properties**: - `destination` _string_ - Absolute destination path in the Sandbox. Relative paths are resolved based on the sandbox working directory. - `source` _string \| Buffer\_ - File to upload. If a Buffer, it is interpreted as the file content which is loaded into memory. Make sure it fits into memory, otherwise use the local file path which content will be streamed to the Sandbox. ## Git Provides Git operations within a Sandbox. ### Constructors #### new Git() ```ts new Git(apiClient: GitApi): Git ``` **Parameters**: - `apiClient` _GitApi_ **Returns**: - `Git` ### Methods #### add() ```ts add(path: string, files: string[]): Promise ``` Stages the specified files for the next commit, similar to running 'git add' on the command line. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `files` _string\[\]_ - List of file paths or directories to stage, relative to the repository root **Returns**: - `Promise` **Examples:** ```ts // Stage a single file await git.add('workspace/repo', ['file.txt']); ``` ```ts // Stage whole repository await git.add('workspace/repo', ['.']); ``` *** #### branches() ```ts branches(path: string): Promise ``` List branches in the repository. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Promise` - List of branches in the repository **Example:** ```ts const response = await git.branches('workspace/repo'); console.log(`Branches: ${response.branches}`); ``` *** #### checkoutBranch() ```ts checkoutBranch(path: string, branch: string): Promise ``` Checkout branche in the repository. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `branch` _string_ - Name of the branch to checkout **Returns**: - `Promise` **Example:** ```ts await git.checkoutBranch('workspace/repo', 'new-feature'); ``` *** #### clone() ```ts clone( url: string, path: string, branch?: string, commitId?: string, username?: string, password?: string): Promise ``` Clones a Git repository into the specified path. It supports cloning specific branches or commits, and can authenticate with the remote repository if credentials are provided. **Parameters**: - `url` _string_ - Repository URL to clone from - `path` _string_ - Path where the repository should be cloned. Relative paths are resolved based on the sandbox working directory. - `branch?` _string_ - Specific branch to clone. If not specified, clones the default branch - `commitId?` _string_ - Specific commit to clone. If specified, the repository will be left in a detached HEAD state at this commit - `username?` _string_ - Git username for authentication - `password?` _string_ - Git password or token for authentication **Returns**: - `Promise` **Examples:** ```ts // Clone the default branch await git.clone( 'https://github.com/user/repo.git', 'workspace/repo' ); ``` ```ts // Clone a specific branch with authentication await git.clone( 'https://github.com/user/private-repo.git', 'workspace/private', branch='develop', username='user', password='token' ); ``` ```ts // Clone a specific commit await git.clone( 'https://github.com/user/repo.git', 'workspace/repo-old', commitId='abc123' ); ``` *** #### commit() ```ts commit( path: string, message: string, author: string, email: string, allowEmpty?: boolean): Promise ``` Commits staged changes. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `message` _string_ - Commit message describing the changes - `author` _string_ - Name of the commit author - `email` _string_ - Email address of the commit author - `allowEmpty?` _boolean_ - Allow creating an empty commit when no changes are staged **Returns**: - `Promise` **Example:** ```ts // Stage and commit changes await git.add('workspace/repo', ['README.md']); await git.commit( 'workspace/repo', 'Update documentation', 'John Doe', 'john@example.com', true ); ``` *** #### createBranch() ```ts createBranch(path: string, name: string): Promise ``` Create branch in the repository. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _string_ - Name of the new branch to create **Returns**: - `Promise` **Example:** ```ts await git.createBranch('workspace/repo', 'new-feature'); ``` *** #### deleteBranch() ```ts deleteBranch(path: string, name: string): Promise ``` Delete branche in the repository. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `name` _string_ - Name of the branch to delete **Returns**: - `Promise` **Example:** ```ts await git.deleteBranch('workspace/repo', 'new-feature'); ``` *** #### pull() ```ts pull( path: string, username?: string, password?: string): Promise ``` Pulls changes from the remote repository. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username?` _string_ - Git username for authentication - `password?` _string_ - Git password or token for authentication **Returns**: - `Promise` **Examples:** ```ts // Pull from a public repository await git.pull('workspace/repo'); ``` ```ts // Pull from a private repository await git.pull( 'workspace/repo', 'user', 'token' ); ``` *** #### push() ```ts push( path: string, username?: string, password?: string): Promise ``` Push local changes to the remote repository. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. - `username?` _string_ - Git username for authentication - `password?` _string_ - Git password or token for authentication **Returns**: - `Promise` **Examples:** ```ts // Push to a public repository await git.push('workspace/repo'); ``` ```ts // Push to a private repository await git.push( 'workspace/repo', 'user', 'token' ); ``` *** #### status() ```ts status(path: string): Promise ``` Gets the current status of the Git repository. **Parameters**: - `path` _string_ - Path to the Git repository root. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Promise` - Current repository status including: - currentBranch: Name of the current branch - ahead: Number of commits ahead of the remote branch - behind: Number of commits behind the remote branch - branchPublished: Whether the branch has been published to the remote repository - fileStatus: List of file statuses **Example:** ```ts const status = await sandbox.git.status('workspace/repo'); console.log(`Current branch: ${status.currentBranch}`); console.log(`Commits ahead: ${status.ahead}`); console.log(`Commits behind: ${status.behind}`); ``` *** ## GitCommitResponse Response from the git commit. **Properties**: - `sha` _string_ - The SHA of the commit ## Image Represents an image definition for a Daytona sandbox. Do not construct this class directly. Instead use one of its static factory methods, such as `Image.base()`, `Image.debianSlim()` or `Image.fromDockerfile()`. ### Accessors #### contextList ##### Get Signature ```ts get contextList(): Context[] ``` ###### Returns `Context`[] The list of context files to be added to the image. *** #### dockerfile ##### Get Signature ```ts get dockerfile(): string ``` **Returns**: - `string` - The Dockerfile content. ### Methods #### base() ```ts static base(image: string): Image ``` Creates an Image from an existing base image. **Parameters**: - `image` _string_ - The base image to use. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image.base('python:3.12-slim-bookworm') ``` *** #### debianSlim() ```ts static debianSlim(pythonVersion?: "3.9" | "3.10" | "3.11" | "3.12" | "3.13"): Image ``` Creates a Debian slim image based on the official Python Docker image. **Parameters**: - `pythonVersion?` _The Python version to use._ - `"3.9"` | `"3.10"` | `"3.11"` | `"3.12"` | `"3.13"` **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image.debianSlim('3.12') ``` *** #### fromDockerfile() ```ts static fromDockerfile(path: string): Image ``` Creates an Image from an existing Dockerfile. **Parameters**: - `path` _string_ - The path to the Dockerfile. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image.fromDockerfile('Dockerfile') ``` *** #### addLocalDir() ```ts addLocalDir(localPath: string, remotePath: string): Image ``` Adds a local directory to the image. **Parameters**: - `localPath` _string_ - The path to the local directory. - `remotePath` _string_ - The path of the directory in the image. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .addLocalDir('src', '/home/daytona/src') ``` *** #### addLocalFile() ```ts addLocalFile(localPath: string, remotePath: string): Image ``` Adds a local file to the image. **Parameters**: - `localPath` _string_ - The path to the local file. - `remotePath` _string_ - The path of the file in the image. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .addLocalFile('requirements.txt', '/home/daytona/requirements.txt') ``` *** #### cmd() ```ts cmd(cmd: string[]): Image ``` Sets the default command for the image. **Parameters**: - `cmd` _string\[\]_ - The command to set as the default command. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .cmd(['/bin/bash']) ``` *** #### dockerfileCommands() ```ts dockerfileCommands(dockerfileCommands: string[], contextDir?: string): Image ``` Extends an image with arbitrary Dockerfile-like commands. **Parameters**: - `dockerfileCommands` _string\[\]_ - The commands to add to the Dockerfile. - `contextDir?` _string_ - The path to the context directory. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .dockerfileCommands(['RUN echo "Hello, world!"']) ``` *** #### entrypoint() ```ts entrypoint(entrypointCommands: string[]): Image ``` Sets the entrypoint for the image. **Parameters**: - `entrypointCommands` _string\[\]_ - The commands to set as the entrypoint. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .entrypoint(['/bin/bash']) ``` *** #### env() ```ts env(envVars: Record): Image ``` Sets environment variables in the image. **Parameters**: - `envVars` _Record\_ - The environment variables to set. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .env({ FOO: 'bar' }) ``` *** #### pipInstall() ```ts pipInstall(packages: string | string[], options?: PipInstallOptions): Image ``` Adds commands to install packages using pip. **Parameters**: - `packages` _The packages to install._ - `string` | `string`[] - `options?` _PipInstallOptions_ - The options for the pip install command. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image.debianSlim('3.12').pipInstall('numpy', { findLinks: ['https://pypi.org/simple'] }) ``` *** #### pipInstallFromPyproject() ```ts pipInstallFromPyproject(pyprojectToml: string, options?: PyprojectOptions): Image ``` Installs dependencies from a pyproject.toml file. **Parameters**: - `pyprojectToml` _string_ - The path to the pyproject.toml file. - `options?` _PyprojectOptions_ - The options for the pip install command. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image.debianSlim('3.12') image.pipInstallFromPyproject('pyproject.toml', { optionalDependencies: ['dev'] }) ``` *** #### pipInstallFromRequirements() ```ts pipInstallFromRequirements(requirementsTxt: string, options?: PipInstallOptions): Image ``` Installs dependencies from a requirements.txt file. **Parameters**: - `requirementsTxt` _string_ - The path to the requirements.txt file. - `options?` _PipInstallOptions_ - The options for the pip install command. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image.debianSlim('3.12') image.pipInstallFromRequirements('requirements.txt', { findLinks: ['https://pypi.org/simple'] }) ``` *** #### runCommands() ```ts runCommands(...commands: (string | string[])[]): Image ``` Runs commands in the image. **Parameters**: - `commands` _...\(string \| string\[\]\)\[\]_ - The commands to run. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .runCommands( 'echo "Hello, world!"', ['bash', '-c', 'echo Hello, world, again!'] ) ``` *** #### workdir() ```ts workdir(dirPath: string): Image ``` Sets the working directory in the image. **Parameters**: - `dirPath` _string_ - The path to the working directory. **Returns**: - `Image` - The Image instance. **Example:** ```ts const image = Image .debianSlim('3.12') .workdir('/home/daytona') ``` *** ## Context Represents a context file to be added to the image. **Properties**: - `archivePath` _string_ - The path inside the archive file in object storage. - `sourcePath` _string_ - The path to the source file or directory. ## PipInstallOptions Options for the pip install command. **Properties**: - `extraIndexUrls?` _string\[\]_ - The extra index URLs to use for the pip install command. - `extraOptions?` _string_ - The extra options to use for the pip install command. Given string is passed directly to the pip install command. - `findLinks?` _string\[\]_ - The find-links to use for the pip install command. - `indexUrl?` _string_ - The index URL to use for the pip install command. - `pre?` _boolean_ - Whether to install pre-release versions. ### Extended by - `PyprojectOptions` ## PyprojectOptions Options for the pip install command from a pyproject.toml file. **Properties**: - `extraIndexUrls?` _string\[\]_ - The extra index URLs to use for the pip install command. - _Inherited from_: `PipInstallOptions.extraIndexUrls` - `extraOptions?` _string_ - The extra options to use for the pip install command. Given string is passed directly to the pip install command. - _Inherited from_: `PipInstallOptions.extraOptions` - `findLinks?` _string\[\]_ - The find-links to use for the pip install command. - _Inherited from_: `PipInstallOptions.findLinks` - `indexUrl?` _string_ - The index URL to use for the pip install command. - _Inherited from_: `PipInstallOptions.indexUrl` - `optionalDependencies?` _string\[\]_ - The optional dependencies to install. - `pre?` _boolean_ - Whether to install pre-release versions. - _Inherited from_: `PipInstallOptions.pre` **Extends:** - `PipInstallOptions` The Daytona TypeScript SDK provides a powerful interface for programmatically interacting with Daytona Sandboxes. ## Installation Install the Daytona TypeScript SDK using npm: ```bash npm install @daytonaio/sdk ``` Or using yarn: ```bash yarn add @daytonaio/sdk ``` ## Getting Started ### Create a Sandbox Create a Daytona Sandbox to run your code securely in an isolated environment. The following snippet is an example “Hello World” program that runs securely inside a Daytona Sandbox. ```typescript import { Daytona } from '@daytonaio/sdk' async function main() { // Initialize the SDK (uses environment variables by default) const daytona = new Daytona() // Create a new sandbox const sandbox = await daytona.create({ language: 'typescript', envVars: { NODE_ENV: 'development' }, }) // Execute a command const response = await sandbox.process.executeCommand('echo "Hello, World!"') console.log(response.result) } main().catch(console.error) ``` ## Configuration The Daytona SDK can be configured using environment variables or by passing options to the constructor: ```typescript import { Daytona } from '@daytonaio/sdk'; // Using environment variables (DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET) const daytona = new Daytona(); // Using explicit configuration const daytona = new Daytona({ apiKey: 'YOUR_API_KEY', apiUrl: 'https://app.daytona.io/api', target: 'us' }); ``` For more information on configuring the Daytona SDK, see [configuration](https://www.daytona.io/docs/en/configuration.md). ## Multiple runtime support Daytona supports multiple programming language runtimes for direct code execution inside the sandbox. [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md) works across multiple **JavaScript runtimes** including **Node.js**, **browsers**, and **serverless platforms**: Cloudflare Workers, AWS Lambda, Azure Functions, etc. Using the Daytona SDK in browser-based environments or frameworks like [**Vite**](https://www.daytona.io/docs/en/getting-started.md#daytona-in-vite-projects) and [**Next.js**](https://www.daytona.io/docs/en/getting-started.md#daytona-in-nextjs-projects) requires configuring node polyfills. ### Daytona in Vite projects When using Daytona SDK in a Vite-based project, configure node polyfills to ensure compatibility. Add the following configuration to your `vite.config.ts` file in the `plugins` array: ```typescript import { nodePolyfills } from 'vite-plugin-node-polyfills' plugins: [ // ... other plugins nodePolyfills({ globals: { global: true, process: true, Buffer: true }, overrides: { path: 'path-browserify-win32', }, }), ], // ... rest of your config }) ``` ### Daytona in Next.js projects When using Daytona SDK in a Next.js project, configure node polyfills to ensure compatibility with Webpack and Turbopack bundlers. Add the following configuration to your `next.config.ts` file: ```typescript import type { NextConfig } from 'next' import NodePolyfillPlugin from 'node-polyfill-webpack-plugin' import { env, nodeless } from 'unenv' const { alias: turbopackAlias } = env(nodeless, {}) const nextConfig: NextConfig = { // Turbopack experimental: { turbo: { resolveAlias: { ...turbopackAlias, }, }, }, // Webpack webpack: (config, { isServer }) => { if (!isServer) { config.plugins.push(new NodePolyfillPlugin()) } return config }, } ``` ## LspServer Provides Language Server Protocol functionality for code intelligence to provide IDE-like features such as code completion, symbol search, and more. ### Constructors #### new LspServer() ```ts new LspServer( languageId: LspLanguageId, pathToProject: string, apiClient: LspApi): LspServer ``` **Parameters**: - `languageId` _LspLanguageId_ - `pathToProject` _string_ - `apiClient` _LspApi_ **Returns**: - `LspServer` ### Methods #### completions() ```ts completions(path: string, position: Position): Promise ``` Gets completion suggestions at a position in a file. **Parameters**: - `path` _string_ - Path to the file. Relative paths are resolved based on the project path set in the LSP server constructor. - `position` _Position_ - The position in the file where completion was requested **Returns**: - `Promise` - List of completion suggestions. The list includes: - isIncomplete: Whether more items might be available - items: List of completion items, each containing: - label: The text to insert - kind: The kind of completion - detail: Additional details about the item - documentation: Documentation for the item - sortText: Text used to sort the item in the list - filterText: Text used to filter the item - insertText: The actual text to insert (if different from label) **Example:** ```ts // Get completions at a specific position const completions = await lsp.completions('workspace/project/src/index.ts', { line: 10, character: 15 }); completions.items.forEach(item => { console.log(`${item.label} (${item.kind}): ${item.detail}`); }); ``` *** #### didClose() ```ts didClose(path: string): Promise ``` Notifies the language server that a file has been closed, should be called when a file is closed in the editor to allow the language server to clean up any resources associated with that file. **Parameters**: - `path` _string_ - Path to the closed file. Relative paths are resolved based on the project path set in the LSP server constructor. **Returns**: - `Promise` **Example:** ```ts // When done editing a file await lsp.didClose('workspace/project/src/index.ts'); ``` *** #### didOpen() ```ts didOpen(path: string): Promise ``` Notifies the language server that a file has been opened, enabling language features like diagnostics and completions for that file. The server will begin tracking the file's contents and providing language features. **Parameters**: - `path` _string_ - Path to the opened file. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Promise` **Example:** ```ts // When opening a file for editing await lsp.didOpen('workspace/project/src/index.ts'); // Now can get completions, symbols, etc. for this file ``` *** #### documentSymbols() ```ts documentSymbols(path: string): Promise ``` Get symbol information (functions, classes, variables, etc.) from a document. **Parameters**: - `path` _string_ - Path to the file to get symbols from. Relative paths are resolved based on the project path set in the LSP server constructor. **Returns**: - `Promise` - List of symbols in the document. Each symbol includes: - name: The symbol's name - kind: The symbol's kind (function, class, variable, etc.) - location: The location of the symbol in the file **Example:** ```ts // Get all symbols in a file const symbols = await lsp.documentSymbols('workspace/project/src/index.ts'); symbols.forEach(symbol => { console.log(`${symbol.kind} ${symbol.name}: ${symbol.location}`); }); ``` *** #### sandboxSymbols() ```ts sandboxSymbols(query: string): Promise ``` Searches for symbols matching the query string across the entire Sandbox. **Parameters**: - `query` _string_ - Search query to match against symbol names **Returns**: - `Promise` - List of matching symbols from all files. Each symbol includes: - name: The symbol's name - kind: The symbol's kind (function, class, variable, etc.) - location: The location of the symbol in the file **Example:** ```ts // Search for all symbols containing "User" const symbols = await lsp.sandboxSymbols('User'); symbols.forEach(symbol => { console.log(`${symbol.name} (${symbol.kind}) in ${symbol.location}`); }); ``` *** #### start() ```ts start(): Promise ``` Starts the language server, must be called before using any other LSP functionality. It initializes the language server for the specified language and project. **Returns**: - `Promise` **Example:** ```ts const lsp = await sandbox.createLspServer('typescript', 'workspace/project'); await lsp.start(); // Initialize the server // Now ready for LSP operations ``` *** #### stop() ```ts stop(): Promise ``` Stops the language server, should be called when the LSP server is no longer needed to free up system resources. **Returns**: - `Promise` **Example:** ```ts // When done with LSP features await lsp.stop(); // Clean up resources ``` *** #### ~~workspaceSymbols()~~ ```ts workspaceSymbols(query: string): Promise ``` Searches for symbols matching the query string across the entire Sandbox. **Parameters**: - `query` _string_ - Search query to match against symbol names **Returns**: - `Promise` - List of matching symbols from all files. Each symbol includes: - name: The symbol's name - kind: The symbol's kind (function, class, variable, etc.) - location: The location of the symbol in the file ##### Deprecated Use `sandboxSymbols` instead. This method will be removed in a future version. *** ## LspLanguageId Supported language server types. **Enum Members**: - `JAVASCRIPT` ("javascript") - `PYTHON` ("python") - `TYPESCRIPT` ("typescript") ## Position Represents a zero-based position within a text document, specified by line number and character offset. **Properties**: - `character` _number_ - Zero-based character offset on the line - `line` _number_ - Zero-based line number in the document **Example:** ```ts const position: Position = { line: 10, // Line 11 (zero-based) character: 15 // Character 16 on the line (zero-based) }; ``` ## ObjectStorage ObjectStorage class for interacting with object storage services. ### Param The configuration for the object storage service. ### Constructors #### new ObjectStorage() ```ts new ObjectStorage(config: ObjectStorageConfig): ObjectStorage ``` **Parameters**: - `config` _ObjectStorageConfig_ **Returns**: - `ObjectStorage` ### Methods #### upload() ```ts upload( path: string, organizationId: string, archiveBasePath: string): Promise ``` Upload a file or directory to object storage. **Parameters**: - `path` _string_ - The path to the file or directory to upload. - `organizationId` _string_ - The organization ID to use for the upload. - `archiveBasePath` _string_ - The base path to use for the archive. **Returns**: - `Promise` - The hash of the uploaded file or directory. *** ## ObjectStorageConfig Configuration for the ObjectStorage class. **Properties**: - `accessKeyId` _string_ - The access key ID for the object storage service. - `bucketName?` _string_ - The name of the bucket to use. - `endpointUrl` _string_ - The endpoint URL for the object storage service. - `secretAccessKey` _string_ - The secret access key for the object storage service. - `sessionToken?` _string_ - The session token for the object storage service. Used for temporary credentials. ## CodeRunParams Parameters for code execution. **Properties**: - `argv?` _string\[\]_ - Command line arguments - `env?` _Record\_ - Environment variables ### Constructors #### new CodeRunParams() ```ts new CodeRunParams(): CodeRunParams ``` **Returns**: - `CodeRunParams` ## Process Handles process and code execution within a Sandbox. ### Constructors #### new Process() ```ts new Process( clientConfig: Configuration, codeToolbox: SandboxCodeToolbox, apiClient: ProcessApi, getPreviewToken: () => Promise): Process ``` **Parameters**: - `clientConfig` _Configuration_ - `codeToolbox` _SandboxCodeToolbox_ - `apiClient` _ProcessApi_ - `getPreviewToken` _\(\) =\> Promise\_ **Returns**: - `Process` ### Methods #### codeRun() ```ts codeRun( code: string, params?: CodeRunParams, timeout?: number): Promise ``` Executes code in the Sandbox using the appropriate language runtime. **Parameters**: - `code` _string_ - Code to execute - `params?` _CodeRunParams_ - Parameters for code execution - `timeout?` _number_ - Maximum time in seconds to wait for execution to complete **Returns**: - `Promise` - Code execution results containing: - exitCode: The execution's exit status - result: Standard output from the code - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) **Examples:** ```ts // Run TypeScript code const response = await process.codeRun(` const x = 10; const y = 20; console.log(\`Sum: \${x + y}\`); `); console.log(response.artifacts.stdout); // Prints: Sum: 30 ``` ```ts // Run Python code with matplotlib const response = await process.codeRun(` import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 10, 30) y = np.sin(x) plt.figure(figsize=(8, 5)) plt.plot(x, y, 'b-', linewidth=2) plt.title('Line Chart') plt.xlabel('X-axis (seconds)') plt.ylabel('Y-axis (amplitude)') plt.grid(True) plt.show() `); if (response.artifacts?.charts) { const chart = response.artifacts.charts[0]; console.log(`Type: ${chart.type}`); console.log(`Title: ${chart.title}`); if (chart.type === ChartType.LINE) { const lineChart = chart as LineChart console.log('X Label:', lineChart.x_label) console.log('Y Label:', lineChart.y_label) console.log('X Ticks:', lineChart.x_ticks) console.log('Y Ticks:', lineChart.y_ticks) console.log('X Tick Labels:', lineChart.x_tick_labels) console.log('Y Tick Labels:', lineChart.y_tick_labels) console.log('X Scale:', lineChart.x_scale) console.log('Y Scale:', lineChart.y_scale) console.log('Elements:') console.dir(lineChart.elements, { depth: null }) } } ``` *** #### connectPty() ```ts connectPty(sessionId: string, options?: PtyConnectOptions): Promise ``` Connect to an existing PTY session in the sandbox. Establishes a WebSocket connection to an existing PTY session, allowing you to interact with a previously created terminal session. **Parameters**: - `sessionId` _string_ - ID of the PTY session to connect to - `options?` _PtyConnectOptions_ - Options for the connection including data handler **Returns**: - `Promise` - PTY handle for managing the session **Example:** ```ts // Connect to an existing PTY session const handle = await process.connectPty('my-session', { onData: (data) => { // Handle terminal output const text = new TextDecoder().decode(data); process.stdout.write(text); }, }); // Wait for connection to be established await handle.waitForConnection(); // Send commands to the existing session await handle.sendInput('pwd\n'); await handle.sendInput('ls -la\n'); await handle.sendInput('exit\n'); // Wait for completion const result = await handle.wait(); console.log(`Session exited with code: ${result.exitCode}`); // Clean up await handle.disconnect(); ``` *** #### createPty() ```ts createPty(options?: PtyCreateOptions & PtyConnectOptions): Promise ``` Create a new PTY (pseudo-terminal) session in the sandbox. Creates an interactive terminal session that can execute commands and handle user input. The PTY session behaves like a real terminal, supporting features like command history. **Parameters**: - `options?` _PtyCreateOptions & PtyConnectOptions_ - PTY session configuration including creation and connection options **Returns**: - `Promise` - PTY handle for managing the session **Example:** ```ts // Create a PTY session with custom configuration const ptyHandle = await process.createPty({ id: 'my-interactive-session', cwd: '/workspace', envs: { TERM: 'xterm-256color', LANG: 'en_US.UTF-8' }, cols: 120, rows: 30, onData: (data) => { // Handle terminal output const text = new TextDecoder().decode(data); process.stdout.write(text); }, }); // Wait for connection to be established await ptyHandle.waitForConnection(); // Send commands to the terminal await ptyHandle.sendInput('ls -la\n'); await ptyHandle.sendInput('echo "Hello, PTY!"\n'); await ptyHandle.sendInput('exit\n'); // Wait for completion and get result const result = await ptyHandle.wait(); console.log(`PTY session completed with exit code: ${result.exitCode}`); // Clean up await ptyHandle.disconnect(); ``` *** #### createSession() ```ts createSession(sessionId: string): Promise ``` Creates a new long-running background session in the Sandbox. Sessions are background processes that maintain state between commands, making them ideal for scenarios requiring multiple related commands or persistent environment setup. You can run long-running commands and monitor process status. **Parameters**: - `sessionId` _string_ - Unique identifier for the new session **Returns**: - `Promise` **Example:** ```ts // Create a new session const sessionId = 'my-session'; await process.createSession(sessionId); const session = await process.getSession(sessionId); // Do work... await process.deleteSession(sessionId); ``` *** #### deleteSession() ```ts deleteSession(sessionId: string): Promise ``` Delete a session from the Sandbox. **Parameters**: - `sessionId` _string_ - Unique identifier of the session to delete **Returns**: - `Promise` **Example:** ```ts // Clean up a completed session await process.deleteSession('my-session'); ``` *** #### executeCommand() ```ts executeCommand( command: string, cwd?: string, env?: Record, timeout?: number): Promise ``` Executes a shell command in the Sandbox. **Parameters**: - `command` _string_ - Shell command to execute - `cwd?` _string_ - Working directory for command execution. If not specified, uses the sandbox working directory. - `env?` _Record\_ - Environment variables to set for the command - `timeout?` _number_ - Maximum time in seconds to wait for the command to complete. 0 means wait indefinitely. **Returns**: - `Promise` - Command execution results containing: - exitCode: The command's exit status - result: Standard output from the command - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) **Examples:** ```ts // Simple command const response = await process.executeCommand('echo "Hello"'); console.log(response.artifacts.stdout); // Prints: Hello ``` ```ts // Command with working directory const result = await process.executeCommand('ls', 'workspace/src'); ``` ```ts // Command with timeout const result = await process.executeCommand('sleep 10', undefined, 5); ``` *** #### executeSessionCommand() ```ts executeSessionCommand( sessionId: string, req: SessionExecuteRequest, timeout?: number): Promise ``` Executes a command in an existing session. **Parameters**: - `sessionId` _string_ - Unique identifier of the session to use - `req` _SessionExecuteRequest_ - Command execution request containing: - command: The command to execute - runAsync: Whether to execute asynchronously - suppressInputEcho: Whether to suppress input echo. Default is `false`. - `timeout?` _number_ - Timeout in seconds **Returns**: - `Promise` - Command execution results containing: - cmdId: Unique identifier for the executed command - output: Combined command output (stdout and stderr) (if synchronous execution) - stdout: Standard output from the command - stderr: Standard error from the command - exitCode: Command exit status (if synchronous execution) **Example:** ```ts // Execute commands in sequence, maintaining state const sessionId = 'my-session'; // Change directory await process.executeSessionCommand(sessionId, { command: 'cd /home/daytona' }); // Run command in new directory const result = await process.executeSessionCommand(sessionId, { command: 'pwd' }); console.log('[STDOUT]:', result.stdout); console.log('[STDERR]:', result.stderr); ``` *** #### getEntrypointLogs() ##### Call Signature ```ts getEntrypointLogs(): Promise ``` Get the logs for the sandbox entrypoint session. **Returns**: - `Promise` - Command logs containing: output (combined stdout and stderr), stdout and stderr **Example:** ```ts const logs = await process.getEntrypointLogs(); console.log('[STDOUT]:', logs.stdout); console.log('[STDERR]:', logs.stderr); ``` ##### Call Signature ```ts getEntrypointLogs(onStdout: (chunk: string) => void, onStderr: (chunk: string) => void): Promise ``` Asynchronously retrieve and process the logs for the entrypoint session as they become available. **Parameters**: - `onStdout` _\(chunk: string\) =\> void_ - Callback function to handle stdout log chunks - `onStderr` _\(chunk: string\) =\> void_ - Callback function to handle stderr log chunks **Returns**: - `Promise` **Example:** ```ts const logs = await process.getEntrypointLogs((chunk) => { console.log('[STDOUT]:', chunk); }, (chunk) => { console.log('[STDERR]:', chunk); }); ``` *** #### getEntrypointSession() ```ts getEntrypointSession(): Promise ``` Get the sandbox entrypoint session **Returns**: - `Promise` - Entrypoint session information including: - sessionId: The entrypoint session's unique identifier - commands: List of commands executed in the entrypoint session **Example:** ```ts const session = await process.getEntrypointSession(); session.commands.forEach(cmd => { console.log(`Command: ${cmd.command}`); }); ``` *** #### getPtySessionInfo() ```ts getPtySessionInfo(sessionId: string): Promise ``` Get detailed information about a specific PTY session. Retrieves comprehensive information about a PTY session including its current state, configuration, and metadata. **Parameters**: - `sessionId` _string_ - ID of the PTY session to retrieve information for **Returns**: - `Promise` - PTY session information **Throws**: If the PTY session doesn't exist **Example:** ```ts // Get details about a specific PTY session const session = await process.getPtySessionInfo('my-session'); console.log(`Session ID: ${session.id}`); console.log(`Active: ${session.active}`); console.log(`Working Directory: ${session.cwd}`); console.log(`Terminal Size: ${session.cols}x${session.rows}`); if (session.processId) { console.log(`Process ID: ${session.processId}`); } ``` *** #### getSession() ```ts getSession(sessionId: string): Promise ``` Get a session in the sandbox. **Parameters**: - `sessionId` _string_ - Unique identifier of the session to retrieve **Returns**: - `Promise` - Session information including: - sessionId: The session's unique identifier - commands: List of commands executed in the session **Example:** ```ts const session = await process.getSession('my-session'); session.commands.forEach(cmd => { console.log(`Command: ${cmd.command}`); }); ``` *** #### getSessionCommand() ```ts getSessionCommand(sessionId: string, commandId: string): Promise ``` Gets information about a specific command executed in a session. **Parameters**: - `sessionId` _string_ - Unique identifier of the session - `commandId` _string_ - Unique identifier of the command **Returns**: - `Promise` - Command information including: - id: The command's unique identifier - command: The executed command string - exitCode: Command's exit status (if completed) **Example:** ```ts const cmd = await process.getSessionCommand('my-session', 'cmd-123'); if (cmd.exitCode === 0) { console.log(`Command ${cmd.command} completed successfully`); } ``` *** #### getSessionCommandLogs() ##### Call Signature ```ts getSessionCommandLogs(sessionId: string, commandId: string): Promise ``` Get the logs for a command executed in a session. **Parameters**: - `sessionId` _string_ - Unique identifier of the session - `commandId` _string_ - Unique identifier of the command **Returns**: - `Promise` - Command logs containing: output (combined stdout and stderr), stdout and stderr **Example:** ```ts const logs = await process.getSessionCommandLogs('my-session', 'cmd-123'); console.log('[STDOUT]:', logs.stdout); console.log('[STDERR]:', logs.stderr); ``` ##### Call Signature ```ts getSessionCommandLogs( sessionId: string, commandId: string, onStdout: (chunk: string) => void, onStderr: (chunk: string) => void): Promise ``` Asynchronously retrieve and process the logs for a command executed in a session as they become available. **Parameters**: - `sessionId` _string_ - Unique identifier of the session - `commandId` _string_ - Unique identifier of the command - `onStdout` _\(chunk: string\) =\> void_ - Callback function to handle stdout log chunks - `onStderr` _\(chunk: string\) =\> void_ - Callback function to handle stderr log chunks **Returns**: - `Promise` **Example:** ```ts const logs = await process.getSessionCommandLogs('my-session', 'cmd-123', (chunk) => { console.log('[STDOUT]:', chunk); }, (chunk) => { console.log('[STDERR]:', chunk); }); ``` *** #### killPtySession() ```ts killPtySession(sessionId: string): Promise ``` Kill a PTY session and terminate its associated process. Forcefully terminates the PTY session and cleans up all associated resources. This will close any active connections and kill the underlying shell process. **Parameters**: - `sessionId` _string_ - ID of the PTY session to kill **Returns**: - `Promise` **Throws**: If the PTY session doesn't exist or cannot be killed ##### Note This operation is irreversible. Any unsaved work in the terminal session will be lost. **Example:** ```ts // Kill a specific PTY session await process.killPtySession('my-session'); // Verify the session is no longer active try { const info = await process.getPtySessionInfo('my-session'); console.log(`Session still exists but active: ${info.active}`); } catch (error) { console.log('Session has been completely removed'); } ``` *** #### listPtySessions() ```ts listPtySessions(): Promise ``` List all PTY sessions in the sandbox. Retrieves information about all PTY sessions, both active and inactive, that have been created in this sandbox. **Returns**: - `Promise` - Array of PTY session information **Example:** ```ts // List all PTY sessions const sessions = await process.listPtySessions(); for (const session of sessions) { console.log(`Session ID: ${session.id}`); console.log(`Active: ${session.active}`); console.log(`Created: ${session.createdAt}`); } console.log('---'); } ``` *** #### listSessions() ```ts listSessions(): Promise ``` Lists all active sessions in the Sandbox. **Returns**: - `Promise` - Array of active sessions **Example:** ```ts const sessions = await process.listSessions(); sessions.forEach(session => { console.log(`Session ${session.sessionId}:`); session.commands.forEach(cmd => { console.log(`- ${cmd.command} (${cmd.exitCode})`); }); }); ``` *** #### resizePtySession() ```ts resizePtySession( sessionId: string, cols: number, rows: number): Promise ``` Resize a PTY session's terminal dimensions. Changes the terminal size of an active PTY session. This is useful when the client terminal is resized or when you need to adjust the display for different output requirements. **Parameters**: - `sessionId` _string_ - ID of the PTY session to resize - `cols` _number_ - New number of terminal columns - `rows` _number_ - New number of terminal rows **Returns**: - `Promise` - Updated session information reflecting the new terminal size **Throws**: If the PTY session doesn't exist or resize operation fails ##### Note The resize operation will send a SIGWINCH signal to the shell process, allowing terminal applications to adapt to the new size. **Example:** ```ts // Resize a PTY session to a larger terminal const updatedInfo = await process.resizePtySession('my-session', 150, 40); console.log(`Terminal resized to ${updatedInfo.cols}x${updatedInfo.rows}`); // You can also use the PtyHandle's resize method await ptyHandle.resize(150, 40); // cols, rows ``` *** #### sendSessionCommandInput() ```ts sendSessionCommandInput( sessionId: string, commandId: string, data: string): Promise ``` Sends input data to a command executed in a session. **Parameters**: - `sessionId` _string_ - Unique identifier of the session - `commandId` _string_ - Unique identifier of the command - `data` _string_ - Input data to send **Returns**: - `Promise` *** ## SessionCommandLogsResponse **Properties**: - `output?` _string_ - `stderr?` _string_ - `stdout?` _string_ ## SessionExecuteResponse **Extends:** **Properties**: - `cmdId` _string_ - _Inherited from_: `SessionExecuteResponse.cmdId` - `exitCode?` _number_ - _Inherited from_: `SessionExecuteResponse.exitCode` - `output?` _string_ - _Inherited from_: `SessionExecuteResponse.output` - `stderr?` _string_ - `stdout?` _string_ - `SessionExecuteResponse` ## MAX\_PREFIX\_LEN ```ts const MAX_PREFIX_LEN: number; ``` *** ## STDERR\_PREFIX\_BYTES ```ts const STDERR_PREFIX_BYTES: Uint8Array; ``` *** ## STDOUT\_PREFIX\_BYTES ```ts const STDOUT_PREFIX_BYTES: Uint8Array; ``` ## PtyHandle PTY session handle for managing a single PTY session. **Properties**: - `sessionId` _string_ Provides methods for sending input, resizing the terminal, waiting for completion, and managing the WebSocket connection to a PTY session. **Example:** ```typescript // Create a PTY session const ptyHandle = await process.createPty({ id: 'my-session', cols: 120, rows: 30, onData: (data) => { const text = new TextDecoder().decode(data); process.stdout.write(text); }, }); // Send commands await ptyHandle.sendInput('ls -la\n'); await ptyHandle.sendInput('exit\n'); // Wait for completion const result = await ptyHandle.wait(); console.log(`PTY exited with code: ${result.exitCode}`); // Clean up await ptyHandle.disconnect(); ``` ### Accessors #### error ##### Get Signature ```ts get error(): string ``` Error message if the PTY failed **Returns**: - `string` *** #### exitCode ##### Get Signature ```ts get exitCode(): number ``` Exit code of the PTY process (if terminated) **Returns**: - `number` ### Constructors #### new PtyHandle() ```ts new PtyHandle( ws: WebSocket, handleResize: (cols: number, rows: number) => Promise, handleKill: () => Promise, onPty: (data: Uint8Array) => void | Promise, sessionId: string): PtyHandle ``` **Parameters**: - `ws` _WebSocket_ - `handleResize` _\(cols: number, rows: number\) =\> Promise\_ - `handleKill` _\(\) =\> Promise\_ - `onPty` _\(data: Uint8Array\) =\> void \| Promise\_ - `sessionId` _string_ **Returns**: - `PtyHandle` ### Methods #### disconnect() ```ts disconnect(): Promise ``` Disconnect from the PTY session and clean up resources. Closes the WebSocket connection and releases any associated resources. Should be called when done with the PTY session. **Returns**: - `Promise` **Example:** ```ts // Always clean up when done try { // ... use PTY session } finally { await ptyHandle.disconnect(); } ``` *** #### isConnected() ```ts isConnected(): boolean ``` Check if connected to the PTY session **Returns**: - `boolean` *** #### kill() ```ts kill(): Promise ``` Kill the PTY process and terminate the session. Forcefully terminates the PTY session and its associated process. This operation is irreversible and will cause the PTY to exit immediately. **Returns**: - `Promise` **Throws**: If the kill operation fails **Example:** ```ts // Kill a long-running process await ptyHandle.kill(); // Wait to confirm termination const result = await ptyHandle.wait(); console.log(`Process terminated with exit code: ${result.exitCode}`); ``` *** #### resize() ```ts resize(cols: number, rows: number): Promise ``` Resize the PTY terminal dimensions. Changes the terminal size which will notify terminal applications about the new dimensions via SIGWINCH signal. **Parameters**: - `cols` _number_ - New number of terminal columns - `rows` _number_ - New number of terminal rows **Returns**: - `Promise` **Example:** ```ts // Resize to 120x30 await ptyHandle.resize(120, 30); ``` *** #### sendInput() ```ts sendInput(data: string | Uint8Array): Promise ``` Send input data to the PTY session. Sends keyboard input or commands to the terminal session. The data will be processed as if it was typed in the terminal. **Parameters**: - `data` _Input data to send \(commands, keystrokes, etc.\)_ - `string` | `Uint8Array`\<`ArrayBufferLike`\> **Returns**: - `Promise` **Throws**: If PTY is not connected or sending fails **Example:** ```ts // Send a command await ptyHandle.sendInput('ls -la\n'); // Send raw bytes await ptyHandle.sendInput(new Uint8Array([3])); // Ctrl+C ``` *** #### wait() ```ts wait(): Promise ``` Wait for the PTY process to exit and return the result. This method blocks until the PTY process terminates and returns information about how it exited. **Returns**: - `Promise` - Result containing exit code and error information **Example:** ```ts // Wait for process to complete const result = await ptyHandle.wait(); if (result.exitCode === 0) { console.log('Process completed successfully'); } else { console.log(`Process failed with code: ${result.exitCode}`); if (result.error) { console.log(`Error: ${result.error}`); } } ``` *** #### waitForConnection() ```ts waitForConnection(): Promise ``` Wait for the WebSocket connection to be established. This method ensures the PTY session is ready to receive input and send output. It waits for the server to confirm the connection is established. **Returns**: - `Promise` **Throws**: If connection times out (10 seconds) or connection fails ## PtyConnectOptions Options for connecting to a PTY session **Properties**: - `onData()` _\(data: Uint8Array\) =\> void \| Promise\_ - Callback to handle PTY output data **Parameters**: - `data` _Uint8Array_ ##### Returns `void` \| `Promise` ## PtyCreateOptions Options for creating a PTY session **Properties**: - `cols?` _number_ - Number of terminal columns - `cwd?` _string_ - Starting directory for the PTY session, defaults to the sandbox's working directory - `envs?` _Record\_ - Environment variables for the PTY session - `id` _string_ - The unique identifier for the PTY session - `rows?` _number_ - Number of terminal rows ## PtyResult PTY session result on exit **Properties**: - `error?` _string_ - Error message if the PTY failed - `exitCode?` _number_ - Exit code when the PTY process ends ## Sandbox Represents a Daytona Sandbox. **Properties**: - `autoArchiveInterval?` _number_ - Auto-archive interval in minutes ##### Implementation of ```ts SandboxDto.autoArchiveInterval ``` - `autoDeleteInterval?` _number_ - Auto-delete interval in minutes ##### Implementation of ```ts SandboxDto.autoDeleteInterval ``` - `autoStopInterval?` _number_ - Auto-stop interval in minutes ##### Implementation of ```ts SandboxDto.autoStopInterval ``` - `backupCreatedAt?` _string_ - When the backup was created ##### Implementation of ```ts SandboxDto.backupCreatedAt ``` - `backupState?` _SandboxBackupStateEnum_ - Current state of Sandbox backup ##### Implementation of ```ts SandboxDto.backupState ``` - `buildInfo?` _BuildInfo_ - Build information for the Sandbox if it was created from dynamic build ##### Implementation of ```ts SandboxDto.buildInfo ``` - `codeInterpreter` _CodeInterpreter_ - Stateful interpreter interface for executing code. Currently supports only Python. For other languages, use the `process.codeRun` method. - `computerUse` _ComputerUse_ - Computer use operations interface for desktop automation - `cpu` _number_ - Number of CPUs allocated to the Sandbox ##### Implementation of ```ts SandboxDto.cpu ``` - `createdAt?` _string_ - When the Sandbox was created ##### Implementation of ```ts SandboxDto.createdAt ``` - `disk` _number_ - Amount of disk space allocated to the Sandbox in GiB ##### Implementation of ```ts SandboxDto.disk ``` - `env` _Record\_ - Environment variables set in the Sandbox ##### Implementation of ```ts SandboxDto.env ``` - `errorReason?` _string_ - Error message if Sandbox is in error state ##### Implementation of ```ts SandboxDto.errorReason ``` - `fs` _FileSystem_ - File system operations interface - `git` _Git_ - Git operations interface - `gpu` _number_ - Number of GPUs allocated to the Sandbox ##### Implementation of ```ts SandboxDto.gpu ``` - `id` _string_ - Unique identifier for the Sandbox ##### Implementation of ```ts SandboxDto.id ``` - `labels` _Record\_ - Custom labels attached to the Sandbox ##### Implementation of ```ts SandboxDto.labels ``` - `memory` _number_ - Amount of memory allocated to the Sandbox in GiB ##### Implementation of ```ts SandboxDto.memory ``` - `name` _string_ - The name of the sandbox ##### Implementation of ```ts SandboxDto.name ``` - `networkAllowList?` _string_ - Comma-separated list of allowed CIDR network addresses for the Sandbox ##### Implementation of ```ts SandboxDto.networkAllowList ``` - `networkBlockAll` _boolean_ - Whether to block all network access for the Sandbox ##### Implementation of ```ts SandboxDto.networkBlockAll ``` - `organizationId` _string_ - Organization ID of the Sandbox ##### Implementation of ```ts SandboxDto.organizationId ``` - `process` _Process_ - Process execution interface - `public` _boolean_ - Whether the Sandbox is publicly accessible ##### Implementation of ```ts SandboxDto.public ``` - `recoverable?` _boolean_ - Whether the Sandbox error is recoverable. ##### Implementation of ```ts SandboxDto.recoverable ``` - `snapshot?` _string_ - Daytona snapshot used to create the Sandbox ##### Implementation of ```ts SandboxDto.snapshot ``` - `state?` _SandboxState_ - Current state of the Sandbox (e.g., "started", "stopped") ##### Implementation of ```ts SandboxDto.state ``` - `target` _string_ - Target location of the runner where the Sandbox runs ##### Implementation of ```ts SandboxDto.target ``` - `toolboxProxyUrl` _string_ - The toolbox proxy URL for the sandbox ##### Implementation of ```ts SandboxDto.toolboxProxyUrl ``` - `updatedAt?` _string_ - When the Sandbox was last updated ##### Implementation of ```ts SandboxDto.updatedAt ``` - `user` _string_ - OS user running in the Sandbox ##### Implementation of ```ts SandboxDto.user ``` - `volumes?` _SandboxVolume\[\]_ - Volumes attached to the Sandbox ##### Implementation of ```ts SandboxDto.volumes ``` ### Implements - `Sandbox` ### Constructors #### new Sandbox() ```ts new Sandbox( sandboxDto: Sandbox, clientConfig: Configuration, axiosInstance: AxiosInstance, sandboxApi: SandboxApi, codeToolbox: SandboxCodeToolbox): Sandbox ``` Creates a new Sandbox instance **Parameters**: - `sandboxDto` _Sandbox_ - The API Sandbox instance - `clientConfig` _Configuration_ - `axiosInstance` _AxiosInstance_ - `sandboxApi` _SandboxApi_ - API client for Sandbox operations - `codeToolbox` _SandboxCodeToolbox_ - Language-specific toolbox implementation **Returns**: - `Sandbox` ### Methods #### archive() ```ts archive(): Promise ``` Archives the sandbox, making it inactive and preserving its state. When sandboxes are archived, the entire filesystem state is moved to cost-effective object storage, making it possible to keep sandboxes available for an extended period. The tradeoff between archived and stopped states is that starting an archived sandbox takes more time, depending on its size. Sandbox must be stopped before archiving. **Returns**: - `Promise` *** #### createLspServer() ```ts createLspServer(languageId: string, pathToProject: string): Promise ``` Creates a new Language Server Protocol (LSP) server instance. The LSP server provides language-specific features like code completion, diagnostics, and more. **Parameters**: - `languageId` _string_ - The language server type (e.g., "typescript") - `pathToProject` _string_ - Path to the project root directory. Relative paths are resolved based on the sandbox working directory. **Returns**: - `Promise` - A new LSP server instance configured for the specified language **Example:** ```ts const lsp = await sandbox.createLspServer('typescript', 'workspace/project'); ``` *** #### createSshAccess() ```ts createSshAccess(expiresInMinutes?: number): Promise ``` Creates an SSH access token for the sandbox. **Parameters**: - `expiresInMinutes?` _number_ - The number of minutes the SSH access token will be valid for. **Returns**: - `Promise` - The SSH access token. *** #### delete() ```ts delete(timeout: number): Promise ``` Deletes the Sandbox. **Parameters**: - `timeout` _number = 60_ **Returns**: - `Promise` *** #### expireSignedPreviewUrl() ```ts expireSignedPreviewUrl(port: number, token: string): Promise ``` Expires a signed preview url for the sandbox at the specified port. **Parameters**: - `port` _number_ - The port to expire the signed preview url on. - `token` _string_ - The token to expire the signed preview url on. **Returns**: - `Promise` *** #### getPreviewLink() ```ts getPreviewLink(port: number): Promise ``` Retrieves the preview link for the sandbox at the specified port. If the port is closed, it will be opened automatically. For private sandboxes, a token is included to grant access to the URL. **Parameters**: - `port` _number_ - The port to open the preview link on. **Returns**: - `Promise` - The response object for the preview link, which includes the `url` and the `token` (to access private sandboxes). **Example:** ```ts const previewLink = await sandbox.getPreviewLink(3000); console.log(`Preview URL: ${previewLink.url}`); console.log(`Token: ${previewLink.token}`); ``` *** #### getSignedPreviewUrl() ```ts getSignedPreviewUrl(port: number, expiresInSeconds?: number): Promise ``` Retrieves a signed preview url for the sandbox at the specified port. **Parameters**: - `port` _number_ - The port to open the preview link on. - `expiresInSeconds?` _number_ - The number of seconds the signed preview url will be valid for. Defaults to 60 seconds. **Returns**: - `Promise` - The response object for the signed preview url. *** #### getUserHomeDir() ```ts getUserHomeDir(): Promise ``` Gets the user's home directory path for the logged in user inside the Sandbox. **Returns**: - `Promise` - The absolute path to the Sandbox user's home directory for the logged in user **Example:** ```ts const userHomeDir = await sandbox.getUserHomeDir(); console.log(`Sandbox user home: ${userHomeDir}`); ``` *** #### ~~getUserRootDir()~~ ```ts getUserRootDir(): Promise ``` **Returns**: - `Promise` ##### Deprecated Use `getUserHomeDir` instead. This method will be removed in a future version. *** #### getWorkDir() ```ts getWorkDir(): Promise ``` Gets the working directory path inside the Sandbox. **Returns**: - `Promise` - The absolute path to the Sandbox working directory. Uses the WORKDIR specified in the Dockerfile if present, or falling back to the user's home directory if not. **Example:** ```ts const workDir = await sandbox.getWorkDir(); console.log(`Sandbox working directory: ${workDir}`); ``` *** #### recover() ```ts recover(timeout?: number): Promise ``` Recover the Sandbox from a recoverable error and wait for it to be ready. **Parameters**: - `timeout?` _number = 60_ - Maximum time to wait in seconds. 0 means no timeout. Defaults to 60-second timeout. **Returns**: - `Promise` **Throws**: - `DaytonaError` - If Sandbox fails to recover or times out **Example:** ```ts const sandbox = await daytona.get('my-sandbox-id'); await sandbox.recover(); console.log('Sandbox recovered successfully'); ``` *** #### refreshActivity() ```ts refreshActivity(): Promise ``` Refreshes the sandbox activity to reset the timer for automated lifecycle management actions. This method updates the sandbox's last activity timestamp without changing its state. It is useful for keeping long-running sessions alive while there is still user activity. **Returns**: - `Promise` **Example:** ```ts // Keep sandbox activity alive await sandbox.refreshActivity(); ``` *** #### refreshData() ```ts refreshData(): Promise ``` Refreshes the Sandbox data from the API. **Returns**: - `Promise` **Example:** ```ts await sandbox.refreshData(); console.log(`Sandbox ${sandbox.id}:`); console.log(`State: ${sandbox.state}`); console.log(`Resources: ${sandbox.cpu} CPU, ${sandbox.memory} GiB RAM`); ``` *** #### resize() ```ts resize(resources: Resources, timeout?: number): Promise ``` Resizes the Sandbox resources. Changes the CPU, memory, or disk allocation for the Sandbox. Hot resize (on running sandbox) only allows CPU/memory increases. Disk resize requires a stopped sandbox. **Parameters**: - `resources` _Resources_ - New resource configuration. Only specified fields will be updated. - cpu: Number of CPU cores (minimum: 1). For hot resize, can only be increased. - memory: Memory in GiB (minimum: 1). For hot resize, can only be increased. - disk: Disk space in GiB (can only be increased, requires stopped sandbox). - `timeout?` _number = 60_ - Timeout in seconds for the resize operation. 0 means no timeout. **Returns**: - `Promise` **Throws**: - If hot resize constraints are violated, disk resize attempted on running sandbox, disk size decrease is attempted, no resource changes are specified, or resize operation times out. **Example:** ```ts // Increase CPU/memory on running sandbox (hot resize) await sandbox.resize({ cpu: 4, memory: 8 }); // Change disk (sandbox must be stopped) await sandbox.stop(); await sandbox.resize({ cpu: 2, memory: 4, disk: 30 }); ``` *** #### revokeSshAccess() ```ts revokeSshAccess(token: string): Promise ``` Revokes an SSH access token for the sandbox. **Parameters**: - `token` _string_ - The token to revoke. **Returns**: - `Promise` *** #### setAutoArchiveInterval() ```ts setAutoArchiveInterval(interval: number): Promise ``` Set the auto-archive interval for the Sandbox. The Sandbox will automatically archive after being continuously stopped for the specified interval. **Parameters**: - `interval` _number_ - Number of minutes after which a continuously stopped Sandbox will be auto-archived. Set to 0 for the maximum interval. Default is 7 days. **Returns**: - `Promise` **Throws**: - `DaytonaError` - If interval is not a non-negative integer **Example:** ```ts // Auto-archive after 1 hour await sandbox.setAutoArchiveInterval(60); // Or use the maximum interval await sandbox.setAutoArchiveInterval(0); ``` *** #### setAutoDeleteInterval() ```ts setAutoDeleteInterval(interval: number): Promise ``` Set the auto-delete interval for the Sandbox. The Sandbox will automatically delete after being continuously stopped for the specified interval. **Parameters**: - `interval` _number_ - Number of minutes after which a continuously stopped Sandbox will be auto-deleted. Set to negative value to disable auto-delete. Set to 0 to delete immediately upon stopping. By default, auto-delete is disabled. **Returns**: - `Promise` **Example:** ```ts // Auto-delete after 1 hour await sandbox.setAutoDeleteInterval(60); // Or delete immediately upon stopping await sandbox.setAutoDeleteInterval(0); // Or disable auto-delete await sandbox.setAutoDeleteInterval(-1); ``` *** #### setAutostopInterval() ```ts setAutostopInterval(interval: number): Promise ``` Set the auto-stop interval for the Sandbox. The Sandbox will automatically stop after being idle (no new events) for the specified interval. Events include any state changes or interactions with the Sandbox through the sdk. Interactions using Sandbox Previews are not included. **Parameters**: - `interval` _number_ - Number of minutes of inactivity before auto-stopping. Set to 0 to disable auto-stop. Default is 15 minutes. **Returns**: - `Promise` **Throws**: - `DaytonaError` - If interval is not a non-negative integer **Example:** ```ts // Auto-stop after 1 hour await sandbox.setAutostopInterval(60); // Or disable auto-stop await sandbox.setAutostopInterval(0); ``` *** #### setLabels() ```ts setLabels(labels: Record): Promise> ``` Sets labels for the Sandbox. Labels are key-value pairs that can be used to organize and identify Sandboxes. **Parameters**: - `labels` _Record\_ - Dictionary of key-value pairs representing Sandbox labels **Returns**: - `Promise>` **Example:** ```ts // Set sandbox labels await sandbox.setLabels({ project: 'my-project', environment: 'development', team: 'backend' }); ``` *** #### start() ```ts start(timeout?: number): Promise ``` Start the Sandbox. This method starts the Sandbox and waits for it to be ready. **Parameters**: - `timeout?` _number = 60_ - Maximum time to wait in seconds. 0 means no timeout. Defaults to 60-second timeout. **Returns**: - `Promise` **Throws**: - `DaytonaError` - If Sandbox fails to start or times out **Example:** ```ts const sandbox = await daytona.getCurrentSandbox('my-sandbox'); await sandbox.start(40); // Wait up to 40 seconds console.log('Sandbox started successfully'); ``` *** #### stop() ```ts stop(timeout?: number): Promise ``` Stops the Sandbox. This method stops the Sandbox and waits for it to be fully stopped. **Parameters**: - `timeout?` _number = 60_ - Maximum time to wait in seconds. 0 means no timeout. Defaults to 60-second timeout. **Returns**: - `Promise` **Example:** ```ts const sandbox = await daytona.get('my-sandbox-id'); await sandbox.stop(); console.log('Sandbox stopped successfully'); ``` *** #### validateSshAccess() ```ts validateSshAccess(token: string): Promise ``` Validates an SSH access token for the sandbox. **Parameters**: - `token` _string_ - The token to validate. **Returns**: - `Promise` - The SSH access validation result. *** #### waitForResizeComplete() ```ts waitForResizeComplete(timeout?: number): Promise ``` Waits for the Sandbox resize operation to complete. This method polls the Sandbox status until the state is no longer 'resizing'. **Parameters**: - `timeout?` _number = 60_ - Maximum time to wait in seconds. 0 means no timeout. **Returns**: - `Promise` **Throws**: - If the sandbox ends up in an error state or resize times out. *** #### waitUntilStarted() ```ts waitUntilStarted(timeout?: number): Promise ``` Waits for the Sandbox to reach the 'started' state. This method polls the Sandbox status until it reaches the 'started' state or encounters an error. **Parameters**: - `timeout?` _number = 60_ - Maximum time to wait in seconds. 0 means no timeout. Defaults to 60 seconds. **Returns**: - `Promise` **Throws**: - `DaytonaError` - If the sandbox ends up in an error state or fails to start within the timeout period. *** #### waitUntilStopped() ```ts waitUntilStopped(timeout?: number): Promise ``` Wait for Sandbox to reach 'stopped' state. This method polls the Sandbox status until it reaches the 'stopped' state or encounters an error. **Parameters**: - `timeout?` _number = 60_ - Maximum time to wait in seconds. 0 means no timeout. Defaults to 60 seconds. **Returns**: - `Promise` **Throws**: - `DaytonaError` - If the sandbox fails to stop within the timeout period. ## PaginatedSandboxes **Extends:** **Properties**: - `items` _Sandbox\[\]_ - `page` _number_ - _Inherited from_: `PaginatedSandboxes.page` - `total` _number_ - _Inherited from_: `PaginatedSandboxes.total` - `totalPages` _number_ - _Inherited from_: `PaginatedSandboxes.totalPages` - `Omit`\<`PaginatedSandboxesDto`, `"items"`\> ## SandboxCodeToolbox Interface defining methods that a code toolbox must implement ### Methods #### getRunCommand() ```ts getRunCommand(code: string, params?: CodeRunParams): string ``` Generates a command to run the provided code **Parameters**: - `code` _string_ - `params?` _CodeRunParams_ **Returns**: - `string` ## SnapshotService Service for managing Daytona Snapshots. Can be used to list, get, create and delete Snapshots. ### Constructors #### new SnapshotService() ```ts new SnapshotService( clientConfig: Configuration, snapshotsApi: SnapshotsApi, objectStorageApi: ObjectStorageApi, defaultRegionId?: string): SnapshotService ``` **Parameters**: - `clientConfig` _Configuration_ - `snapshotsApi` _SnapshotsApi_ - `objectStorageApi` _ObjectStorageApi_ - `defaultRegionId?` _string_ **Returns**: - `SnapshotService` ### Methods #### activate() ```ts activate(snapshot: Snapshot): Promise ``` Activates a snapshot. **Parameters**: - `snapshot` _Snapshot_ - Snapshot to activate **Returns**: - `Promise` - The activated Snapshot instance *** #### create() ```ts create(params: CreateSnapshotParams, options: { onLogs: (chunk: string) => void; timeout: number; }): Promise ``` Creates and registers a new snapshot from the given Image definition. **Parameters**: - `params` _CreateSnapshotParams_ - Parameters for snapshot creation. - `options` _Options for the create operation._ - `onLogs?` _\(chunk: string\) =\> void_ - This callback function handles snapshot creation logs. - `timeout?` _number_ - Default is no timeout. Timeout in seconds (0 means no timeout). **Returns**: - `Promise` **Example:** ```ts const image = Image.debianSlim('3.12').pipInstall('numpy'); await daytona.snapshot.create({ name: 'my-snapshot', image: image }, { onLogs: console.log }); ``` *** #### delete() ```ts delete(snapshot: Snapshot): Promise ``` Deletes a Snapshot. **Parameters**: - `snapshot` _Snapshot_ - Snapshot to delete **Returns**: - `Promise` **Throws**: If the Snapshot does not exist or cannot be deleted **Example:** ```ts const daytona = new Daytona(); const snapshot = await daytona.snapshot.get("snapshot-name"); await daytona.snapshot.delete(snapshot); console.log("Snapshot deleted successfully"); ``` *** #### get() ```ts get(name: string): Promise ``` Gets a Snapshot by its name. **Parameters**: - `name` _string_ - Name of the Snapshot to retrieve **Returns**: - `Promise` - The requested Snapshot **Throws**: If the Snapshot does not exist or cannot be accessed **Example:** ```ts const daytona = new Daytona(); const snapshot = await daytona.snapshot.get("snapshot-name"); console.log(`Snapshot ${snapshot.name} is in state ${snapshot.state}`); ``` *** #### list() ```ts list(page?: number, limit?: number): Promise ``` List paginated list of Snapshots. **Parameters**: - `page?` _number_ - Page number for pagination (starting from 1) - `limit?` _number_ - Maximum number of items per page **Returns**: - `Promise` - Paginated list of Snapshots **Example:** ```ts const daytona = new Daytona(); const result = await daytona.snapshot.list(2, 10); console.log(`Found ${result.total} snapshots`); result.items.forEach(snapshot => console.log(`${snapshot.name} (${snapshot.imageName})`)); ``` *** ## PaginatedSnapshots Represents a paginated list of Daytona Snapshots. **Properties**: - `items` _Snapshot\[\]_ - List of Snapshot instances in the current page. - `page` _number_ - Current page number. - _Inherited from_: `Omit.page` - `total` _number_ - Total number of Snapshots across all pages. - _Inherited from_: `Omit.total` - `totalPages` _number_ - Total number of pages available. - _Inherited from_: `Omit.totalPages` **Extends:** - `Omit`\<`PaginatedSnapshotsDto`, `"items"`\> ## CreateSnapshotParams ```ts type CreateSnapshotParams = { entrypoint: string[]; image: string | Image; name: string; regionId: string; resources: Resources; }; ``` Parameters for creating a new snapshot. **Type declaration**: - `entrypoint?` _string\[\]_ - `image` _string \| Image_ - `name` _string_ - `regionId?` _string_ - `resources?` _Resources_ ## Snapshot ```ts type Snapshot = SnapshotDto & { __brand: "Snapshot"; }; ``` Represents a Daytona Snapshot which is a pre-configured sandbox. **Type declaration**: - `\_\_brand` _"Snapshot"_ ## VolumeService Service for managing Daytona Volumes. This service provides methods to list, get, create, and delete Volumes. Volumes can be mounted to Sandboxes with an optional subpath parameter to mount only a specific S3 prefix within the volume. When no subpath is specified, the entire volume is mounted. ### Constructors #### new VolumeService() ```ts new VolumeService(volumesApi: VolumesApi): VolumeService ``` **Parameters**: - `volumesApi` _VolumesApi_ **Returns**: - `VolumeService` ### Methods #### create() ```ts create(name: string): Promise ``` Creates a new Volume with the specified name. **Parameters**: - `name` _string_ - Name for the new Volume **Returns**: - `Promise` - The newly created Volume **Throws**: If the Volume cannot be created **Example:** ```ts const daytona = new Daytona(); const volume = await daytona.volume.create("my-data-volume"); console.log(`Created volume ${volume.name} with ID ${volume.id}`); ``` *** #### delete() ```ts delete(volume: Volume): Promise ``` Deletes a Volume. **Parameters**: - `volume` _Volume_ - Volume to delete **Returns**: - `Promise` **Throws**: If the Volume does not exist or cannot be deleted **Example:** ```ts const daytona = new Daytona(); const volume = await daytona.volume.get("volume-name"); await daytona.volume.delete(volume); console.log("Volume deleted successfully"); ``` *** #### get() ```ts get(name: string, create: boolean): Promise ``` Gets a Volume by its name. **Parameters**: - `name` _string_ - Name of the Volume to retrieve - `create` _boolean = false_ - Whether to create the Volume if it does not exist **Returns**: - `Promise` - The requested Volume **Throws**: If the Volume does not exist or cannot be accessed **Example:** ```ts const daytona = new Daytona(); const volume = await daytona.volume.get("volume-name", true); console.log(`Volume ${volume.name} is in state ${volume.state}`); ``` *** #### list() ```ts list(): Promise ``` Lists all available Volumes. **Returns**: - `Promise` - List of all Volumes accessible to the user **Example:** ```ts const daytona = new Daytona(); const volumes = await daytona.volume.list(); console.log(`Found ${volumes.length} volumes`); volumes.forEach(vol => console.log(`${vol.name} (${vol.id})`)); ``` *** ## Volume ```ts type Volume = VolumeDto & { __brand: "Volume"; }; ``` Represents a Daytona Volume which is a shared storage volume for Sandboxes. **Type declaration**: - `\_\_brand` _"Volume"_ VNC (Virtual Network Computing) access provides a graphical desktop environment for your Daytona Sandbox directly in the browser. This allows you to interact with GUI applications, desktop tools, and visual interfaces running inside your sandbox. VNC and [Computer Use](https://www.daytona.io/docs/en/computer-use.md) work together to enable both manual and automated desktop interactions. VNC provides the visual interface for users to manually interact with the desktop, while Computer Use provides the programmatic API for AI agents to automate mouse, keyboard, and screenshot operations. Through VNC, you can observe AI agents performing automated tasks via Computer Use in real-time. - **GUI application development**: build and test desktop applications with visual interfaces - **Browser testing**: run and debug web applications in a full browser environment - **Visual debugging**: inspect graphical output and UI behavior in real-time - **Desktop tool access**: use graphical IDEs, design tools, or other desktop software - **Agent observation**: watch AI agents perform automated tasks through Computer Use :::note[Sandbox image requirement] VNC and Computer Use require a sandbox with the default image. Sandboxes created with custom images do not include VNC support unless you install the [required packages](#required-packages). ::: ## Access VNC from Dashboard Access the VNC desktop environment directly from the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/sandboxes). 1. Navigate to [Daytona Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Locate the sandbox you want to access via VNC 3. Click the options menu (**⋮**) next to the sandbox 4. Select **VNC** from the dropdown menu This opens a VNC viewer in your browser with a **Connect** button. 5. Click **Connect** to establish the VNC session Once connected, a full desktop environment loads in your browser, providing mouse and keyboard control over the sandbox's graphical interface. :::note VNC sessions remain active as long as the sandbox is running. If the sandbox auto-stops due to inactivity, you need to start the sandbox again before reconnecting via VNC. ::: ## Programmatic VNC management Daytona provides methods to [start](#start-vnc), [stop](#stop-vnc), and [monitor](#get-vnc-status) VNC sessions and processes programmatically using the [Computer Use](https://www.daytona.io/docs/en/computer-use.md) references as part of automated workflows. ### Start VNC Start all VNC processes (Xvfb, xfce4, x11vnc, novnc) in the sandbox to enable desktop access. ```python result = sandbox.computer_use.start() print("VNC processes started:", result.message) ``` ```typescript const result = await sandbox.computerUse.start(); console.log('VNC processes started:', result.message); ``` ```ruby result = sandbox.computer_use.start puts "VNC processes started: #{result.message}" ``` ```go err := sandbox.ComputerUse.Start(ctx) if err != nil { log.Fatal(err) } defer sandbox.ComputerUse.Stop(ctx) fmt.Println("VNC processes started") ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/start' \ --request POST ``` For more information, see the [Computer Use](https://www.daytona.io/docs/en/computer-use.md#start-computer-use) reference. > [**start (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computerusestart) > > [**start (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#start) > > [**start (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#start) > > [**Start (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ComputerUseService.Start) > > [**Start Computer Use Processes (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/start) ### Stop VNC Stop all VNC processes in the sandbox. ```python result = sandbox.computer_use.stop() print("VNC processes stopped:", result.message) ``` ```typescript const result = await sandbox.computerUse.stop(); console.log('VNC processes stopped:', result.message); ``` ```ruby result = sandbox.computer_use.stop puts "VNC processes stopped: #{result.message}" ``` ```go err := sandbox.ComputerUse.Stop(ctx) if err != nil { log.Fatal(err) } fmt.Println("VNC processes stopped") ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/stop' \ --request POST ``` For more information, see the [Computer Use](https://www.daytona.io/docs/en/computer-use.md#stop-computer-use) reference. > [**stop (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computerusestop) > > [**stop (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#stop) > > [**stop (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#stop) > > [**Stop (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ComputerUseService.Stop) > > [**Stop Computer Use Processes (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/POST/computeruse/stop) ### Get VNC status Check the status of VNC processes to verify they are running. ```python response = sandbox.computer_use.get_status() print("VNC status:", response.status) ``` ```typescript const status = await sandbox.computerUse.getStatus(); console.log('VNC status:', status.status); ``` ```ruby response = sandbox.computer_use.status puts "VNC status: #{response.status}" ``` ```go status, err := sandbox.ComputerUse.GetStatus(ctx) if err != nil { log.Fatal(err) } fmt.Printf("VNC status: %v\n", status["status"]) ``` ```bash curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/status' ``` For more information, see the [Computer Use](https://www.daytona.io/docs/en/computer-use.md#get-status) reference. > [**get_status (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/computer-use.md#computeruseget_status) > > [**getStatus (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/computer-use.md#getstatus) > > [**status (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/computer-use.md#status) > > [**GetStatus (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#ComputerUseService.GetStatus) > > [**Get Computer Use Status (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona-toolbox/tag/computer-use/GET/computeruse/status) For additional process management operations including restarting individual processes and viewing logs, see the [Computer Use](https://www.daytona.io/docs/en/computer-use.md) reference. ## Automating desktop interactions Once VNC is running, you can automate desktop interactions using Computer Use. This enables AI agents to programmatically control the mouse, keyboard, and capture screenshots within the VNC session. **Available operations:** - **Mouse**: click, move, drag, scroll, and get cursor position - **Keyboard**: type text, press keys, and execute hotkey combinations - **Screenshot**: capture full screen, regions, or compressed images - **Display**: get display information and list open windows For complete documentation on automating desktop interactions, see [Computer Use](https://www.daytona.io/docs/en/computer-use.md). > **Example**: Automated browser interaction ```python # Start VNC processes sandbox.computer_use.start() # Click to open browser sandbox.computer_use.mouse.click(50, 50) # Type a URL sandbox.computer_use.keyboard.type("https://www.daytona.io/docs/") sandbox.computer_use.keyboard.press("Return") # Take a screenshot screenshot = sandbox.computer_use.screenshot.take_full_screen() ``` ```typescript // Start VNC processes await sandbox.computerUse.start(); // Click to open browser await sandbox.computerUse.mouse.click(50, 50); // Type a URL await sandbox.computerUse.keyboard.type('https://www.daytona.io/docs/'); await sandbox.computerUse.keyboard.press('Return'); // Take a screenshot const screenshot = await sandbox.computerUse.screenshot.takeFullScreen(); ``` ## Required packages The default sandbox image includes all packages required for VNC and Computer Use. If you are using a custom image, you need to install the following packages. ### VNC and desktop environment | Package | Description | | -------------------- | ------------------------------------------ | | **`xvfb`** | X Virtual Framebuffer for headless display | | **`xfce4`** | Desktop environment | | **`xfce4-terminal`** | Terminal emulator | | **`x11vnc`** | VNC server | | **`novnc`** | Web-based VNC client | | **`dbus-x11`** | D-Bus session support | ### X11 libraries | Library | Description | | ----------------- | ------------------------------------------- | | **`libx11-6`** | X11 client library | | **`libxrandr2`** | X11 RandR extension (display configuration) | | **`libxext6`** | X11 extensions library | | **`libxrender1`** | X11 rendering extension | | **`libxfixes3`** | X11 fixes extension | | **`libxss1`** | X11 screen saver extension | | **`libxtst6`** | X11 testing extension (input simulation) | | **`libxi6`** | X11 input extension | Volumes are FUSE-based mounts that provide shared file access across Daytona Sandboxes. They enable sandboxes to read from large files instantly - no need to upload files manually to each sandbox. Volume data is stored in an S3-compatible object store. - multiple volumes can be mounted to a single sandbox - a single volume can be mounted to multiple sandboxes ## Create volumes Daytona provides volumes as a shared storage solution for sandboxes. To create a volume: 1. Navigate to [Daytona Volumes ↗](https://app.daytona.io/dashboard/volumes) 2. Click the **Create Volume** button 3. Enter the volume name The following snippets demonstrate how to create a volume using the Daytona SDK: ```python daytona = Daytona() volume = daytona.volume.create("my-awesome-volume") ``` ```typescript const daytona = new Daytona(); const volume = await daytona.volume.create("my-awesome-volume"); ``` ```ruby daytona = Daytona::Daytona.new volume = daytona.volume.create("my-awesome-volume") ``` ```go client, err := daytona.NewClient() if err != nil { log.Fatal(err) } volume, err := client.Volume.Create(context.Background(), "my-awesome-volume") if err != nil { log.Fatal(err) } ``` ```shell daytona volume create my-awesome-volume ``` ```bash curl 'https://app.daytona.io/api/volumes' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "name": "my-awesome-volume" }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**volume.create (Python SDK)**](https://www.daytona.io/docs/python-sdk/sync/volume.md#volumeservicecreate) > > [**volume.create (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/volume.md#create) > > [**volume.create (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/volume-service.md#create) > > [**Volume.Create (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#VolumeService.Create) > > [**create volume (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/volumes/POST/volumes) ## Mount volumes Daytona provides an option to mount a volume to a sandbox. Once a volume is created, it can be mounted to a sandbox by specifying it in the `CreateSandboxFromSnapshotParams` object. Volume mount paths must meet the following requirements: - **Must be absolute paths**: Mount paths must start with `/` (e.g., `/home/daytona/volume`) - **Cannot be root directory**: Cannot mount to `/` or `//` - **No relative path components**: Cannot contain `/../`, `/./`, or end with `/..` or `/.` - **No consecutive slashes**: Cannot contain multiple consecutive slashes like `//` (except at the beginning) - **Cannot mount to system directories**: The following system directories are prohibited: `/proc`, `/sys`, `/dev`, `/boot`, `/etc`, `/bin`, `/sbin`, `/lib`, `/lib64` The following snippets demonstrate how to mount a volume to a sandbox: ```python import os from daytona import CreateSandboxFromSnapshotParams, Daytona, VolumeMount daytona = Daytona() # Create a new volume or get an existing one volume = daytona.volume.get("my-volume", create=True) # Mount the volume to the sandbox mount_dir_1 = "/home/daytona/volume" params = CreateSandboxFromSnapshotParams( language="python", volumes=[VolumeMount(volume_id=volume.id, mount_path=mount_dir_1)], ) sandbox = daytona.create(params) # Mount a specific subpath within the volume # This is useful for isolating data or implementing multi-tenancy params = CreateSandboxFromSnapshotParams( language="python", volumes=[VolumeMount(volume_id=volume.id, mount_path=mount_dir_1, subpath="users/alice")], ) sandbox2 = daytona.create(params) ``` ```typescript import { Daytona } from '@daytonaio/sdk' import path from 'path' const daytona = new Daytona() // Create a new volume or get an existing one const volume = await daytona.volume.get('my-volume', true) // Mount the volume to the sandbox const mountDir1 = '/home/daytona/volume' const sandbox1 = await daytona.create({ language: 'typescript', volumes: [{ volumeId: volume.id, mountPath: mountDir1 }], }) // Mount a specific subpath within the volume // This is useful for isolating data or implementing multi-tenancy const sandbox2 = await daytona.create({ language: 'typescript', volumes: [ { volumeId: volume.id, mountPath: mountDir1, subpath: 'users/alice' }, ], }) ``` ```ruby require 'daytona' daytona = Daytona::Daytona.new # Create a new volume or get an existing one volume = daytona.volume.get('my-volume', create: true) # Mount the volume to the sandbox mount_dir = '/home/daytona/volume' params = Daytona::CreateSandboxFromSnapshotParams.new( language: Daytona::CodeLanguage::PYTHON, volumes: [DaytonaApiClient::SandboxVolume.new(volume_id: volume.id, mount_path: mount_dir)] ) sandbox = daytona.create(params) # Mount a specific subpath within the volume # This is useful for isolating data or implementing multi-tenancy params2 = Daytona::CreateSandboxFromSnapshotParams.new( language: Daytona::CodeLanguage::PYTHON, volumes: [DaytonaApiClient::SandboxVolume.new( volume_id: volume.id, mount_path: mount_dir, subpath: 'users/alice' )] ) sandbox2 = daytona.create(params2) ``` ```go import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" "github.com/daytonaio/daytona/libs/sdk-go/pkg/types" ) client, err := daytona.NewClient() if err != nil { log.Fatal(err) } // Create a new volume or get an existing one volume, err := client.Volume.Get(context.Background(), "my-volume") if err != nil { // If volume doesn't exist, create it volume, err = client.Volume.Create(context.Background(), "my-volume") if err != nil { log.Fatal(err) } } // Mount the volume to the sandbox mountDir := "/home/daytona/volume" sandbox1, err := client.Create(context.Background(), types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ Language: types.CodeLanguagePython, Volumes: []types.VolumeMount{ {VolumeID: volume.ID, MountPath: mountDir}, }, }, }) if err != nil { log.Fatal(err) } // Mount a specific subpath within the volume // This is useful for isolating data or implementing multi-tenancy subpath := "users/alice" sandbox2, err := client.Create(context.Background(), types.SnapshotParams{ SandboxBaseParams: types.SandboxBaseParams{ Language: types.CodeLanguagePython, Volumes: []types.VolumeMount{ {VolumeID: volume.ID, MountPath: mountDir, Subpath: &subpath}, }, }, }) if err != nil { log.Fatal(err) } ``` ```shell daytona volume create my-volume daytona create --volume my-volume:/home/daytona/volume ``` ```bash curl 'https://app.daytona.io/api/sandbox' \ --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "volumes": [ { "volumeId": "", "mountPath": "/home/daytona/volume" } ] }' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**CreateSandboxFromSnapshotParams (Python SDK)**](https://www.daytona.io/docs/python-sdk/sync/daytona.md#createsandboxfromsnapshotparams) > > [**CreateSandboxFromSnapshotParams (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/daytona.md#createsandboxfromsnapshotparams) > > [**create (Ruby SDK)**](https://www.daytona.io/docs/en/ruby-sdk/daytona.md#create) > > [**Create (Go SDK)**](https://www.daytona.io/docs/en/go-sdk/daytona.md#Client.Create) > > [**create sandbox (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/sandbox/POST/sandbox) ## Work with volumes Daytona provides an option to read from and write to the volume just like any other directory in the sandbox file system. Files written to the volume persist beyond the lifecycle of any individual sandbox. The following snippet demonstrate how to read from and write to a volume: ```python # Write to a file in the mounted volume using the Sandbox file system API sandbox.fs.upload_file(b"Hello from Daytona volume!", "/home/daytona/volume/example.txt") # When you're done with the sandbox, you can remove it # The volume will persist even after the sandbox is removed sandbox.delete() ``` ```typescript // Write to a file in the mounted volume using the Sandbox file system API await sandbox1.fs.uploadFile(Buffer.from('Hello from Daytona volume!'), '/home/daytona/volume/example.txt') // When you're done with the sandbox, you can remove it // The volume will persist even after the sandbox is removed await daytona.delete(sandbox1) ``` ```ruby # Write to a file in the mounted volume using the Sandbox file system API sandbox.fs.upload_file('Hello from Daytona volume!', '/home/daytona/volume/example.txt') # When you're done with the sandbox, you can remove it # The volume will persist even after the sandbox is removed daytona.delete(sandbox) ``` ```go import ( "context" "log" ) // Write to a file in the mounted volume err := sandbox1.FileSystem.UploadFile(context.Background(), []byte("Hello from Daytona volume!"), "/home/daytona/volume/example.txt") if err != nil { log.Fatal(err) } // When you're done with the sandbox, you can remove it // The volume will persist even after the sandbox is removed err = sandbox1.Delete(context.Background()) if err != nil { log.Fatal(err) } ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), and [Go SDK](https://www.daytona.io/docs/en/go-sdk.md) references. ## Get a volume by name Daytona provides an option to get a volume by its name. ```python daytona = Daytona() volume = daytona.volume.get("my-awesome-volume", create=True) print(f"{volume.name} ({volume.id})") ``` ```typescript const daytona = new Daytona() const volume = await daytona.volume.get('my-awesome-volume', true) console.log(`Volume ${volume.name} is in state ${volume.state}`) ``` ```ruby daytona = Daytona::Daytona.new volume = daytona.volume.get('my-awesome-volume', create: true) puts "#{volume.name} (#{volume.id})" ``` ```go import ( "context" "fmt" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) client, err := daytona.NewClient() if err != nil { log.Fatal(err) } volume, err := client.Volume.Get(context.Background(), "my-awesome-volume") if err != nil { log.Fatal(err) } fmt.Printf("Volume %s is in state %s\n", volume.Name, volume.State) ``` ```shell daytona volume get my-awesome-volume ``` ```bash curl 'https://app.daytona.io/api/volumes/by-name/my-awesome-volume' \ --header 'Authorization: Bearer ' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**volume.get (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/volume.md#volumeserviceget) > > [**volume.get (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/volume.md#get) > > [**volume.get (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/volume-service.md#get) > > [**Volume.Get (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#VolumeService.Get) > > [**get volume by name (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/volumes/GET/volumes/by-name/{name}) ## List volumes Daytona provides an option to list all volumes. ```python daytona = Daytona() volumes = daytona.volume.list() for volume in volumes: print(f"{volume.name} ({volume.id})") ``` ```typescript const daytona = new Daytona() const volumes = await daytona.volume.list() console.log(`Found ${volumes.length} volumes`) volumes.forEach(vol => console.log(`${vol.name} (${vol.id})`)) ``` ```ruby daytona = Daytona::Daytona.new volumes = daytona.volume.list volumes.each do |volume| puts "#{volume.name} (#{volume.id})" end ``` ```go import ( "context" "fmt" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) client, err := daytona.NewClient() if err != nil { log.Fatal(err) } volumes, err := client.Volume.List(context.Background()) if err != nil { log.Fatal(err) } fmt.Printf("Found %d volumes\n", len(volumes)) for _, vol := range volumes { fmt.Printf("%s (%s)\n", vol.Name, vol.ID) } ``` ```shell daytona volume list ``` ```bash curl 'https://app.daytona.io/api/volumes' \ --header 'Authorization: Bearer ' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**volume.list (Python SDK)**](https://www.daytona.io/docs/en/python-sdk/sync/volume.md#volumeservicelist) > > [**volume.list (TypeScript SDK)**](https://www.daytona.io/docs/en/typescript-sdk/volume.md#list) > > [**volume.list (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/volume-service.md#list) > > [**Volume.List (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#VolumeService.List) > > [**list volumes (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/volumes/GET/volumes) ## Delete volumes Daytona provides an option to delete a volume. Deleted volumes cannot be recovered. The following snippet demonstrate how to delete a volume: ```python volume = daytona.volume.get("my-volume", create=True) daytona.volume.delete(volume) ``` ```typescript const volume = await daytona.volume.get('my-volume', true) await daytona.volume.delete(volume) ``` ```ruby volume = daytona.volume.get('my-volume', create: true) daytona.volume.delete(volume) ``` ```go import ( "context" "log" "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona" ) client, err := daytona.NewClient() if err != nil { log.Fatal(err) } volume, err := client.Volume.Get(context.Background(), "my-volume") if err != nil { log.Fatal(err) } err = client.Volume.Delete(context.Background(), volume) if err != nil { log.Fatal(err) } ``` ```shell daytona volume delete ``` ```bash curl 'https://app.daytona.io/api/volumes/' \ --request DELETE \ --header 'Authorization: Bearer ' ``` For more information, see the [Python SDK](https://www.daytona.io/docs/en/python-sdk.md), [TypeScript SDK](https://www.daytona.io/docs/en/typescript-sdk.md), [Ruby SDK](https://www.daytona.io/docs/en/ruby-sdk.md), [Go SDK](https://www.daytona.io/docs/en/go-sdk.md), and [API](https://www.daytona.io/docs/en/tools/api.md#daytona) references: > [**volume.delete (Python SDK)**](https://www.daytona.io/docs/python-sdk/sync/volume.md#volumeservicedelete) > > [**volume.delete (TypeScript SDK)**](https://www.daytona.io/docs/typescript-sdk/volume.md#delete) > > [**volume.delete (Ruby SDK)**](https://www.daytona.io/docs/ruby-sdk/volume-service.md#delete) > > [**Volume.Delete (Go SDK)**](https://www.daytona.io/docs/go-sdk/daytona.md#VolumeService.Delete) > > [**delete volume (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/volumes/DELETE/volumes/{volumeId}) ## Limitations Since volumes are FUSE-based mounts, they can not be used for applications that require block storage access (like database tables). Volumes are generally slower for both read and write operations compared to the local sandbox file system. ## Pricing & Limits Daytona Volumes are included at no additional cost. Each organization can create up to 100 volumes, and volume data does not count against your storage quota. You can view your current volume usage in the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/volumes). VPN connections are a way to connect your Daytona Sandboxes to private networks. By establishing a VPN connection, your sandbox can access network resources using private IP addresses and can be accessed by other devices on the same VPN network. This integration enables communication between your development environment and existing infrastructure, allowing you to test applications against services within the private network, access shared development resources, and collaborate with team members. Daytona supports the following VPN network providers: - [Tailscale](#tailscale) - [OpenVPN](#openvpn) :::note For connecting to a VPN network, you need to [create or access your Daytona Sandbox](https://www.daytona.io/docs/en/sandboxes.md), **have access to your VPN network provider credentials**, and be on [**Tier 3** or higher](https://www.daytona.io/docs/en/limits.md#resources). ::: ## Tailscale Daytona provides multiple ways to connect to a Daytona Sandbox with a Tailscale network: - [Connect with browser login](#connect-with-browser-login) - [Connect with auth key](#connect-with-auth-key) - [Connect with web terminal](#connect-with-web-terminal) When you connect a Daytona Sandbox to a Tailscale network, the sandbox becomes part of your private Tailscale network, allowing you to access resources that are available within the network and enabling other devices on the network to access the sandbox. This integration makes your sandbox appear as a device within your Tailscale network, with its own Tailscale IP address and access to other devices and services on the network. ### Connect with browser login The browser login method initiates an interactive authentication flow where Tailscale generates a unique login URL that you visit in your web browser to authenticate the Dayona Sandbox. The process involves installing Tailscale, starting the daemon, initiating the login process, and then polling for the authentication status until the connection is established. The following snippet demonstrates connecting to a Tailscale network using a browser login. ```python from daytona import Daytona, DaytonaConfig import time import re # Configuration DAYTONA_API_KEY = "YOUR_API_KEY" # Replace with your API key # Initialize the Daytona client config = DaytonaConfig(api_key=DAYTONA_API_KEY) daytona = Daytona(config) def setup_tailscale_vpn_interactive(): """ Connect a Daytona sandbox to a Tailscale network using the Python SDK. Uses interactive login via browser URL (no auth key required). """ # Create the sandbox print("Creating sandbox...") sandbox = daytona.create() print(f"Sandbox created: {sandbox.id}") # Step 1: Install Tailscale print("\nInstalling Tailscale (this may take a few minutes)...") response = sandbox.process.exec( "curl -fsSL https://tailscale.com/install.sh | sh", timeout=300 ) if response.exit_code != 0: print(f"Error installing Tailscale: {response.result}") return sandbox print("Tailscale installed successfully.") # Step 2: Start tailscaled daemon in background print("\nStarting tailscaled daemon...") sandbox.process.exec("nohup sudo tailscaled > /dev/null 2>&1 &", timeout=10) # Wait for daemon to initialize time.sleep(3) # Step 3: Run tailscale up in background and capture output to a file print("\nInitiating Tailscale login...") sandbox.process.exec( "sudo tailscale up > /tmp/tailscale-login.txt 2>&1 &", timeout=10 ) # Wait for the login URL to be written to the file time.sleep(3) # Read the login URL from the output file response = sandbox.process.exec("cat /tmp/tailscale-login.txt", timeout=10) output = response.result url_match = re.search(r'https://login\.tailscale\.com/a/[^\s]+', output) if url_match: login_url = url_match.group(0) print(f"\n{'='*60}") print("To authenticate, visit this URL in your browser:") print(f"\n {login_url}") print(f"\n{'='*60}") print("\nWaiting for authentication...") # Poll for connection status max_wait = 300 poll_interval = 5 waited = 0 while waited < max_wait: time.sleep(poll_interval) waited += poll_interval status_response = sandbox.process.exec("tailscale status 2>&1", timeout=30) status_output = status_response.result # Check if connected if status_response.exit_code == 0 and "logged out" not in status_output.lower(): # Verify IP is assigned ip_response = sandbox.process.exec("tailscale ip -4 2>&1", timeout=10) if ip_response.exit_code == 0 and ip_response.result.strip(): print(f"\nConnected to Tailscale network!") print(f"Tailscale IP: {ip_response.result.strip()}") break print(f" Still waiting... ({waited}s)") else: print("\nTimeout waiting for authentication. Please try again.") return sandbox else: # Already connected or different output print(f"Output from tailscale up:\n{output}") # Check if already connected status_response = sandbox.process.exec("tailscale status", timeout=30) if status_response.exit_code == 0: print("\nTailscale status:") print(status_response.result) # Final status check print("\nFinal Tailscale status:") response = sandbox.process.exec("tailscale status", timeout=30) print(response.result) return sandbox if __name__ == "__main__": sandbox = setup_tailscale_vpn_interactive() ``` ```typescript import { Daytona } from '@daytonaio/sdk' // Configuration const DAYTONA_API_KEY = 'YOUR_API_KEY' // Replace with your API key // Initialize the Daytona client const daytona = new Daytona({ apiKey: DAYTONA_API_KEY, }) function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)) } async function setupTailscaleVpnInteractive(): Promise { /** * Connect a Daytona sandbox to a Tailscale network using the TypeScript SDK. * Uses interactive login via browser URL (no auth key required). */ // Create the sandbox console.log('Creating sandbox...') const sandbox = await daytona.create() console.log(`Sandbox created: ${sandbox.id}`) // Step 1: Install Tailscale console.log('\nInstalling Tailscale (this may take a few minutes)...') let response = await sandbox.process.executeCommand( 'curl -fsSL https://tailscale.com/install.sh | sh', undefined, // cwd undefined, // env 300 // timeout ) if (response.exitCode !== 0) { console.log(`Error installing Tailscale: ${response.result}`) return } console.log('Tailscale installed successfully.') // Step 2: Start tailscaled daemon in background console.log('\nStarting tailscaled daemon...') await sandbox.process.executeCommand( 'nohup sudo tailscaled > /dev/null 2>&1 &', undefined, // cwd undefined, // env 10 // timeout ) // Wait for daemon to initialize await sleep(3000) // Step 3: Run tailscale up in background and capture output to a file console.log('\nInitiating Tailscale login...') await sandbox.process.executeCommand( 'sudo tailscale up > /tmp/tailscale-login.txt 2>&1 &', undefined, // cwd undefined, // env 10 // timeout ) // Wait for the login URL to be written to the file await sleep(3000) // Read the login URL from the output file response = await sandbox.process.executeCommand( 'cat /tmp/tailscale-login.txt', undefined, // cwd undefined, // env 10 // timeout ) const output = response.result || '' const urlMatch = output.match(/https:\/\/login\.tailscale\.com\/a\/[^\s]+/) if (urlMatch) { const loginUrl = urlMatch[0] console.log('\n' + '='.repeat(60)) console.log('To authenticate, visit this URL in your browser:') console.log(`\n ${loginUrl}`) console.log('\n' + '='.repeat(60)) console.log('\nWaiting for authentication...') // Poll for connection status const maxWait = 300 // 5 minutes max wait const pollInterval = 5 let waited = 0 while (waited < maxWait) { await sleep(pollInterval * 1000) waited += pollInterval const statusResponse = await sandbox.process.executeCommand( 'tailscale status 2>&1', undefined, // cwd undefined, // env 30 // timeout ) const statusOutput = statusResponse.result || '' // Check if we're connected (status shows our machine without login prompt) if ( statusResponse.exitCode === 0 && !statusOutput.toLowerCase().includes('logged out') ) { // Verify we have an IP assigned const ipResponse = await sandbox.process.executeCommand( 'tailscale ip -4 2>&1', undefined, // cwd undefined, // env 10 // timeout ) if (ipResponse.exitCode === 0 && ipResponse.result?.trim()) { console.log('\nConnected to Tailscale network!') console.log(`Tailscale IP: ${ipResponse.result.trim()}`) break } } console.log(` Still waiting... (${waited}s)`) } if (waited >= maxWait) { console.log('\nTimeout waiting for authentication. Please try again.') return } } else { // Maybe already connected or different output console.log(`Output from tailscale up:\n${output}`) // Check if already connected const statusResponse = await sandbox.process.executeCommand( 'tailscale status', undefined, // cwd undefined, // env 30 // timeout ) if (statusResponse.exitCode === 0) { console.log('\nTailscale status:') console.log(statusResponse.result) } } // Final status check console.log('\nFinal Tailscale status:') response = await sandbox.process.executeCommand( 'tailscale status', undefined, // cwd undefined, // env 30 // timeout ) console.log(response.result) } // Run the main function setupTailscaleVpnInteractive().catch(console.error) ``` Once the connection is established and authentication is complete, the sandbox will maintain its connection as long as the service is running. ### Connect with auth key Using an auth key provides a non-interactive way to connect your Daytona Sandbox to Tailscale, making it suitable for automated scripts, CI/CD pipelines, or any scenario where manual browser interaction is not available. 1. Access your [Tailscale admin console ↗](https://login.tailscale.com/admin/machines) 2. Click **Add device** and select **Linux server** 3. Apply the configuration and click **Generate install script** This will generate a script that you can use to install Tailscale and connect to the Tailscale network. ```bash curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up --auth-key=tskey-auth- ``` Copy the auth key from the generated script and use it to connect your Daytona Sandbox to Tailscale: ```python from daytona import Daytona, DaytonaConfig import time # Configuration DAYTONA_API_KEY = "YOUR_API_KEY" # Replace with your API key TAILSCALE_AUTH_KEY = "YOUR_AUTH_KEY" # Replace with your auth key # Initialize the Daytona client config = DaytonaConfig(api_key=DAYTONA_API_KEY) daytona = Daytona(config) def setup_tailscale_vpn(auth_key: str): """ Connect a Daytona sandbox to a Tailscale network using the Python SDK. Uses auth-key for non-interactive authentication. """ # Create the sandbox print("Creating sandbox...") sandbox = daytona.create() print(f"Sandbox created: {sandbox.id}") # Step 1: Install Tailscale print("\nInstalling Tailscale (this may take a few minutes)...") response = sandbox.process.exec( "curl -fsSL https://tailscale.com/install.sh | sh", timeout=300 ) if response.exit_code != 0: print(f"Error installing Tailscale: {response.result}") return sandbox print("Tailscale installed successfully.") # Step 2: Start tailscaled daemon manually (systemd doesn't auto-start in sandboxes) print("\nStarting tailscaled daemon...") sandbox.process.exec("nohup sudo tailscaled > /dev/null 2>&1 &", timeout=10) # Wait for daemon to initialize time.sleep(3) # Step 3: Connect with auth key print("\nConnecting to Tailscale network...") response = sandbox.process.exec( f"sudo tailscale up --auth-key={auth_key}", timeout=60 ) if response.exit_code != 0: print(f"Error connecting: {response.result}") return sandbox print("Connected to Tailscale network.") # Verify connection status print("\nChecking Tailscale status...") response = sandbox.process.exec("tailscale status", timeout=30) print(f"Status:\n{response.result}") return sandbox if __name__ == "__main__": sandbox = setup_tailscale_vpn(TAILSCALE_AUTH_KEY) ``` ```typescript import { Daytona } from '@daytonaio/sdk' // Configuration const DAYTONA_API_KEY = 'YOUR_API_KEY' // Replace with your API key const TAILSCALE_AUTH_KEY = 'YOUR_AUTH_KEY' // Replace with your auth key // Initialize the Daytona client const daytona = new Daytona({ apiKey: DAYTONA_API_KEY, }) function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)) } async function setupTailscaleVpn(authKey: string): Promise { /** * Connect a Daytona sandbox to a Tailscale network using the TypeScript SDK. * Uses auth-key for non-interactive authentication. */ // Create the sandbox console.log('Creating sandbox...') const sandbox = await daytona.create() console.log(`Sandbox created: ${sandbox.id}`) // Step 1: Install Tailscale console.log('\nInstalling Tailscale (this may take a few minutes)...') let response = await sandbox.process.executeCommand( 'curl -fsSL https://tailscale.com/install.sh | sh', undefined, // cwd undefined, // env 300 // timeout ) if (response.exitCode !== 0) { console.log(`Error installing Tailscale: ${response.result}`) return } console.log('Tailscale installed successfully.') // Step 2: Start tailscaled daemon manually (systemd doesn't auto-start in sandboxes) console.log('\nStarting tailscaled daemon...') await sandbox.process.executeCommand( 'nohup sudo tailscaled > /dev/null 2>&1 &', undefined, // cwd undefined, // env 10 // timeout ) // Wait for daemon to initialize await sleep(3000) // Step 3: Connect with auth key console.log('\nConnecting to Tailscale network...') response = await sandbox.process.executeCommand( `sudo tailscale up --auth-key=${authKey}`, undefined, // cwd undefined, // env 60 // timeout ) if (response.exitCode !== 0) { console.log(`Error connecting: ${response.result}`) return } console.log('Connected to Tailscale network.') // Verify connection status console.log('\nChecking Tailscale status...') response = await sandbox.process.executeCommand( 'tailscale status', undefined, // cwd undefined, // env 30 // timeout ) console.log(`Status:\n${response.result}`) } // Run the main function setupTailscaleVpn(TAILSCALE_AUTH_KEY).catch(console.error) ``` Once the connection is established and authentication is complete, the sandbox will maintain its connection as long as the service is running. ### Connect with web terminal For working directly in the terminal or for more control over the Tailscale connection process, you can set up Tailscale manually through the Daytona [web terminal](https://www.daytona.io/docs/en/web-terminal.md) or [SSH](https://www.daytona.io/docs/en/ssh-access.md). This approach provides visibility into each step of the installation and connection process, and allows you to customize the setup if needed. The process involves installing Tailscale, starting the daemon in a persistent session using tmux, and then authenticating through the interactive login flow. 1. Navigate to your sandbox [web terminal](https://www.daytona.io/docs/en/web-terminal.md) in [Daytona Dashboard ↗](https://app.daytona.io/), or [access it via SSH](https://www.daytona.io/docs/en/ssh-access.md) 2. Install Tailscale using the official installation script: ```bash curl -fsSL https://tailscale.com/install.sh | sh ``` This begins the Tailscale installation process and initializes the Tailscale CLI inside the sandbox. Daytona requires the Tailscale daemon to be running in the background to connect the sandbox to the Tailscale network. The recommended approach is to run it in a detached tmux (or similar) session to ensure the daemon is running in the background: 3. Install tmux ```bash sudo apt install tmux ``` 4. Start the Tailscale daemon in a detached tmux session ```bash tmux new -d -s tailscale 'sudo tailscaled' ``` 5. Connect and authenticate your sandbox with the Tailscale network ```bash sudo tailscale up ``` 6. Visit the authentication URL in the web browser and follow the instructions to authenticate ```txt To authenticate, visit: https://login.tailscale.com/a/ ``` Once authenticated, you will see the following confirmation message: ```txt Your device is logged in to the
tailnet. ``` You've now successfully connected your Daytona sandbox to your Tailscale network. The sandbox should appear in your [Tailscale dashboard](https://login.tailscale.com/admin/machines). ## OpenVPN Daytona provides multiple ways to connect to a Daytona Sandbox with an OpenVPN network: - [Connect with client configuration](#connect-with-client-configuration) - [Connect with web terminal](#connect-with-web-terminal) OpenVPN uses a client-server model where your Daytona Sandbox acts as a client connecting to an OpenVPN server. This approach is suitable for connecting to existing corporate VPNs, accessing resources behind firewalls, or integrating with infrastructure that already uses OpenVPN. :::note Connecting a Daytona Sandbox to OpenVPN network requires a [client configuration file](#client-configuration-file). ::: ### Client configuration file Client configuration file contains the connection parameters, certificates, and keys required to establish a secure connection to your OpenVPN server. This file is typically provided by your network administrator or generated from your OpenVPN server setup. The configuration file should be named `client.ovpn` or similar, and it must contain all the required connection settings, including server address, port, protocol, encryption settings, and authentication credentials. To create this file, you can use a text editor such as nano or vim, or upload it to your sandbox if you have it prepared elsewhere. The following snippet is an example of a client configuration file. Replace the placeholders with the actual values provided by your OpenVPN server. ```bash client proto udp explicit-exit-notify remote dev tun resolv-retry infinite nobind persist-key persist-tun remote-cert-tls server verify-x509-name name auth SHA256 auth-nocache cipher AES-128-GCM ignore-unknown-option data-ciphers data-ciphers AES-128-GCM ncp-ciphers AES-128-GCM tls-client tls-version-min 1.2 tls-cipher TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 ignore-unknown-option block-outside-dns setenv opt block-outside-dns # Prevent Windows 10 DNS leak verb 3 -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- -----BEGIN PRIVATE KEY----- -----END PRIVATE KEY----- -----BEGIN OpenVPN tls-crypt-v2 client key----- -----END OpenVPN tls-crypt-v2 client key----- ``` ### Connect with client configuration ```python from daytona import Daytona, DaytonaConfig import time # Configuration DAYTONA_API_KEY = "YOUR_API_KEY" # Replace with your API key # OpenVPN client configuration (paste your .ovpn config here) OPENVPN_CONFIG = """ """.strip() # Initialize the Daytona client config = DaytonaConfig(api_key=DAYTONA_API_KEY) daytona = Daytona(config) def setup_openvpn(ovpn_config: str): """ Connect a Daytona sandbox to an OpenVPN network using the Python SDK. """ # Create the sandbox print("Creating sandbox...") sandbox = daytona.create() print(f"Sandbox created: {sandbox.id}") # Step 1: Install OpenVPN print("\nInstalling OpenVPN...") response = sandbox.process.exec( "sudo apt update && sudo apt install -y openvpn", timeout=120 ) if response.exit_code != 0: print(f"Error installing OpenVPN: {response.result}") return sandbox print("OpenVPN installed successfully.") # Step 2: Write the OpenVPN config file print("\nWriting OpenVPN configuration...") sandbox.fs.upload_file(ovpn_config.encode(), "/home/daytona/client.ovpn") print("Configuration written to /home/daytona/client.ovpn") # Step 3: Start OpenVPN in background print("\nStarting OpenVPN tunnel...") sandbox.process.exec( "nohup sudo openvpn /home/daytona/client.ovpn > /tmp/openvpn.log 2>&1 &", timeout=10 ) # Wait for connection to establish print("Waiting for VPN connection to establish...") time.sleep(10) # Step 4: Verify connection print("\nVerifying OpenVPN connection...") # Check if tun interface exists response = sandbox.process.exec("ip addr show tun0", timeout=10) if response.exit_code == 0: print("VPN tunnel interface (tun0) is up:") print(response.result) else: print("Warning: tun0 interface not found. Checking OpenVPN logs...") log_response = sandbox.process.exec("cat /tmp/openvpn.log", timeout=10) print(f"OpenVPN log:\n{log_response.result}") return sandbox # Get public IP through VPN print("\nChecking public IP (should be VPN server IP)...") response = sandbox.process.exec("curl -s ifconfig.me", timeout=30) if response.exit_code == 0: print(f"Public IP: {response.result}") else: print(f"Could not determine public IP: {response.result}") print("\nOpenVPN connection established successfully.") return sandbox if __name__ == "__main__": sandbox = setup_openvpn(OPENVPN_CONFIG) ``` ```typescript import { Daytona } from '@daytonaio/sdk'; // Configuration const DAYTONA_API_KEY = "YOUR_API_KEY"; // Replace with your API key // OpenVPN client configuration (paste your .ovpn config here) const OPENVPN_CONFIG = ` `.trim(); // Initialize the Daytona client const daytona = new Daytona({ apiKey: DAYTONA_API_KEY, }); function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } async function setupOpenvpn(ovpnConfig: string): Promise { /** * Connect a Daytona sandbox to an OpenVPN network using the TypeScript SDK. */ // Create the sandbox console.log("Creating sandbox..."); const sandbox = await daytona.create(); console.log(`Sandbox created: ${sandbox.id}`); // Step 1: Install OpenVPN console.log("\nInstalling OpenVPN..."); let response = await sandbox.process.executeCommand( "sudo apt update && sudo apt install -y openvpn", undefined, // cwd undefined, // env 120 // timeout ); if (response.exitCode !== 0) { console.log(`Error installing OpenVPN: ${response.result}`); return; } console.log("OpenVPN installed successfully."); // Step 2: Write the OpenVPN config file console.log("\nWriting OpenVPN configuration..."); // Use heredoc to write the config file await sandbox.process.executeCommand( `cat << 'OVPNEOF' > /home/daytona/client.ovpn ${ovpnConfig} OVPNEOF`, undefined, undefined, 30 ); console.log("Configuration written to /home/daytona/client.ovpn"); // Step 3: Start OpenVPN in background console.log("\nStarting OpenVPN tunnel..."); await sandbox.process.executeCommand( "nohup sudo openvpn /home/daytona/client.ovpn > /tmp/openvpn.log 2>&1 &", undefined, // cwd undefined, // env 10 // timeout ); // Wait for connection to establish console.log("Waiting for VPN connection to establish..."); await sleep(10000); // Step 4: Verify connection console.log("\nVerifying OpenVPN connection..."); // Check if tun interface exists response = await sandbox.process.executeCommand( "ip addr show tun0", undefined, // cwd undefined, // env 10 // timeout ); if (response.exitCode === 0) { console.log("VPN tunnel interface (tun0) is up:"); console.log(response.result); } else { console.log("Warning: tun0 interface not found. Checking OpenVPN logs..."); const logResponse = await sandbox.process.executeCommand( "cat /tmp/openvpn.log", undefined, // cwd undefined, // env 10 // timeout ); console.log(`OpenVPN log:\n${logResponse.result}`); return; } // Get public IP through VPN console.log("\nChecking public IP (should be VPN server IP)..."); response = await sandbox.process.executeCommand( "curl -s ifconfig.me", undefined, // cwd undefined, // env 30 // timeout ); if (response.exitCode === 0) { console.log(`Public IP: ${response.result}`); } else { console.log(`Could not determine public IP: ${response.result}`); } console.log("\nOpenVPN connection established successfully."); } // Run the main function setupOpenvpn(OPENVPN_CONFIG).catch(console.error); ``` ### Connect with web terminal Daytona provides a [web terminal](https://www.daytona.io/docs/en/web-terminal.md) for interacting with your sandboxes, allowing you to install OpenVPN and connect to your OpenVPN network. 1. Navigate to your sandbox [web terminal](https://www.daytona.io/docs/en/web-terminal.md) in [Daytona Dashboard ↗](https://app.daytona.io/) by clicking on the Terminal icon `>_`, or [access it via SSH](https://www.daytona.io/docs/en/ssh-access.md) 2. Install OpenVPN and tmux ```bash sudo apt update && sudo apt install -y openvpn tmux ``` 3. Create the OpenVPN [client configuration file](#client-configuration-file) for your Daytona sandbox ```bash sudo nano client.ovpn ``` 4. Save the file by pressing `Ctrl+O`, then `Enter`, and exit by pressing `Ctrl+X` Daytona requires the OpenVPN tunnel to be running in the background to connect the sandbox to the OpenVPN network. The recommended approach is to run it in a detached tmux (or similar) session: 5. Start OpenVPN tunnel in a background tmux session ```bash tmux new -d -s openvpn 'sudo openvpn client.ovpn' ``` This starts the OpenVPN tunnel in a background tmux session that persists even if you disconnect from the sandbox. 6. Verify the OpenVPN connection by running the following command ```bash curl ifconfig.me ``` This will return the IP address of the sandbox connected to the OpenVPN network. You've now successfully connected your Daytona sandbox to your OpenVPN network. Daytona provides a browser-based web terminal for interacting with your sandboxes. The web terminal allows you to run commands, view files, and debug directly from your browser without installing any local tools. - **Remote command execution**: run shell commands directly in your sandbox - **File management**: navigate the file system, view and edit files - **Debugging**: inspect logs, monitor processes, and troubleshoot issues - **Package management**: install dependencies and configure your environment ## Access from Dashboard Access the web terminal directly from the [Daytona Dashboard ↗](https://app.daytona.io/dashboard/sandboxes). 1. Navigate to [Sandboxes ↗](https://app.daytona.io/dashboard/sandboxes) 2. Locate the running sandbox you want to access 3. Click the terminal icon **`>_`** This opens the web terminal in a new browser tab, providing a full terminal session connected to your sandbox. The web terminal is available only for sandboxes in the `STARTED` state. If your sandbox is stopped, start it before attempting to access the terminal. ## Access via CLI When you create a sandbox using the Daytona CLI, the web terminal URL is displayed automatically in the output. ```shell daytona create ``` The CLI output includes the terminal URL: ```text Sandbox '' created successfully Connect via SSH: daytona ssh Open the Web Terminal: https://22222-.proxy.daytona.work ``` ## Access via URL The web terminal runs on port `22222` inside each sandbox. You can obtain the terminal URL programmatically using [Preview URLs](https://www.daytona.io/docs/en/preview.md). Pass port `22222` to the preview URL method: ```python terminal_info = sandbox.get_preview_link(22222) print(f"Web Terminal URL: {terminal_info.url}") ``` ```typescript const terminalInfo = await sandbox.getPreviewLink(22222); console.log(`Web Terminal URL: ${terminalInfo.url}`); ``` ```ruby terminal_info = sandbox.preview_url(22222) puts "Web Terminal URL: #{terminal_info.url}" ``` ```go url, err := sandbox.GetPreviewLink(ctx, 22222) ``` ```bash daytona preview-url --port 22222 ``` ```bash curl 'https://app.daytona.io/api/sandbox/{sandboxId}/ports/22222/preview-url' \ --header 'Authorization: Bearer ' ``` ## Security Terminal access is restricted to authenticated members of your [Organization](https://www.daytona.io/docs/en/organizations.md). Even when a sandbox has its `public` parameter set to `true`, the web terminal remains accessible only to organization members. :::warning The web terminal provides full shell access to your sandbox. Treat terminal URLs with the same care as SSH credentials. Do not share terminal URLs with untrusted parties. ::: ## Related - [SSH Access](https://www.daytona.io/docs/en/ssh-access.md): connect to your sandbox from a local terminal or IDE - [Pseudo Terminal (PTY)](https://www.daytona.io/docs/en/pty.md): programmatic terminal sessions for automated workflows - [Process and Code Execution](https://www.daytona.io/docs/en/process-code-execution.md): execute commands and run code in sandboxes - [Preview](https://www.daytona.io/docs/en/preview.md): generate preview URLs for accessing sandbox services Webhooks are HTTP callbacks that Daytona sends to your specified endpoints when specific events occur. Think of them as "reverse API calls" - instead of your application asking Daytona for updates, Daytona proactively notifies your application when something important happens. Webhooks enable powerful automation and integration scenarios: - **Real-time notifications**: get instant alerts when sandboxes are created, started, or stopped - **Automated workflows**: trigger deployment pipelines when snapshots are created - **Monitoring & analytics**: track usage patterns and resource utilization across organizations - **Integration**: connect Daytona with existing tools like Slack, Discord, or custom applications - **Audit & compliance**: maintain detailed logs of all important changes :::note Webhooks are available to organization admins and members with appropriate permissions. If you don't see **Webhooks** in [Daytona Dashboard ↗](https://app.daytona.io/dashboard), contact [support@daytona.io](mailto:support@daytona.io) to enable webhooks for your organization. Provide your organization ID (found in your organization settings) when requesting access. ::: ## Accessing webhooks Daytona provides a webhook management interface to access and manage webhook endpoints. 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard) 2. Click **Webhooks** in the sidebar The webhooks management interface contains two tabs: [Endpoints](#endpoints) and [Messages](#messages). ### Endpoints The endpoints tab lists all the webhook endpoints for the organization. Each endpoint has the following details: - **Name**: the name of the webhook endpoint - **URL**: the URL of the webhook endpoint - **Status**: the status of the webhook endpoint - **Created**: the timestamp when the webhook endpoint was created Clicking on an endpoint opens the endpoint details page with additional endpoint configuration details: **name**, **URL**, **events**, **status**, **delivery statistics**, and **event history**. ### Messages The messages tab lists all the webhook messages for the organization. Each message has the following details: - **Message ID**: the ID of the webhook message - **Event type**: the event type of the webhook message - **Timestamp**: the timestamp when the webhook message was created Clicking on a message opens the message details dialog with additional message details: **message ID**, **event type**, **timestamp**, **payload**, and **delivery attempts**. Delivery attempts are shown in a separate table with the following columns: - **Status**: the status of the delivery attempt - **URL**: the URL of the delivery attempt - **Timestamp**: the timestamp when the delivery attempt was created Expanding a delivery attempt displays additional delivery attempt details: **status code**, **duration**, **trigger**, **endpoint ID**, and **response body**. ## Create webhook endpoints Daytona provides a webhook management interface to create webhook endpoints. 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard) 2. Click **Webhooks** in the sidebar 3. Click **Add Endpoint** 4. Configure your endpoint: - **Endpoint name**: a name for the endpoint - **Endpoint URL**: HTTPS endpoint where you want to receive events - [Events](#webhook-events): select which events to subscribe to 5. Click **Create** ## Edit webhook endpoints Daytona provides a webhook management interface to edit webhook endpoints. 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard) 2. Click **Webhooks** in the sidebar 3. Select a webhook endpoint from the [Endpoints](#endpoints) tab 4. Click the three dots menu (**⋮**) and select **Edit** 5. Update the endpoint details 6. Click **Save** ## Delete webhook endpoints Daytona provides a webhook management interface to delete webhook endpoints. 1. Navigate to [Daytona Dashboard ↗](https://app.daytona.io/dashboard) 2. Click **Webhooks** in the sidebar 3. Select a webhook endpoint from the [Endpoints](#endpoints) tab 4. Click the three dots menu (**⋮**) and select **Delete** 5. Confirm the deletion ## Webhook events Daytona sends webhooks for lifecycle events across your infrastructure resources. You can subscribe to specific event types or receive all events and filter them in your application. For more information, see the [API](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/webhooks) reference: > [**Send a webhook message (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/webhooks/POST/webhooks/organizations/{organizationId}/send) > > [**Get delivery attempts for a webhook message (API)**](https://www.daytona.io/docs/en/tools/api.md#daytona/tag/webhooks/GET/webhooks/organizations/{organizationId}/messages/{messageId}/attempts) ### Sandbox events | Event Type | Description | | --------------------------- | ------------------------------ | | **`sandbox.created`** | A new sandbox has been created | | **`sandbox.state.updated`** | A sandbox's state has changed | ### Snapshot events | Event Type | Description | | ---------------------------- | ------------------------------- | | **`snapshot.created`** | A new snapshot has been created | | **`snapshot.state.updated`** | A snapshot's state has changed | | **`snapshot.removed`** | A snapshot has been removed | ### Volume events | Event Type | Description | | -------------------------- | ----------------------------- | | **`volume.created`** | A new volume has been created | | **`volume.state.updated`** | A volume's state has changed | ## Webhook payload format All webhook payloads are JSON objects following a consistent format with common fields and event-specific data. **Common Fields:** | Field | Type | Description | | --------------- | ------ | ----------------------------------------------- | | **`event`** | string | Event type identifier (e.g., `sandbox.created`) | | **`timestamp`** | string | ISO 8601 timestamp when the event occurred | ### **`sandbox.created`** Sent when a new sandbox is created. ```json { "event": "sandbox.created", "timestamp": "2025-12-19T10:30:00.000Z", "id": "sandbox123", "organizationId": "org123", "state": "started", "class": "small", "createdAt": "2025-12-19T10:30:00.000Z" } ``` | Field | Type | Description | | -------------------- | ------ | ----------------------------------------------- | | **`id`** | string | Sandbox ID | | **`organizationId`** | string | Organization ID | | **`state`** | string | Sandbox state | | **`class`** | string | Sandbox class (`small`, `medium`, or `large`) | | **`createdAt`** | string | ISO 8601 timestamp when the sandbox was created | ### **`sandbox.state.updated`** Sent when a sandbox's state changes. ```json { "event": "sandbox.state.updated", "timestamp": "2025-12-19T10:30:00.000Z", "id": "sandbox123", "organizationId": "org123", "oldState": "started", "newState": "stopped", "updatedAt": "2025-12-19T10:30:00.000Z" } ``` | Field | Type | Description | | -------------------- | ------ | ---------------------------------------------------- | | **`id`** | string | Sandbox ID | | **`organizationId`** | string | Organization ID | | **`oldState`** | string | Previous sandbox state | | **`newState`** | string | New sandbox state | | **`updatedAt`** | string | ISO 8601 timestamp when the sandbox was last updated | ### **`snapshot.created`** Sent when a new snapshot is created. ```json { "event": "snapshot.created", "timestamp": "2025-12-19T10:30:00.000Z", "id": "snapshot123", "name": "my-snapshot", "organizationId": "org123", "state": "active", "createdAt": "2025-12-19T10:30:00.000Z" } ``` | Field | Type | Description | | -------------------- | ------ | ------------------------------------------------ | | **`id`** | string | Snapshot ID | | **`name`** | string | Snapshot name | | **`organizationId`** | string | Organization ID | | **`state`** | string | Snapshot state | | **`createdAt`** | string | ISO 8601 timestamp when the snapshot was created | ### **`snapshot.state.updated`** Sent when a snapshot's state changes. ```json { "event": "snapshot.state.updated", "timestamp": "2025-12-19T10:30:00.000Z", "id": "snapshot123", "name": "my-snapshot", "organizationId": "org123", "oldState": "building", "newState": "active", "updatedAt": "2025-12-19T10:30:00.000Z" } ``` | Field | Type | Description | | -------------------- | ------ | ----------------------------------------------------- | | **`id`** | string | Snapshot ID | | **`name`** | string | Snapshot name | | **`organizationId`** | string | Organization ID | | **`oldState`** | string | Previous snapshot state | | **`newState`** | string | New snapshot state | | **`updatedAt`** | string | ISO 8601 timestamp when the snapshot was last updated | ### **`snapshot.removed`** Sent when a snapshot is removed. ```json { "event": "snapshot.removed", "timestamp": "2025-12-19T10:30:00.000Z", "id": "snapshot123", "name": "my-snapshot", "organizationId": "org123", "removedAt": "2025-12-19T10:30:00.000Z" } ``` | Field | Type | Description | | -------------------- | ------ | ------------------------------------------------ | | **`id`** | string | Snapshot ID | | **`name`** | string | Snapshot name | | **`organizationId`** | string | Organization ID | | **`removedAt`** | string | ISO 8601 timestamp when the snapshot was removed | ### **`volume.created`** Sent when a new volume is created. ```json { "event": "volume.created", "timestamp": "2025-12-19T10:30:00.000Z", "id": "vol-12345678", "name": "my-volume", "organizationId": "org123", "state": "ready", "createdAt": "2025-12-19T10:30:00.000Z" } ``` | Field | Type | Description | | -------------------- | ------ | ---------------------------------------------- | | **`id`** | string | Volume ID | | **`name`** | string | Volume name | | **`organizationId`** | string | Organization ID | | **`state`** | string | Volume state | | **`createdAt`** | string | ISO 8601 timestamp when the volume was created | ### **`volume.state.updated`** Sent when a volume's state changes. ```json { "event": "volume.state.updated", "timestamp": "2025-12-19T10:30:00.000Z", "id": "vol-12345678", "name": "my-volume", "organizationId": "org123", "oldState": "creating", "newState": "ready", "updatedAt": "2025-12-19T10:30:00.000Z" } ``` | Field | Type | Description | | -------------------- | ------ | --------------------------------------------------- | | **`id`** | string | Volume ID | | **`name`** | string | Volume name | | **`organizationId`** | string | Organization ID | | **`oldState`** | string | Previous volume state | | **`newState`** | string | New volume state | | **`updatedAt`** | string | ISO 8601 timestamp when the volume was last updated |