docs: reposition README around scoped-agent wedge and note DoH
test / run tests/run_tests.py (push) Successful in 21s

Lead with what the project does for the user — scoped Claude Code
agents on self-hosted infrastructure with per-agent secret and egress
limits — instead of the 2024-coded "isolated container" framing.
Tagline, "Why claude-bottle?" intro, and goals list now name secret
minimization, egress allowlisting, and self-hosted operation as the
load-bearing properties.

Also adds a sentence to the security model noting that DoH is
blocked structurally by the existing egress allowlist, since the
bottle has no L3 path off-box except through pipelock's hostname-
allowlisted CONNECT proxy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 03:00:19 -04:00
parent fe232744a6
commit 79604fded7
+21 -18
View File
@@ -6,23 +6,23 @@
[![test](https://gitea.dideric.is/didericis/claude-bottle/actions/workflows/test.yml/badge.svg?branch=main)](https://gitea.dideric.is/didericis/claude-bottle/actions?workflow=test.yml) [![test](https://gitea.dideric.is/didericis/claude-bottle/actions/workflows/test.yml/badge.svg?branch=main)](https://gitea.dideric.is/didericis/claude-bottle/actions?workflow=test.yml)
Spins up an isolated container for running Claude Code with a curated set of skills and env vars. Run multiple Claude Code agents on your own machine, each scoped to its own secrets, skills, and egress allowlist.
## Why "claude-bottle"? ## Why "claude-bottle"?
Each container is a bottle; Claude is the genie inside. The genie has Each container is a bottle; Claude is the genie inside. The genie's
broad powers within the bottle — read, write, run anything — but it powers are exactly what the manifest grants it — a specific set of
cannot escape to the host. You uncork one bottle per agent skills, a specific set of secrets, and a specific set of hosts it can
(`./cli.py start <agent>`), many bottles run in parallel, and each reach — nothing more. You uncork one bottle per agent
one's powers are scoped to what the manifest grants it: a curated set (`./cli.py start <agent>`), many bottles run in parallel, and each is
of skills, env vars, and a starting prompt. When the session ends the scoped to its task. When the session ends the bottle is destroyed and
bottle is destroyed and the genie does not persist. the genie does not persist.
## Goals ## Goals
- Minimize risk of running claude with full permissions - Scope each agent to the minimum credentials and network egress its task actually needs
- Allow me to easily spin up agent tasks in parallel - Run multiple agents in parallel, isolated from each other
- Create isolated, well defined, easily updated, shareable agents - Keep code, credentials, and agent activity on infrastructure I control — no third-party agent runtime
## Security model ## Security model
@@ -39,13 +39,16 @@ not a personal SSH key — so even a compromised or misbehaving agent
only handles credentials it was already trusted with for its job. only handles credentials it was already trusted with for its job.
Egress flows through pipelock, which constrains where those Egress flows through pipelock, which constrains where those
credentials can travel: an agent with a Gitea token can reach credentials can travel: an agent with a Gitea token can reach
`gitea.dideric.is`, not arbitrary attacker-controlled hosts. The `gitea.dideric.is`, not arbitrary attacker-controlled hosts. The same
container itself adds a layer between the agent and the host, but the constraint blocks DNS-over-HTTPS as an exfil channel — a DoH resolver
v1 design leans more on secret minimization and egress allowlisting like `cloudflare-dns.com` would have to be on the allowlist for the
than on the container as a hardened boundary. Linux hosts can opt into agent to reach it at all. The container itself adds a layer between
[gVisor](https://gvisor.dev/) per bottle (see `runtime` in the the agent and the host, but the v1 design leans more on secret
manifest below) for a userspace syscall barrier; the broader v2 minimization and egress allowlisting than on the container as a
discussion lives in `docs/research/stronger-isolation-alternatives.md`. hardened boundary. Linux hosts can opt into [gVisor](https://gvisor.dev/)
per bottle (see `runtime` in the manifest below) for a userspace
syscall barrier; the broader v2 discussion lives in
`docs/research/stronger-isolation-alternatives.md`.
The egress proxy and OAuth-token handling below are the load-bearing The egress proxy and OAuth-token handling below are the load-bearing
pieces of v1. pieces of v1.