Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions docs/setup/secure-agent-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -2864,7 +2864,7 @@ records which main checkout it confirmed the first time, under
sandbox-writable; a later session that derives a different one is refused
until you delete that record (the log line names it).

Wire it as a `SessionStart` / `SessionEnd` pair in `~/.claude/settings.json`, alongside any other hooks already there, **by its absolute path** (your real home, `/home/<you>` on Linux). A `~` in a hook command is expanded from `$HOME` by the launching shell, and a session environment that redirects `$HOME` would run another script:
Wire it as a `SessionStart` / `SessionEnd` pair in your user settings, alongside any other hooks already there, **by its absolute path** (your real home, `/home/<you>` on Linux). A `~` in a hook command is expanded from `$HOME` by the launching shell, and a session environment that redirects `$HOME` would run another script. Because that path is per-machine, it goes in `~/.claude/settings.local.json` when your `~/.claude/settings.json` is [synced across machines](#syncing-user-scope-config-across-machines) — a `/Users/<you>/...` path synced to a Linux box points at nothing, and the gateway never starts there; otherwise `~/.claude/settings.json` is fine. Claude Code merges hooks from both files:

```jsonc
{
Expand All @@ -2879,6 +2879,17 @@ Wire it as a `SessionStart` / `SessionEnd` pair in `~/.claude/settings.json`, al
}
```

**Fixing your other machines.** If the hook was registered in a synced `~/.claude/settings.json`, move it: delete the two `container-gateway-hook.sh` entries from the synced file (once, on any machine), then on **every** machine add them to its own `~/.claude/settings.local.json` with that machine's home:

```bash
jq --arg h "$(cd ~ && pwd -P)" '
.hooks.SessionStart += [{"hooks":[{"type":"command","command":($h+"/.claude/scripts/container-gateway-hook.sh start")}]}]
| .hooks.SessionEnd += [{"hooks":[{"type":"command","command":($h+"/.claude/scripts/container-gateway-hook.sh stop")}]}]
' ~/.claude/settings.local.json > ~/.claude/settings.local.json.new && mv ~/.claude/settings.local.json.new ~/.claude/settings.local.json
```

`setup-isolated-setup-verify` (check 12a) and `setup-isolated-setup-update` flag a hook whose registered path does not exist on the machine they run on.

Every setting that points something at a gateway socket needs that socket's **absolute** path, which is per-machine, so the whole project-settings block belongs in the gitignored `.claude/settings.local.json` — nothing is committed.
Add it by hand, substituting your own project's absolute path for `<project>` — nothing writes it for you.
The gateway serves from the `run/` directory of the personal config layer:
Expand Down Expand Up @@ -3214,6 +3225,8 @@ Three reasons make this non-negotiable:
Public dotfile repos are fine for shell aliases and editor configs;
they are the wrong shape for agent-runtime files.

**Per-machine entries stay out of the synced file.** Anything that names an absolute path under your home — the container gateway's `SessionStart` / `SessionEnd` hooks above, a pinned interpreter, socket paths — differs between macOS (`/Users/<you>`) and Linux (`/home/<you>`). Keep those in each machine's `~/.claude/settings.local.json`, which is never synced; Claude Code merges hooks and settings from both files.

## Adopter setup

If you are adopting the framework into your own tracker repo, copy
Expand Down Expand Up @@ -3601,11 +3614,13 @@ below and report ✓ done / ✗ missing / ⚠ partial, with the evidence
and the `gh tofile` alias workaround).
12. **Container gateway wired.** Only meaningful when `podman` or
`docker` is on `PATH`; report n/a otherwise. Four things:
- User-scope `~/.claude/settings.json` has a `SessionStart`
hook running `container-gateway-hook.sh start` and a
`SessionEnd` hook running `container-gateway-hook.sh stop`,
and `~/.claude/scripts/container-gateway-hook.sh` exists and
is executable.
- User-scope `~/.claude/settings.json` or
`~/.claude/settings.local.json` has a `SessionStart` hook
running `container-gateway-hook.sh start` and a `SessionEnd`
hook running `container-gateway-hook.sh stop`, by an absolute
path that exists on this machine (✗ if it names another
machine's home), and `~/.claude/scripts/container-gateway-hook.sh`
exists and is executable.
- The project `.claude/settings.json` or
`.claude/settings.local.json` has `env.CONTAINER_HOST` and
`env.DOCKER_HOST`, and both gateway sockets appear in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,18 @@ until you delete that record (the log line names it).

**L.2 — Hooks.** Wire a `SessionStart` hook running
`container-gateway-hook.sh start` and a `SessionEnd` hook running
`container-gateway-hook.sh stop` into `~/.claude/settings.json`, each
`container-gateway-hook.sh stop` into the user settings, each
**by the script's absolute path** with the home directory written out (a `~`
there is expanded from `$HOME`, which the session environment can redirect),
executed directly rather than through `bash`/`sh` (its `#!/bin/bash -p`
shebang keeps `BASH_ENV` and exported functions out) —
merging into existing arrays with a diff the operator approves,
exactly as for K.2's touch-overlay hooks.
exactly as for K.2's touch-overlay hooks. The file is
`~/.claude/settings.local.json` when `~/.claude/settings.json` is a link
into a synced config repo (the absolute path differs per machine;
macOS `/Users/<you>`, Linux `/home/<you>`), and `~/.claude/settings.json`
otherwise. If a synced file already carries the two entries, propose moving
them, per the setup guide's "Fixing your other machines".

