migrate to the new tiered structure
This commit is contained in:
86
README.md
86
README.md
@ -1,33 +1,75 @@
|
||||
# Claude Code — Dockerized
|
||||
# safeclaude
|
||||
|
||||
A minimal, guardrailed container for running Claude Code.
|
||||
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.
|
||||
|
||||
## Setup
|
||||
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
|
||||
# 1. Build the image
|
||||
docker compose build
|
||||
|
||||
# 2. Link the binary where it's accessible
|
||||
ln -s `readlink -f ./safeclaude` `readlink -f ~/.local/bin`
|
||||
|
||||
# 3. Run against your code
|
||||
cd ~/zenmaid-webapp && safeclaude .
|
||||
# Put the launcher on your PATH (any dir on your PATH works)
|
||||
ln -s "$(readlink -f ./safeclaude)" ~/.local/bin/safeclaude
|
||||
```
|
||||
|
||||
## Security notes
|
||||
That's it — the first launch builds what it needs automatically.
|
||||
|
||||
- Runs as a non-root user (`coder`, uid 1001)
|
||||
- All Linux capabilities are dropped except `NET_BIND_SERVICE`
|
||||
- Privilege escalation is disabled (`no-new-privileges`)
|
||||
- The container has no network restrictions beyond what Docker provides —
|
||||
add a custom network or `--network none` with `--add-host` if you want
|
||||
to lock that down further
|
||||
## Use
|
||||
|
||||
## Limitations & future updates
|
||||
```bash
|
||||
cd ~/my-project
|
||||
safeclaude init # create a .safeclaude/ folder, then edit it for your project
|
||||
safeclaude # launch Claude in this project's container
|
||||
```
|
||||
|
||||
- System package requirement changes require updates to the Dockerfile and a restart/rebuild - the claude user can't make these changes itself due to restricted access.
|
||||
| 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. |
|
||||
|
||||
- Bundles need to be updated separately inside the container
|
||||
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.
|
||||
|
||||
- The setup is fairly tightly married to a ruby/psql application and would need to be tweaked to be configurable for other environments or platforms
|
||||
## 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.
|
||||
|
||||
Reference in New Issue
Block a user