contree-mcp 0.1.0__py3-none-any.whl

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 (46) hide show
  1. contree_mcp/__init__.py +0 -0
  2. contree_mcp/__main__.py +25 -0
  3. contree_mcp/app.py +240 -0
  4. contree_mcp/arguments.py +35 -0
  5. contree_mcp/auth/__init__.py +2 -0
  6. contree_mcp/auth/registry.py +236 -0
  7. contree_mcp/backend_types.py +301 -0
  8. contree_mcp/cache.py +208 -0
  9. contree_mcp/client.py +711 -0
  10. contree_mcp/context.py +53 -0
  11. contree_mcp/docs.py +1203 -0
  12. contree_mcp/file_cache.py +381 -0
  13. contree_mcp/prompts.py +238 -0
  14. contree_mcp/py.typed +0 -0
  15. contree_mcp/resources/__init__.py +17 -0
  16. contree_mcp/resources/guide.py +715 -0
  17. contree_mcp/resources/image_lineage.py +46 -0
  18. contree_mcp/resources/image_ls.py +32 -0
  19. contree_mcp/resources/import_operation.py +52 -0
  20. contree_mcp/resources/instance_operation.py +52 -0
  21. contree_mcp/resources/read_file.py +33 -0
  22. contree_mcp/resources/static.py +12 -0
  23. contree_mcp/server.py +77 -0
  24. contree_mcp/tools/__init__.py +39 -0
  25. contree_mcp/tools/cancel_operation.py +36 -0
  26. contree_mcp/tools/download.py +128 -0
  27. contree_mcp/tools/get_guide.py +54 -0
  28. contree_mcp/tools/get_image.py +30 -0
  29. contree_mcp/tools/get_operation.py +26 -0
  30. contree_mcp/tools/import_image.py +99 -0
  31. contree_mcp/tools/list_files.py +80 -0
  32. contree_mcp/tools/list_images.py +50 -0
  33. contree_mcp/tools/list_operations.py +46 -0
  34. contree_mcp/tools/read_file.py +47 -0
  35. contree_mcp/tools/registry_auth.py +71 -0
  36. contree_mcp/tools/registry_token_obtain.py +80 -0
  37. contree_mcp/tools/rsync.py +46 -0
  38. contree_mcp/tools/run.py +97 -0
  39. contree_mcp/tools/set_tag.py +31 -0
  40. contree_mcp/tools/upload.py +50 -0
  41. contree_mcp/tools/wait_operations.py +79 -0
  42. contree_mcp-0.1.0.dist-info/METADATA +450 -0
  43. contree_mcp-0.1.0.dist-info/RECORD +46 -0
  44. contree_mcp-0.1.0.dist-info/WHEEL +4 -0
  45. contree_mcp-0.1.0.dist-info/entry_points.txt +2 -0
  46. contree_mcp-0.1.0.dist-info/licenses/LICENSE +176 -0
