trusty-cage 0.2.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 (35) hide show
  1. trusty_cage-0.2.0/.claude/settings.local.json +12 -0
  2. trusty_cage-0.2.0/.env.example +17 -0
  3. trusty_cage-0.2.0/.gitignore +35 -0
  4. trusty_cage-0.2.0/CLAUDE.md +128 -0
  5. trusty_cage-0.2.0/LICENSE +21 -0
  6. trusty_cage-0.2.0/Makefile +25 -0
  7. trusty_cage-0.2.0/PKG-INFO +186 -0
  8. trusty_cage-0.2.0/README.md +154 -0
  9. trusty_cage-0.2.0/docs/v1-spec.md +345 -0
  10. trusty_cage-0.2.0/pyproject.toml +58 -0
  11. trusty_cage-0.2.0/src/trusty_cage/__init__.py +3 -0
  12. trusty_cage-0.2.0/src/trusty_cage/assets/Dockerfile +96 -0
  13. trusty_cage-0.2.0/src/trusty_cage/assets/__init__.py +0 -0
  14. trusty_cage-0.2.0/src/trusty_cage/assets/env.template +20 -0
  15. trusty_cage-0.2.0/src/trusty_cage/assets/init-network.sh +61 -0
  16. trusty_cage-0.2.0/src/trusty_cage/auth.py +98 -0
  17. trusty_cage-0.2.0/src/trusty_cage/cli.py +574 -0
  18. trusty_cage-0.2.0/src/trusty_cage/config.py +43 -0
  19. trusty_cage-0.2.0/src/trusty_cage/constants.py +40 -0
  20. trusty_cage-0.2.0/src/trusty_cage/docker.py +238 -0
  21. trusty_cage-0.2.0/src/trusty_cage/dotfiles.py +109 -0
  22. trusty_cage-0.2.0/src/trusty_cage/environment.py +131 -0
  23. trusty_cage-0.2.0/src/trusty_cage/image.py +90 -0
  24. trusty_cage-0.2.0/src/trusty_cage/network.py +33 -0
  25. trusty_cage-0.2.0/tests/__init__.py +0 -0
  26. trusty_cage-0.2.0/tests/conftest.py +26 -0
  27. trusty_cage-0.2.0/tests/test_auth.py +86 -0
  28. trusty_cage-0.2.0/tests/test_cli.py +194 -0
  29. trusty_cage-0.2.0/tests/test_config.py +103 -0
  30. trusty_cage-0.2.0/tests/test_docker.py +133 -0
  31. trusty_cage-0.2.0/tests/test_environment.py +154 -0
  32. trusty_cage-0.2.0/tests/test_image.py +53 -0
  33. trusty_cage-0.2.0/tests/test_init.py +58 -0
  34. trusty_cage-0.2.0/tests/test_network.py +40 -0
  35. trusty_cage-0.2.0/v2-spec.md +32 -0
