v_2-0_local-projects #1

Open
justin wants to merge 7 commits from v_2-0_local-projects into main
22 changed files with 574 additions and 214 deletions
Showing only changes of commit 8ed08b7c0e - Show all commits

View File

@ -47,8 +47,13 @@ subdirectory still finds the right one.
cache/ # scratch space on the host, gitignored (dependencies, downloads…)
.env # secrets, kept out of git (.env.example shows the format)
version # the safeclaude version this config was created with
README.md # how this environment works and how to change it
```
That `README.md` is also what the sandboxed Claude reads to learn how the
environment is set up — so it can tell you exactly what to change without
digging through your project.
A few things worth knowing:
- **Two places setup can live, and the difference matters.** Slow, one-time

View File

@ -0,0 +1,35 @@
# .safeclaude/ — this project's sandboxed environment
This folder defines the container that `safeclaude` runs Claude in. The container
is built from these files, so changing the environment means editing them on the
host and rebuilding — not installing things inside the running container (which
is a non-root sandbox and gets reset each run).
## What's here
- `Dockerfile` — the container image: system packages and pinned language
versions (one Ruby, one Node, etc.). Built once, then cached.
- `hooks/*.sh` — scripts that run at every startup, with the project at `/code`.
Use these for setup that needs your code present or should run each launch
(installing dependencies, starting a service proxy). Keep them safe to re-run.
- `cache/` — scratch space on the host, gitignored. A good home for installed
dependencies, downloads, or "already did this" markers; survives rebuilds and
`docker volume` resets.
- `.env` — secrets passed into the container at runtime (gitignored; copy from
`.env.example`).
- `version` — the safeclaude version this config was created with.
## How to change the environment
The container runs as a non-root user with no sudo, so you can't install system
packages from inside it. Instead, edit these files on the host:
- **Add a system package:** add it to `Dockerfile`, then run `safeclaude build`.
- **Add a language or tool:** install a specific version in `Dockerfile` — pin
it, since a project only needs one. See the repo's `example/` for a worked
Ruby + Node setup.
- **Run setup at startup:** add or edit a script in `hooks/` (no rebuild needed).
- **Add a secret:** put it in `.env` (see `.env.example`).
After editing the `Dockerfile`, run `safeclaude build` to rebuild. Hook, `.env`,
and `cache/` changes take effect on the next launch with no rebuild.

View File

@ -21,6 +21,7 @@ reference you can copy from when setting up your own project.
| `hooks/30-pg-proxy.sh` | each launch | lets the app reach the host's Postgres at the usual `127.0.0.1:5432` |
| `.env.example` | — | copy to `.env` for a private gem token (kept out of git) |
| `version` | — | the safeclaude version this config was created with |
| `README.md` | — | how this environment works (also read by the sandboxed Claude) |
A couple of things to take away:

View File

@ -29,8 +29,16 @@ has a .safeclaude/ folder.
EOF
}
# Turn a folder name into something Docker is happy to use as a name.
proj_name() { basename "$1" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9_.-' '-'; }
# Turn a folder name into something Docker is happy to use as a name fragment:
# lowercase, only [a-z0-9_.-], and no leading/trailing separators (Docker rejects
# those). We capture basename into a variable first so the trailing newline is
# gone before tr runs — otherwise tr -c turns that newline into a stray '-'.
proj_name() {
local n; n="$(basename "$1")"
n="$(printf '%s' "$n" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9_.-' '-')"
n="$(printf '%s' "$n" | sed -e 's/^[-_.]*//' -e 's/[-_.]*$//')"
printf '%s' "${n:-project}"
}
# Look in this folder, then its parents, for a project (one that has a
# .safeclaude/) — so you can launch from a subdirectory and still find it.
@ -97,6 +105,7 @@ cmd_run() {
- This project is mounted at /code. On the host it lives at: ${proj}
- You run as the non-root user 'coder'. You cannot use sudo or install system packages.
- The .safeclaude/ directory configures this container. NEVER edit anything under .safeclaude/ yourself — instead, tell the developer exactly what to change and have them do it on the host.
- How this environment is set up and how to change it is documented in /code/.safeclaude/README.md — read it before advising on environment changes.
- To add a system package: ask the developer to add it to .safeclaude/Dockerfile and run 'safeclaude build' on the host.
- To add setup that runs at container startup: ask the developer to add a script to .safeclaude/hooks/.
- /home/coder persists between runs. Edits under /code are real and shared with the host. Everything else is discarded when the container exits."

35
skeleton/README.md Normal file
View File

@ -0,0 +1,35 @@
# .safeclaude/ — this project's sandboxed environment
This folder defines the container that `safeclaude` runs Claude in. The container
is built from these files, so changing the environment means editing them on the
host and rebuilding — not installing things inside the running container (which
is a non-root sandbox and gets reset each run).
## What's here
- `Dockerfile` — the container image: system packages and pinned language
versions (one Ruby, one Node, etc.). Built once, then cached.
- `hooks/*.sh` — scripts that run at every startup, with the project at `/code`.
Use these for setup that needs your code present or should run each launch
(installing dependencies, starting a service proxy). Keep them safe to re-run.
- `cache/` — scratch space on the host, gitignored. A good home for installed
dependencies, downloads, or "already did this" markers; survives rebuilds and
`docker volume` resets.
- `.env` — secrets passed into the container at runtime (gitignored; copy from
`.env.example`).
- `version` — the safeclaude version this config was created with.
## How to change the environment
The container runs as a non-root user with no sudo, so you can't install system
packages from inside it. Instead, edit these files on the host:
- **Add a system package:** add it to `Dockerfile`, then run `safeclaude build`.
- **Add a language or tool:** install a specific version in `Dockerfile` — pin
it, since a project only needs one. See the repo's `example/` for a worked
Ruby + Node setup.
- **Run setup at startup:** add or edit a script in `hooks/` (no rebuild needed).
- **Add a secret:** put it in `.env` (see `.env.example`).
After editing the `Dockerfile`, run `safeclaude build` to rebuild. Hook, `.env`,
and `cache/` changes take effect on the next launch with no rebuild.