contree-cli 0.6.0__tar.gz → 0.7.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 (74) hide show
  1. {contree_cli-0.6.0 → contree_cli-0.7.0}/PKG-INFO +11 -7
  2. {contree_cli-0.6.0 → contree_cli-0.7.0}/README.md +10 -6
  3. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/__main__.py +10 -1
  4. contree_cli-0.7.0/contree_cli/agent.md +477 -0
  5. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/arguments.py +15 -6
  6. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/build.py +5 -4
  7. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/env.py +2 -2
  8. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/file.py +32 -33
  9. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/images.py +32 -49
  10. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/ls.py +7 -8
  11. contree_cli-0.7.0/contree_cli/cli/operation.py +554 -0
  12. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/run.py +11 -18
  13. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/session.py +40 -24
  14. contree_cli-0.7.0/contree_cli/cli/show.py +116 -0
  15. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/skill.py +3 -1
  16. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/tag.py +2 -2
  17. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/client.py +152 -8
  18. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/manual.md +39 -10
  19. contree_cli-0.7.0/contree_cli/output.py +517 -0
  20. contree_cli-0.7.0/contree_cli/refs.py +157 -0
  21. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/session.py +78 -0
  22. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/argmap.py +5 -2
  23. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/skill.py +18 -4
  24. contree_cli-0.7.0/contree_cli/skill_body.md +121 -0
  25. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/types.py +1 -0
  26. {contree_cli-0.6.0 → contree_cli-0.7.0}/pyproject.toml +1 -1
  27. contree_cli-0.6.0/contree_cli/agent.md +0 -460
  28. contree_cli-0.6.0/contree_cli/cli/kill.py +0 -96
  29. contree_cli-0.6.0/contree_cli/cli/operation.py +0 -157
  30. contree_cli-0.6.0/contree_cli/cli/ps.py +0 -220
  31. contree_cli-0.6.0/contree_cli/cli/show.py +0 -135
  32. contree_cli-0.6.0/contree_cli/output.py +0 -392
  33. contree_cli-0.6.0/contree_cli/skill_body.md +0 -492
  34. {contree_cli-0.6.0 → contree_cli-0.7.0}/LICENSE +0 -0
  35. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/__init__.py +0 -0
  36. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/__init__.py +0 -0
  37. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/agent.py +0 -0
  38. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/auth.py +0 -0
  39. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/cat.py +0 -0
  40. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/cd.py +0 -0
  41. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/cp.py +0 -0
  42. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/cli/use.py +0 -0
  43. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/config.py +0 -0
  44. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/__init__.py +0 -0
  45. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/context.py +0 -0
  46. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/dockerignore.py +0 -0
  47. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/keyword.py +0 -0
  48. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_add.py +0 -0
  49. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_arg.py +0 -0
  50. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_copy.py +0 -0
  51. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_env.py +0 -0
  52. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_from.py +0 -0
  53. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_run.py +0 -0
  54. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_skipped.py +0 -0
  55. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_user.py +0 -0
  56. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/kw_workdir.py +0 -0
  57. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/local_context.py +0 -0
  58. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/parser.py +0 -0
  59. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/docker/url_fetch.py +0 -0
  60. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/log.py +0 -0
  61. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/man.py +0 -0
  62. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/mapped_file.py +0 -0
  63. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/migrations.py +0 -0
  64. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/py.typed +0 -0
  65. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/__init__.py +0 -0
  66. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/argspec.py +0 -0
  67. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/cache.py +0 -0
  68. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/completer.py +0 -0
  69. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/history.py +0 -0
  70. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/parser.py +0 -0
  71. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/repl.py +0 -0
  72. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/sources.py +0 -0
  73. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/shell/trie.py +0 -0
  74. {contree_cli-0.6.0 → contree_cli-0.7.0}/contree_cli/update_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: contree-cli
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: CLI client for the ConTree sandbox platform
5
5
  Keywords: sandbox,cli,vm,ai-agent,contree
6
6
  Author: Dmitry Orlov
@@ -220,7 +220,7 @@ contree run apt-get install -y curl # builds on the previous snapshot
220
220
  contree session branch experiment # branch the sandbox state
221
221
  contree run -- make test # experiment freely
222
222
  contree session checkout main # switch back instantly
223
- contree session rollback 2 # or rewind two steps
223
+ contree session rollback -- -2 # or rewind two steps
224
224
  ```
225
225
 
226
226
  ## What is ConTree?
@@ -323,7 +323,7 @@ contree cp /app/output.log . # download to local machine
323
323
  contree session branch experiment # create a branch
324
324
  contree run -- make test # experiment on it
325
325
  contree session checkout main # switch back
326
- contree session rollback 1 # undo last run
326
+ contree session rollback # undo last run (default: back 1 entry)
327
327
  ```
328
328
 
329
329
  ## Interactive Shell
@@ -358,9 +358,13 @@ The shell provides tab completion for commands, paths, image tags, and operation
358
358
  | `run [-- CMD]` | `r` | Spawn a sandbox instance, execute command |
359
359
  | `images [--prefix]` | `i`, `img` | List and import images |