@@ -0,0 +1,12 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(python:*)",
5
+ "Bash(python3:*)",
6
+ "Bash(source:*)"
7
+ ],
8
+ "additionalDirectories": [
9
+ "/Users/areese/.dotfiles"
10
+ ]
11
+ }
12
+ }
@@ -0,0 +1,17 @@
1
+ # trusty-cage user configuration
2
+ #
3
+ # IMPORTANT: Do NOT use this file at the project root.
4
+ # Copy it to ~/.trusty-cage/.env — that's where trusty-cage reads it from.
5
+ #
6
+ # mkdir -p ~/.trusty-cage
7
+ # cp .env.example ~/.trusty-cage/.env
8
+ # # then edit ~/.trusty-cage/.env with your values
9
+ #
10
+ # This file lives at ~/.trusty-cage/.env so your config persists across
11
+ # installs and works regardless of where you cloned the repo.
12
+
13
+ TRUSTY_CAGE_DOTFILES_REPO=https://github.com/youruser/dotfiles
14
+ TRUSTY_CAGE_PYTHON_VERSION=3.12
15
+ TRUSTY_CAGE_DEFAULT_SHELL=zsh
16
+ TRUSTY_CAGE_DEFAULT_AUTH_MODE=api_key
17
+ TRUSTY_CAGE_TMUX_PREFIX=C-a
@@ -0,0 +1,35 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+
8
+ # Virtual environment
9
+ venv/
10
+
11
+ # Environment / secrets
12
+ .env
13
+ set_creds.sh
14
+
15
+ # IDE
16
+ .idea/
17
+ .vscode/
18
+ .zed/
19
+
20
+ # OS
21
+ .DS_Store
22
+
23
+ # pytest
24
+ .pytest_cache/
25
+
26
+ # Ruff
27
+ .ruff_cache/
28
+
29
+ # Docker image export artifacts
30
+ info/
31
+ isolated-dev-*/
32
+ trusty-cage:*/
33
+
34
+ # trusty-cage working files
35
+ TODO.md
@@ -0,0 +1,128 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ **trusty-cage** is a host-side Python CLI tool that creates fully isolated, persistent Docker-based development environments on macOS (via OrbStack). Each environment is scoped to a single git repo, contains no git credentials, and provides an interactive dev experience (tmux + Neovim/LazyVim + Claude Code) inside a container. Work is exported back to the host for git operations.
8
+
9
+ v1 is feature-complete. The archived v1 specification is at `docs/v1-spec.md`. Planned enhancements are in `v2-spec.md`.
10
+
11
+ ## Build & Development
12
+
13
+ ```bash
14
+ # Setup
15
+ python -m venv venv
16
+ source venv/bin/activate
17
+ pip install -e ".[dev]"
18
+
19
+ # Run
20
+ trusty-cage --help
21
+
22
+ # Lint & format
23
+ ruff format .
24
+ ruff check --fix .
25
+
26
+ # Tests
27
+ pytest
28
+ pytest tests/test_foo.py # single file
29
+ pytest tests/test_foo.py::test_bar # single test
30
+
31
+ # Build & publish (requires build + twine in dev deps)
32
+ make build # Build wheel and sdist
33
+ make publish-test # Upload to TestPyPI
34
+ make publish # Upload to PyPI
35
+ make help # Show all targets
36
+ ```
37
+
38
+ ## Architecture
39
+
40
+ ### CLI Framework
41
+
42
+ - **Typer** for CLI with **Rich** for terminal output
43
+ - All Docker operations via **subprocess calls to `docker` CLI** (not the Docker Python SDK)
44
+
45
+ ### CLI Commands
46
+
47
+ The CLI is available as `trusty-cage` or the short alias `tc`.
48
+
49
+ | Command | Purpose |
50
+ |---|---|
51
+ | `init [--force]` | Create config directory and default `.env` file |
52
+ | `create <git-repo-url> [--name] [--no-attach]` | Clone repo, build image, create container+volume, copy files in, init local git, apply dotfiles, attach |
53
+ | `attach <name>` | Start container if stopped, apply iptables, create/attach tmux session |
54
+ | `stop <name>` | Stop container (preserves volume) |
55
+ | `list` | Show all environments with status, date, repo URL |
56
+ | `export <name>` | Copy container files → host clone via rsync (preserving host `.git/`) |
57
+ | `destroy <name>` | Remove container + volume (keeps host clone) |
58
+ | `rebuild-image` | Force rebuild Docker image |
59
+
60
+ ### Host File Layout
61
+
62
+ ```
63
+ ~/.trusty-cage/
64
+ .env # User config (created by `trusty-cage init`)
65
+ image.sha # SHA of Dockerfile for rebuild detection
66
+ envs/<name>/
67
+ meta.json # Source of truth: repo_url, created_at, volume_name, host_clone_path, auth_mode
68
+ repo/ # Full host clone with remotes (for export)
69
+ ```
70
+
71
+ ### Container Setup
72
+
73
+ - Base: `ubuntu:24.04` (ARM64)
74
+ - Non-root user: `trustycage` (UID 1000), home `/home/trustycage`
75
+ - Working directory: `/home/trustycage/project` (Docker named volume: `isolated-dev-<name>`)
76
+ - No bind mounts, no SSH keys, no git credentials, no `.netrc`, no `~/.config/gh`
77
+ - `ANTHROPIC_API_KEY` injected at runtime via `docker exec -e` (never on disk)
78
+ - Dotfiles: cloned on host → `docker cp` into container (`.git/` stripped) → run install script if present
79
+
80
+ ### Network Policy
81
+
82
+ Applied via `init-network.sh` at attach time (run as root, then drops to `trustycage`). Must be idempotent (use `iptables -C` before adding rules).
83
+
84
+ - **Blocked**: Port 22 (SSH) to all hosts; `hub.docker.com` / `registry-1.docker.io`
85
+ - **Allowed**: Everything else (HTTPS git, packages, web, DNS)
86
+ - Primary protection is **credential absence**, not network blocking
87
+
88
+ ### Authentication Modes
89
+
90
+ Chosen at `create` time, stored in `meta.json`:
91
+
92
+ - **api_key**: Reads host env var at attach time, injected via `docker exec -e`
93
+ - **subscription**: Copies `~/.claude/` into container via `docker cp` at create time; persists in volume
94
+
95
+ ## Code Conventions
96
+
97
+ ### Imports
98
+ - All imports must be at the top of the file — no inline or lazy imports inside functions
99
+ - This applies to all Python files in the project
100
+
101
+ ## Git Workflow
102
+
103
+ - Work happens on feature branches off `develop`
104
+ - Merges to `main` are done via PR on GitHub — never merge locally
105
+ - Push the feature/develop branch and open a PR
106
+
107
+ ## Versioning
108
+
109
+ This project follows [Semantic Versioning](https://semver.org/): `MAJOR.MINOR.PATCH`
110
+
111
+ - **MAJOR** — breaking changes (renamed commands, changed config format, dropped features)
112
+ - **MINOR** — new features, backwards-compatible (new commands, new config options)
113
+ - **PATCH** — bug fixes, docs-only changes, no behavior change
114
+
115
+ Version is set in two places (keep in sync):
116
+ - `pyproject.toml` → `version`
117
+ - `src/trusty_cage/__init__.py` → `__version__`
118
+
119
+ **When to prompt about version bumps:** Before committing work that adds new features (minor bump) or fixes bugs (patch bump), suggest the appropriate version increment to the user. Don't bump automatically — ask first.
120
+
121
+ ## Key Design Constraints
122
+
123
+ - `meta.json` is the source of truth for environment state — never infer from Docker state alone
124
+ - All operations should be **idempotent** where possible
125
+ - The tool must **never** run `git push` or configure git credentials
126
+ - Container's local git repo has no remotes — Claude Code uses git locally only
127
+ - Export uses rsync to overlay container files onto host clone, preserving host's `.git/`
128
+ - Published on PyPI as `trusty-cage` — installable via `pip install trusty-cage` or `pipx install trusty-cage`
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Adam Reese
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,25 @@
1
+ .PHONY: help build publish publish-test lint format test clean
2
+
3
+ help: ## Show this help
4
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}'
5
+
6
+ build: clean ## Build wheel and sdist
7
+ python -m build
8
+
9
+ publish: build ## Build and upload to PyPI
10
+ . ./set_creds.sh && twine upload dist/*
11
+
12
+ publish-test: build ## Build and upload to TestPyPI
13
+ . ./set_creds.sh && twine upload --repository testpypi dist/*
14
+
15
+ lint: ## Run ruff check
16
+ ruff check .
17
+
18
+ format: ## Run ruff format
19
+ ruff format .
20
+
21
+ test: ## Run pytest
22
+ pytest -q
23
+
24
+ clean: ## Remove build artifacts
25
+ rm -rf dist/ build/ src/*.egg-info
@@ -0,0 +1,186 @@
1
+ Metadata-Version: 2.4
2
+ Name: trusty-cage
3
+ Version: 0.2.0
4
+ Summary: Isolated Docker-based development environments for AI coding agents
5
+ Project-URL: Homepage, https://github.com/areese801/trusty-cage
6
+ Project-URL: Repository, https://github.com/areese801/trusty-cage
7
+ Project-URL: Issues, https://github.com/areese801/trusty-cage/issues
8
+ Author: Adam Reese
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,ai,claude,containers,development,docker,isolation
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: python-dotenv>=1.0
24
+ Requires-Dist: typer[all]>=0.12
25
+ Provides-Extra: dev
26
+ Requires-Dist: build; extra == 'dev'
27
+ Requires-Dist: pytest-mock>=3.12; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.4; extra == 'dev'
30
+ Requires-Dist: twine; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # trusty-cage
34
+
35
+ Isolated Docker-based development environments for AI coding agents. Run Claude Code (or any agent) with full autonomy inside a disposable container — no risk to your host machine, no credentials exposed, no accidental pushes.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install trusty-cage
41
+ ```
42
+
43
+ Or with [pipx](https://pipx.pypa.io/) for isolated CLI installs:
44
+
45
+ ```bash
46
+ pipx install trusty-cage
47
+ ```
48
+
49
+ `tc` is available as a shorthand for `trusty-cage` (e.g. `tc create ...`, `tc attach ...`).
50
+
51
+ ## Quick Start
52
+
53
+ ```bash
54
+ # One-time setup: create config directory and default .env file
55
+ trusty-cage init
56
+
57
+ # Create an environment from any git repo
58
+ trusty-cage create https://github.com/octocat/Hello-World
59
+
60
+ # You're now inside a tmux session (prefix: Ctrl-a) with:
61
+ # Left pane (60%) — Neovim at the project root
62
+ # Top-right pane — Claude Code running with --dangerously-skip-permissions
63
+ # Bottom-right pane — plain shell
64
+
65
+ # Switch panes with Ctrl-a <arrow>, detach with Ctrl-a d
66
+
67
+ # When done, export your work back to the host:
68
+ trusty-cage export hello-world
69
+
70
+ # Review and push from the host clone:
71
+ cd ~/.trusty-cage/envs/hello-world/repo/
72
+ git diff
73
+ git add -A && git commit -m "work from trusty-cage"
74
+ git push
75
+ ```
76
+
77
+ ## Example: Hello World
78
+
79
+ ```bash
80
+ # Create (environment name is derived as lowercase: "hello-world")
81
+ trusty-cage create https://github.com/octocat/Hello-World --no-attach
82
+
83
+ # Verify
84
+ trusty-cage list
85
+ docker ps -a | grep isolated-dev
86
+
87
+ # Attach — drops you into tmux inside the container
88
+ trusty-cage attach hello-world
89
+
90
+ # Inside the container:
91
+ # Ctrl-a <arrow> — switch tmux panes
92
+ # git remote -v — empty (no remotes, by design)
93
+ # curl example.com — works (outbound web allowed)
94
+ # Ctrl-a d — detach
95
+
96
+ # Export work back to host
97
+ trusty-cage export hello-world
98
+
99
+ # Clean up
100
+ trusty-cage destroy hello-world
101
+ ```
102
+
103
+ ## Commands
104
+
105
+ | Command | Description |
106
+ |---|---|
107
+ | `trusty-cage init [--force]` | Create config directory and default `.env` file |
108
+ | `trusty-cage create <url> [--name NAME] [--no-attach]` | Create a new environment from a git repo |
109
+ | `trusty-cage attach <name>` | Attach to an existing environment |
110
+ | `trusty-cage stop <name>` | Stop a container (preserves work) |
111
+ | `trusty-cage list` | List all environments with status |
112
+ | `trusty-cage export <name>` | Copy work back to host clone |
113
+ | `trusty-cage destroy <name>` | Remove container and volume (keeps host clone) |
114
+ | `trusty-cage rebuild-image` | Force rebuild the Docker image |
115
+
116
+ ## Configuration
117
+
118
+ Configuration is resolved in order: CLI flags > environment variables > `~/.trusty-cage/.env` > defaults.
119
+
120
+ | Variable | Default | Description |
121
+ |---|---|---|
122
+ | `TRUSTY_CAGE_DOTFILES_REPO` | *(empty)* | HTTPS URL of dotfiles repo to clone into containers |
123
+ | `TRUSTY_CAGE_PYTHON_VERSION` | `3.12` | Python version installed via pyenv |
124
+ | `TRUSTY_CAGE_DEFAULT_SHELL` | `zsh` | Default shell inside the container |
125
+ | `TRUSTY_CAGE_DEFAULT_AUTH_MODE` | `api_key` | Auth mode: `api_key` or `subscription` |
126
+ | `TRUSTY_CAGE_TMUX_PREFIX` | `C-a` | tmux prefix key inside containers (default `Ctrl-a` to avoid conflict with host `Ctrl-b`) |
127
+ | `ANTHROPIC_API_KEY` | *(none)* | API key for Claude Code (required for `api_key` auth mode) |
128
+
129
+ Run `trusty-cage init` to create `~/.trusty-cage/.env` with a commented template you can customize.
130
+
131
+ ## Dotfiles
132
+
133
+ If you set `TRUSTY_CAGE_DOTFILES_REPO`, your dotfiles are automatically applied to every new container at `create` time. The repo is cloned on the host, `.git/` is stripped, and the files are copied into the container's home directory. If an install script is found (`install.sh`, `setup.sh`, `bootstrap.sh`, etc.), it runs automatically. GNU Stow layouts are detected and handled (files are copied from `common/` if present).
134
+
135
+ This means your shell config, tmux settings, Neovim config, aliases, and other personalizations carry over — the container feels like your own machine.
136
+
137
+ **Without dotfiles**, the container ships with sensible defaults: oh-my-zsh (robbyrussell theme), LazyVim starter config, pyenv on PATH, and `vim`/`vi` aliased to `nvim`. Everything works out of the box, just without your personal customizations.
138
+
139
+ ## Authentication
140
+
141
+ Chosen at `create` time:
142
+
143
+ - **api_key** — Reads `ANTHROPIC_API_KEY` from your host shell at attach time. Injected via `docker exec -e`, never written to disk.
144
+ - **subscription** — Copies `~/.claude/` credentials into the container at create time. Persists in the volume.
145
+
146
+ ## Security Model
147
+
148
+ The container is the blast radius. If an agent does something destructive, your host is unaffected.
149
+
150
+ **What agents can do inside:**
151
+ - Clone/fetch public repos over HTTPS
152
+ - Browse the web, read docs, hit public APIs
153
+ - Install packages (pip, apt, npm)
154
+ - Full read/write access to the project directory
155
+
156
+ **What agents cannot do:**
157
+ - Push to any git remote (no credentials present)
158
+ - Use SSH (port 22 blocked)
159
+ - Pull Docker images from Docker Hub (blocked)
160
+ - Access any host files (no bind mounts)
161
+
162
+ Protection is enforced by **credential absence**, not network blocking. The container has no SSH keys, no `.netrc`, no `GH_TOKEN`, no git credential helper.
163
+
164
+ ## Requirements
165
+
166
+ - macOS with OrbStack or Docker Desktop
167
+ - Python 3.11+
168
+ - Git
169
+ - rsync (pre-installed on macOS; used by `export`)
170
+
171
+ ## Development
172
+
173
+ ```bash
174
+ git clone https://github.com/areese801/trusty-cage.git
175
+ cd trusty-cage
176
+ python -m venv venv
177
+ source venv/bin/activate
178
+ pip install -e ".[dev]"
179
+
180
+ # Available make targets
181
+ make help
182
+ ```
183
+
184
+ ## License
185
+
186
+ MIT
@@ -0,0 +1,154 @@
1
+ # trusty-cage
2
+
3
+ Isolated Docker-based development environments for AI coding agents. Run Claude Code (or any agent) with full autonomy inside a disposable container — no risk to your host machine, no credentials exposed, no accidental pushes.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install trusty-cage
9
+ ```
10
+
11
+ Or with [pipx](https://pipx.pypa.io/) for isolated CLI installs:
12
+
13
+ ```bash
14
+ pipx install trusty-cage
15
+ ```
16
+
17
+ `tc` is available as a shorthand for `trusty-cage` (e.g. `tc create ...`, `tc attach ...`).
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # One-time setup: create config directory and default .env file
23
+ trusty-cage init
24
+
25
+ # Create an environment from any git repo
26
+ trusty-cage create https://github.com/octocat/Hello-World
27
+
28
+ # You're now inside a tmux session (prefix: Ctrl-a) with:
29
+ # Left pane (60%) — Neovim at the project root
30
+ # Top-right pane — Claude Code running with --dangerously-skip-permissions
31
+ # Bottom-right pane — plain shell
32
+
33
+ # Switch panes with Ctrl-a <arrow>, detach with Ctrl-a d
34
+
35
+ # When done, export your work back to the host:
36
+ trusty-cage export hello-world
37
+
38
+ # Review and push from the host clone:
39
+ cd ~/.trusty-cage/envs/hello-world/repo/
40
+ git diff
41
+ git add -A && git commit -m "work from trusty-cage"
42
+ git push
43
+ ```
44
+
45
+ ## Example: Hello World
46
+
47
+ ```bash
48
+ # Create (environment name is derived as lowercase: "hello-world")
49
+ trusty-cage create https://github.com/octocat/Hello-World --no-attach
50
+
51
+ # Verify
52
+ trusty-cage list
53
+ docker ps -a | grep isolated-dev
54
+
55
+ # Attach — drops you into tmux inside the container
56
+ trusty-cage attach hello-world
57
+
58
+ # Inside the container:
59
+ # Ctrl-a <arrow> — switch tmux panes
60
+ # git remote -v — empty (no remotes, by design)
61
+ # curl example.com — works (outbound web allowed)
62
+ # Ctrl-a d — detach
63
+
64
+ # Export work back to host
65
+ trusty-cage export hello-world
66
+
67
+ # Clean up
68
+ trusty-cage destroy hello-world
69
+ ```
70
+
71
+ ## Commands
72
+
73
+ | Command | Description |
74
+ |---|---|
75
+ | `trusty-cage init [--force]` | Create config directory and default `.env` file |
76
+ | `trusty-cage create <url> [--name NAME] [--no-attach]` | Create a new environment from a git repo |
77
+ | `trusty-cage attach <name>` | Attach to an existing environment |
78
+ | `trusty-cage stop <name>` | Stop a container (preserves work) |
79
+ | `trusty-cage list` | List all environments with status |
80
+ | `trusty-cage export <name>` | Copy work back to host clone |
81
+ | `trusty-cage destroy <name>` | Remove container and volume (keeps host clone) |
82
+ | `trusty-cage rebuild-image` | Force rebuild the Docker image |
83
+
84
+ ## Configuration
85
+
86
+ Configuration is resolved in order: CLI flags > environment variables > `~/.trusty-cage/.env` > defaults.
87
+
88
+ | Variable | Default | Description |
89
+ |---|---|---|
90
+ | `TRUSTY_CAGE_DOTFILES_REPO` | *(empty)* | HTTPS URL of dotfiles repo to clone into containers |
91
+ | `TRUSTY_CAGE_PYTHON_VERSION` | `3.12` | Python version installed via pyenv |
92
+ | `TRUSTY_CAGE_DEFAULT_SHELL` | `zsh` | Default shell inside the container |
93
+ | `TRUSTY_CAGE_DEFAULT_AUTH_MODE` | `api_key` | Auth mode: `api_key` or `subscription` |
94
+ | `TRUSTY_CAGE_TMUX_PREFIX` | `C-a` | tmux prefix key inside containers (default `Ctrl-a` to avoid conflict with host `Ctrl-b`) |
95
+ | `ANTHROPIC_API_KEY` | *(none)* | API key for Claude Code (required for `api_key` auth mode) |
96
+
97
+ Run `trusty-cage init` to create `~/.trusty-cage/.env` with a commented template you can customize.
98
+
99
+ ## Dotfiles
100
+
101
+ If you set `TRUSTY_CAGE_DOTFILES_REPO`, your dotfiles are automatically applied to every new container at `create` time. The repo is cloned on the host, `.git/` is stripped, and the files are copied into the container's home directory. If an install script is found (`install.sh`, `setup.sh`, `bootstrap.sh`, etc.), it runs automatically. GNU Stow layouts are detected and handled (files are copied from `common/` if present).
102
+
103
+ This means your shell config, tmux settings, Neovim config, aliases, and other personalizations carry over — the container feels like your own machine.
104
+
105
+ **Without dotfiles**, the container ships with sensible defaults: oh-my-zsh (robbyrussell theme), LazyVim starter config, pyenv on PATH, and `vim`/`vi` aliased to `nvim`. Everything works out of the box, just without your personal customizations.
106
+
107
+ ## Authentication
108
+
109
+ Chosen at `create` time:
110
+
111
+ - **api_key** — Reads `ANTHROPIC_API_KEY` from your host shell at attach time. Injected via `docker exec -e`, never written to disk.
112
+ - **subscription** — Copies `~/.claude/` credentials into the container at create time. Persists in the volume.
113
+
114
+ ## Security Model
115
+
116
+ The container is the blast radius. If an agent does something destructive, your host is unaffected.
117
+
118
+ **What agents can do inside:**
119
+ - Clone/fetch public repos over HTTPS
120
+ - Browse the web, read docs, hit public APIs
121
+ - Install packages (pip, apt, npm)
122
+ - Full read/write access to the project directory
123
+
124
+ **What agents cannot do:**
125
+ - Push to any git remote (no credentials present)
126
+ - Use SSH (port 22 blocked)
127
+ - Pull Docker images from Docker Hub (blocked)
128
+ - Access any host files (no bind mounts)
129
+
130
+ Protection is enforced by **credential absence**, not network blocking. The container has no SSH keys, no `.netrc`, no `GH_TOKEN`, no git credential helper.
131
+
132
+ ## Requirements
133
+
134
+ - macOS with OrbStack or Docker Desktop
135
+ - Python 3.11+
136
+ - Git
137
+ - rsync (pre-installed on macOS; used by `export`)
138
+
139
+ ## Development
140
+
141
+ ```bash
142
+ git clone https://github.com/areese801/trusty-cage.git
143
+ cd trusty-cage
144
+ python -m venv venv
145
+ source venv/bin/activate
146
+ pip install -e ".[dev]"
147
+
148
+ # Available make targets
149
+ make help
150
+ ```
151
+
152
+ ## License
153
+
154
+ MIT