pocketdock 1.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.
Files changed (96) hide show
  1. pocketdock-1.1.0/.github/workflows/ci.yml +58 -0
  2. pocketdock-1.1.0/.github/workflows/docs.yml +18 -0
  3. pocketdock-1.1.0/.github/workflows/publish.yml +18 -0
  4. pocketdock-1.1.0/.gitignore +51 -0
  5. pocketdock-1.1.0/.pre-commit-config.yaml +24 -0
  6. pocketdock-1.1.0/CHANGELOG.md +201 -0
  7. pocketdock-1.1.0/CONTRIBUTING.md +56 -0
  8. pocketdock-1.1.0/LICENSE +24 -0
  9. pocketdock-1.1.0/PKG-INFO +126 -0
  10. pocketdock-1.1.0/README.md +102 -0
  11. pocketdock-1.1.0/dev/status.md +76 -0
  12. pocketdock-1.1.0/docs/changelog.md +3 -0
  13. pocketdock-1.1.0/docs/cli.md +298 -0
  14. pocketdock-1.1.0/docs/concepts/architecture.md +104 -0
  15. pocketdock-1.1.0/docs/concepts/connection-model.md +117 -0
  16. pocketdock-1.1.0/docs/contributing.md +21 -0
  17. pocketdock-1.1.0/docs/guide/async.md +135 -0
  18. pocketdock-1.1.0/docs/guide/commands.md +144 -0
  19. pocketdock-1.1.0/docs/guide/containers.md +159 -0
  20. pocketdock-1.1.0/docs/guide/files.md +76 -0
  21. pocketdock-1.1.0/docs/guide/persistence.md +134 -0
  22. pocketdock-1.1.0/docs/guide/profiles.md +122 -0
  23. pocketdock-1.1.0/docs/guide/projects.md +146 -0
  24. pocketdock-1.1.0/docs/guide/sessions.md +113 -0
  25. pocketdock-1.1.0/docs/index.md +74 -0
  26. pocketdock-1.1.0/docs/quickstart.md +105 -0
  27. pocketdock-1.1.0/docs/reference/api.md +303 -0
  28. pocketdock-1.1.0/docs/reference/configuration.md +119 -0
  29. pocketdock-1.1.0/docs/reference/errors.md +188 -0
  30. pocketdock-1.1.0/docs/reference/types.md +143 -0
  31. pocketdock-1.1.0/examples/README.md +5 -0
  32. pocketdock-1.1.0/images/agent/Dockerfile +13 -0
  33. pocketdock-1.1.0/images/dev/Dockerfile +10 -0
  34. pocketdock-1.1.0/images/embedded/Dockerfile +30 -0
  35. pocketdock-1.1.0/images/minimal/Dockerfile +6 -0
  36. pocketdock-1.1.0/mkdocs.yml +65 -0
  37. pocketdock-1.1.0/plan/acceptance-gates.md +214 -0
  38. pocketdock-1.1.0/plan/checklist.md +106 -0
  39. pocketdock-1.1.0/plan/pocketdock-plan.md +2537 -0
  40. pocketdock-1.1.0/pyproject.toml +114 -0
  41. pocketdock-1.1.0/python/pocketdock/__init__.py +183 -0
  42. pocketdock-1.1.0/python/pocketdock/_async_container.py +678 -0
  43. pocketdock-1.1.0/python/pocketdock/_buffer.py +76 -0
  44. pocketdock-1.1.0/python/pocketdock/_callbacks.py +54 -0
  45. pocketdock-1.1.0/python/pocketdock/_config.py +76 -0
  46. pocketdock-1.1.0/python/pocketdock/_helpers.py +181 -0
  47. pocketdock-1.1.0/python/pocketdock/_logger.py +161 -0
  48. pocketdock-1.1.0/python/pocketdock/_process.py +239 -0
  49. pocketdock-1.1.0/python/pocketdock/_session.py +237 -0
  50. pocketdock-1.1.0/python/pocketdock/_socket_client.py +886 -0
  51. pocketdock-1.1.0/python/pocketdock/_stream.py +147 -0
  52. pocketdock-1.1.0/python/pocketdock/_sync_container.py +435 -0
  53. pocketdock-1.1.0/python/pocketdock/async_.py +48 -0
  54. pocketdock-1.1.0/python/pocketdock/cli/__init__.py +2 -0
  55. pocketdock-1.1.0/python/pocketdock/cli/_commands.py +883 -0
  56. pocketdock-1.1.0/python/pocketdock/cli/_output.py +168 -0
  57. pocketdock-1.1.0/python/pocketdock/cli/main.py +86 -0
  58. pocketdock-1.1.0/python/pocketdock/errors.py +96 -0
  59. pocketdock-1.1.0/python/pocketdock/persistence.py +249 -0
  60. pocketdock-1.1.0/python/pocketdock/profiles.py +111 -0
  61. pocketdock-1.1.0/python/pocketdock/projects.py +255 -0
  62. pocketdock-1.1.0/python/pocketdock/py.typed +0 -0
  63. pocketdock-1.1.0/python/pocketdock/types.py +78 -0
  64. pocketdock-1.1.0/tests/__init__.py +0 -0
  65. pocketdock-1.1.0/tests/conftest.py +43 -0
  66. pocketdock-1.1.0/tests/test_buffer.py +189 -0
  67. pocketdock-1.1.0/tests/test_callbacks.py +97 -0
  68. pocketdock-1.1.0/tests/test_cli_integration.py +99 -0
  69. pocketdock-1.1.0/tests/test_cli_output.py +270 -0
  70. pocketdock-1.1.0/tests/test_cli_unit.py +1635 -0
  71. pocketdock-1.1.0/tests/test_concurrent.py +106 -0
  72. pocketdock-1.1.0/tests/test_config.py +151 -0
  73. pocketdock-1.1.0/tests/test_container_async.py +149 -0
  74. pocketdock-1.1.0/tests/test_container_sync.py +100 -0
  75. pocketdock-1.1.0/tests/test_container_unit.py +2068 -0
  76. pocketdock-1.1.0/tests/test_doctor_unit.py +228 -0
  77. pocketdock-1.1.0/tests/test_errors.py +164 -0
  78. pocketdock-1.1.0/tests/test_file_ops_async.py +168 -0
  79. pocketdock-1.1.0/tests/test_file_ops_sync.py +72 -0
  80. pocketdock-1.1.0/tests/test_file_ops_unit.py +289 -0
  81. pocketdock-1.1.0/tests/test_helpers.py +380 -0
  82. pocketdock-1.1.0/tests/test_import.py +162 -0
  83. pocketdock-1.1.0/tests/test_info_integration.py +173 -0
  84. pocketdock-1.1.0/tests/test_logger.py +237 -0
  85. pocketdock-1.1.0/tests/test_persistence_integration.py +247 -0
  86. pocketdock-1.1.0/tests/test_persistence_unit.py +703 -0
  87. pocketdock-1.1.0/tests/test_process_unit.py +432 -0
  88. pocketdock-1.1.0/tests/test_profiles.py +124 -0
  89. pocketdock-1.1.0/tests/test_projects.py +324 -0
  90. pocketdock-1.1.0/tests/test_session_integration.py +162 -0
  91. pocketdock-1.1.0/tests/test_session_unit.py +581 -0
  92. pocketdock-1.1.0/tests/test_socket_client.py +302 -0
  93. pocketdock-1.1.0/tests/test_socket_client_unit.py +1186 -0
  94. pocketdock-1.1.0/tests/test_stream.py +268 -0
  95. pocketdock-1.1.0/tests/test_streaming_integration.py +203 -0
  96. pocketdock-1.1.0/tests/test_types.py +166 -0