360
360
  | `tag UUID TAG` | `t` | Tag or untag an image |
361
- | `ps` | | List operations (instances, imports) |
362
- | `kill UUID` | | Cancel an operation (`--all` for all) |
361
+ | `ps` | | List operations (shortcut for `operation ls`) |
362
+ | `kill UUID [UUID...]` | | Cancel operations (shortcut for `operation cancel`; `--all` for all active) |
363
363
  | `show UUID` | | Show operation result |
364
+ | `operation list` | `op`, `ls` | Same as `ps` (canonical) |
365
+ | `operation show UUID...` | `sh` | Multi-UUID inspect |
366
+ | `operation wait UUID...` | `w` | Block until each op finishes (or `--all`; `--timeout`) |
367
+ | `operation cancel UUID...` | `kill`, `k` | Multi-UUID cancel (or `--all`) |
364
368
  | `ls [PATH]` | | List files in session image (no VM) |
365
369
  | `cat PATH` | | Show file content from session image (no VM) |
366
370
  | `cp PATH DEST` | | Download file from image to local path |
@@ -444,7 +448,7 @@ contree session # show current state
444
448
  contree session show # display history DAG
445
449
  contree session branch feature # create branch from HEAD
446
450
  contree session checkout feature # switch to it
447
- contree session rollback 3 # go back 3 steps
451
+ contree session rollback -- -3 # go back 3 steps (note `--`; bare `3` is absolute id)
448
452
  contree session use other-session # import image from another session
449
453
  ```
450
454
 
@@ -466,7 +470,7 @@ Pipe JSON output into `jq`, feed CSV into spreadsheets, or parse programmaticall
466
470
 
467
471
  ### Config file
468
472
 
469
- `~/.config/contree-cli/config.ini`:
473
+ `$XDG_CONFIG_HOME/contree/auth.ini` (default: `~/.config/contree/auth.ini`; override via `$CONTREE_HOME`):
470
474
 
471
475
  ```ini
472
476
  [DEFAULT]
@@ -13,7 +13,7 @@ contree run apt-get install -y curl # builds on the previous snapshot
13
13
  contree session branch experiment # branch the sandbox state
14
14
  contree run -- make test # experiment freely
15
15
  contree session checkout main # switch back instantly
16
- contree session rollback 2 # or rewind two steps
16
+ contree session rollback -- -2 # or rewind two steps
17
17
  ```
18
18
 
19
19
  ## What is ConTree?
@@ -116,7 +116,7 @@ contree cp /app/output.log . # download to local machine
116
116
  contree session branch experiment # create a branch
117
117
  contree run -- make test # experiment on it
118
118
  contree session checkout main # switch back
119
- contree session rollback 1 # undo last run
119
+ contree session rollback # undo last run (default: back 1 entry)
120
120
  ```
121
121
 
122
122
  ## Interactive Shell
@@ -151,9 +151,13 @@ The shell provides tab completion for commands, paths, image tags, and operation
151
151
  | `run [-- CMD]` | `r` | Spawn a sandbox instance, execute command |
152
152
  | `images [--prefix]` | `i`, `img` | List and import images |
153
153
  | `tag UUID TAG` | `t` | Tag or untag an image |
154
- | `ps` | | List operations (instances, imports) |
155
- | `kill UUID` | | Cancel an operation (`--all` for all) |
154
+ | `ps` | | List operations (shortcut for `operation ls`) |
155
+ | `kill UUID [UUID...]` | | Cancel operations (shortcut for `operation cancel`; `--all` for all active) |
156
156
  | `show UUID` | | Show operation result |
157
+ | `operation list` | `op`, `ls` | Same as `ps` (canonical) |
158
+ | `operation show UUID...` | `sh` | Multi-UUID inspect |
159
+ | `operation wait UUID...` | `w` | Block until each op finishes (or `--all`; `--timeout`) |
160
+ | `operation cancel UUID...` | `kill`, `k` | Multi-UUID cancel (or `--all`) |
157
161
  | `ls [PATH]` | | List files in session image (no VM) |
158
162
  | `cat PATH` | | Show file content from session image (no VM) |
159
163
  | `cp PATH DEST` | | Download file from image to local path |
@@ -237,7 +241,7 @@ contree session # show current state
237
241
  contree session show # display history DAG
238
242
  contree session branch feature # create branch from HEAD
239
243
  contree session checkout feature # switch to it
240
- contree session rollback 3 # go back 3 steps
244
+ contree session rollback -- -3 # go back 3 steps (note `--`; bare `3` is absolute id)
241
245
  contree session use other-session # import image from another session
242
246
  ```
243
247
 
@@ -259,7 +263,7 @@ Pipe JSON output into `jq`, feed CSV into spreadsheets, or parse programmaticall
259
263
 
260
264
  ### Config file
261
265
 
262
- `~/.config/contree-cli/config.ini`:
266
+ `$XDG_CONFIG_HOME/contree/auth.ini` (default: `~/.config/contree/auth.ini`; override via `$CONTREE_HOME`):
263
267
 
264
268
  ```ini
265
269
  [DEFAULT]
