76 lines
3.0 KiB
Markdown
76 lines
3.0 KiB
Markdown
# safeclaude
|
|
|
|
Run Claude Code inside a locked-down container, one per project. Your code is
|
|
shared with the container so Claude can edit it, but everything Claude *runs*
|
|
stays boxed in — so a bad command can't touch the rest of your machine.
|
|
|
|
It works like a language version manager (think `rvm`/`nvm`/`pyenv`): this repo
|
|
holds only the **shared plumbing**, and each project keeps its own setup in a
|
|
small `.safeclaude/` folder. When you launch, safeclaude reads that folder,
|
|
builds the container once, and reuses it after that.
|
|
|
|
## Install
|
|
|
|
```bash
|
|
# Put the launcher on your PATH (any dir on your PATH works)
|
|
ln -s "$(readlink -f ./safeclaude)" ~/.local/bin/safeclaude
|
|
```
|
|
|
|
That's it — the first launch builds what it needs automatically.
|
|
|
|
## Use
|
|
|
|
```bash
|
|
cd ~/my-project
|
|
safeclaude init # create a .safeclaude/ folder, then edit it for your project
|
|
safeclaude # launch Claude in this project's container
|
|
```
|
|
|
|
| Command | What it does |
|
|
| --- | --- |
|
|
| `safeclaude [PATH] [claude-args...]` | Launch Claude for a project (default: current dir). Anything extra is passed straight to `claude`. |
|
|
| `safeclaude build [PATH]` | Rebuild the project's container from scratch. |
|
|
| `safeclaude init [PATH]` | Create a starter `.safeclaude/` folder. |
|
|
| `safeclaude envs` | List the containers and stored data safeclaude has created. |
|
|
|
|
A "project" is any folder (or a parent of it) that has a `.safeclaude/` folder,
|
|
so you can launch from a subdirectory and it'll still find the right one.
|
|
|
|
## What goes in `.safeclaude/`
|
|
|
|
```
|
|
.safeclaude/
|
|
Dockerfile # which system packages / language versions this project needs
|
|
hooks/ # setup scripts that run each time the container starts
|
|
.env # secrets, kept out of git (.env.example shows the format)
|
|
```
|
|
|
|
A few things worth knowing:
|
|
|
|
- **Two places setup can live, and the difference matters.** Slow, one-time
|
|
installs (system packages, a language toolchain) go in the `Dockerfile` —
|
|
these get cached, so they don't repeat. Anything that needs your actual code
|
|
present, or that should persist between runs (installing dependencies,
|
|
starting a database proxy), goes in a `hooks/` script that runs at launch.
|
|
- **It only rebuilds when something changed.** safeclaude remembers what it
|
|
already built, so a normal launch starts right up with no waiting.
|
|
- **Hooks are safe to run every time.** They check before doing work — e.g. the
|
|
starter dependency hook only reinstalls when your lockfile actually changed.
|
|
|
|
See [`example/`](example/) for a real, filled-in Ruby + Postgres setup you can
|
|
copy from.
|
|
|
|
## Security
|
|
|
|
These are applied every launch, by safeclaude itself — a project's own config
|
|
can't loosen them:
|
|
|
|
- Claude runs as a normal user, not root, so it can't make system-wide changes.
|
|
- The container is stripped of special privileges it doesn't need.
|
|
- It can't gain new privileges partway through.
|
|
- Each project gets its own private storage, so one project can't see or break
|
|
another's setup.
|
|
|
|
Network access is otherwise normal. If you want to cut it off, that's a small
|
|
change in the launcher.
|