@@ -0,0 +1,715 @@
1
+ from collections.abc import Mapping
2
+ from textwrap import dedent
3
+ from types import MappingProxyType
4
+
5
+ WORKFLOW_GUIDE = """
6
+ # Contree Workflow Guide
7
+
8
+ ## Decision Tree: Which Image to Use?
9
+
10
+ ```
11
+ Need to run code in container?
12
+
13
+ ├─ YES: Do I need specific packages/tools?
14
+ │ │
15
+ │ ├─ YES: Check for prepared environment
16
+ │ │ │
17
+ │ │ list_images(tag_prefix="common/")
18
+ │ │ │
19
+ │ │ ├─ FOUND: Use it directly
20
+ │ │ │ run(image="tag:common/python-ml/python:3.11-slim")
21
+ │ │ │
22
+ │ │ └─ NOT FOUND: Build and tag it
23
+ │ │ 1. import_image(registry_url="docker://python:3.11-slim")
24
+ │ │ 2. run(command="pip install ...", disposable=false)
25
+ │ │ 3. set_tag(tag="common/python-ml/python:3.11-slim")
26
+ │ │ 4. Use the tagged image
27
+ │ │
28
+ │ └─ NO: Use base image directly
29
+ │ run(image="tag:python:3.11-slim")
30
+
31
+ └─ NO: (not using Contree)
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Complete Example: Python ML Environment
37
+
38
+ ### Step 1: Check for Existing Environment
39
+
40
+ ```json
41
+ // list_images
42
+ {"tag_prefix": "common/python-ml"}
43
+ ```
44
+
45
+ **If found:** Skip to Step 4.
46
+
47
+ ### Step 2: Import Base Image
48
+
49
+ ```json
50
+ // import_image
51
+ {"registry_url": "docker://docker.io/python:3.11-slim"}
52
+ // Returns: {"result_image": "uuid-base"}
53
+ ```
54
+
55
+ ### Step 3: Install Dependencies and Tag
56
+
57
+ ```json
58
+ // run - install packages
59
+ {
60
+ "command": "pip install numpy pandas scikit-learn",
61
+ "image": "uuid-base",
62
+ "disposable": false
63
+ }
64
+ // Returns: {"result_image": "uuid-with-deps"}
65
+
66
+ // set_tag - save for reuse
67
+ {"image_uuid": "uuid-with-deps", "tag": "common/python-ml/python:3.11-slim"}
68
+ ```
69
+
70
+ ### Step 4: Execute Task
71
+
72
+ ```json
73
+ // run - use prepared environment
74
+ {
75
+ "command": "python train_model.py",
76
+ "image": "tag:common/python-ml/python:3.11-slim",
77
+ "directory_state_id": "ds_abc123"
78
+ }
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Common Prepared Environments
84
+
85
+ Before building, search for these common patterns:
86
+
87
+ | Search Query | Use Case |
88
+ |--------------|----------|
89
+ | `common/python-ml` | ML libraries (numpy, pandas, sklearn) |
90
+ | `common/python-web` | Web frameworks (flask, fastapi) |
91
+ | `common/rust-toolchain` | Rust compiler and cargo |
92
+ | `common/node` | Node.js with common packages |
93
+ | `common/build-essentials` | C/C++ build tools |
94
+
95
+ ```json
96
+ // Example search
97
+ {"tag_prefix": "common/python"}
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Anti-Patterns to Avoid
103
+
104
+ ### ❌ Importing Without Checking
105
+
106
+ ```json
107
+ // WRONG: Imports every time (wastes 10-30s)
108
+ {"registry_url": "docker://python:3.11-slim"}
109
+ ```
110
+
111
+ ```json
112
+ // CORRECT: Check first
113
+ {"tag_prefix": "python"} // list_images
114
+ // Only import if not found
115
+ ```
116
+
117
+ ### ❌ Not Tagging Prepared Images
118
+
119
+ ```json
120
+ // WRONG: Installs deps but doesn't tag
121
+ {"command": "pip install numpy pandas", "disposable": false}
122
+ // Next time: must reinstall everything
123
+ ```
124
+
125
+ ```json
126
+ // CORRECT: Tag after installing
127
+ {"image_uuid": "result-uuid", "tag": "common/python-ml/python:3.11-slim"}
128
+ // Next time: instant reuse
129
+ ```
130
+
131
+ ### ❌ Chaining Commands
132
+
133
+ ```json
134
+ // WRONG: Can't rollback individual steps
135
+ {"command": "apt update && apt install -y curl && pip install requests"}
136
+ ```
137
+
138
+ ```json
139
+ // CORRECT: One step per command
140
+ {"command": "apt update", "disposable": false}
141
+ {"command": "apt install -y curl", "disposable": false}
142
+ {"command": "pip install requests", "disposable": false}
143
+ // Can rollback to any step
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Project-Specific Environments
149
+
150
+ For project-specific setups, use the project name as scope:
151
+
152
+ ```json
153
+ // Tag with project scope
154
+ {"image_uuid": "uuid", "tag": "myproject/dev-env/python:3.11-slim"}
155
+
156
+ // Search for project environments
157
+ {"tag_prefix": "myproject/"}
158
+ ```
159
+
160
+ This keeps common environments separate from project-specific ones.
161
+ """
162
+
163
+ REFERENCE_GUIDE = """
164
+ # Contree Tools Reference
165
+
166
+ ## Quick Reference
167
+
168
+ | Tool | Action | Key Params | Returns | Cost |
169
+ |------|--------|------------|---------|------|
170
+ | `run` | Execute command | `command`, `image`, `disposable` | stdout, result_image | VM |
171
+ | `rsync` | Sync files | `source`, `destination` | directory_state_id | Free |
172
+ | `import_image` | Import from registry | `registry_url`, `tag` | result_image | VM |
173
+ | `list_images` | List images | `tag_prefix`, `tagged` | images[] | Free |
174
+ | `get_image` | Get image details | `image` | uuid, tag | Free |
175
+ | `set_tag` | Tag/untag image | `image_uuid`, `tag` | uuid, tag | Free |
176
+ | `upload` | Upload file | `content` or `path` | uuid | Free |
177
+ | `download` | Download file | `image`, `path` | local file | Free |
178
+ | `get_operation` | Poll operation | `operation_id` | state, stdout | Free |
179
+ | `list_operations` | List operations | `status`, `kind` | operations[] | Free |
180
+ | `wait_operations` | Wait for multiple | `operation_ids` | results{} | Free |
181
+ | `cancel_operation` | Cancel operation | `operation_id` | cancelled | Free |
182
+
183
+ ---
184
+
185
+ ## run
186
+
187
+ Execute command in isolated container. Spawns microVM.
188
+
189
+ **Key Parameters:**
190
+ - `command` (required): Shell command to execute (runs as root)
191
+ - `image` (required): Source image UUID or `tag:name`
192
+ - `disposable`: `true` (default) = discard changes, `false` = save result_image
193
+ - `wait`: `true` (default) = block for result, `false` = return operation_id
194
+ - `directory_state_id`: Inject files from `rsync`
195
+ - `files`: Inject files from `upload` as `{"/path": "uuid"}`
196
+ - `env`: Environment variables (prefer over shell export)
197
+ - `timeout`: Max execution time in seconds (default: 30)
198
+
199
+ **Data Flow:** rsync/upload -> run -> result_image (chain) or stdout
200
+
201
+ ---
202
+
203
+ ## rsync
204
+
205
+ Sync local files to Contree for container injection. Free (no VM).
206
+
207
+ **Key Parameters:**
208
+ - `source` (required): Local path or glob pattern (`/path/dir`, `/path/**/*.py`)
209
+ - `destination` (required): Container target path (`/app`)
210
+ - `exclude`: Patterns to skip (`["__pycache__", ".git", "node_modules"]`)
211
+
212
+ **Data Flow:** local files -> rsync -> directory_state_id -> run
213
+
214
+ ---
215
+
216
+ ## import_image
217
+
218
+ Import OCI container image from registry. Spawns microVM.
219
+
220
+ **Key Parameters:**
221
+ - `registry_url` (required): Registry URL (`docker://docker.io/python:3.11-slim`)
222
+ - `tag`: Optional tag to assign (prefer UUIDs for one-off use)
223
+ - `wait`: `true` (default) = block for result, `false` = return operation_id
224
+
225
+ **Data Flow:** registry -> import_image -> result_image -> run
226
+
227
+ ---
228
+
229
+ ## Image References
230
+
231
+ All tools accepting `image` parameter support two formats:
232
+ - **UUID**: `abc-123-def-456` (direct reference)
233
+ - **Tag**: `tag:python:3.11` (resolved to UUID)
234
+
235
+ Prefer UUIDs for one-off operations. Tags are useful for frequently-used base images.
236
+
237
+ ---
238
+
239
+ ## Resources
240
+
241
+ ### Guide Resource
242
+
243
+ **URI:** `contree://guide/{section}`
244
+
245
+ Available sections: `workflow`, `reference`, `quickstart`, `state`, `async`, `tagging`, `errors`.
246
+ """
247
+
248
+ QUICKSTART_GUIDE = """
249
+ # Contree Quickstart Guide
250
+
251
+ ## 1. Basic Command Execution
252
+
253
+ ```json
254
+ {"command": "python -c 'print(1+1)'", "image": "tag:python:3.11"}
255
+ ```
256
+
257
+ ## 2. File Sync + Execute
258
+
259
+ First sync local files:
260
+ ```json
261
+ // rsync
262
+ {"source": "/path/to/project", "destination": "/app", "exclude": ["__pycache__", ".git"]}
263
+ // Returns: {"directory_state_id": "ds_abc123", ...}
264
+ ```
265
+
266
+ Then run with injected files:
267
+ ```json
268
+ // run
269
+ {"command": "python /app/main.py", "image": "tag:python:3.11", "directory_state_id": "ds_abc123"}
270
+ ```
271
+
272
+ ## 3. Build Dependency Chain
273
+
274
+ Install dependencies once, reuse:
275
+ ```json
276
+ // run - create checkpoint
277
+ {"command": "pip install numpy pandas", "image": "tag:python:3.11", "disposable": false}
278
+ // Returns: {"result_image": "img-with-deps", ...}
279
+ ```
280
+
281
+ Run multiple experiments on the prepared image:
282
+ ```json
283
+ {"command": "python train_model.py", "image": "img-with-deps"}
284
+ ```
285
+
286
+ ## 4. Import and Use External Image
287
+
288
+ ```json
289
+ // import_image
290
+ {"registry_url": "docker://docker.io/golang:1.21", "tag": "golang:1.21"}
291
+ // Returns: {"result_image": "uuid...", "result_tag": "golang:1.21"}
292
+
293
+ // run
294
+ {"command": "go version", "image": "tag:golang:1.21"}
295
+ ```
296
+
297
+ ---
298
+
299
+ ## Best Practices
300
+
301
+ ### UUIDs vs Tags
302
+
303
+ **Prefer UUIDs** for:
304
+ - One-off operations
305
+ - Chaining operations (use returned `result_image`)
306
+ - Reproducibility
307
+
308
+ **Use Tags** for:
309
+ - Frequently-used base images (`python:3.11`, `alpine:latest`)
310
+ - Human-readable references
311
+
312
+ ### Output Management
313
+
314
+ Default `truncate_output_at` is 8000 bytes. Adjust based on expected output:
315
+
316
+ ```json
317
+ // Verbose output expected
318
+ {"command": "find / -name '*.py'", "image": "...", "truncate_output_at": 32000}
319
+ ```
320
+
321
+ ### Environment Variables
322
+
323
+ Use `env` parameter, not shell export:
324
+
325
+ ```json
326
+ // Good
327
+ {"command": "python app.py", "image": "...", "env": {"DEBUG": "1", "API_KEY": "secret"}}
328
+
329
+ // Avoid
330
+ {"command": "export DEBUG=1 && python app.py", "image": "..."}
331
+ ```
332
+
333
+ ### File Sync Patterns
334
+
335
+ Exclude build artifacts and caches:
336
+
337
+ ```json
338
+ {
339
+ "source": "/project",
340
+ "destination": "/app",
341
+ "exclude": ["__pycache__", "*.pyc", ".git", "node_modules", ".venv", "dist", "build"]
342
+ }
343
+ ```
344
+ """
345
+
346
+ STATE_GUIDE = """
347
+ # Contree State Management Guide
348
+
349
+ ## Immutable Snapshots
350
+
351
+ Every image UUID represents an immutable filesystem snapshot.
352
+ The same UUID always means the exact same state.
353
+
354
+ ## Disposable Mode
355
+
356
+ `disposable` parameter controls whether filesystem changes are preserved:
357
+
358
+ - **disposable=true** (default): Changes are discarded, no new image created
359
+ - **disposable=false**: Changes are saved to a new image
360
+
361
+ ### When to Use Each
362
+
363
+ **Use disposable=true (default)** for:
364
+ - Read-only operations: `cat`, `ls`, `python -c "print(x)"`
365
+ - Tests: Run tests without saving test artifacts
366
+ - Exploration: Try commands, check output
367
+
368
+ **Use disposable=false** for:
369
+ - Install dependencies: `pip install`, `apt install`
370
+ - Build artifacts: Compile code, generate files to extract
371
+ - Create checkpoints: Save state for rollback
372
+
373
+ ---
374
+
375
+ ## Rollback Model
376
+
377
+ ```
378
+ Base Image (tag:python:3.11)
379
+ |
380
+ +-- Run "pip install flask" (disposable=false)
381
+ | |
382
+ | v
383
+ | Result Image A (uuid-a)
384
+ | |
385
+ | +-- Run "pip install sqlalchemy" (disposable=false)
386
+ | | |
387
+ | | v
388
+ | | Result Image B (uuid-b)
389
+ | |
390
+ | +-- Run "pip install redis" (disposable=false)
391
+ | |
392
+ | v
393
+ | Result Image C (uuid-c)
394
+ ```
395
+
396
+ ### Undo Last Change
397
+
398
+ If `uuid-b` has issues, just use `uuid-a` instead:
399
+ ```json
400
+ {"command": "python app.py", "image": "uuid-a"} // Back to Flask-only state
401
+ ```
402
+
403
+ ### Try Alternative Path
404
+
405
+ From any point, branch in a different direction:
406
+ ```json
407
+ {"command": "pip install fastapi", "image": "uuid-a", "disposable": false}
408
+ // Creates uuid-e, parallel to uuid-b and uuid-c
409
+ ```
410
+
411
+ ### Recover from Mistakes
412
+
413
+ Accidentally corrupted something? Previous UUIDs are untouched:
414
+ ```json
415
+ // This broke things
416
+ {"command": "rm -rf /important", "image": "uuid-x", "disposable": false}
417
+ // Returns uuid-y (corrupted)
418
+
419
+ // Just use uuid-x again
420
+ {"command": "python app.py", "image": "uuid-x"} // Original state intact
421
+ ```
422
+
423
+ ---
424
+
425
+ ## Response Fields
426
+
427
+ When `disposable=false`:
428
+
429
+ ```json
430
+ {
431
+ "exit_code": 0,
432
+ "state": "SUCCESS",
433
+ "result_image": "uuid-new",
434
+ "filesystem_changed": true,
435
+ "stdout": "Successfully installed numpy-1.24.0"
436
+ }
437
+ ```
438
+
439
+ - `result_image`: UUID of new image (or same as input if no changes)
440
+ - `filesystem_changed`: Whether any modifications occurred
441
+ """
442
+
443
+ ASYNC_GUIDE = """
444
+ # Contree Async Execution Guide
445
+
446
+ ## When to Use Each Mode
447
+
448
+ ### Sequential (wait=true, default)
449
+ - Single commands: Just run and get result
450
+ - Chained operations: Each step depends on previous
451
+ - Most workflows: No need for parallelism
452
+
453
+ ### Parallel (wait=false)
454
+ - Multiple independent experiments
455
+ - Batch processing: Launch many, wait for all
456
+ - Resource optimization: Maximize throughput
457
+
458
+ ---
459
+
460
+ ## Sequential Pattern (Default)
461
+
462
+ ```json
463
+ // Just run commands - wait=true is the default
464
+ {"command": "pip install flask", "image": "tag:python:3.11", "disposable": false}
465
+ // Returns immediately with result: {"stdout": "...", "result_image": "uuid-1"}
466
+
467
+ {"command": "python app.py", "image": "uuid-1"}
468
+ // Returns: {"stdout": "...", "exit_code": 0}
469
+ ```
470
+
471
+ ---
472
+
473
+ ## Parallel Pattern
474
+
475
+ ### Launch Multiple Async
476
+
477
+ ```json
478
+ // run with wait=false (make 3 parallel tool calls)
479
+ {"command": "python exp1.py", "image": "tag:python:3.11", "wait": false} // -> op-1
480
+ {"command": "python exp2.py", "image": "tag:python:3.11", "wait": false} // -> op-2
481
+ {"command": "python exp3.py", "image": "tag:python:3.11", "wait": false} // -> op-3
482
+ ```
483
+
484
+ ### Wait for All Results
485
+
486
+ ```json
487
+ // wait_operations - single call, waits for all
488
+ {"operation_ids": ["op-1", "op-2", "op-3"]}
489
+ // Returns: {"results": {"op-1": {...}, "op-2": {...}, "op-3": {...}}}
490
+ ```
491
+
492
+ ---
493
+
494
+ ## Operation States
495
+
496
+ | Status | Meaning |
497
+ |--------|---------|
498
+ | `pending` | Queued, waiting for VM |
499
+ | `running` | Command actively executing |
500
+ | `success` | Completed successfully |
501
+ | `failed` | Completed with error |
502
+ | `cancelled` | Cancelled by user |
503
+
504
+ ---
505
+
506
+ ## wait_operations Modes
507
+
508
+ | Mode | Behavior |
509
+ |------|----------|
510
+ | `all` (default) | Wait until ALL operations complete |
511
+ | `any` | Return when FIRST operation completes |
512
+
513
+ ```json
514
+ // Wait for any (returns on first completion)
515
+ {"operation_ids": ["op-1", "op-2", "op-3"], "mode": "any"}
516
+ // Returns: {"results": {"op-1": {...}}, "completed": ["op-1"], "pending": ["op-2", "op-3"]}
517
+ ```
518
+
519
+ ---
520
+
521
+ ## Tips
522
+
523
+ 1. **Default is fine**: Use wait=true for sequential workflows
524
+ 2. **Parallel when needed**: Only use wait=false for concurrent tasks
525
+ 3. **Use wait_operations**: Single call to wait for multiple operations
526
+ 4. **Cancel early**: Don't waste resources on unneeded tasks
527
+ """
528
+
529
+ TAGGING_GUIDE = """
530
+ # Contree Tagging Convention
531
+
532
+ This convention helps AI agents organize prepared environments for reuse.
533
+
534
+ ## Tag Format
535
+
536
+ ```
537
+ {scope}/{purpose}/{base}:{tag}
538
+ ```
539
+
540
+ ## Components
541
+
542
+ | Component | Description | Examples |
543
+ |-----------|-------------|----------|
544
+ | `{scope}` | `common` or project name | `common`, `myproject` |
545
+ | `{purpose}` | What was added/configured | `rust-toolchain`, `python-ml`, `web-deps` |
546
+ | `{base}:{tag}` | Original base image | `ubuntu:noble`, `python:3.11-slim` |
547
+
548
+ ## Examples
549
+
550
+ | Scenario | Tag |
551
+ |----------|-----|
552
+ | Ubuntu + Rust toolchain | `common/rust-toolchain/ubuntu:noble` |
553
+ | Python + ML libraries | `common/python-ml/python:3.11-slim` |
554
+ | Python + web frameworks | `common/python-web/python:3.11-slim` |
555
+ | Project dev environment | `myproject/dev-env/python:3.11-slim` |
556
+ | Build tools on Alpine | `common/build-essentials/alpine:latest` |
557
+
558
+ ---
559
+
560
+ ## When to Tag
561
+
562
+ ### Tag as COMMON (`common/...`) when:
563
+ - Installing standard packages (build-essential, curl, git)
564
+ - Adding language runtimes/compilers (rust, go, node)
565
+ - Installing widely-used libraries (numpy, pandas, flask)
566
+
567
+ ### Tag as PROJECT-SPECIFIC (`{project}/...`) when:
568
+ - Installing project-specific dependencies
569
+ - Setting up development environment for a specific project
570
+ - Contains application code or config
571
+
572
+ ---
573
+
574
+ ## Workflow
575
+
576
+ ### Before Creating New Images
577
+
578
+ Search for existing prepared environments first:
579
+ ```json
580
+ // list_images
581
+ {"tag_prefix": "common/python"}
582
+ ```
583
+
584
+ ### After Installing Dependencies
585
+
586
+ Tag the `result_image` with `set_tag`:
587
+ ```json
588
+ // set_tag
589
+ {"image_uuid": "result-uuid", "tag": "common/python-ml/python:3.11-slim"}
590
+ ```
591
+
592
+ ### Using Tagged Images
593
+
594
+ Reference by tag in subsequent operations:
595
+ ```json
596
+ // run
597
+ {"command": "python train.py", "image": "tag:common/python-ml/python:3.11-slim"}
598
+ ```
599
+
600
+ ---
601
+
602
+ ## Common Tags to Search For
603
+
604
+ | Search | Use Case |
605
+ |--------|----------|
606
+ | `common/python-ml` | numpy, pandas, scikit-learn |
607
+ | `common/python-web` | flask, fastapi, requests |
608
+ | `common/rust-toolchain` | rustc, cargo |
609
+ | `common/node` | node, npm, common packages |
610
+ | `common/build-essentials` | gcc, make, cmake |
611
+ """
612
+
613
+ ERRORS_GUIDE = """
614
+ # Contree Error Handling Guide
615
+
616
+ ## Common Error Patterns
617
+
618
+ ### Command Failures
619
+
620
+ **Symptom:** `exit_code` is non-zero
621
+
622
+ ```json
623
+ {
624
+ "exit_code": 1,
625
+ "state": "SUCCESS",
626
+ "stdout": "",
627
+ "stderr": "python: can't open file 'missing.py': [Errno 2] No such file or directory"
628
+ }
629
+ ```
630
+
631
+ **Note:** `state: SUCCESS` means the operation completed (VM ran), not that the command succeeded.
632
+ Check `exit_code` for command result.
633
+
634
+ **Solutions:**
635
+ - Check `stderr` for error message
636
+ - Verify file paths with `ls` command first
637
+ - Ensure dependencies are installed
638
+
639
+ ---
640
+
641
+ ### Timeout Exceeded
642
+
643
+ **Symptom:** `timed_out: true`
644
+
645
+ ```json
646
+ {
647
+ "exit_code": -1,
648
+ "state": "SUCCESS",
649
+ "timed_out": true,
650
+ "stdout": "[partial output...]"
651
+ }
652
+ ```
653
+
654
+ **Solutions:**
655
+ - Increase `timeout` parameter (default: 30s, max: 600s)
656
+ - Break long operations into smaller steps
657
+ - Use `wait=false` for long operations, poll with `get_operation`
658
+
659
+ ---
660
+
661
+ ### Image Not Found
662
+
663
+ **Symptom:** Error message about missing image
664
+
665
+ **Solutions:**
666
+ 1. Check available images: `list_images(tag_prefix="python")`
667
+ 2. Import missing image: `import_image(registry_url="docker://...")`
668
+ 3. Verify tag format: Use `tag:python:3.11` not just `python:3.11`
669
+
670
+ ---
671
+
672
+ ### Directory State Not Found
673
+
674
+ **Symptom:** `Directory state not found: ds_xxx`
675
+
676
+ **Cause:** Directory states expire or were created in a different session.
677
+
678
+ **Solutions:**
679
+ - Re-run `rsync` to create new directory state
680
+ - Use the `directory_state_id` immediately after `rsync`
681
+
682
+ ---
683
+
684
+ ### Output Truncated
685
+
686
+ **Symptom:** `[TRUNCATED]` at end of stdout/stderr
687
+
688
+ **Solutions:**
689
+ - Increase `truncate_output_at` (default: 8000 bytes)
690
+ - Write output to file, then `download` it
691
+ - Filter output in command (e.g., `| head -100`)
692
+
693
+ ---
694
+
695
+ ## Debugging Workflow
696
+
697
+ 1. **Check exit_code first** - 0 means success, non-zero means failure
698
+ 2. **Read stderr** - Contains error messages and stack traces
699
+ 3. **Verify inputs** - Images exist, files synced, paths correct
700
+ 4. **Try interactively** - Run simpler commands to isolate issue
701
+ 5. **Check state** - Use `list_operations` to see recent operations
702
+ """
703
+
704
+
705
+ SECTIONS: Mapping[str, str] = MappingProxyType(
706
+ {
707
+ "workflow": dedent(WORKFLOW_GUIDE).strip(),
708
+ "reference": dedent(REFERENCE_GUIDE).strip(),
709
+ "quickstart": dedent(QUICKSTART_GUIDE).strip(),
710
+ "state": dedent(STATE_GUIDE).strip(),
711
+ "async": dedent(ASYNC_GUIDE).strip(),
712
+ "tagging": dedent(TAGGING_GUIDE).strip(),
713
+ "errors": dedent(ERRORS_GUIDE).strip(),
714
+ }
715
+ )