Skip to main content

useshards

The Python SDK for shard, the sandbox manager. Shard is for blocking code and AsyncShard is for asyncio. Both have the same verbs.

pip install useshards

To run the code on main instead, install it from the repository:

pip install "useshards @ git+https://github.com/presmihaylov/shard#subdirectory=sdks/python"

Python 3.11 or later. The runtime dependencies are HTTPX, attrs and typing-extensions.

Connect

The SDK talks to shard serve over HTTPS, or over HTTP on localhost or a trusted encrypted network, where it warns once per client as the CLI does. Mint a key on the host with shard tokens mint, then:

export SHARD_REMOTE=https://shard.example.com
export SHARD_API_KEY=<the token>

An argument beats the environment: Shard(remote=..., api_key=...). ca_file= (or SHARD_CA_FILE) trusts a private CA, for an https remote only. A remote with no port takes 443 for https and 80 for http.

Quickstart

from useshards import Shard

with Shard() as shard:
    sandbox = shard.create("docker.io/library/alpine:3")
    try:
        result = sandbox.exec(["uname", "-sr"])
        print(result.exit_code, result.stdout)

        sandbox.files.write("/tmp/hello.txt", "hello\n")
        print(sandbox.exec("cat /tmp/hello.txt").stdout)
    finally:
        sandbox.remove(force=True)

The same on asyncio:

import asyncio
from useshards import AsyncShard

async def main() -> None:
    async with AsyncShard() as shard:
        sandbox = await shard.create("docker.io/library/alpine:3")
        try:
            results = await asyncio.gather(*(sandbox.exec(f"echo {n}") for n in range(3)))
            print([r.stdout for r in results])
        finally:
            await sandbox.remove(force=True)

asyncio.run(main())

examples/ has both in full. Set SHARD_REMOTE and SHARD_API_KEY, then run python examples/quickstart.py.

What to know

  • create() runs no command. It returns a running sandbox, or one in state failed with info.failed_reason. Run commands in it with exec().
  • A sandbox outlives its processes. sandbox.run(command, name=...) starts a named process that shard-init supervises and returns a Process, whose restart policy defaults to unless-stopped. processes.list() and processes.get(name) find them again; wait(), logs(), follow_logs() and kill() act on one. When a process exits or is killed, its sandbox stays running, so you can still exec into it. Only stop() or remove() ends it.
  • A string command runs under /bin/sh -c. A list runs as it is.
  • exec(..., background=True) returns a Command. wait(), kill(), write_stdin(), close_stdin() and resize() act on it. commands.get(id) finds it again from another client. In the foreground stdin= is the whole input; in the background stdin=True keeps the input open for write_stdin().
  • A cancel never kills the remote command. An asyncio cancel, a timeout or a dropped connection ends only the wait. The command runs on until it exits or you call kill().
  • Output may hold only its end. A result keeps the newest 8 MiB of stdout and stderr together (output_limit_bytes=, 0 keeps none). on_stdout= and on_stderr= see every chunk as it arrives. result.lost_bytes is different: it counts output the daemon dropped before any client read it. A process's logs() is bounded on the host too, so a long run may hold only its end.
  • Files stream. files.download() writes to a temporary file and renames it at the end, so a large file never sits in memory. An upload sends its length first: files.upload() takes a path, and files.write() takes bytes, a seekable file, or a stream with size=.
  • A forward carries a host port to the sandbox's own 127.0.0.1. sandbox.ports.add(9000, 8000) listens on the host's 127.0.0.1:9000, or on every interface with public=True. A running sandbox listens at once, any other from its next start. ports.list(), ports.remove(9000) and shard.ports() read and end them, and create(..., ports=[PortForward(9000, 8000)]) forwards from the first start.
  • A verb the provider lacks raises UnsupportedError. shard.capabilities() says which of the nine lifecycle verbs the daemon's provider supports (create, start, stop, remove, pause, resume, fork, snapshot and port), and whether it gives swap, before you call them.

Lists

shard.list() returns SandboxList(sandboxes, warnings). shard.secrets.list() returns SecretList(secrets, warnings). The async client returns the same result types. The warnings name entries the daemon could not read. Both lists collect warnings from every page, keeping each exact text once in first-seen order. Check them before you treat the result as complete. Other lists return plain lists.

Errors

ShardError is the base of every exception below, which covers the daemon, the transport and the settings. A bad local argument raises the native exception instead: an upload of a missing file raises FileNotFoundError, and create() with neither an image nor a snapshot raises ValueError.

Exception When
ConfigurationError A setting is missing or refused. The message never shows the API key, and names a CA file path or the remote when that is what to fix.
ShardConnectionError The daemon is unreachable, or a stream ended before the command did.
CommandNotStartedError The command never ran, as when its binary does not exist.
APIError The daemon refused the request: AuthenticationError (401), PermissionDeniedError (403), NotFoundError (404), InvalidRequestError (400, 413), ConflictError (409), UnsupportedError, ServerError (5xx). An exec past the running-exec bound is a plain APIError with status 429 and code exec_limit.

ProtocolError is an answer the SDK cannot read, UnknownLengthError an upload of unknown size or one whose source changed size while it was sent, and UnsafeArchiveError a download_dir tar entry the SDK refuses to land, as one outside the destination, named by entry and reason. A non-zero exit code is not an exception. Read result.exit_code.

An APIError can carry holders, the sandbox ids that prevent an operation such as secret removal. The attribute is None when the error has no holders field.

License

Apache-2.0.

Metadata

Release files for useshards 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for useshards 0.1.5
File Size Uploaded Provenance
useshards-0.1.5.tar.gz 81.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for useshards 0.1.5
File Interpreter ABI Platform
useshards-0.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 261.9 kB

Release files / useshards-0.1.5.tar.gz

Download URL useshards-0.1.5.tar.gz
Size 81.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d00edd5d711fba923ff1f89fa65c8c213031dffb2976c4659b27ec205856e77d
BLAKE2b-256 checksum
How to use checksums
a7ef4599673063a8b7692c98690ecaece14bbda5506b78e703c6a605c30bd5a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / useshards-0.1.5-py3-none-any.whl

Download URL useshards-0.1.5-py3-none-any.whl
Size 180.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
441de712267d9eaaed7d4f6546635ce7f475598ef0e42a10074cc22c265a72d1
BLAKE2b-256 checksum
How to use checksums
fd87f67376a02b19ab33a98e75ab2a0bf31293e5fecfa3fc4e257ee180bb24ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Security for useshards 0.1.5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for useshards-0.1.5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page