From 5e8ca21669f03db262b1a30aa86c116921253fc3 Mon Sep 17 00:00:00 2001 From: didericis Date: Mon, 25 May 2026 06:32:42 -0400 Subject: [PATCH] docs: replace stale bash-first framing with Python-stdlib-first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The project started life as bash scripts and got rewritten to Python (documented in docs/research/bash-vs-python-vs-go.md). Several docs still carried the old "bash-first" framing — misleading for anyone reading them now (8.7k lines of Python vs. ~130 lines of bash, all in scripts/demo*.sh). - CLAUDE.md "What this is" + "Conventions": orchestrator is Python, posture is stdlib-first. - docs/prds/0010-cred-proxy.md, docs/research/manifest-format-and- grouping.md: quoted CLAUDE.md's old wording — re-quote. - docs/research/built-in-supervisor-design.md, landscape-containerized- claude.md, agent-sandbox-landscape.md, pipelock-assessment.md, network-egress-guard.md: drop "bash-first" claims about the project, keep accurate descriptions of external tools' bash usage. Leaves untouched: bash code-fence syntax in examples, README's literal `bash scripts/demo.sh` invocation (the demo IS bash), Claude Code's "Bash tool" references, IVIJL/devbox bash description (that project actually is bash), and the bash-vs-python-vs-go research note that records the rewrite decision. Co-Authored-By: Claude Opus 4.7 --- CLAUDE.md | 10 ++++++---- docs/prds/0010-cred-proxy.md | 4 ++-- docs/research/agent-sandbox-landscape.md | 2 +- docs/research/built-in-supervisor-design.md | 6 +++--- docs/research/landscape-containerized-claude.md | 4 ++-- docs/research/manifest-format-and-grouping.md | 2 +- docs/research/network-egress-guard.md | 12 +++++++----- docs/research/pipelock-assessment.md | 2 +- 8 files changed, 23 insertions(+), 19 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index fb4606f..ce798a3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,8 +5,8 @@ claude-bottle spins up an isolated container for running Claude Code with a curated set of skills and env vars. The point is to run Claude with broad permissions inside a sandbox, so a misbehaving agent cannot reach the host. -Bash scripts orchestrate the container lifecycle and the copying of skills -and env vars into it. +A Python CLI (entry point `cli.py`, package `claude_bottle/`) orchestrates +the container lifecycle and the copying of skills and env vars into it. ## Goals @@ -36,8 +36,10 @@ and env vars into it. - Product requirement docs live in `docs/prds/`. - Research notes live in `docs/research/`. -- Low dependencies by default. The project is bash-first; ask before adding new - tools, runtimes, or package managers. +- Low dependencies by default. The project is Python, stdlib-first (no + runtime pip dependencies in the package itself; the only language + runtime is the Python 3.13 used by the CLI + sidecars). Ask before + adding new tools, runtimes, or package managers. - Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/): `[(scope)][!]: `, where `` is one of `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. diff --git a/docs/prds/0010-cred-proxy.md b/docs/prds/0010-cred-proxy.md index 4d58c83..b375130 100644 --- a/docs/prds/0010-cred-proxy.md +++ b/docs/prds/0010-cred-proxy.md @@ -407,8 +407,8 @@ cannot smuggle a stolen token through this path. The proxy binary. Two real options: - **Python (stdlib)** — `http.server` + `urllib`/`http.client`, - no new pip packages. Matches CLAUDE.md's "bash-first, low-deps" - posture. SSE pass-through is fiddly but doable. + no new pip packages. Matches CLAUDE.md's "Python, stdlib-first, + low-deps" posture. SSE pass-through is fiddly but doable. - **Go single binary** — cleaner SSE story, smaller runtime, one static binary in a scratch/distroless image. New build dependency. diff --git a/docs/research/agent-sandbox-landscape.md b/docs/research/agent-sandbox-landscape.md index 73957b4..b82621c 100644 --- a/docs/research/agent-sandbox-landscape.md +++ b/docs/research/agent-sandbox-landscape.md @@ -197,7 +197,7 @@ differentiators: - Bottle / agent split (manifest layer above the isolation primitive). - gVisor auto-detection on Linux. -Ideas worth considering, without abandoning the bash-first / local-Docker +Ideas worth considering, without abandoning the Python-stdlib-first / local-Docker stance: 1. **Per-use SSH key confirmation** (from litterbox). Even with diff --git a/docs/research/built-in-supervisor-design.md b/docs/research/built-in-supervisor-design.md index 724ef41..7da623d 100644 --- a/docs/research/built-in-supervisor-design.md +++ b/docs/research/built-in-supervisor-design.md @@ -2,7 +2,7 @@ ## Question -Can claude-bottle grow a built-in supervisor — TUI inventory plus PR-feedback routing — without breaking the per-bottle isolation model, and without departing from the bash-first, low-dependency posture? +Can claude-bottle grow a built-in supervisor — TUI inventory plus PR-feedback routing — without breaking the per-bottle isolation model, and without departing from the Python-stdlib-first, low-dependency posture? ## Context @@ -35,7 +35,7 @@ No new daemons. No new ports. No new credentials. ~100 lines. Same data as `status`, rendered with auto-refresh and keyboard shortcuts that shell out to the existing `cli.py attach / stop / start` commands. -Library choice: prefer the stdlib `curses` module to stay bash-first-adjacent; fall back to `rich` or `textual` only if the curses path proves painful. Both `rich` and `textual` are single-purpose, pure-Python deps with no transitive bloat, but they are still new deps and per the project conventions warrant a deliberate decision. +Library choice: prefer the stdlib `curses` module to stay stdlib-first; fall back to `rich` or `textual` only if the curses path proves painful. Both `rich` and `textual` are single-purpose, pure-Python deps with no transitive bloat, but they are still new deps and per the project conventions warrant a deliberate decision. This is the Claude Squad / tmux-agent-status pattern, applied to bottles instead of tmux sessions. The whole category exists *because* a TUI is the lightweight shape that doesn't require what the SPA tier requires. @@ -85,7 +85,7 @@ A few design defaults worth holding: ## Scope estimate -The full `status` / `watch` / `supervise` trio is plausibly ~500 lines of Python on top of the existing CLI, no new runtimes, no new daemons, no new ports, and (with `curses`) no new deps. That fits "Low dependencies by default. The project is bash-first; ask before adding new tools, runtimes, or package managers" without requiring an exception. +The full `status` / `watch` / `supervise` trio is plausibly ~500 lines of Python on top of the existing CLI, no new runtimes, no new daemons, no new ports, and (with `curses`) no new deps. That fits "Low dependencies by default. The project is Python, stdlib-first; ask before adding new tools, runtimes, or package managers" without requiring an exception. Phased: `status` first (purely additive, no design decisions), then `watch` (the design decisions are mostly UX, not architecture), then `supervise` (the only layer that introduces a new behavioral default and warrants a PRD of its own). diff --git a/docs/research/landscape-containerized-claude.md b/docs/research/landscape-containerized-claude.md index 9c43ae6..3f42820 100644 --- a/docs/research/landscape-containerized-claude.md +++ b/docs/research/landscape-containerized-claude.md @@ -25,7 +25,7 @@ manifest merge. ## Other surveyed projects - **textcortex/claude-code-sandbox → spritz** — evolved toward - Kubernetes-native multi-agent infra; not bash-first or local-Docker. + Kubernetes-native multi-agent infra; not stdlib-first or local-Docker. Original sandbox repo is archived. - **trailofbits/claude-code-devcontainer** — devcontainer config for security audits; not a general agent launcher. @@ -58,7 +58,7 @@ None combine: Worth publishing. Differentiators that matter to the target audience (power users running parallel Claude Code sessions with distinct personas/tooling): -- The bash-first, low-dependency design — competitors are npm-based or +- The Python-stdlib-first, low-dependency design — competitors are npm-based or Kubernetes-native. - Named agents with distinct skills and system prompts, not just language profiles. - SSH forwarding without key copying. diff --git a/docs/research/manifest-format-and-grouping.md b/docs/research/manifest-format-and-grouping.md index 52f28cc..8f8c601 100644 --- a/docs/research/manifest-format-and-grouping.md +++ b/docs/research/manifest-format-and-grouping.md @@ -162,7 +162,7 @@ ruamel.yaml). - **New runtime dependency.** The project today uses zero third-party Python packages for production code; YAML parsing - pulls in PyYAML. (CLAUDE.md: "bash-first, low-deps by default.") + pulls in PyYAML. (CLAUDE.md: "Python, stdlib-first; low-deps by default.") - YAML's footguns: indentation sensitivity, the Norway problem (`country: NO` → boolean False), implicit type coercion that's surprised non-trivial production projects. diff --git a/docs/research/network-egress-guard.md b/docs/research/network-egress-guard.md index 58398dd..eb51d63 100644 --- a/docs/research/network-egress-guard.md +++ b/docs/research/network-egress-guard.md @@ -369,7 +369,8 @@ services: - ALL ``` -In a bash-first project without Docker Compose, the equivalent is: +In a project without Docker Compose, the equivalent (shell or Python orchestrator +shelling out to `docker`) is: ```bash # create isolated network @@ -712,10 +713,11 @@ updates ipset without a container restart. ### Tier 1 (v1, implement first): in-container iptables + ipset + dnsmasq Adopt approach 2a with the dnsmasq complement from IVIJL/devbox. This is the -pattern validated by Anthropic's own devcontainer, is bash-first, adds no new -runtime dependencies (iptables and ipset are standard in the base Debian/Ubuntu -image used by Claude Code; dnsmasq is a single `apt-get install`), and works -on both macOS Docker Desktop and Linux Docker Engine. +pattern validated by Anthropic's own devcontainer, configures cleanly from +plain shell + standard system packages, adds no new runtime dependencies +(iptables and ipset are standard in the base Debian/Ubuntu image used by +Claude Code; dnsmasq is a single `apt-get install`), and works on both +macOS Docker Desktop and Linux Docker Engine. Key PRD scope for this work: diff --git a/docs/research/pipelock-assessment.md b/docs/research/pipelock-assessment.md index 5c6c1d2..a2d87d0 100644 --- a/docs/research/pipelock-assessment.md +++ b/docs/research/pipelock-assessment.md @@ -270,7 +270,7 @@ its own scanner. This avoids a second container but introduces the the proxy run in the same failure domain. The sidecar topology is recommended for claude-bottle because it matches -the existing bash-orchestrated multi-container model (the SSH key agent +the existing Python-orchestrated multi-container model (the SSH key agent already uses a separate process), keeps pipelock outside the agent's kill reach, and avoids the `--best-effort` issue on macOS Docker Desktop.