@@ -1,4 +1,5 @@
1
1
  import contextvars
2
+ import http.client
2
3
  import logging
3
4
  import sys
4
5
  from collections.abc import Callable
@@ -98,11 +99,19 @@ def main() -> None:
98
99
  except ApiError as exc:
99
100
  log.error("%s", exc)
100
101
  exit(1)
102
+ except ValueError as exc:
103
+ # Raised by loader.from_args for malformed user input
104
+ # (invalid UUIDs, etc.); the message is already user-facing.
105
+ log.error("%s", exc)
106
+ exit(1)
107
+ except (OSError, http.client.HTTPException) as exc:
108
+ log.error("Network error: %s", exc)
109
+ exit(1)
101
110
  except KeyboardInterrupt:
102
111
  log.error("User interrupted")
103
112
  exit(1)
104
113
  finally:
105
- formatter.flush()
114
+ formatter.close()
106
115
 
107
116
  exit(exit_code or 0)
108
117
 
@@ -0,0 +1,477 @@
1
+ ConTree CLI Manual
2
+ ==================
3
+
4
+ Core workflow
5
+ =============
6
+
7
+ Agent protocol — follow this sequence for every task:
8
+
9
+ 1. Choose a session key: agent_<task> or agent_<task>_<subagent>. Pass it with -S on every command. Do not rely on env vars.
10
+
11
+ 2. Resume or start a session:
12
+ contree session list --filter <hint>
13
+ contree -S <key> use <image-or-tag>
14
+
15
+ 3. Set working directory early:
16
+ contree -S <key> cd /work
17
+
18
+ 4. Inspect first (read-only):
19
+ contree ls /path
20
+ contree cat /path/file
21
+ contree images --prefix=...
22
+ contree session show
23
+
24
+ 5. Execute in small steps — one mutating step per run. Pick the run mode by the command's needs, not by category. `apt-get install` and `pip install` are plain executables; direct mode is fine. `-s` is for shell features (pipes, redirects, `&&`, `;`, `$`):
25
+ contree -S <key> run -- apt-get update -qq
26
+ contree -S <key> run -- apt-get install -y curl
27
+ contree -S <key> run -- make -C /work test
28
+ contree -S <key> run -s -- 'apt list --installed 2>/dev/null | wc -l'
29
+
30
+ 6. Tag useful results immediately:
31
+ contree -S <key> tag my-env:latest
32
+
33
+ 7. Branch before risky changes:
34
+ contree -S <key> session branch experiment
35
+ contree -S <key> session checkout experiment
36
+ (if it fails: contree -S <key> session checkout main)
37
+
38
+ Full example — build and tag a Python environment:
39
+
40
+ contree -S agent_pyenv use tag:python:3.12
41
+ contree -S agent_pyenv cd /work
42
+ contree -S agent_pyenv run -- pip install uv
43
+ contree -S agent_pyenv run -- uv pip install pytest
44
+ contree -S agent_pyenv run -- python -c 'import pytest; print(pytest.__version__)'
45
+ contree -S agent_pyenv tag python-dev:3.12
46
+
47
+ More: contree run --help, contree session --help
48
+
49
+ Sessions
50
+ ========
51
+
52
+ Sessions track image, working directory, pending files, and history. Each non-disposable run creates a new image checkpoint you can rollback to or branch from.
53
+
54
+ Session key resolution (priority):
55
+ 1. -S / --session flag (most reliable, survives terminal restarts)
56
+ 2. CONTREE_SESSION env var (stable within a shell session)
57
+ 3. Auto-generated from profile + PID + TTY (changes on terminal close)
58
+
59
+ Always use -S for agent workflows. Auto-generated keys are unreliable across terminal restarts.
60
+
61
+ Starting and resuming:
62
+ contree -S <key> use tag:alpine:latest start new session
63
+ contree -S <key> use show current state
64
+ contree session list list all sessions
65
+ contree session list --filter agent filter by key substring
66
+
67
+ Branch workflow:
68
+ contree -S <key> session branch experiment
69
+ contree -S <key> session checkout experiment
70
+ contree -S <key> run -- risky-command
71
+ contree -S <key> session checkout main # abandon if failed
72
+ contree -S <key> session branch --delete experiment # clean up
73
+
74
+ Rollback:
75
+ contree -S <key> session rollback back one entry (default)
76
+ contree -S <key> session rollback -- -3 back three entries (note `--`)
77
+ contree -S <key> session rollback +1 forward one entry
78
+ contree -S <key> session rollback 42 absolute jump to history id 42
79
+
80
+ WARNING: a bare positive N is an ABSOLUTE id, not "back N steps". Use `--` plus a negative N for relative navigation.
81
+ contree -S <key> session show view history before rollback
82
+
83
+ History DAG (contree session show output):
84
+ ID IMAGE PARENT KIND TITLE BRANCHES
85
+ 1 abc123 use tag:alpine:latest main
86
+ 2 def456 1 run apt-get update main
87
+ 3 789abc 2 run apt-get install curl main, experiment
88
+
89
+ Sessions are agent memory — reuse the same key to resume later. Different profiles have separate session databases.
90
+
91
+ Cleanup:
92
+ contree -S <key> session delete <key> -y delete session
93
+ contree -S <key> session branch --prune prune disposable branches
94
+
95
+ More: contree session --help, contree session branch --help
96
+
97
+ Images and tags
98
+ ===============
99
+
100
+ All data — images, operations, uploaded files — is scoped to a Project. Multiple tokens can access the same project. Different projects have separate scopes.
101
+
102
+ Listing:
103
+ contree images all tagged images
104
+ contree images --prefix=python filter by tag prefix
105
+ contree images -a include untagged
106
+ contree images --since 1d last 24 hours
107
+ contree -f json images JSON output for scripting
108
+
109
+ Tagging:
110
+ contree tag my-app:v1.0 tag current session image
111
+ contree tag UUID my-app:v1.0 tag specific image by UUID
112
+ contree tag tag:alpine:latest my-copy re-tag by reference
113
+ contree tag -U UUID my-tag remove tag (or --delete/--rm)
114
+
115
+ Tag rules:
116
+ - Tags are unique per project — assigning moves the tag.
117
+ - Allowed: a-z 0-9 _ - with : / . separators (max 256 chars).
118
+ - Your tags shadow public tags with the same name.
119
+ - Removing your tag restores the public one.
120
+
121
+ Importing from registries:
122
+ contree images import ubuntu:latest
123
+ contree images import python:3.12-slim node:20-slim
124
+ contree images import --username=user registry.example.com/image:tag
125
+ (password prompted securely; credentials used only for import)
126
+
127
+ Tag conventions:
128
+ common/<purpose>/<base>:<tag> shared environments
129
+ <project>/<purpose>/<base>:<tag> project-specific
130
+ my-app:latest simple app tags
131
+
132
+ Always search before building: `contree images --prefix=python-dev`.
133
+
134
+ Building from a Dockerfile:
135
+ When a project already ships a Dockerfile, prefer `contree build` over hand-running each step. It executes FROM/RUN/COPY/WORKDIR/ENV/ARG/USER against the API and caches every layer as a branch so rebuilds are fast.
136
+
137
+ Layer cache is keyed by abspath(context), shared across invocations:
138
+ contree build . build ./Dockerfile, no tag
139
+ contree build . --tag myapp:dev build + tag the final image
140
+ contree build ./app --dockerfile ./app/Dockerfile.prod --tag svc:prod
141
+ contree build . --build-arg VERSION=1.2
142
+ contree build . --no-cache force rebuild
143
+
144
+ Supported directives: FROM, RUN, COPY, ADD (local files/dirs and http(s) URLs; no tar auto-extract), WORKDIR, ENV, ARG, USER. CMD/ENTRYPOINT/LABEL/EXPOSE/VOLUME/etc. are parsed but skipped with a warning. Multi-stage (AS / --from) is not yet supported.
145
+
146
+ .dockerignore is applied to every COPY/ADD walk on top of the default exclude list (.git, __pycache__, node_modules, etc.).
147
+
148
+ build runs in its own session keyed by abspath(CONTEXT) (visible as "session": "build:<hash>" in -f json output). `-S <agent_key>` on `build` is harmless but does not bind the build to your agent session. Verify the resulting image from a normal session:
149
+ contree build . --tag myapp:dev
150
+ contree -S agent_verify use tag:myapp:dev
151
+ contree -S agent_verify run -D -- myapp --version
152
+
153
+ More: contree build --help, contree images --help, contree tag --help
154
+
155
+ Files and directories
156
+ =====================
157
+
158
+ contree run is remote execution. Local files are NOT visible in the sandbox unless explicitly attached.
159
+
160
+ Single file:
161
+ contree run --file ./app.py:/app/app.py -- python /app/app.py
162
+
163
+ Directory (recursive):
164
+ contree run --file ./src:/app/src -- make -C /app/src
165
+
166
+ Full --file syntax: `host_path[:instance_path][:uUID][:gGID][:mMODE]`
167
+
168
+ ./app.py defaults from stat
169
+ ./app.py:/app/app.py explicit destination
170
+ ./script.sh:m0755 override mode only
171
+ ./app.py:/app.py:u0:g0:m0755 all explicit
172
+ ./app.py:uroot:groot uid/gid by name (local resolve)
173
+
174
+ Directory exclusions (automatic): `.*`, `.git`, `*.pyc`, `__pycache__`, `.venv`, `.mypy_cache`, `.pytest_cache`, `node_modules`, `dist`, `build`.
175
+
176
+ Add custom exclusions:
177
+ contree run --file ./project:/app --file-excludes '*.log' '*.tmp' -- ...
178
+
179
+ Upload caching: files cached locally by path + inode + mtime + size. Cache TTL: 90 days. Server deduplicates by SHA256. Unchanged files skip hash calculation and API calls.
180
+
181
+ Staging files for next run:
182
+ contree file edit /etc/nginx/nginx.conf download, edit, stage
183
+ contree file cp ./config.yaml /etc/app/ upload and stage
184
+
185
+ Pending files are injected into the next run, including disposable ones (the run sees them; the active branch only commits them after a successful non-disposable run). Explicit --file takes priority over pending files at the same path. Pending files are branch-aware.
186
+
187
+ Listing uploaded files:
188
+ contree file ls list all uploaded files in the project
189
+ contree file ls --since 1d narrow by upload time
190
+ contree file ls -q uuid + sha256 + source only (quiet)
191
+ contree -f json file ls JSON output for jq
192
+
193
+ Output joins remote files (uuid, sha256, size, created_at) with the local upload cache. The SOURCE column shows whatever this machine used to produce the file:
194
+ - absolute host path for files uploaded via `run --file` / `COPY`;
195
+ - https://... URL for files fetched via `ADD URL`.
196
+
197
+ IMPORTANT: SOURCE is resolved ONLY for files uploaded from this specific machine. The mapping lives in the local SQLite cache (per profile, under $CONTREE_HOME/cli/sessions/<profile>.db) keyed by path+inode+mtime+size (for host paths) or by the URL itself (for URL fetches), and is NOT shared between hosts. Rows show empty SOURCE when:
198
+ - the file was uploaded from a different machine or by a teammate;
199
+ - the host file has been moved, renamed, or its inode/mtime/size changed since upload (the cache key no longer matches);
200
+ - the upload happened before tracking landed (older entries backfill on the next match).
201
+ An agent must not assume SOURCE is authoritative across hosts; for cross-machine identity always use the remote UUID or sha256.
202
+
203
+ More: contree run --help, contree file --help
204
+
205
+ Execution modes
206
+ ===============
207
+
208
+ Direct command (default) — each arg is a separate argv entry. Use this for plain executables that do not need shell features:
209
+ contree run -- uname -a
210
+ contree run -- make -C /app test
211
+ contree run -- python /app/script.py
212
+
213
+ Shell mode (-s) — joins args and passes to sh -c. Use when you need pipes, redirects, &&, ;, or variable expansion. Do not wrap manually in `sh -c '...'`; -s already does that for you. For working directory use `-C /path` or `contree cd /path`, NOT `cd` inside `-s`:
214
+ contree run -s -- 'echo hello && ls /'
215
+ contree run -C /app -s -- 'echo $PWD && make test'
216
+ contree run -s -- 'cat /etc/passwd | grep root'
217
+ contree run -- apt-get install -y curl (direct mode is fine)
218
+
219
+ Login shell (`run -- sh -lc '…'`) — only when /etc/profile.d behavior is explicitly required, e.g. PATH set by `agent` provisioning. Prefer `contree env` / `-e` and `cd` / `-C` over login-shell magic:
220
+ contree run -- sh -lc 'cargo build' (only if PATH needs profile)
221
+
222
+ When to use which:
223
+ Direct: contree run -- make test (no shell features needed)
224
+ Shell: contree run -C /app -s -- 'a | grep b' (need pipes/&&/$expand)
225
+ Login: contree run -- sh -lc 'cargo build' (rare; PATH from profile)
226
+
227
+ Interpreter mode (-I) — shebang scripts:
228
+ #!/usr/bin/env -S contree run -I
229
+ echo "Hello from sandbox"
230
+ uname -a
231
+
232
+ chmod +x script.sh && ./script.sh
233
+
234
+ Piped stdin:
235
+ echo 'uname -a' | contree run /bin/sh
236
+ cat deploy.sh | contree run /bin/sh
237
+
238
+ Detached mode (-d):
239
+ contree run -d -- long-running-task
240
+ contree ps check status
241
+ contree ps -a --status FAILED --since=1h recent failures
242
+ contree show UUID view result
243
+ contree session wait block until done + advance branch
244
+ contree session wait UUID1 UUID2 poll only (NO branch advance)
245
+
246
+ NOTE: status filtering uses --status, NOT -S. `-S` is the global session flag and only works BEFORE the subcommand. Also, the default `run -d` output is plain/table -- use `contree -f json run -d ...` to capture the UUID via `jq -r .uuid` reliably.
247
+
248
+ Operation references (UUID_OR_REF):
249
+ Every positional that `--help` labels `UUID_OR_REF` -- `op show`, `op cancel`, `op wait`, top-level `show`/`kill`, and `session wait` -- accepts either a real operation UUID OR a session-history reference. References are resolved against the active session (the one selected by `-S <key>`) before the API is called, so the same notation works everywhere.
250
+
251
+ Accepted forms:
252
+ @ / : / HEAD latest op on the active branch tip
253
+ @N / :N / bare N absolute history id N
254
+ @-N / :-N / HEAD~N N steps back from the tip
255
+ HEAD~ shorthand for HEAD~1
256
+ @+N / :+N N steps forward (latest child)
257
+
258
+ Examples:
259
+ contree -S <key> op show HEAD latest op in this session
260
+ contree -S <key> op show HEAD~ HEAD~2 last two ops
261
+ contree -S <key> op wait HEAD wait on the latest detached run
262
+ contree -S <key> kill @5 cancel by absolute history id
263
+ contree -S <key> session wait HEAD~1 poll the previous op
264
+
265
+ Caveats:
266
+ * Requires an active session (-S <key>); otherwise resolution errors.
267
+ * HEAD on a `use` entry has no operation_uuid and errors clearly ("has no operation UUID"); pick HEAD~1 or an explicit id instead.
268
+ * @0 and HEAD~0 are rejected with "non-zero" -- use HEAD for "now".
269
+
270
+ Monitoring background operations:
271
+ Use the `operation` namespace (alias `op`) when juggling several detached runs. `op ls` is the canonical command — `contree ps` is its top-level shortcut. `op show` and `op cancel` accept multiple UUIDs in one call (`op cancel` has aliases `kill` and `k`).
272
+
273
+ contree op ls EXECUTING only (default)
274
+ contree op ls -a every status
275
+ contree op ls --status PENDING list PENDING ops
276
+ contree op ls --status FAILED --since 1h recent failures
277
+ contree op show UUID1 UUID2 UUID3 inspect a batch in one call
278
+ contree op cancel UUID1 UUID2 cancel selected operations
279
+ contree kill UUID1 UUID2 same -- top-level shortcut
280
+ contree op cancel --all cancel every active op (rare)
281
+
282
+ Default `op ls`/`ps` lists only `EXECUTING`; `PENDING` and `ASSIGNED` are hidden until `-a` or an explicit `--status`. For a full active snapshot, fetch with `-a` and filter client-side.
283
+
284
+ `op wait` is a pure observer: polls and prints one operation record per completion. Default formatter pins uuid, status, exit_code, timed_out, duration first and error last; every other scalar API field appears between them, so column count is not fixed. For scripts use `-f json` (one object per line) or `-f tsv` and select fields explicitly. `status` is the server's word verbatim (orchestration outcome — did the API run the job?); the sandbox process's exit code lives in the separate `exit_code` column. The CLI exit code is 1 when any op finishes non-SUCCESS, or the actual `exit_code` when a SUCCESS op had a non-zero sandbox exit (so `op wait && next-step` still composes naturally with `run -- false`). --timeout (default 60s) caps the wait. Use --all to wait for every currently active op in the project.
285
+
286
+ Rule of thumb -- use `op wait` ONLY outside session context: `op wait` is the right tool when the UUIDs came from somewhere else (different session, different agent, `images import`, raw API call) and you only need "is it done yet?". For ops you spawned in *this* session, use `session wait` (no-arg form) instead -- it polls AND advances the active branch to each result image, which `op wait` will not do.
287
+
288
+ Caveat 1 -- `op wait` does NOT advance session state: each `run -d` (non-disposable) creates a `detached-<op-uuid>` branch pointing at the START image. `op wait` does not move those branches to the result image; the result lives only on the server. After fan-out + wait the session looks the same as before the wait, just with `detached-*` branches accumulated.
289
+
290
+ PREFERRED fan-out (--disposable, no image-tracking concerns):
291
+ A=$(contree -S <key> -f json run -d --disposable -- pytest tests/a | jq -r .uuid)
292
+ B=$(contree -S <key> -f json run -d --disposable -- pytest tests/b | jq -r .uuid)
293
+ C=$(contree -S <key> -f json run -d --disposable -- pytest tests/c | jq -r .uuid)
294
+ contree -S <key> op wait "$A" "$B" "$C" block until all complete
295
+ contree -S <key> op show "$A" "$B" "$C" stdout/stderr per op
296
+
297
+ Non-disposable fan-out (must recover images manually):
298
+ A=$(contree -S <key> -f json run -d -- apt-get install -y curl | jq -r .uuid)
299
+ B=$(contree -S <key> -f json run -d -- apt-get install -y wget | jq -r .uuid)
300
+ contree -S <key> op wait "$A" "$B"
301
+ IMG_A=$(contree -f json op show "$A" | jq -r .image)
302
+ contree use "$IMG_A" bind chosen result back
303
+
304
+ Caveat 2 -- `op wait --all` is project-wide: if another agent (or another shell of yours) is running concurrently in the same project, your --all will block on its ops too. The result is still a valid wait, just possibly not over the set you expected. For session-spawned fan-out the correct alternative is `contree -S <key> session wait` (no args): it drains only this session's pending detached ops and advances the active branch with each result image. Reach for `op wait --all` only when you really want a project-wide observer (admin/cleanup tooling).
305
+
306
+ Background checks are cheap: terminal results are cached locally, so repeated `op show` / `show` calls do not re-hit the API.
307
+
308
+ Disposable mode (-D) — no image checkpoint:
309
+ contree run -D -- rm -rf /tmp/*
310
+ contree run -D -- cat /etc/passwd
311
+
312
+ Environment variables (-e):
313
+ contree run -e KEY=VALUE -e DEBUG=1 -- ./app
314
+
315
+ Session-level environment variables:
316
+ contree env PATH=/root/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/sbin
317
+ contree env DEBUG=1
318
+ contree run -- cargo build # injects PATH and DEBUG per-run
319
+ contree env -U DEBUG # unset
320
+ contree env # list all
321
+
322
+ Session env is injected on every run but NOT saved into the image unless --preserve-env is passed.
323
+
324
+ Preserve env into the image (persists across runs server-side):
325
+ contree run --preserve-env -e PATH="/root/.cargo/bin:/usr/bin:/bin" -- cargo build
326
+ contree run -- cargo test # PATH is in the image now
327
+
328
+ Use for PATH after tool installs (rustup, nvm, pyenv):
329
+
330
+ contree run -s -- 'curl -sSf https://sh.rustup.rs | sh -s -- -y'
331
+ contree run --preserve-env -e PATH=/root/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/sbin -- cargo build
332
+ contree run -- cargo test # PATH persisted in image
333
+
334
+ Or with session env:
335
+ contree env PATH=/root/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/sbin
336
+ contree run --preserve-env -- cargo build # saves session env into image
337
+ contree run -- cargo test # PATH from image
338
+
339
+ Timeout:
340
+ contree run -t 300 -- slow-build
341
+
342
+ Working directory override:
343
+ contree run -C /app -- make test
344
+
345
+ Exit codes propagate from sandbox to CLI process:
346
+ contree run -- /bin/sh -c 'exit 42'; echo $? # prints 42
347
+
348
+ More: contree run --help
349
+
350
+ Command safety
351
+ ==============
352
+
353
+ Rules for reliable agent workflows:
354
+
355
+ 1. Read-only first, then mutate. Never blind-write.
356
+
357
+ 2. One mutating step per run. Each run = one history entry.
358
+ Wrong: contree run -s -- 'apt install curl && make test'
359
+ Right: contree run -s -- apt install -y curl
360
+ contree run -- make test
361
+
362
+ 3. Why split? Chained runs collapse into one checkpoint. If `make test` fails, you can't rollback to just after `apt install`. Split runs give you granular rollback.
363
+
364
+ 4. Global flags (-f, -S, -p) MUST come before the subcommand:
365
+ Right: contree -S key -f json images
366
+ Wrong: contree images -S key -f json
367
+
368
+ 5. Use -f json for structured output in automation: `contree -f json images | jq '.uuid'`.
369
+
370
+ 6. Agents must never run `contree auth`. Only users manage auth.
371
+
372
+ 7. Use --disposable (-D) for throwaway checks that should not advance the session image. Omit -D to keep snapshots.
373
+
374
+ 8. Prefer absolute paths for -C/--cwd and --file destinations.
375
+
376
+ 9. Branch before risky changes. Rollback is always available but branching is cleaner.
377
+
378
+ Output formats
379
+ ==============
380
+
381
+ Global -f flag goes before the subcommand. Always available formats:
382
+
383
+ contree -f json images one JSON object per line (JSONL)
384
+ contree -f json-pretty ps pretty-printed JSON array
385
+ contree -f csv images CSV with header row
386
+ contree -f tsv ps tab-separated values
387
+ contree -f plain images key: value blocks
388
+
389
+ `-f toml` is available only on Python 3.11+ (it relies on stdlib `tomllib`). On Python 3.10 it is silently absent from --help.
390
+
391
+ Scripting examples:
392
+ contree -f json images --prefix=python | jq -r '.uuid'
393
+ contree -f json ps -a | jq 'select(.status=="SUCCESS")'
394
+ contree -f csv images > images.csv
395
+ contree ps -q | xargs contree show
396
+
397
+ Note: `run` with default formatter prints raw stdout/stderr. Use -f json to get structured operation metadata instead.
398
+
399
+ Profiles
400
+ ========
401
+
402
+ Profiles store API tokens for different projects. Each profile has its own session database — switching profiles isolates sessions.
403
+
404
+ contree auth save token (secure prompt)
405
+ contree auth ls list with status check
406
+ contree auth ls -O list without network check
407
+ contree auth switch personal persistent switch
408
+ contree -p personal images per-command override
409
+ export CONTREE_PROFILE=personal env var override
410
+ contree auth remove personal -y delete profile + sessions
411
+
412
+ Per-command -p is useful for cross-project operations:
413
+ contree -p project-a images --prefix=base
414
+ contree -p project-b images import tag:base:latest
415
+
416
+ Data directory: $XDG_CONFIG_HOME/contree/ (or ~/.config/contree/)
417
+ auth.ini profile credentials (mode 0600)
418
+ cli.ini optional CLI defaults
419
+ cli/sessions/{profile}.db per-profile sessions, history, cache
420
+ cli/skills.db installed agent skill registry
421
+ cli/version_check.json cached PyPI update-check state
422
+
423
+ Environment variables:
424
+ CONTREE_HOME data directory override
425
+ CONTREE_PROFILE active profile (selects which profile commands use)
426
+ CONTREE_SESSION explicit session key
427
+
428
+ Read only by `contree auth` (registration-time fallbacks):
429
+ CONTREE_TOKEN / NEBIUS_API_KEY token when --token is omitted
430
+ CONTREE_URL URL when --url is omitted
431
+ CONTREE_PROJECT / NEBIUS_AI_PROJECT project ID when --project is omitted
432
+
433
+ More: contree auth --help
434
+
435
+ All commands
436
+ ============
437
+
438
+ use [IMAGE] Set or show session image (aliases: ci)
439
+ run [-- CMD] Spawn sandbox instance (aliases: r)
440
+ build [CONTEXT] Build image from Dockerfile (aliases: bd)
441
+ images List/import images (aliases: i, img)
442
+ tag [IMAGE] TAG Tag image (aliases: t)
443
+ ps List operations (shortcut for `operation ls`)
444
+ kill UUID [UUID...] Cancel operations (shortcut for `operation cancel`); `--all` cancels every active
445
+ show UUID Show operation result
446
+ operation list List operations (aliases: ls)
447
+ operation show UUID... Show one or more operation results (aliases: sh)
448
+ operation wait UUID... Wait for operations to reach a terminal status (aliases: w); `--all` waits for every active op; `--timeout SECONDS` fails if not all complete (default: 60)
449
+ operation cancel UUID... Cancel one or more operations (aliases: kill, k); `--all` cancels every active
450
+ ls [PATH] List files in image (no VM)
451
+ cat PATH Show file content (no VM)
452
+ cp PATH DEST Download file from image
453
+ cd [PATH] Change session working directory
454
+ env [KEY=VALUE ...] Session env vars (-U to unset)
455
+ file edit PATH Edit remote file via $EDITOR
456
+ file cp SRC DEST Stage local file for next run
457
+ file ls [-q] List uploaded files + local path (aliases: list)
458
+ session list List sessions (aliases: ls)
459
+ session branch [NAME] Create/list branches (aliases: br)
460
+ session checkout BRANCH Switch branch (aliases: co)
461
+ session rollback [N] Jump to history id N (absolute); -N steps back (aliases: rb)
462
+ session show Show history DAG
463
+ session delete KEY Delete session (aliases: rm, del)
464
+ session wait [OPS] Drain detached ops; no-arg form advances branch, UUID form polls only
465
+ auth Save token
466
+ auth ls List profiles (aliases: profiles)
467
+ auth switch NAME Switch profile
468
+ auth remove NAME Delete profile (aliases: rm, del)
469
+ skill install [SPEC] Install agent skills
470
+ skill upgrade [SPEC] Upgrade skills
471
+ skill remove SPEC Remove skills
472
+ skill list List installed skills (aliases: ls)
473
+ shell Interactive REPL (aliases: sh)
474
+ agent This manual (aliases: man)
475
+
476
+ Per-command help: contree <command> --help
477
+ Nested help: contree session branch --help
@@ -13,13 +13,10 @@ from contree_cli.cli import (
13
13
  env,
14
14
  file,
15
15
  images,
16
- kill,
17
16
  ls,
18
17
  operation,
19
- ps,
20
18
  run,
21
19
  session,
22
- show,
23
20
  skill,
24
21
  tag,
25
22
  use,
@@ -214,9 +211,21 @@ register("run", "Spawn a sandbox instance", run.setup_parser, aliases=["r"])
214
211
  register("build", "Build image from Dockerfile", build.setup_parser, aliases=["bd"])
215
212
  register("images", "List and import images", images.setup_parser, aliases=["i", "img"])
216
213
  register("tag", "Tag an image", tag.setup_parser, aliases=["t"])
217
- register("ps", "List operations/instances", ps.setup_parser)
218
- register("kill", "Cancel an operation", kill.setup_parser)
219
- register("show", "Show operation result", show.setup_parser)
214
+ register(
215
+ "ps",
216
+ "List operations (alias for `operation ls`)",
217
+ operation.setup_list_parser,
218
+ )
219
+ register(
220
+ "kill",
221
+ "Cancel operations (alias for `operation cancel`)",
222
+ operation.setup_cancel_parser,
223
+ )
224
+ register(
225
+ "show",
226
+ "Show operation result (alias for `operation show`)",
227
+ operation.setup_show_parser,
228
+ )
220
229
  register(
221
230
  "operation",
222
231
  "Manage operations (list/show/cancel)",
@@ -6,10 +6,11 @@ the absolute path of the context directory. Successful layers are
6
6
  materialised as branches named ``layer:<chain-hash>`` so that
7
7
  re-running the same Dockerfile reuses prior work.
8
8
 
9
- Supported directives (MVP): FROM, RUN, COPY, ADD (without URL/tar),
10
- WORKDIR, ENV, ARG, USER. Other Dockerfile directives parse cleanly
11
- but are skipped with a warning (CMD, ENTRYPOINT, LABEL, EXPOSE,
12
- VOLUME, STOPSIGNAL, MAINTAINER, HEALTHCHECK, ONBUILD, SHELL).
9
+ Supported directives (MVP): FROM, RUN, COPY, ADD (local files/dirs
10
+ and http(s) URLs; no tar auto-extraction), WORKDIR, ENV, ARG, USER.
11
+ Other Dockerfile directives parse cleanly but are skipped with a
12
+ warning (CMD, ENTRYPOINT, LABEL, EXPOSE, VOLUME, STOPSIGNAL,
13
+ MAINTAINER, HEALTHCHECK, ONBUILD, SHELL).
13
14
  """
14
15
 
15
16
  from __future__ import annotations