createos-sandbox 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- createos_sandbox-0.1.0/.github/workflows/ci.yml +82 -0
- createos_sandbox-0.1.0/.gitignore +12 -0
- createos_sandbox-0.1.0/CHANGELOG.md +29 -0
- createos_sandbox-0.1.0/CONTRIBUTING.md +69 -0
- createos_sandbox-0.1.0/LICENSE +21 -0
- createos_sandbox-0.1.0/PKG-INFO +384 -0
- createos_sandbox-0.1.0/README.md +350 -0
- createos_sandbox-0.1.0/SECURITY.md +31 -0
- createos_sandbox-0.1.0/examples/command_streaming/README.md +12 -0
- createos_sandbox-0.1.0/examples/command_streaming/main.py +58 -0
- createos_sandbox-0.1.0/examples/custom_template/README.md +13 -0
- createos_sandbox-0.1.0/examples/custom_template/main.py +159 -0
- createos_sandbox-0.1.0/examples/desktop/README.md +13 -0
- createos_sandbox-0.1.0/examples/desktop/main.py +138 -0
- createos_sandbox-0.1.0/examples/execution_server/README.md +43 -0
- createos_sandbox-0.1.0/examples/execution_server/main.py +268 -0
- createos_sandbox-0.1.0/examples/files_and_snapshots/README.md +12 -0
- createos_sandbox-0.1.0/examples/files_and_snapshots/main.py +102 -0
- createos_sandbox-0.1.0/examples/hello_world/README.md +11 -0
- createos_sandbox-0.1.0/examples/hello_world/main.py +28 -0
- createos_sandbox-0.1.0/examples/ingress_preview/README.md +13 -0
- createos_sandbox-0.1.0/examples/ingress_preview/main.py +66 -0
- createos_sandbox-0.1.0/examples/managed_process/README.md +12 -0
- createos_sandbox-0.1.0/examples/managed_process/main.py +196 -0
- createos_sandbox-0.1.0/examples/network/README.md +11 -0
- createos_sandbox-0.1.0/examples/network/main.py +59 -0
- createos_sandbox-0.1.0/pyproject.toml +80 -0
- createos_sandbox-0.1.0/scripts/publish.sh +29 -0
- createos_sandbox-0.1.0/src/createos/__init__.py +106 -0
- createos_sandbox-0.1.0/src/createos/_streams.py +177 -0
- createos_sandbox-0.1.0/src/createos/_transport.py +297 -0
- createos_sandbox-0.1.0/src/createos/_version.py +1 -0
- createos_sandbox-0.1.0/src/createos/client.py +224 -0
- createos_sandbox-0.1.0/src/createos/errors.py +76 -0
- createos_sandbox-0.1.0/src/createos/instance.py +415 -0
- createos_sandbox-0.1.0/src/createos/models.py +833 -0
- createos_sandbox-0.1.0/src/createos/py.typed +1 -0
- createos_sandbox-0.1.0/src/createos/self.py +27 -0
- createos_sandbox-0.1.0/src/createos/services.py +836 -0
- createos_sandbox-0.1.0/tests/test_execution_server.py +72 -0
- createos_sandbox-0.1.0/tests/test_sdk.py +235 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
|
18
|
+
PYTHONUNBUFFERED: "1"
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
test:
|
|
22
|
+
name: Test Python ${{ matrix.python-version }}
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
strategy:
|
|
25
|
+
fail-fast: false
|
|
26
|
+
matrix:
|
|
27
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v7
|
|
30
|
+
- uses: actions/setup-python@v7
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python-version }}
|
|
33
|
+
cache: pip
|
|
34
|
+
cache-dependency-path: pyproject.toml
|
|
35
|
+
- name: Install package and development tools
|
|
36
|
+
run: python -m pip install -e '.[dev]'
|
|
37
|
+
- name: Run tests
|
|
38
|
+
run: python -m pytest -q
|
|
39
|
+
|
|
40
|
+
quality:
|
|
41
|
+
name: Quality
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v7
|
|
45
|
+
- uses: actions/setup-python@v7
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.14"
|
|
48
|
+
cache: pip
|
|
49
|
+
cache-dependency-path: pyproject.toml
|
|
50
|
+
- name: Install package and development tools
|
|
51
|
+
run: python -m pip install -e '.[dev]'
|
|
52
|
+
- name: Check formatting
|
|
53
|
+
run: python -m ruff format --check src tests examples
|
|
54
|
+
- name: Lint
|
|
55
|
+
run: python -m ruff check src tests examples
|
|
56
|
+
- name: Type check
|
|
57
|
+
run: python -m mypy src/createos --ignore-missing-imports
|
|
58
|
+
- name: Check test coverage
|
|
59
|
+
run: >-
|
|
60
|
+
python -m pytest
|
|
61
|
+
--cov=createos
|
|
62
|
+
--cov-report=term-missing
|
|
63
|
+
--cov-fail-under=70
|
|
64
|
+
|
|
65
|
+
package:
|
|
66
|
+
name: Package
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v7
|
|
70
|
+
- uses: actions/setup-python@v7
|
|
71
|
+
with:
|
|
72
|
+
python-version: "3.14"
|
|
73
|
+
cache: pip
|
|
74
|
+
cache-dependency-path: pyproject.toml
|
|
75
|
+
- name: Install build frontend
|
|
76
|
+
run: python -m pip install build
|
|
77
|
+
- name: Build source and wheel distributions
|
|
78
|
+
run: python -m build
|
|
79
|
+
- name: Install and import the built wheel
|
|
80
|
+
run: |
|
|
81
|
+
python -m pip install --force-reinstall dist/*.whl
|
|
82
|
+
python -c "import createos; print(createos.__version__)"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `createos-sandbox` are documented here.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
Versions follow [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## Deprecation policy
|
|
8
|
+
|
|
9
|
+
- Anything re-exported from `src/createos/__init__.py` is part of the public
|
|
10
|
+
API.
|
|
11
|
+
- We are pre-1.0, so the API is allowed to break in MINOR bumps — breaking
|
|
12
|
+
changes ship as MINOR, and PATCH releases are bug-fix only.
|
|
13
|
+
- Where possible, breaking changes are announced one minor before removal: the
|
|
14
|
+
old surface keeps working, gains a `DeprecationWarning`, and this file points
|
|
15
|
+
at the replacement.
|
|
16
|
+
|
|
17
|
+
## [Unreleased]
|
|
18
|
+
|
|
19
|
+
## [0.1.0] — 2026-09-11
|
|
20
|
+
|
|
21
|
+
Initial release.
|
|
22
|
+
|
|
23
|
+
- `Client` with sandbox lifecycle (create, pause, resume, fork, destroy),
|
|
24
|
+
command execution and NDJSON streaming, file transfer and snapshots,
|
|
25
|
+
managed processes, networks, ingress previews, and custom templates.
|
|
26
|
+
- Typed wire-contract models, typed errors, and `py.typed`.
|
|
27
|
+
|
|
28
|
+
[Unreleased]: https://github.com/NodeOps-app/createos-python-sdk/compare/v0.1.0...HEAD
|
|
29
|
+
[0.1.0]: https://github.com/NodeOps-app/createos-python-sdk/releases/tag/v0.1.0
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for contributing to the CreateOS Python SDK.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
Create a virtual environment and install the SDK with its development tools:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
python -m venv .venv
|
|
11
|
+
.venv/bin/pip install -e '.[dev]'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Run the complete local check suite:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
.venv/bin/ruff format --check src tests examples
|
|
18
|
+
.venv/bin/ruff check src tests examples
|
|
19
|
+
.venv/bin/mypy src/createos --ignore-missing-imports
|
|
20
|
+
.venv/bin/pytest --cov=createos --cov-fail-under=70
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Commit convention
|
|
24
|
+
|
|
25
|
+
Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/):
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
<type>(<optional-scope>): <subject>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Accepted types are `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`,
|
|
32
|
+
and `perf`. Write the subject in imperative mood, keep it at 50 characters or
|
|
33
|
+
fewer, start it with a lowercase letter, and do not end it with a period.
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
feat(sandbox): add disk attachment
|
|
39
|
+
fix(transport): honor retry-after header
|
|
40
|
+
docs(readme): add network example
|
|
41
|
+
test(processes): cover output replay
|
|
42
|
+
chore: prepare v0.1.0 release
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For an incompatible public API change, add `!` before the colon and explain the
|
|
46
|
+
change in a `BREAKING CHANGE:` commit footer:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
feat(sandbox)!: change create response
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Before opening a pull request
|
|
53
|
+
|
|
54
|
+
Run the complete local check suite. Add or update tests for behavior changes,
|
|
55
|
+
and update public docstrings and README examples when the public API changes.
|
|
56
|
+
|
|
57
|
+
## Releasing
|
|
58
|
+
|
|
59
|
+
The package is published manually to PyPI as `createos-sandbox`.
|
|
60
|
+
|
|
61
|
+
1. Bump `__version__` in `src/createos/_version.py` (the single source of
|
|
62
|
+
truth — `pyproject.toml` reads it) and move the `CHANGELOG.md`
|
|
63
|
+
`[Unreleased]` entries under the new version.
|
|
64
|
+
2. Dry run the release gate: `./scripts/publish.sh --dry`.
|
|
65
|
+
3. Publish: `./scripts/publish.sh`. It reruns tests, lint, types, builds the
|
|
66
|
+
sdist and wheel, uploads with `twine`, then tags and pushes `v<version>`.
|
|
67
|
+
|
|
68
|
+
Uploading needs a PyPI API token, e.g. in `~/.pypirc` or as
|
|
69
|
+
`TWINE_USERNAME=__token__ TWINE_PASSWORD=pypi-...`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NodeOps Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: createos-sandbox
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Isolated sandboxes for AI agents and untrusted code: create, run commands, egress allowlist, pause/resume/fork, destroy. Python SDK for CreateOS Sandbox.
|
|
5
|
+
Project-URL: Homepage, https://createos.sh
|
|
6
|
+
Project-URL: Repository, https://github.com/NodeOps-app/createos-python-sdk
|
|
7
|
+
Project-URL: Issues, https://github.com/NodeOps-app/createos-python-sdk/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/NodeOps-app/createos-python-sdk/blob/main/CHANGELOG.md
|
|
9
|
+
Author: NodeOps Inc.
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agent,agents,ai,ai-agents,code-execution,compute,createos,createos-sandbox,e2b-alternative,egress,isolated-sandbox,isolation,runtime,sandbox,sdk,untrusted-code
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: httpx<1,>=0.27
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
32
|
+
Requires-Dist: twine>=5; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# CreateOS Python SDK
|
|
36
|
+
|
|
37
|
+
Launch an isolated cloud sandbox, run real commands, stream output, move files,
|
|
38
|
+
open a preview URL, and tear everything down from Python.
|
|
39
|
+
|
|
40
|
+
## Your first sandbox
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
pip install createos-sandbox
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Python 3.10 or newer is required.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from createos import Client, CreateSandboxRequest, RunCommandRequest
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
with Client(api_key="your-api-key") as client:
|
|
53
|
+
sandbox = client.create_sandbox(
|
|
54
|
+
CreateSandboxRequest(
|
|
55
|
+
name="hello-python",
|
|
56
|
+
shape="s-4vcpu-4gb",
|
|
57
|
+
rootfs="devbox:1",
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
try:
|
|
61
|
+
response = sandbox.run_command(
|
|
62
|
+
RunCommandRequest(
|
|
63
|
+
command="sh",
|
|
64
|
+
arguments=[
|
|
65
|
+
"-c",
|
|
66
|
+
'printf "Python says hello from $(uname -m)\\n"',
|
|
67
|
+
],
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
print(response.result.standard_output, end="")
|
|
71
|
+
finally:
|
|
72
|
+
sandbox.destroy()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
Python says hello from x86_64
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Do not commit a real API key to source control; inject it through your
|
|
80
|
+
application's secret manager. You can configure the endpoint and default
|
|
81
|
+
request timeout when constructing the client:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
client = Client(
|
|
85
|
+
api_key=api_key,
|
|
86
|
+
base_url="http://localhost:8080",
|
|
87
|
+
timeout=30,
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
As an alternative, `Client()` reads `CREATEOS_SANDBOX_API_KEY` and
|
|
92
|
+
`CREATEOS_SANDBOX_BASE_URL`. Explicit constructor arguments take precedence.
|
|
93
|
+
|
|
94
|
+
## Documentation
|
|
95
|
+
|
|
96
|
+
- [CreateOS Sandbox overview](https://nodeops.network/createos/docs/Sandbox/Overview)
|
|
97
|
+
explains the sandbox model, lifecycle, networking, storage, and isolation.
|
|
98
|
+
- [CreateOS Sandbox documentation](https://nodeops.network/createos/docs)
|
|
99
|
+
contains the REST API reference and product guides.
|
|
100
|
+
- [CreateOS Go SDK](https://github.com/NodeOps-app/createos-go-sdk) provides the
|
|
101
|
+
same sandbox capabilities for Go applications.
|
|
102
|
+
- [CreateOS TypeScript SDK](https://github.com/NodeOps-app/createos-sandbox-sdk)
|
|
103
|
+
provides the same sandbox capabilities for JavaScript and TypeScript
|
|
104
|
+
applications.
|
|
105
|
+
- [Runnable examples](#examples) demonstrate complete SDK workflows.
|
|
106
|
+
- The public Python API is typed and documented with Python docstrings.
|
|
107
|
+
- [Contributing guide](CONTRIBUTING.md) documents development checks and commit
|
|
108
|
+
conventions.
|
|
109
|
+
|
|
110
|
+
## Stream output as it happens
|
|
111
|
+
|
|
112
|
+
Long-running commands do not need to disappear behind a buffered HTTP call:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import sys
|
|
116
|
+
|
|
117
|
+
from createos import ExecStreamEventType, RunCommandRequest
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
request = RunCommandRequest(
|
|
121
|
+
command="sh",
|
|
122
|
+
arguments=[
|
|
123
|
+
"-c",
|
|
124
|
+
'for n in 1 2 3; do echo "step $n"; sleep 1; done',
|
|
125
|
+
],
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
with sandbox.stream_command(request) as stream:
|
|
129
|
+
for event in stream:
|
|
130
|
+
if event.type is ExecStreamEventType.STDOUT:
|
|
131
|
+
print(event.data, end="")
|
|
132
|
+
elif event.type is ExecStreamEventType.STDERR:
|
|
133
|
+
print(event.data, end="", file=sys.stderr)
|
|
134
|
+
elif event.type is ExecStreamEventType.EXIT:
|
|
135
|
+
print(f"exit code: {event.exit_code}")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Stopping early is safe: leaving the `with` block closes the response body and
|
|
139
|
+
releases the underlying HTTP connection.
|
|
140
|
+
|
|
141
|
+
## Move files without shell escaping
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
sandbox.files.upload(
|
|
145
|
+
"/workspace/config.json",
|
|
146
|
+
b'{"mode":"production"}',
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
with sandbox.files.download("/workspace/config.json") as download:
|
|
150
|
+
contents = download.read()
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`upload()` also accepts a binary file-like object, allowing large files to be
|
|
154
|
+
transferred without reading them all into memory first.
|
|
155
|
+
|
|
156
|
+
## Keep a process alive after disconnecting
|
|
157
|
+
|
|
158
|
+
Managed processes are resources rather than fragile terminal sessions. Start
|
|
159
|
+
one, reconnect from its output sequence, send input or signals, and wait for
|
|
160
|
+
either the leader or its complete process tree:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from createos import (
|
|
164
|
+
ManagedProcessCreateRequest,
|
|
165
|
+
ManagedProcessWaitOptions,
|
|
166
|
+
ManagedProcessWaitScope,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
process = sandbox.processes.create(
|
|
171
|
+
ManagedProcessCreateRequest(
|
|
172
|
+
command="sh",
|
|
173
|
+
arguments=["-c", "sleep 1; echo managed process finished"],
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
finished = sandbox.processes.wait(
|
|
178
|
+
process.process_id,
|
|
179
|
+
ManagedProcessWaitOptions(
|
|
180
|
+
scope=ManagedProcessWaitScope.TREE,
|
|
181
|
+
wait_timeout=30,
|
|
182
|
+
),
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Turn a service into a URL
|
|
187
|
+
|
|
188
|
+
Create a sandbox with ingress enabled, wait for the server to listen, then ask
|
|
189
|
+
the instance for its public URL:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from createos import CreateSandboxRequest, ManagedProcessCreateRequest
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
sandbox = client.create_sandbox(
|
|
196
|
+
CreateSandboxRequest(
|
|
197
|
+
shape="s-4vcpu-4gb",
|
|
198
|
+
rootfs="devbox:1",
|
|
199
|
+
ingress_enabled=True,
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
sandbox.processes.create(
|
|
204
|
+
ManagedProcessCreateRequest(
|
|
205
|
+
command="python3",
|
|
206
|
+
arguments=[
|
|
207
|
+
"-m",
|
|
208
|
+
"http.server",
|
|
209
|
+
"8080",
|
|
210
|
+
"--bind",
|
|
211
|
+
"0.0.0.0",
|
|
212
|
+
],
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
sandbox.wait_for_port(8080, host="127.0.0.1", timeout=15)
|
|
217
|
+
print(sandbox.preview_url(8080))
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Everything is already connected
|
|
221
|
+
|
|
222
|
+
Account-level services are initialized by `Client`:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
templates = client.templates
|
|
226
|
+
networks = client.networks
|
|
227
|
+
disks = client.disks
|
|
228
|
+
|
|
229
|
+
custom_templates = templates.list()
|
|
230
|
+
print(
|
|
231
|
+
f"{len(custom_templates)} templates ready; "
|
|
232
|
+
f"networks={type(networks).__name__} disks={type(disks).__name__}"
|
|
233
|
+
)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Instance-level services are initialized when a sandbox handle is created or
|
|
237
|
+
retrieved:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
sandbox.files
|
|
241
|
+
sandbox.processes
|
|
242
|
+
sandbox.computer.mouse
|
|
243
|
+
sandbox.computer.keyboard
|
|
244
|
+
sandbox.computer.windows
|
|
245
|
+
sandbox.computer.screens
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Connect sandboxes on a private network
|
|
249
|
+
|
|
250
|
+
Create an overlay network, attach a running sandbox, and inspect the resulting
|
|
251
|
+
membership. Cleanup runs in reverse order, so the sandbox detaches before the
|
|
252
|
+
network is deleted:
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
from createos import NetworkCreateRequest
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
network = client.networks.create(NetworkCreateRequest(name="agent-mesh"))
|
|
259
|
+
try:
|
|
260
|
+
sandbox.attach_network(network.id)
|
|
261
|
+
try:
|
|
262
|
+
connected = client.networks.get(network.id)
|
|
263
|
+
for member in connected.members:
|
|
264
|
+
print(
|
|
265
|
+
f"sandbox={member.sandbox_id} "
|
|
266
|
+
f"private-ip={member.ip_address} "
|
|
267
|
+
f"status={member.status}"
|
|
268
|
+
)
|
|
269
|
+
finally:
|
|
270
|
+
sandbox.detach_network(network.id)
|
|
271
|
+
finally:
|
|
272
|
+
client.networks.delete(network.id)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Lifecycle reads like the domain
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
sandbox.pause().wait_until_paused()
|
|
279
|
+
|
|
280
|
+
clone = sandbox.fork()
|
|
281
|
+
try:
|
|
282
|
+
sandbox.resume().wait_until_running()
|
|
283
|
+
finally:
|
|
284
|
+
clone.destroy()
|
|
285
|
+
|
|
286
|
+
sandbox.destroy()
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The `SandboxInstance` handle safely caches the latest server projection.
|
|
290
|
+
Lifecycle mutations and `refresh()` update it, while `id`, `name`, `status`,
|
|
291
|
+
`ip_address`, and `data` provide safe reads.
|
|
292
|
+
|
|
293
|
+
## Errors stay inspectable
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from createos import APIError, OperationTimeout
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
try:
|
|
300
|
+
sandbox.wait_until_running()
|
|
301
|
+
except APIError as error:
|
|
302
|
+
print(
|
|
303
|
+
f"HTTP {error.status_code}, code={error.code}, "
|
|
304
|
+
f"request={error.request_id}"
|
|
305
|
+
)
|
|
306
|
+
except OperationTimeout:
|
|
307
|
+
# A lifecycle or readiness wait exhausted its budget.
|
|
308
|
+
pass
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
GET, HEAD, PUT, and DELETE requests are retried for transient network failures
|
|
312
|
+
and retryable server responses. HTTP 429 and 503 are retried for every method.
|
|
313
|
+
Configure the client with `RetryOptions`, or disable retries for one request
|
|
314
|
+
with `RequestOptions(disable_retry=True)`.
|
|
315
|
+
|
|
316
|
+
## Examples
|
|
317
|
+
|
|
318
|
+
Runnable examples live under [`examples/`](examples/):
|
|
319
|
+
|
|
320
|
+
- [Hello world](examples/hello_world/README.md)
|
|
321
|
+
- [HTTP execution server](examples/execution_server/README.md)
|
|
322
|
+
- [Command streaming](examples/command_streaming/README.md)
|
|
323
|
+
- [Files and snapshots](examples/files_and_snapshots/README.md)
|
|
324
|
+
- [Ingress preview](examples/ingress_preview/README.md)
|
|
325
|
+
- [Private overlay network](examples/network/README.md)
|
|
326
|
+
- [Custom template](examples/custom_template/README.md)
|
|
327
|
+
- [Managed process lifecycle](examples/managed_process/README.md)
|
|
328
|
+
- [Desktop and noVNC](examples/desktop/README.md)
|
|
329
|
+
|
|
330
|
+
Together these examples cover command execution, file transfer, streaming,
|
|
331
|
+
ingress, snapshots, networking, templates, managed processes, and desktop use.
|
|
332
|
+
|
|
333
|
+
## Development
|
|
334
|
+
|
|
335
|
+
Create a virtual environment and install the development dependencies:
|
|
336
|
+
|
|
337
|
+
```sh
|
|
338
|
+
python -m venv .venv
|
|
339
|
+
.venv/bin/pip install -e '.[dev]'
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Run the same checks used while developing the SDK:
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
.venv/bin/ruff format --check src tests examples
|
|
346
|
+
.venv/bin/ruff check src tests examples
|
|
347
|
+
.venv/bin/mypy src/createos --ignore-missing-imports
|
|
348
|
+
.venv/bin/pytest --cov=createos --cov-fail-under=70
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
The project follows the
|
|
352
|
+
[Google Python Style Guide](https://google.github.io/styleguide/pyguide.html).
|
|
353
|
+
Formatting, import ordering, public docstrings, and static analysis are enforced
|
|
354
|
+
through the project configuration.
|
|
355
|
+
|
|
356
|
+
GitHub Actions runs these quality checks, tests Python 3.10 through 3.14, builds
|
|
357
|
+
both package distributions, and verifies that the generated wheel imports.
|
|
358
|
+
|
|
359
|
+
Commits follow Conventional Commits. See
|
|
360
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for accepted types, examples, and the checks
|
|
361
|
+
to run before opening a pull request.
|
|
362
|
+
|
|
363
|
+
## Package layout
|
|
364
|
+
|
|
365
|
+
```text
|
|
366
|
+
src/createos/client.py client configuration and account-level operations
|
|
367
|
+
src/createos/instance.py stateful sandbox lifecycle and command operations
|
|
368
|
+
src/createos/services.py files, processes, desktop, templates, disks, networks
|
|
369
|
+
src/createos/models.py public requests, responses, options, and enums
|
|
370
|
+
src/createos/_transport.py HTTP, authentication, retries, and JSend handling
|
|
371
|
+
src/createos/_streams.py NDJSON, SSE, command, process, and binary streams
|
|
372
|
+
examples/ runnable Python programs
|
|
373
|
+
tests/ mocked API contract tests
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## About CreateOS
|
|
377
|
+
|
|
378
|
+
[CreateOS](https://createos.sh) is an execution and governance platform for AI
|
|
379
|
+
agents and applications. Learn more about isolated Firecracker-based workloads
|
|
380
|
+
on the [CreateOS Sandbox product page](https://createos.sh/products/sandbox).
|
|
381
|
+
|
|
382
|
+
## License
|
|
383
|
+
|
|
384
|
+
This SDK is available under the [MIT License](LICENSE).
|