@@ -0,0 +1,58 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: astral-sh/setup-uv@v4
15
+ - run: uv sync --dev --all-extras
16
+ - run: uv run ruff check .
17
+ - run: uv run ruff format --check .
18
+ - run: uv run mypy --strict python/pocketdock/
19
+ - run: uv run bandit -r python/pocketdock/ -c pyproject.toml
20
+ - name: Check license headers
21
+ run: |
22
+ find python/pocketdock -name '*.py' | while read f; do
23
+ head -2 "$f" | grep -q 'SPDX-License-Identifier: BSD-2-Clause' || \
24
+ (echo "Missing license header: $f" && exit 1)
25
+ done
26
+
27
+ test:
28
+ runs-on: ubuntu-latest
29
+ strategy:
30
+ matrix:
31
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ - uses: astral-sh/setup-uv@v4
35
+ - run: uv python install ${{ matrix.python-version }}
36
+ - run: uv sync --dev --all-extras --python ${{ matrix.python-version }}
37
+ - run: systemctl --user start podman.socket
38
+ - run: podman build -t pocketdock/minimal images/minimal/
39
+ - name: Run parallel-safe tests
40
+ run: uv run pytest -n auto --ignore=tests/test_persistence_integration.py
41
+ - name: Run serial tests (race-prone)
42
+ run: uv run pytest tests/test_persistence_integration.py --cov-append --cov-fail-under=100
43
+
44
+ docs:
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ - uses: astral-sh/setup-uv@v4
49
+ - run: uv sync --dev
50
+ - run: uv run mkdocs build --strict
51
+
52
+ audit:
53
+ runs-on: ubuntu-latest
54
+ steps:
55
+ - uses: actions/checkout@v4
56
+ - uses: astral-sh/setup-uv@v4
57
+ - run: uv sync --dev
58
+ - run: uv run pip-audit
@@ -0,0 +1,18 @@
1
+ name: Deploy docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ deploy:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: astral-sh/setup-uv@v4
17
+ - run: uv sync --dev
18
+ - run: uv run mkdocs gh-deploy --force
@@ -0,0 +1,18 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ id-token: write
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ environment: pypi
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: astral-sh/setup-uv@v4
17
+ - run: uv build
18
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,51 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ *.egg
7
+ dist/
8
+ build/
9
+ *.whl
10
+
11
+ # Virtual environments
12
+ .venv/
13
+ venv/
14
+
15
+ # uv
16
+ uv.lock
17
+
18
+ # Testing / coverage
19
+ .coverage
20
+ .coverage.*
21
+ htmlcov/
22
+ .pytest_cache/
23
+
24
+ # mypy
25
+ .mypy_cache/
26
+
27
+ # ruff
28
+ .ruff_cache/
29
+
30
+ # IDE
31
+ .vscode/
32
+ .idea/
33
+ *.swp
34
+ *.swo
35
+ *~
36
+
37
+ # OS
38
+ .DS_Store
39
+ Thumbs.db
40
+
41
+ # mkdocs
42
+ site/
43
+
44
+ # pocketdock runtime data
45
+ .pocketdock/
46
+
47
+ # Environment / secrets
48
+ .env
49
+ .env.*
50
+
51
+ .claude
@@ -0,0 +1,24 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.9.0
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: https://github.com/pre-commit/mirrors-mypy
10
+ rev: v1.14.0
11
+ hooks:
12
+ - id: mypy
13
+ additional_dependencies: [click, types-click]
14
+
15
+ - repo: https://github.com/PyCQA/bandit
16
+ rev: "1.8.0"
17
+ hooks:
18
+ - id: bandit
19
+ args: [-c, pyproject.toml]
20
+
21
+ - repo: https://github.com/mgedmin/check-manifest
22
+ rev: "0.50"
23
+ hooks:
24
+ - id: check-manifest
@@ -0,0 +1,201 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.1.0] - 2026-02-11
11
+
12
+ ### Changed
13
+
14
+ - Renamed project from `pocket-dock` to `pocketdock` — package, imports, CLI command, labels, image tags, project directories, and all references
15
+ - PyPI package name: `pocketdock` (was `pocket-dock`)
16
+ - CLI command: `pocketdock` (was `pocket-dock`)
17
+ - Python import: `import pocketdock` (was `import pocket_dock`)
18
+ - Image tags: `pocketdock/minimal` etc. (was `pocket-dock/minimal`)
19
+ - Project directory: `.pocketdock/` (was `.pocket-dock/`)
20
+ - Config file: `pocketdock.yaml` (was `pocket-dock.yaml`)
21
+ - Container labels: `pocketdock.*` (was `pocket-dock.*`)
22
+
23
+ ## [1.0.1] - 2026-02-11
24
+
25
+ ### Changed
26
+
27
+ - Rewrote README as a focused landing page with features list, quick example, and docs links
28
+ - Comprehensive docs site with 17 pages: user guide, CLI reference, API reference, concepts
29
+ - GitHub Pages deployment via `mkdocs gh-deploy` workflow
30
+ - Added `navigation.tabs`, `navigation.top`, and `content.tabs.link` theme features to mkdocs
31
+
32
+ ## [1.0.0] - 2026-02-10
33
+
34
+ ### Added
35
+
36
+ - Four image profiles: `minimal`, `dev`, `agent`, `embedded` — pre-baked Dockerfiles for common use cases
37
+ - `profiles.py` module — `ProfileInfo` dataclass, `resolve_profile()`, `list_profiles()`, `get_dockerfile_path()`
38
+ - `profile` parameter on `create_new_container()` — resolves profile name to image tag automatically
39
+ - `devices` parameter on `create_new_container()` — USB/device passthrough to containers
40
+ - `build_image()`, `save_image()`, `load_image()` socket client methods for image management via engine API
41
+ - CLI `build` command — build profile images from Dockerfiles via socket API
42
+ - CLI `export` command — save images to tar/tar.gz files for air-gap transfer
43
+ - CLI `import` command — load images from tar/tar.gz files
44
+ - CLI `profiles` command — list available profiles (table or `--json`)
45
+ - `--profile` and `--device` options on CLI `create` command
46
+ - Exported `ProfileInfo`, `resolve_profile`, `list_profiles` from `pocketdock` and `pocketdock.async_`
47
+
48
+ ### Changed
49
+
50
+ - Version bump to 1.0.0 — stable API
51
+
52
+ ## [0.9.0] - 2026-02-10
53
+
54
+ ### Added
55
+
56
+ - Full CLI with 17 commands: `init`, `list`, `info`, `doctor`, `status`, `logs`, `create`, `run`, `push`, `pull`, `reboot`, `stop`, `resume`, `shutdown`, `snapshot`, `prune`, `shell`
57
+ - `stop_container()` — stop a running container by name without removing it (sync and async)
58
+ - `--json` flag on read commands (`list`, `info`, `doctor`, `status`, `logs`) for machine-readable output
59
+ - `--stream` and `--detach` flags on `run` for streaming and background execution
60
+ - `--yes/-y` flag on destructive commands (`shutdown`, `prune`) to skip confirmation prompts
61
+ - `--socket` global option and `POCKET_DOCK_SOCKET` env var for engine socket override
62
+ - Rich-formatted output: tables for container lists, panels for info/doctor, colored success/error messages
63
+ - `shell` command — interactive shell via engine CLI passthrough (`podman`/`docker exec -it`)
64
+ - Entry point: `pocketdock` (via `pyproject.toml` console script)
65
+ - `click` and `rich` CLI dependencies (optional `[cli]` extra)
66
+
67
+ ## [0.8.0] - 2026-02-10
68
+
69
+ ### Added
70
+
71
+ - `.pocketdock/` project management — `init_project()`, `find_project_root()`, `get_project_name()`
72
+ - Instance directory lifecycle — `ensure_instance_dir()`, `write_instance_metadata()`, `read_instance_metadata()`, `remove_instance_dir()`, `list_instance_dirs()`
73
+ - `PocketDockConfig` dataclass and `load_config()` with install-level → project-level precedence
74
+ - `pocketdock.yaml` project configuration file with logging and persistence defaults
75
+ - `instance.toml` metadata files per persistent container (container info, resources, provenance)
76
+ - `project` parameter on `create_new_container()` — associates containers with a project
77
+ - `pocketdock.project` and `pocketdock.data-path` labels on persistent containers
78
+ - `list_containers(project=...)` and `prune(project=...)` — filter by project name
79
+ - `destroy_container()` now cleans up the instance directory when `pocketdock.data-path` label is present
80
+ - `InstanceLogger` — auto-logging of `run()` results, session I/O, and detached process output to disk
81
+ - `history.jsonl` command history per instance
82
+ - `doctor()` — cross-references local instance dirs with engine containers to find orphaned containers and stale dirs
83
+ - `DoctorReport` dataclass with `orphaned_containers`, `stale_instance_dirs`, `healthy`
84
+ - `ProjectNotInitialized` exception
85
+ - `PyYAML` and `tomli` (Python < 3.11) added as core dependencies for config/metadata parsing
86
+ - All new functions available as sync (from `pocketdock`) and async (from `pocketdock.async_`)
87
+
88
+ ## [0.7.0] - 2026-02-10
89
+
90
+ ### Added
91
+
92
+ - `persist=True` parameter for `create_new_container()` — container survives `shutdown()` (stop without remove)
93
+ - `volumes` parameter for `create_new_container()` — mount host directories into the container
94
+ - `container.snapshot(image_name)` — commit container filesystem as a new reusable image
95
+ - `container.persist` property — check if container is persistent
96
+ - `resume_container(name)` — resume a stopped persistent container by name
97
+ - `list_containers()` — list all pocketdock managed containers (running and stopped)
98
+ - `destroy_container(name)` — permanently remove a container regardless of persist setting
99
+ - `prune()` — remove all stopped pocketdock managed containers
100
+ - `ContainerListItem` dataclass with `id`, `name`, `status`, `image`, `created_at`, `persist`
101
+ - `pocketdock.persist` and `pocketdock.created-at` labels on all containers
102
+ - `list_containers()` and `commit_container()` socket client methods
103
+ - All new functions available as sync (from `pocketdock`) and async (from `pocketdock.async_`)
104
+
105
+ ## [0.6.0] - 2026-02-09
106
+
107
+ ### Added
108
+
109
+ - `AsyncSession` / `Session` — persistent shell sessions with state persistence (cwd, env vars, shell history)
110
+ - `session()` method on `AsyncContainer` and `Container` to open a persistent shell
111
+ - `send()` — fire-and-forget command to the shell
112
+ - `send_and_wait()` — send a command and wait for completion with exit code, stdout, stderr, and duration
113
+ - `read()` — drain accumulated output from the session (thread-safe)
114
+ - `on_output()` — register callbacks for session output
115
+ - `close()` — close the session without stopping the container
116
+ - Sentinel protocol (`__PD_{uuid}_${?}__`) for reliable command boundary and exit code detection
117
+ - `SessionClosed` error for operations on closed sessions
118
+ - `attach_stdin` support in socket client `_exec_create()` for bidirectional exec connections
119
+ - Automatic session cleanup during `shutdown()`
120
+ - Exported `AsyncSession` from `pocketdock.async_` and `Session` (alias for `SyncSession`) from `pocketdock`
121
+
122
+ ## [0.5.0] - 2026-02-08
123
+
124
+ ### Added
125
+
126
+ - `run(stream=True)` — streaming mode returns `AsyncExecStream` / `ExecStream` async iterator yielding `StreamChunk` objects in real-time
127
+ - `run(detach=True)` — detached mode returns `AsyncProcess` / `Process` handle for background execution
128
+ - `StreamChunk` dataclass with `stream` ("stdout"/"stderr") and `data` fields
129
+ - `AsyncExecStream` / `ExecStream` — async iterator with `.result` property after iteration
130
+ - `AsyncProcess` / `Process` — detached process handle with `id`, `is_running()`, `kill()`, `wait()`, `read()`, `peek()`, `buffer_size`, `buffer_overflow`
131
+ - `RingBuffer` — thread-safe bounded ring buffer (1 MB default) for detached process output
132
+ - `BufferSnapshot` dataclass with `stdout` and `stderr` strings
133
+ - `CallbackRegistry` — register callbacks for stdout, stderr, and exit events
134
+ - `on_stdout()`, `on_stderr()`, `on_exit()` callback methods on `AsyncContainer` and `Container`
135
+ - `demux_stream_iter()` — incremental async generator for stream frame parsing
136
+ - `_exec_start_stream()` — streaming exec with Docker chunked TE and Podman raw stream support
137
+ - `_demux_chunked_stream()` — handles misalignment between HTTP chunk and demux frame boundaries
138
+ - Automatic cleanup of active streams and processes in `shutdown()`
139
+ - `@overload` type signatures on `run()` for all three output modes
140
+ - Exported `ExecStream`, `Process`, `BufferSnapshot`, `StreamChunk` from `pocketdock`
141
+ - Exported `AsyncExecStream`, `AsyncProcess` from `pocketdock.async_`
142
+
143
+ ## [0.4.0] - 2026-02-08
144
+
145
+ ### Added
146
+
147
+ - `info()` — live container snapshot: status, uptime, memory, CPU, PIDs, processes, network
148
+ - `reboot()` — restart in place; `reboot(fresh=True)` recreates with same config
149
+ - `mem_limit` parameter for `create_new_container()` (e.g. `"256m"`, `"1g"`)
150
+ - `cpu_percent` parameter for `create_new_container()` (e.g. `50` for 50% CPU cap)
151
+ - `ContainerInfo` dataclass with 15 fields for container introspection
152
+ - `get_container_stats()`, `get_container_top()`, `restart_container()` socket client endpoints
153
+ - `_helpers.py` module with `format_bytes`, `parse_mem_limit`, `parse_iso_timestamp`, `compute_cpu_percent`
154
+ - Resource limits via `HostConfig` (`Memory`, `NanoCpus`) in container creation
155
+ - All new methods available on both `AsyncContainer` (async) and `Container` (sync)
156
+
157
+ ## [0.3.0] - 2026-02-07
158
+
159
+ ### Added
160
+
161
+ - `write_file()` — write text or binary content into the container via tar archive API
162
+ - `read_file()` — read file contents from the container via tar archive API
163
+ - `list_files()` — list directory contents inside the container
164
+ - `push()` — copy a file or directory from the host into the container
165
+ - `pull()` — copy a file or directory from the container to the host
166
+ - `push_archive()` and `pull_archive()` in socket client for raw tar transfer
167
+ - All methods available on both `AsyncContainer` (async) and `Container` (sync)
168
+
169
+ ## [0.2.0] - 2026-02-07
170
+
171
+ ### Added
172
+
173
+ - `AsyncContainer` class with async `run()`, `shutdown()`, and context manager
174
+ - `Container` class (sync facade) with background event loop thread
175
+ - `create_new_container()` factory function (sync in `pocketdock`, async in `pocketdock.async_`)
176
+ - Blocking `run()` with configurable timeout and output capping
177
+ - `lang` parameter for `run()` (e.g. `lang="python"` wraps command with `python3 -c`)
178
+ - Timeout support in `exec_command` via `asyncio.wait_for`
179
+ - Container labels (`pocketdock.managed`, `pocketdock.instance`) for discovery
180
+ - Auto-generated container names (`pd-{8 hex}`)
181
+ - Multiple independent containers from a single process
182
+ - Thread-safe sync facade via `asyncio.run_coroutine_threadsafe`
183
+
184
+ ## [0.1.0] - 2026-02-07
185
+
186
+ ### Added
187
+
188
+ - Project scaffold: README, CONTRIBUTING, LICENSE (BSD-2-Clause), docs site, CI pipeline
189
+ - Async socket client over Unix socket (`_socket_client.py`)
190
+ - HTTP/1.1 request/response over Unix domain sockets
191
+ - Stream demultiplexing for Docker/Podman exec stream protocol (`_stream.py`)
192
+ - Podman and Docker socket auto-detection
193
+ - Container lifecycle operations: create, start, stop, remove, inspect
194
+ - Exec command with stdout/stderr demux and exit code retrieval
195
+ - Error hierarchy: `PocketDockError`, `SocketError`, `ContainerError`, `ImageNotFound`
196
+ - `ExecResult` dataclass with `ok` property, timing, and truncation tracking
197
+ - Minimal container image Dockerfile (Alpine 3.21 + Python + bash, ~25MB)
198
+ - GitHub Actions CI: lint + test matrix (Python 3.10-3.13) + docs + audit
199
+ - Pre-commit hooks: ruff, mypy, bandit, check-manifest
200
+ - mkdocs-material documentation site
201
+ - PEP 561 `py.typed` marker for type checking support
@@ -0,0 +1,56 @@
1
+ # Contributing to pocketdock
2
+
3
+ ## Development Setup
4
+
5
+ ```bash
6
+ # Clone the repo
7
+ git clone https://github.com/deftio/pocketdock.git
8
+ cd pocketdock
9
+
10
+ # Install uv (if not already installed)
11
+ curl -LsSf https://astral.sh/uv/install.sh | sh
12
+
13
+ # Install all dependencies
14
+ uv sync --dev
15
+
16
+ # Install pre-commit hooks
17
+ uv run pre-commit install
18
+ ```
19
+
20
+ ## Quality Bar
21
+
22
+ Every commit must pass:
23
+
24
+ - **100% line coverage** — no `# pragma: no cover`, no exclusions
25
+ - **Zero ruff warnings** — `select = ["ALL"]`, `ignore = ["D1"]`
26
+ - **mypy --strict clean** — every function has type annotations
27
+ - **bandit clean** — security linting for socket/file/tar operations
28
+ - **BSD-2-Clause SPDX header** in every `.py` source file under `python/pocketdock/`
29
+
30
+ ## Running Checks
31
+
32
+ ```bash
33
+ uv run ruff check . # Lint
34
+ uv run ruff format --check . # Format check
35
+ uv run mypy --strict python/pocketdock/ # Type check
36
+ uv run bandit -r python/pocketdock/ -c pyproject.toml # Security lint
37
+ uv run pytest # Tests (100% coverage)
38
+ ```
39
+
40
+ ## Test Strategy
41
+
42
+ All tests are integration tests against a real Podman socket. No mocks.
43
+
44
+ - Tests skip gracefully if no Podman socket is found locally
45
+ - CI always has Podman available — all tests must pass there
46
+ - Use the `minimal` profile (~25MB, <500ms startup) for tests
47
+
48
+ ## Git Workflow
49
+
50
+ - **Branch naming**: `{type}/{description}` — e.g., `feat/m1-blocking-run`, `fix/stream-demux`
51
+ - **Commit messages**: Conventional prefix — `feat:`, `fix:`, `test:`, `docs:`, `ci:`, `refactor:`
52
+ - **Development cycle**: TDD — write tests first, red, implement, green, full lint suite, doc sync, PR
53
+
54
+ ## License
55
+
56
+ By contributing, you agree that your contributions will be licensed under the BSD-2-Clause license.
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) deftio llc
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: pocketdock
3
+ Version: 1.1.0
4
+ Summary: Portable, offline-first container sandboxes for LLM agents and dev workflows
5
+ Author: deftio llc
6
+ License-Expression: BSD-2-Clause
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: BSD License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: pyyaml>=6.0
19
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
20
+ Provides-Extra: cli
21
+ Requires-Dist: click; extra == 'cli'
22
+ Requires-Dist: rich; extra == 'cli'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # pocketdock
26
+
27
+ [![CI](https://github.com/deftio/pocketdock/actions/workflows/ci.yml/badge.svg)](https://github.com/deftio/pocketdock/actions/workflows/ci.yml)
28
+ [![Coverage: 100%](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/deftio/pocketdock/actions/workflows/ci.yml)
29
+ [![Docs](https://img.shields.io/badge/docs-deftio.github.io%2Fpocket--dock-blue)](https://deftio.github.io/pocketdock/)
30
+ [![License: BSD-2-Clause](https://img.shields.io/badge/License-BSD_2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause)
31
+
32
+ **Portable, offline-first container sandboxes for LLM agents and dev workflows.**
33
+
34
+ One Container class. Podman-first, Docker-compatible. Python SDK + CLI. Zero cloud. Zero API keys.
35
+
36
+ ## Why pocketdock?
37
+
38
+ Managed sandbox platforms require API keys, cloud accounts, and an internet connection. Rolling your own container glue means rewriting hundreds of lines of boilerplate every time. pocketdock sits in between: a clean Python SDK that talks directly to your container engine over its Unix socket, works entirely offline, and has zero external dependencies for the core SDK.
39
+
40
+ ## Features
41
+
42
+ - **Three execution modes** — blocking, streaming, and detached (background) with ring buffer
43
+ - **File operations** — read, write, list, push, and pull files between host and container
44
+ - **Persistent sessions** — long-lived shell sessions with state (cwd, env vars, history)
45
+ - **Resource limits** — memory caps, CPU throttling, per-container isolation
46
+ - **Container persistence** — stop/resume, snapshot to image, volume mounts
47
+ - **Project management** — `.pocketdock/` project directories with config, logging, and health checks
48
+ - **Image profiles** — four pre-baked Dockerfiles: minimal, dev, agent, embedded
49
+ - **Full CLI** — 21 commands for container lifecycle, file ops, and project management
50
+ - **Async-first** — sync facade over async core; use either API style
51
+ - **Callbacks** — register handlers for stdout, stderr, and exit events
52
+
53
+ ## Quick Example
54
+
55
+ ```python
56
+ from pocketdock import create_new_container
57
+
58
+ with create_new_container() as c:
59
+ result = c.run("echo hello")
60
+ print(result.stdout) # "hello\n"
61
+ print(result.ok) # True
62
+ ```
63
+
64
+ ## Install
65
+
66
+ ```bash
67
+ pip install pocketdock # SDK only (zero dependencies)
68
+ pip install pocketdock[cli] # SDK + CLI (click, rich)
69
+ ```
70
+
71
+ Requires [Podman](https://podman.io/getting-started/installation) (recommended) or [Docker](https://docs.docker.com/get-docker/).
72
+
73
+ ```bash
74
+ # Build the minimal image (~25MB, <500ms startup)
75
+ pocketdock build minimal
76
+ ```
77
+
78
+ ## Documentation
79
+
80
+ Full documentation is available at **[deftio.github.io/pocketdock](https://deftio.github.io/pocketdock/)**.
81
+
82
+ - [Quickstart](https://deftio.github.io/pocketdock/quickstart/) — install, build, run your first container
83
+ - [User Guide](https://deftio.github.io/pocketdock/guide/containers/) — containers, commands, files, sessions, persistence, profiles
84
+ - [CLI Reference](https://deftio.github.io/pocketdock/cli/) — all 21 commands with examples
85
+ - [API Reference](https://deftio.github.io/pocketdock/reference/api/) — full SDK reference
86
+
87
+ ## Architecture
88
+
89
+ ```
90
+ User Code / LLM Agent / CLI
91
+ |
92
+ v
93
+ pocketdock SDK
94
+ +--------------------------------------+
95
+ | Container (sync) -> AsyncContainer | facade pattern
96
+ | +- _socket_client (raw HTTP/Unix) |
97
+ +- ProjectManager (.pocketdock/) |
98
+ +- Persistence (resume, snapshot) |
99
+ +- Sessions (persistent shells) |
100
+ +--------------------------------------+
101
+ | raw HTTP over Unix socket
102
+ | (one connection per operation)
103
+ v
104
+ Podman (rootless) / Docker Engine
105
+ ```
106
+
107
+ **Design principles:**
108
+
109
+ - **Connection-per-operation** — each API call opens its own Unix socket. No pooling.
110
+ - **Async core, sync facade** — `AsyncContainer` does all real work. `Container` is a sync wrapper.
111
+ - **No cached state** — always polls live from the engine.
112
+ - **Minimal dependencies** — stdlib-only for the core SDK.
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ uv sync --dev # Install dependencies
118
+ uv run pytest # Run tests (100% coverage enforced)
119
+ uv run ruff check . # Lint (zero warnings)
120
+ uv run mypy --strict python/ # Type checking (strict mode)
121
+ uv run mkdocs serve # Local docs site
122
+ ```
123
+
124
+ ## License
125
+
126
+ BSD-2-Clause. Copyright (c) deftio llc.