DocsAutomate with Python and CLI
v1.16+

Automate with Python and CLI

Use SandboxClient in synchronous Python applications and AsyncSandboxClient in async harnesses or agents. The CLI provides the same operations for shell scripts and manual work.

Both interfaces connect to an existing Polyaxon service with plugins.sandbox enabled. A sandbox is a capability of that service, not a separate kind of Polyaxon resource.

This page continues from the Sandbox Quick Start and uses its quick-start project, /workspace directory, and RUN_UUID variable.

Run commands

The Python example binds every operation to the same project and run. The CLI tab shows the equivalent shell commands.

import os

from polyaxon.client import SandboxClient


with SandboxClient(
    project="quick-start",
    run_uuid=os.environ["RUN_UUID"],
) as sandbox:
    sandbox.ping()
    sandbox.fs.upload_file(
        "./sandbox/smoke.py",
        "/workspace/smoke.py",
    )

    result = sandbox.process.exec(
        command=["python", "-V"],
        timeout_ms=30_000,
    )
    print(result.stdout, end="")
    print(result.stderr, end="")

    with sandbox.process.exec_stream(
        command=["python", "/workspace/smoke.py"],
    ) as events:
        for event in events:
            print(event)
polyaxon sandbox ping -p quick-start -uid $RUN_UUID
polyaxon sandbox upload -p quick-start -uid $RUN_UUID \
  ./sandbox/smoke.py /workspace/smoke.py
polyaxon sandbox exec -p quick-start -uid $RUN_UUID -- python -V
polyaxon sandbox exec -p quick-start -uid $RUN_UUID --stream -- python /workspace/smoke.py

Run background work

Start a detached process and keep its execution ID:

import os

from polyaxon.client import SandboxClient


with SandboxClient(
    project="quick-start",
    run_uuid=os.environ["RUN_UUID"],
) as sandbox:
    sandbox.fs.upload_file(
        "./sandbox/profile.py",
        "/workspace/profile.py",
    )
    process = sandbox.process.exec_bg(
        command=["python", "/workspace/profile.py"],
    )
    print(process.id)

    for chunk in process.iter_stdout(timeout=300, interval=0.5):
        print(chunk, end="")

    status = process.wait(timeout=300)
    print(status.state, status.exit_code)
polyaxon sandbox upload -p quick-start -uid $RUN_UUID \
  ./sandbox/profile.py /workspace/profile.py
EXEC_ID=$(polyaxon sandbox exec -p quick-start -uid $RUN_UUID --detach -- python /workspace/profile.py)
polyaxon sandbox logs -p quick-start -uid $RUN_UUID $EXEC_ID

Move files

import os

from polyaxon.client import SandboxClient


with SandboxClient(
    project="quick-start",
    run_uuid=os.environ["RUN_UUID"],
) as sandbox:
    sandbox.fs.upload_file(
        "./sandbox/config.yaml",
        "/workspace/config.yaml",
    )
    sandbox.fs.download_file(
        "/workspace/profile.json",
        "./sandbox/profile.downloaded.json",
    )
polyaxon sandbox upload -p quick-start -uid $RUN_UUID \
  ./sandbox/config.yaml /workspace/config.yaml
polyaxon sandbox download -p quick-start -uid $RUN_UUID \
  /workspace/profile.json ./sandbox/profile.downloaded.json

Remote paths are absolute paths inside the service container. Replace /workspace with a directory that exists in your image.

Use the async Python client

AsyncSandboxClient exposes coroutine methods and async iterators for applications that already use asyncio. Target the service explicitly so the harness does not depend on cached project or run context:

import asyncio
import os

from polyaxon.client import AsyncSandboxClient


async def main():
    async with AsyncSandboxClient(
        project="quick-start",
        run_uuid=os.environ["RUN_UUID"],
    ) as sandbox:
        await sandbox.ping()
        await sandbox.fs.upload_file(
            "./sandbox/smoke.py",
            "/workspace/smoke.py",
        )

        result = await sandbox.process.exec(
            command=["python", "-V"],
            timeout_ms=30_000,
        )
        print(result.stdout, end="")
        print(result.stderr, end="")

        stream = await sandbox.process.exec_stream(
            command=["python", "/workspace/smoke.py"],
        )
        async with stream as events:
            async for event in events:
                print(event)


asyncio.run(main())

Commands must be argument lists. Polyaxon does not pass them through a shell unless you explicitly run a shell such as sh -c.

The sync and async clients provide the same process, filesystem, and terminal APIs. See the client, process, filesystem, and PTY references for the full interface.

Drive a sandbox with an AI agent

Use the Connect LLMs guide to execute generated Python code or connect OpenAI, Anthropic, and LangChain through a shared command tool. It includes provider setup, tool-result handling, and bounded execution with host approval.

Stop the service

Stop the service when your automation finishes:

import os

from polyaxon.client import RunClient


run_client = RunClient(
    project="quick-start",
    run_uuid=os.environ["RUN_UUID"],
)
run_client.stop()
polyaxon ops stop -p quick-start -uid $RUN_UUID

Container files disappear when the run is removed. Upload durable outputs to artifact storage or commit them to Git before stopping the service.

SandboxClient.create() creates a service run but does not approve it or wait for it to become ready. This tutorial attaches to a running service so the first tool call cannot race startup.