codeforge-dev 1.4.0

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 (131) hide show
  1. package/.devcontainer/.env +22 -0
  2. package/.devcontainer/CHANGELOG.md +197 -0
  3. package/.devcontainer/CLAUDE.md +117 -0
  4. package/.devcontainer/README.md +222 -0
  5. package/.devcontainer/config/main-system-prompt.md +502 -0
  6. package/.devcontainer/config/settings.json +47 -0
  7. package/.devcontainer/devcontainer.json +94 -0
  8. package/.devcontainer/features/README.md +113 -0
  9. package/.devcontainer/features/agent-browser/README.md +65 -0
  10. package/.devcontainer/features/agent-browser/devcontainer-feature.json +23 -0
  11. package/.devcontainer/features/agent-browser/install.sh +79 -0
  12. package/.devcontainer/features/ast-grep/README.md +24 -0
  13. package/.devcontainer/features/ast-grep/devcontainer-feature.json +24 -0
  14. package/.devcontainer/features/ast-grep/install.sh +51 -0
  15. package/.devcontainer/features/ccstatusline/README.md +296 -0
  16. package/.devcontainer/features/ccstatusline/devcontainer-feature.json +19 -0
  17. package/.devcontainer/features/ccstatusline/install.sh +290 -0
  18. package/.devcontainer/features/ccusage/README.md +205 -0
  19. package/.devcontainer/features/ccusage/devcontainer-feature.json +38 -0
  20. package/.devcontainer/features/ccusage/install.sh +132 -0
  21. package/.devcontainer/features/claude-code/README.md +498 -0
  22. package/.devcontainer/features/claude-code/config/settings.json +36 -0
  23. package/.devcontainer/features/claude-code/config/system-prompt.md +118 -0
  24. package/.devcontainer/features/claude-code/config/world-building-sp.md +1432 -0
  25. package/.devcontainer/features/claude-code/devcontainer-feature.json +42 -0
  26. package/.devcontainer/features/claude-code/install.sh +466 -0
  27. package/.devcontainer/features/claude-monitor/README.md +74 -0
  28. package/.devcontainer/features/claude-monitor/devcontainer-feature.json +38 -0
  29. package/.devcontainer/features/claude-monitor/install.sh +99 -0
  30. package/.devcontainer/features/lsp-servers/README.md +85 -0
  31. package/.devcontainer/features/lsp-servers/devcontainer-feature.json +40 -0
  32. package/.devcontainer/features/lsp-servers/install.sh +116 -0
  33. package/.devcontainer/features/mcp-qdrant/CHANGES.md +399 -0
  34. package/.devcontainer/features/mcp-qdrant/README.md +474 -0
  35. package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +57 -0
  36. package/.devcontainer/features/mcp-qdrant/install.sh +295 -0
  37. package/.devcontainer/features/mcp-qdrant/poststart-hook.sh +129 -0
  38. package/.devcontainer/features/mcp-reasoner/README.md +177 -0
  39. package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +20 -0
  40. package/.devcontainer/features/mcp-reasoner/install.sh +177 -0
  41. package/.devcontainer/features/mcp-reasoner/poststart-hook.sh +67 -0
  42. package/.devcontainer/features/notify-hook/README.md +86 -0
  43. package/.devcontainer/features/notify-hook/devcontainer-feature.json +23 -0
  44. package/.devcontainer/features/notify-hook/install.sh +38 -0
  45. package/.devcontainer/features/splitrail/README.md +140 -0
  46. package/.devcontainer/features/splitrail/devcontainer-feature.json +34 -0
  47. package/.devcontainer/features/splitrail/install.sh +129 -0
  48. package/.devcontainer/features/tree-sitter/README.md +138 -0
  49. package/.devcontainer/features/tree-sitter/devcontainer-feature.json +52 -0
  50. package/.devcontainer/features/tree-sitter/install.sh +173 -0
  51. package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +106 -0
  52. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +7 -0
  53. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +17 -0
  54. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-file.py +101 -0
  55. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +7 -0
  56. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +17 -0
  57. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +137 -0
  58. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/.claude-plugin/plugin.json +8 -0
  59. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/SKILL.md +387 -0
  60. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/cli-flags-and-output.md +312 -0
  61. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/sdk-and-mcp.md +569 -0
  62. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/SKILL.md +309 -0
  63. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/compose-services.md +438 -0
  64. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/dockerfile-patterns.md +340 -0
  65. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/SKILL.md +412 -0
  66. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/container-lifecycle.md +388 -0
  67. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/resources-and-security.md +444 -0
  68. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/SKILL.md +344 -0
  69. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/middleware-and-lifespan.md +254 -0
  70. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/pydantic-models.md +245 -0
  71. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/routing-and-dependencies.md +255 -0
  72. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/sse-and-streaming.md +318 -0
  73. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/SKILL.md +345 -0
  74. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/agents-and-tools.md +271 -0
  75. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/models-and-streaming.md +422 -0
  76. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/SKILL.md +220 -0
  77. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/cross-vendor-principles.md +139 -0
  78. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/patterns-and-antipatterns.md +376 -0
  79. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/skill-authoring-patterns.md +356 -0
  80. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/SKILL.md +329 -0
  81. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/advanced-queries.md +314 -0
  82. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/javascript-patterns.md +323 -0
  83. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/python-patterns.md +354 -0
  84. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/schema-and-pragmas.md +326 -0
  85. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/SKILL.md +356 -0
  86. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/ai-sdk-svelte.md +128 -0
  87. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/component-patterns.md +332 -0
  88. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/layercake.md +203 -0
  89. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/migration-guide.md +350 -0
  90. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/runes-and-reactivity.md +328 -0
  91. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/spa-and-routing.md +262 -0
  92. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/svelte-dnd-action.md +181 -0
  93. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/SKILL.md +414 -0
  94. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/fastapi-testing.md +411 -0
  95. package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/svelte-testing.md +538 -0
  96. package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/.claude-plugin/plugin.json +7 -0
  97. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/.claude-plugin/plugin.json +7 -0
  98. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/hooks/hooks.json +17 -0
  99. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +110 -0
  100. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/.claude-plugin/plugin.json +7 -0
  101. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +17 -0
  102. package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/.claude-plugin/plugin.json +7 -0
  103. package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/hooks/hooks.json +17 -0
  104. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/.claude-plugin/plugin.json +7 -0
  105. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/hooks/hooks.json +17 -0
  106. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +108 -0
  107. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272create-pr.md +337 -0
  108. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272new.md +166 -0
  109. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272review-commit.md +290 -0
  110. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272work.md +257 -0
  111. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json +8 -0
  112. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md +184 -0
  113. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/.claude-plugin/plugin.json +6 -0
  114. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/config/planning-instructions.md +14 -0
  115. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md +989 -0
  116. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/hooks/hooks.json +33 -0
  117. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/__pycache__/post-enhance-task.cpython-314.pyc +0 -0
  118. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhance-planning.py +71 -0
  119. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-plan.sh +68 -0
  120. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-task.sh +120 -0
  121. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-plan.py +133 -0
  122. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-task.py +253 -0
  123. package/.devcontainer/scripts/setup-aliases.sh +80 -0
  124. package/.devcontainer/scripts/setup-config.sh +28 -0
  125. package/.devcontainer/scripts/setup-irie-claude.sh +32 -0
  126. package/.devcontainer/scripts/setup-plugins.sh +80 -0
  127. package/.devcontainer/scripts/setup.sh +58 -0
  128. package/LICENSE.txt +674 -0
  129. package/README.md +267 -0
  130. package/package.json +44 -0
  131. package/setup.js +83 -0