**L.3 — Project wiring.** Propose the `env` block
(`CONTAINER_HOST` / `DOCKER_HOST`) and the `allowUnixSockets` pair
Expand Down
5 changes: 4 additions & 1 deletion plugins/magpie-setup/skills/isolated-setup-update/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ when_to_use: >-
capability: capability:platform
surface_hash: sha256:1f327e069312dad2
license: Apache-2.0
measured_tokens: 6557
measured_tokens: 6705
---

<!-- Placeholder convention (see AGENTS.md#placeholder-convention-used-in-skill-files):
Expand Down Expand Up @@ -171,6 +171,9 @@ Walk each:
- **`~/.local/share/uv` writable, or no host-only uv cache.**
Earlier defaults put `~/.local/share/uv/` in `allowWrite`, where the interpreters and tool venvs that hooks, MCP servers and the excluded `uvx` / `uv run` commands run outside the sandbox live; and `uvx` ran from the shared, sandbox-writable `~/.cache/uv`.
Report a write grant covering `~/.local/share/uv`, a `~/.config/uv/uv.toml` without an absolute host `cache-dir`, a missing `Read(~/.config/uv/uv.toml)` / `Edit(~/.config/uv/**)` / `Edit(~/.cache/prek/**)` deny, or an `env.PREK_HOME` that is missing or overlaps `~/.cache/prek`, as a **must-fix**; the remedy is `setup-isolated-setup-install` Step U ([Host-only uv state](../../../../docs/setup/secure-agent-setup.md#host-only-uv-state)).
- **A container-gateway hook registered for another machine.**
The `SessionStart` / `SessionEnd` hooks run `container-gateway-hook.sh` by its absolute path, which differs between macOS (`/Users/<you>`) and Linux (`/home/<you>`).
Report a registered path that does not exist on this machine as a **must-fix** (the gateway never starts), and one in a `~/.claude/settings.json` that links into a synced config repo as drift; the remedy is the setup guide's [Fixing your other machines](../../../../docs/setup/secure-agent-setup.md#container-gateway): move the entries into each machine's `~/.claude/settings.local.json`.
- **`enableWeakerNetworkIsolation: true`.**
It is not there for lychee, which runs offline.
It lets native-TLS CLI tools verify TLS through the sandbox's TLS-terminating proxy — the mechanism the schema notes for `gh` / `gcloud` / `terraform`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,14 @@ reading this file; read the section for a check whose condition holds.
for the whole check. Four sub-checks:

- **12a — hooks wired.** User-scope `~/.claude/settings.json`
has a `SessionStart` hook running
`container-gateway-hook.sh start` and a `SessionEnd` hook
running `container-gateway-hook.sh stop`. Either missing is
✗; a hook command naming the script through `~` or `$HOME`
or `~/.claude/settings.local.json` has a `SessionStart` hook
running `container-gateway-hook.sh start` and a `SessionEnd`
hook running `container-gateway-hook.sh stop`. Either missing is
✗, and so is a registered absolute path that does not exist on
this machine (synced from another one, e.g. `/Users/...` on
Linux): point at the setup guide's "Fixing your other machines".
An absolute path in a `~/.claude/settings.json` that links into a
synced config repo is ◐: it breaks on the next machine; a hook command naming the script through `~` or `$HOME`
rather than its absolute path is ◐ (the launching shell expands
it from `$HOME`, which the session environment can redirect),
and so is one that runs it through `bash`/`sh` rather than
Expand Down