Python SDK for Shipyard Neo (Bay API)
Project description
Shipyard Neo Python SDK
Python async SDK for Bay API.
Use it to create sandboxes, run code, manage persistent cargo, and build skills self-update workflows.
Features
- Async-first client (
httpx) - Typed models (
pydantic) - Python / Shell / Filesystem capabilities
- Execution history query + annotation
- Skill lifecycle APIs (candidate/evaluate/promote/release/rollback)
- External cargo management
- Idempotency support for critical operations
Installation
pip install shipyard-neo-sdk
Or from source:
cd shipyard-neo-sdk
pip install -e .
Quick Start
import asyncio
from shipyard_neo import BayClient
async def main():
async with BayClient(
endpoint_url="http://localhost:8000",
access_token="your-token",
) as client:
sandbox = await client.create_sandbox(profile="python-default", ttl=600)
py = await sandbox.python.exec(
"print('hello')",
include_code=True,
description="smoke run",
tags="smoke,python",
)
print(py.output)
print(py.execution_id, py.execution_time_ms)
history = await sandbox.get_execution_history(limit=10)
print("history entries:", history.total)
await sandbox.delete()
asyncio.run(main())
Client API
BayClient(...)
from shipyard_neo import BayClient
async with BayClient(
endpoint_url="http://localhost:8000",
access_token="your-token",
timeout=30.0,
max_retries=3,
) as client:
...
Methods / Properties
| API | Description |
|---|---|
create_sandbox(...) |
Create sandbox |
get_sandbox(sandbox_id) |
Get one sandbox |
list_sandboxes(...) |
List sandboxes |
cargos |
CargoManager |
skills |
SkillManager |
Sandbox API
Lifecycle
| Method | Description |
|---|---|
refresh() |
Refresh sandbox state |
stop() |
Stop current session, keep data |
delete() |
Delete sandbox and managed resources |
extend_ttl(seconds, idempotency_key=None) |
Extend TTL |
keepalive() |
Extend idle timeout only |
Execution History
| Method | Description |
|---|---|
get_execution_history(...) |
Query history list |
get_execution(execution_id) |
Get one entry |
get_last_execution(exec_type=None) |
Get latest entry |
annotate_execution(...) |
Update description/tags/notes |
Example:
history = await sandbox.get_execution_history(
exec_type="python",
success_only=True,
tags="etl",
has_notes=False,
has_description=True,
limit=20,
)
last = await sandbox.get_last_execution(exec_type="python")
await sandbox.annotate_execution(
last.id,
description="useful snippet",
tags="etl,stable",
notes="candidate source",
)
Capabilities
Python
result = await sandbox.python.exec(
"print('hello')",
timeout=30,
include_code=True,
description="python exec",
tags="demo,python",
)
PythonExecResult fields:
successoutputerrordataexecution_idexecution_time_mscode
Shell
result = await sandbox.shell.exec(
"echo hello",
cwd=".",
timeout=30,
include_code=True,
description="shell exec",
tags="demo,shell",
)
ShellExecResult fields:
successoutputerrorexit_codeexecution_idexecution_time_mscommand
Filesystem
await sandbox.filesystem.write_file("app.py", "print('hi')")
content = await sandbox.filesystem.read_file("app.py")
entries = await sandbox.filesystem.list_dir(".")
await sandbox.filesystem.delete("app.py")
await sandbox.filesystem.upload("bin/model.bin", b"binary-bytes")
blob = await sandbox.filesystem.download("bin/model.bin")
Cargo API (client.cargos)
cargo = await client.cargos.create(size_limit_mb=1024)
sandbox = await client.create_sandbox(
profile="python-default",
cargo_id=cargo.id, # attach external cargo
ttl=600,
)
await sandbox.filesystem.write_file("state.txt", "persist-me")
await sandbox.delete() # external cargo still exists
sandbox2 = await client.create_sandbox(profile="python-default", cargo_id=cargo.id)
assert await sandbox2.filesystem.read_file("state.txt") == "persist-me"
await sandbox2.delete()
await client.cargos.delete(cargo.id)
Skill Lifecycle API (client.skills)
Use this to build reusable skills from execution evidence.
from shipyard_neo import SkillReleaseStage
# 1) collect execution evidence
e1 = await sandbox.python.exec("print('step1')", tags="etl")
e2 = await sandbox.shell.exec("echo step2", tags="etl")
# 2) create candidate
candidate = await client.skills.create_candidate(
skill_key="etl-loader",
source_execution_ids=[e1.execution_id, e2.execution_id],
scenario_key="csv-import",
payload_ref="s3://skills/etl-loader/v1",
)
# 3) evaluate
evaluation = await client.skills.evaluate_candidate(
candidate.id,
passed=True,
score=0.96,
benchmark_id="bench-etl-001",
report="all checks passed",
)
# 4) promote
release = await client.skills.promote_candidate(
candidate.id,
stage=SkillReleaseStage.CANARY,
)
# 5) list / rollback
releases = await client.skills.list_releases(skill_key="etl-loader", active_only=True)
rollback_release = await client.skills.rollback_release(release.id)
Idempotency
sandbox = await client.create_sandbox(
profile="python-default",
ttl=600,
idempotency_key="create-req-001",
)
await sandbox.extend_ttl(300, idempotency_key="extend-req-001")
cargo = await client.cargos.create(size_limit_mb=512, idempotency_key="cargo-req-001")
Reliability / Retry Policy
max_retries is now enforced in the HTTP pipeline.
- Auto-retry methods:
GET,PUT,DELETE POSTretries only whenidempotency_keyis provided- Retryable failures: transport timeout/connection errors, HTTP
429, HTTP5xx - Backoff: bounded exponential backoff
This keeps retries safe for non-idempotent operations while still protecting against transient faults.
Error Handling
All exceptions inherit from BayError.
from shipyard_neo import BayError, NotFoundError, ConflictError
try:
sb = await client.get_sandbox("sandbox-missing")
except NotFoundError:
...
except ConflictError:
...
except BayError as e:
print(e.message, e.details)
For non-JSON error responses (e.g. proxy HTML error pages), the SDK keeps status-based exception mapping and includes a bounded raw response snippet in details for diagnosis.
Error Types
| Exception | HTTP Code | Meaning |
|---|---|---|
UnauthorizedError |
401 | Invalid/missing auth |
ForbiddenError |
403 | Permission denied |
NotFoundError |
404 | Resource not found |
QuotaExceededError |
429 | Rate/quota limit |
ConflictError |
409 | State conflict |
ValidationError |
400 | Invalid request |
SessionNotReadyError |
503 | Session not ready |
RequestTimeoutError |
504 | Upstream timeout |
ShipError |
502 | Runtime error from Ship |
SandboxExpiredError |
409 | TTL already expired |
SandboxTTLInfiniteError |
409 | Infinite TTL cannot be extended |
CapabilityNotSupportedError |
400 | Capability not allowed |
InvalidPathError |
400 | Invalid workspace path |
CargoFileNotFoundError |
404 | File not found |
Environment Variables
BayClient fallback env vars:
| Variable | Description |
|---|---|
BAY_ENDPOINT |
Bay API base URL |
BAY_TOKEN |
Bearer token |
BAY_TIMEOUT |
Default timeout (seconds) |
BAY_MAX_RETRIES |
Max retry attempts |
import os
from shipyard_neo import BayClient
os.environ["BAY_ENDPOINT"] = "http://localhost:8000"
os.environ["BAY_TOKEN"] = "your-token"
# endpoint/token omitted -> use env vars
async with BayClient() as client:
...
License
AGPL-3.0-or-later
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shipyard_neo_sdk-0.2.0.tar.gz.
File metadata
- Download URL: shipyard_neo_sdk-0.2.0.tar.gz
- Upload date:
- Size: 77.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc1df8fb6f4349845bbfe06a6fd3d9a6c06290ec1008d0f1557e2ab1282dbcda
|
|
| MD5 |
d67852547b50fc1694a35e0ae44fcbc1
|
|
| BLAKE2b-256 |
c31c4efc6d66afa2cc18c6cdf845a85af5efe86055842d926d889e79bc34fa32
|
File details
Details for the file shipyard_neo_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: shipyard_neo_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 37.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5861a60a0d4308525030b1bab4ed621d536badb8eb37846f8c6612e24d341534
|
|
| MD5 |
1eaa33ca10933959636f80f161caa250
|
|
| BLAKE2b-256 |
f7404ee30d5650dbdca9a52acd8587e6b31777a10c78be8b680bf25bb8abd800
|