@@ -0,0 +1,444 @@
1
+ # Resources and Security -- Deep Dive
2
+
3
+ ## 1. Volume Management
4
+
5
+ ### CRUD Operations
6
+
7
+ ```python
8
+ # Create
9
+ volume = client.volumes.create(
10
+ name="app-data",
11
+ driver="local",
12
+ driver_opts={"type": "tmpfs", "device": "tmpfs", "o": "size=100m"},
13
+ labels={"env": "production"},
14
+ )
15
+
16
+ # List
17
+ volumes = client.volumes.list()
18
+ volumes = client.volumes.list(filters={"label": "env=production"})
19
+
20
+ # Get by name
21
+ volume = client.volumes.get("app-data")
22
+ print(volume.name)
23
+ print(volume.attrs)
24
+
25
+ # Remove
26
+ volume.remove(force=False)
27
+
28
+ # Prune unused
29
+ result = client.volumes.prune(filters={"label": "env=staging"})
30
+ ```
31
+
32
+ ### Using Volumes with Containers
33
+
34
+ **Dict syntax:**
35
+
36
+ ```python
37
+ container = client.containers.run(
38
+ "postgres:16",
39
+ detach=True,
40
+ volumes={
41
+ "pgdata": {"bind": "/var/lib/postgresql/data", "mode": "rw"},
42
+ "/host/backups": {"bind": "/backups", "mode": "ro"},
43
+ },
44
+ )
45
+ ```
46
+
47
+ **Mount objects (preferred):**
48
+
49
+ ```python
50
+ from docker.types import Mount
51
+
52
+ container = client.containers.run(
53
+ "postgres:16",
54
+ detach=True,
55
+ mounts=[
56
+ Mount(target="/var/lib/postgresql/data", source="pgdata", type="volume"),
57
+ Mount(target="/backups", source="/host/backups", type="bind", read_only=True),
58
+ Mount(target="/tmp", type="tmpfs", tmpfs_size=100 * 1024 * 1024),
59
+ ],
60
+ )
61
+ ```
62
+
63
+ Mount types: `"volume"` (managed by Docker), `"bind"` (host path), `"tmpfs"` (memory-backed).
64
+
65
+ ---
66
+
67
+ ## 2. Bind Mount Patterns
68
+
69
+ ### Read-Only Configuration
70
+
71
+ ```python
72
+ from docker.types import Mount
73
+
74
+ mounts = [
75
+ Mount(target="/app/config", source="/etc/myapp", type="bind", read_only=True),
76
+ ]
77
+ ```
78
+
79
+ ### Writable Data Directory
80
+
81
+ ```python
82
+ mounts = [
83
+ Mount(target="/app/data", source="/var/lib/myapp", type="bind", read_only=False),
84
+ ]
85
+ ```
86
+
87
+ ### Bind Mount Security Considerations
88
+
89
+ - Bind mounts expose host filesystem paths directly to the container.
90
+ - A writable bind mount to a sensitive host path (e.g., `/`, `/etc`, `/var/run/docker.sock`) grants significant host access.
91
+ - Prefer named volumes for application data. Use bind mounts only for configuration injection or development workflows.
92
+ - Mount the Docker socket (`/var/run/docker.sock`) only when container management is an explicit requirement, and combine with read-only root filesystem and dropped capabilities.
93
+
94
+ ---
95
+
96
+ ## 3. Network Operations
97
+
98
+ ### Create Networks
99
+
100
+ ```python
101
+ # Basic bridge network
102
+ network = client.networks.create("app-net", driver="bridge")
103
+
104
+ # With IPAM configuration
105
+ import docker.types
106
+ ipam_pool = docker.types.IPAMPool(subnet="192.168.52.0/24", gateway="192.168.52.254")
107
+ ipam_config = docker.types.IPAMConfig(pool_configs=[ipam_pool])
108
+
109
+ network = client.networks.create(
110
+ "app-net",
111
+ driver="bridge",
112
+ ipam=ipam_config,
113
+ internal=False,
114
+ attachable=True,
115
+ labels={"env": "dev"},
116
+ )
117
+ ```
118
+
119
+ ### Connect and Disconnect
120
+
121
+ ```python
122
+ # Connect with aliases (DNS names within the network)
123
+ network.connect(container, aliases=["web-app", "frontend"])
124
+
125
+ # Connect with static IP
126
+ network.connect(container, ipv4_address="192.168.52.10")
127
+
128
+ # Disconnect
129
+ network.disconnect(container, force=False)
130
+ ```
131
+
132
+ ### Inspect Connected Containers
133
+
134
+ ```python
135
+ network.reload()
136
+ for c in network.containers:
137
+ print(f"{c.name}: {c.status}")
138
+ ```
139
+
140
+ ### Remove and Prune
141
+
142
+ ```python
143
+ network.remove()
144
+ client.networks.prune(filters={"until": "24h"})
145
+ ```
146
+
147
+ ---
148
+
149
+ ## 4. Resource Limits
150
+
151
+ ### Memory
152
+
153
+ ```python
154
+ container = client.containers.run(
155
+ "myapp",
156
+ detach=True,
157
+ mem_limit="512m", # hard limit: "100000b", "1000k", "128m", "1g"
158
+ mem_reservation="256m", # soft limit
159
+ memswap_limit="1g", # memory + swap combined
160
+ oom_kill_disable=False, # keep OOM killer enabled
161
+ )
162
+ ```
163
+
164
+ ### CPU
165
+
166
+ ```python
167
+ container = client.containers.run(
168
+ "myapp",
169
+ detach=True,
170
+ nano_cpus=500_000_000, # 0.5 CPU (units: 1e-9 CPUs)
171
+ cpuset_cpus="0-3", # pin to specific CPUs
172
+ cpu_shares=1024, # relative weight (default 1024)
173
+ )
174
+ ```
175
+
176
+ Alternative CPU limit via CFS quota:
177
+
178
+ ```python
179
+ container = client.containers.run(
180
+ "myapp",
181
+ detach=True,
182
+ cpu_period=100000, # CFS period in microseconds
183
+ cpu_quota=50000, # 50% of one CPU
184
+ )
185
+ ```
186
+
187
+ ### Block I/O
188
+
189
+ ```python
190
+ container = client.containers.run(
191
+ "myapp",
192
+ detach=True,
193
+ blkio_weight=500,
194
+ device_read_bps=[{"Path": "/dev/sda", "Rate": 1048576}], # 1 MB/s
195
+ device_write_bps=[{"Path": "/dev/sda", "Rate": 1048576}],
196
+ )
197
+ ```
198
+
199
+ ### PID Limit
200
+
201
+ ```python
202
+ container = client.containers.run("myapp", detach=True, pids_limit=100)
203
+ ```
204
+
205
+ ### Runtime Updates
206
+
207
+ Update resource limits on a running container:
208
+
209
+ ```python
210
+ container.update(
211
+ mem_limit="1g",
212
+ cpu_shares=2048,
213
+ restart_policy={"Name": "on-failure", "MaximumRetryCount": 5},
214
+ )
215
+ ```
216
+
217
+ ---
218
+
219
+ ## 5. Security Options
220
+
221
+ ### Capabilities
222
+
223
+ Drop all capabilities and add only what is needed:
224
+
225
+ ```python
226
+ container = client.containers.run(
227
+ "myapp",
228
+ detach=True,
229
+ cap_drop=["ALL"],
230
+ cap_add=["NET_BIND_SERVICE"], # bind to ports < 1024
231
+ )
232
+ ```
233
+
234
+ Common capabilities:
235
+ - `NET_ADMIN`: network configuration
236
+ - `SYS_PTRACE`: debugging, strace
237
+ - `NET_BIND_SERVICE`: bind to privileged ports
238
+ - `DAC_OVERRIDE`: bypass file permission checks
239
+
240
+ ### Read-Only Root Filesystem
241
+
242
+ ```python
243
+ container = client.containers.run(
244
+ "myapp",
245
+ detach=True,
246
+ read_only=True,
247
+ tmpfs={"/tmp": "size=100m", "/run": "size=10m"},
248
+ )
249
+ ```
250
+
251
+ Combine `read_only=True` with `tmpfs` for directories that need write access. This prevents runtime modification of application code.
252
+
253
+ ### Security Labels and Options
254
+
255
+ ```python
256
+ container = client.containers.run(
257
+ "myapp",
258
+ detach=True,
259
+ security_opt=[
260
+ "no-new-privileges", # prevent privilege escalation
261
+ "label:type:svirt_apache_t", # SELinux label
262
+ ],
263
+ )
264
+ ```
265
+
266
+ ### Namespace Isolation
267
+
268
+ ```python
269
+ container = client.containers.run(
270
+ "myapp",
271
+ detach=True,
272
+ ipc_mode="private", # isolate IPC namespace
273
+ pid_mode="container:other", # share PID namespace with another container
274
+ network_mode="none", # no network access
275
+ userns_mode="host", # share host user namespace
276
+ )
277
+ ```
278
+
279
+ ### Non-Root User
280
+
281
+ ```python
282
+ container = client.containers.run(
283
+ "myapp",
284
+ detach=True,
285
+ user="1000:1000", # UID:GID
286
+ )
287
+ ```
288
+
289
+ ### GPU Access
290
+
291
+ ```python
292
+ import docker.types
293
+
294
+ container = client.containers.run(
295
+ "nvidia/cuda:12.0-runtime",
296
+ detach=True,
297
+ device_requests=[
298
+ docker.types.DeviceRequest(count=-1, capabilities=[["gpu"]]), # all GPUs
299
+ ],
300
+ )
301
+ ```
302
+
303
+ ---
304
+
305
+ ## 6. Image Management
306
+
307
+ ### Pull
308
+
309
+ ```python
310
+ image = client.images.pull("python", tag="3.12-slim")
311
+
312
+ # With authentication
313
+ image = client.images.pull(
314
+ "registry.example.com/private/app",
315
+ auth_config={"username": "user", "password": "token"},
316
+ )
317
+ ```
318
+
319
+ ### Build
320
+
321
+ ```python
322
+ image, build_logs = client.images.build(
323
+ path="/path/to/context",
324
+ tag="myapp:latest",
325
+ nocache=False,
326
+ buildargs={"VERSION": "1.0", "ENV": "production"},
327
+ target="production", # multi-stage target
328
+ platform="linux/amd64",
329
+ rm=True, # remove intermediate containers
330
+ )
331
+
332
+ for log_line in build_logs:
333
+ if "stream" in log_line:
334
+ print(log_line["stream"], end="")
335
+ ```
336
+
337
+ ### Tag and Push
338
+
339
+ ```python
340
+ image = client.images.get("myapp:latest")
341
+ image.tag("registry.example.com/myapp", tag="v1.0")
342
+ client.images.push("registry.example.com/myapp", tag="v1.0")
343
+ ```
344
+
345
+ ### Save and Load
346
+
347
+ ```python
348
+ # Export to tarball
349
+ image = client.images.get("myapp:latest")
350
+ with open("/tmp/myapp.tar", "wb") as f:
351
+ for chunk in image.save(named=True):
352
+ f.write(chunk)
353
+
354
+ # Import from tarball
355
+ with open("/tmp/myapp.tar", "rb") as f:
356
+ images = client.images.load(f.read())
357
+ ```
358
+
359
+ ---
360
+
361
+ ## 7. Error Handling Reference
362
+
363
+ ```python
364
+ from docker.errors import (
365
+ ContainerError, # non-zero exit code (detach=False)
366
+ ImageNotFound, # image does not exist
367
+ NotFound, # container/resource not found
368
+ APIError, # general Docker daemon error
369
+ BuildError, # image build failure
370
+ )
371
+ from requests.exceptions import ReadTimeout, ConnectionError
372
+
373
+ try:
374
+ container = client.containers.run("myapp", detach=True)
375
+ container.wait(timeout=60)
376
+ except ImageNotFound:
377
+ # Image needs to be pulled or built
378
+ client.images.pull("myapp", tag="latest")
379
+ except NotFound:
380
+ # Container was removed (e.g., auto-remove)
381
+ pass
382
+ except ContainerError as e:
383
+ print(f"Exit code: {e.exit_status}")
384
+ print(f"Output: {e.stderr.decode()}")
385
+ except ReadTimeout:
386
+ # wait() timed out
387
+ container.stop(timeout=5)
388
+ except APIError as e:
389
+ print(f"Docker API error: {e.status_code} {e.explanation}")
390
+ ```
391
+
392
+ ---
393
+
394
+ ## 8. aiodocker -- Async Alternative
395
+
396
+ For asyncio applications, `aiodocker` provides native async/await support:
397
+
398
+ ```python
399
+ import aiodocker
400
+
401
+ async def run_container():
402
+ docker = aiodocker.Docker()
403
+ try:
404
+ container = await docker.containers.create_or_replace(
405
+ config={
406
+ "Cmd": ["python", "-c", "print('hello')"],
407
+ "Image": "python:3.12-slim",
408
+ },
409
+ name="async-worker",
410
+ )
411
+ await container.start()
412
+
413
+ # Stream logs
414
+ async for line in container.log(stdout=True, follow=True):
415
+ print(line)
416
+
417
+ await container.wait()
418
+ await container.delete(force=True)
419
+ finally:
420
+ await docker.close()
421
+ ```
422
+
423
+ ### Key Differences from docker-py
424
+
425
+ | Aspect | docker-py | aiodocker |
426
+ |--------|-----------|-----------|
427
+ | Style | Synchronous (blocking) | Asyncio-native |
428
+ | Config format | Keyword arguments | Raw Docker Engine API dicts |
429
+ | Client cleanup | Implicit | Explicit `await docker.close()` |
430
+ | Method names | `run()`, `remove()`, `logs()` | `create_or_replace()`, `delete()`, `log()` |
431
+ | Streaming | Thread-blocking generators | Async iterators |
432
+
433
+ ### When to Use aiodocker
434
+
435
+ - The application already runs an asyncio event loop (FastAPI, aiohttp).
436
+ - Container operations happen alongside other async I/O (database queries, HTTP requests).
437
+ - Log streaming needs to be non-blocking.
438
+
439
+ ### When to Use docker-py
440
+
441
+ - Scripts and CLI tools.
442
+ - Synchronous applications.
443
+ - The official `docker` library is needed for compatibility.
444
+ - Higher-level convenience methods (`run()`, `exec_run()`) are preferred over raw API dicts.