refactor!: rename project to bot-bottle

Assisted-by: Codex
This commit is contained in:
2026-05-28 17:56:14 -04:00
parent 8875d8cc17
commit c08b09dc9f
200 changed files with 1271 additions and 1271 deletions
+42 -42
View File
@@ -6,11 +6,11 @@
## Summary
Replace the single-file `claude-bottle.json` manifest with a
Replace the single-file `bot-bottle.json` manifest with a
per-file Markdown-with-YAML-frontmatter layout. Bottles live as
`$HOME/.claude-bottle/bottles/<name>.md`; agents live as
`$HOME/.claude-bottle/agents/<name>.md` (home-resident) and
`$CWD/.claude-bottle/agents/<name>.md` (repo-supplied). Each file
`$HOME/.bot-bottle/bottles/<name>.md`; agents live as
`$HOME/.bot-bottle/agents/<name>.md` (home-resident) and
`$CWD/.bot-bottle/agents/<name>.md` (repo-supplied). Each file
carries its structured config in YAML frontmatter and (for agents)
its system prompt in the Markdown body.
@@ -28,7 +28,7 @@ PyYAML dependency. The project's "low deps by default" stance
## Problem
`claude-bottle.json` works fine at one bottle and one agent. The
`bot-bottle.json` works fine at one bottle and one agent. The
project is heading for many of both, and the single-JSON shape
starts to fray:
@@ -60,22 +60,22 @@ axes (grouping × format) and lands on this design.
Each test runs against a temporary `$HOME` and a temporary `$CWD`:
1. **A bottle file under `$HOME/.claude-bottle/bottles/`
1. **A bottle file under `$HOME/.bot-bottle/bottles/`
parses.** A `dev.md` file with YAML frontmatter declaring
`cred_proxy.routes`, `git`, `env`, `egress` produces a Bottle
dataclass equivalent to the current JSON shape.
2. **An agent file under `$HOME/.claude-bottle/agents/` parses.**
2. **An agent file under `$HOME/.bot-bottle/agents/` parses.**
`implementer.md` with frontmatter that names `bottle:`,
`skills:`, and other fields, with the body as the system
prompt, produces an Agent dataclass.
3. **An agent file under `$CWD/.claude-bottle/agents/` parses
3. **An agent file under `$CWD/.bot-bottle/agents/` parses
and overrides home-resident agents of the same name.** The
cwd agent's frontmatter and body win; the home bottle it
references stays intact.
4. **A bottle file under `$CWD/.claude-bottle/bottles/` is
4. **A bottle file under `$CWD/.bot-bottle/bottles/` is
ignored.** The directory does not contribute to the
manifest; if a user accidentally creates one, the launcher
emits a `warn`-level log naming the offending files and
@@ -83,7 +83,7 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
is a usability nicety, not a security gate.
5. **No third-party Python dependencies introduced.** A fresh
clone with only stdlib + claude-bottle's own code runs every
clone with only stdlib + bot-bottle's own code runs every
parser test. Frontmatter parsing is hand-rolled against the
declared YAML subset.
@@ -97,30 +97,30 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
`name`, `description`, `model`, `color`, and `memory` fields
from Claude Code's existing subagent spec are accepted in
our frontmatter alongside our own fields. Copying an agent
file from `$HOME/.claude-bottle/agents/` to
file from `$HOME/.bot-bottle/agents/` to
`~/.claude/agents/` produces a working Claude Code subagent
(subject to Claude Code's tolerance for the extra `bottle:`
and `claude_bottle:` fields — see Open Questions).
and `bot_bottle:` fields — see Open Questions).
## Non-goals
- **A general YAML implementation.** The parser handles the
subset claude-bottle's frontmatter actually uses; documents
subset bot-bottle's frontmatter actually uses; documents
that exceed the subset (anchors, multi-line block scalars,
tags, implicit type coercion, flow style, etc.) die with a
pointer at the spec. We are not building a YAML library.
- **Compatibility with the old JSON layout at runtime.** The
resolver no longer reads `claude-bottle.json` files. This is
resolver no longer reads `bot-bottle.json` files. This is
a breaking change; existing users hand-rewrite their JSON
into the new per-file layout (claude-bottle has a single
into the new per-file layout (bot-bottle has a single
primary user today, so the migration is one person rewriting
one file). Documented as part of the README rewrite.
- **`$HOME/.claude/agents/` integration on the input side.** We
don't read agent files out of Claude Code's directory. Our
files can be copied into Claude Code's tree by the user if
they want, but the input path for claude-bottle is its own
they want, but the input path for bot-bottle is its own
directory.
- **A signed-manifest scheme.** Out of scope per the
@@ -139,14 +139,14 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
### In scope
- **Directory layout.**
- `$HOME/.claude-bottle/bottles/<name>.md` — bottle
- `$HOME/.bot-bottle/bottles/<name>.md` — bottle
definitions (full schema; one Bottle per file).
- `$HOME/.claude-bottle/agents/<name>.md` — home-resident
- `$HOME/.bot-bottle/agents/<name>.md` — home-resident
agents.
- `$CWD/.claude-bottle/agents/<name>.md` — cwd-resident
- `$CWD/.bot-bottle/agents/<name>.md` — cwd-resident
agents; same schema as home agents, but bottle names must
resolve against the home set.
- `$CWD/.claude-bottle/bottles/` — ignored with a warn-level
- `$CWD/.bot-bottle/bottles/` — ignored with a warn-level
log (see SC #4). Does not contribute to the manifest.
- `<name>` is the file basename without `.md`. Filenames must
match `[a-z][a-z0-9-]*` (kebab-case, ASCII-only).
@@ -162,7 +162,7 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
- `skills: [<name>, ...]` (optional) — host-side skills under
`~/.claude/skills/`.
- `name`, `description`, `model`, `color`, `memory` — accepted
but treated as Claude Code passthrough; claude-bottle
but treated as Claude Code passthrough; bot-bottle
ignores them at launch but doesn't reject. Lets the same
file double as a Claude Code subagent.
- Unknown top-level keys die with a hint listing accepted
@@ -191,17 +191,17 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
the required-keys check — same diagnostic as malformed).
- **Manifest assembly.** New resolver:
1. Walk `$HOME/.claude-bottle/bottles/*.md` → Bottle dict
1. Walk `$HOME/.bot-bottle/bottles/*.md` → Bottle dict
keyed by filename.
2. Walk `$HOME/.claude-bottle/agents/*.md` → Agent dict.
3. Walk `$CWD/.claude-bottle/agents/*.md` → Agent dict; merge
2. Walk `$HOME/.bot-bottle/agents/*.md` → Agent dict.
3. Walk `$CWD/.bot-bottle/agents/*.md` → Agent dict; merge
into the home agent dict, cwd wins on name collision.
4. Validate every agent's `bottle:` against the bottle dict.
5. Warn if `$CWD/.claude-bottle/bottles/` exists with files.
5. Warn if `$CWD/.bot-bottle/bottles/` exists with files.
6. Return Manifest dataclass — same shape as today.
- **Docs.** README's manifest section rewrites against the new
layout. `claude-bottle.example.json` becomes
layout. `bot-bottle.example.json` becomes
`examples/bottles/dev.md` + `examples/agents/implementer.md`.
The PRD 0010 example block in its own document gets a
follow-up commit noting the new layout (out of scope for
@@ -233,7 +233,7 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
### File layout
```
$HOME/.claude-bottle/
$HOME/.bot-bottle/
├── bottles/
│ ├── dev.md
│ ├── gitea-dev.md
@@ -243,7 +243,7 @@ $HOME/.claude-bottle/
├── researcher.md
└── ...
$CWD/.claude-bottle/
$CWD/.bot-bottle/
└── agents/
└── <repo-specific>.md
```
@@ -261,7 +261,7 @@ cred_proxy:
- path: /anthropic/
upstream: https://api.anthropic.com
auth_scheme: Bearer
token_ref: CLAUDE_BOTTLE_OAUTH_TOKEN
token_ref: BOT_BOTTLE_OAUTH_TOKEN
role: anthropic-base-url
- path: /gitea/dideric/
upstream: https://gitea.dideric.is
@@ -271,8 +271,8 @@ cred_proxy:
git:
remotes:
gitea.dideric.is:
Name: claude-bottle
Upstream: ssh://git@gitea.dideric.is:30009/didericis/claude-bottle.git
Name: bot-bottle
Upstream: ssh://git@gitea.dideric.is:30009/didericis/bot-bottle.git
IdentityFile: ~/.ssh/gitea-delos-2.pem
ExtraHosts:
gitea.dideric.is: 100.78.141.42
@@ -302,7 +302,7 @@ skills:
---
You are a feature-implementation agent running inside an
ephemeral claude-bottle sandbox...
ephemeral bot-bottle sandbox...
```
Drop the same file into `~/.claude/agents/implementer.md` and
@@ -336,7 +336,7 @@ Notable rejections (each dies with a specific error):
be ambiguous, quote it.
- Flow style mappings nested more than one level deep.
Parser lives at `claude_bottle/yaml_subset.py`, ~300 lines.
Parser lives at `bot_bottle/yaml_subset.py`, ~300 lines.
Public API:
```python
@@ -348,14 +348,14 @@ def parse_frontmatter(text: str) -> tuple[dict[str, object], str]:
### Existing code touched
- **`claude_bottle/manifest.py`** — `Manifest.resolve` rewritten
- **`bot_bottle/manifest.py`** — `Manifest.resolve` rewritten
to walk the new directories. `Manifest.from_json_obj` kept as
a programmatic entry point (used by tests). New
`Manifest.from_md_dirs(home_dir, cwd_dir)` for the loader.
- **`claude_bottle/yaml_subset.py`** — new. The parser.
- **`bot_bottle/yaml_subset.py`** — new. The parser.
- **`README.md`** — manifest section rewritten against the new
layout.
- **`claude-bottle.example.json`** — removed; replaced by an
- **`bot-bottle.example.json`** — removed; replaced by an
`examples/` directory with one bottle file + one agent file.
- **Tests** — new parser tests + new loader tests; existing
manifest tests adapt to either build via `from_json_obj`
@@ -368,12 +368,12 @@ etc. all stay the same shape. Only the loader changes.
### Backward compatibility
This is a breaking change for v1 users. claude-bottle has a
This is a breaking change for v1 users. bot-bottle has a
single primary user today, so migration is one person rewriting
one file — no automated migration command is in scope.
If `claude-bottle.json` exists in `$HOME` or `$CWD` *and* the
new `.claude-bottle/` directory does not exist, the resolver
If `bot-bottle.json` exists in `$HOME` or `$CWD` *and* the
new `.bot-bottle/` directory does not exist, the resolver
dies with a clear pointer at the README's manifest section —
not silently merging formats, not silently dropping the JSON
content.
@@ -384,11 +384,11 @@ content.
empirically before settling: drop a file with `bottle: dev`
in `~/.claude/agents/` and see whether Claude Code warns,
ignores, or breaks. If it warns, namespace the field
(`claude-bottle-bottle:` or a nested `claude_bottle:` block).
- **Hidden directory vs visible.** Default `.claude-bottle/`
(`bot-bottle-bottle:` or a nested `bot_bottle:` block).
- **Hidden directory vs visible.** Default `.bot-bottle/`
(hidden — matches `.config/`, `.ssh/`, `.docker/`). If users
routinely want to navigate to it from the file manager,
switch to `claude-bottle/`. Lean hidden.
switch to `bot-bottle/`. Lean hidden.
- **`description:` for bottles.** Should bottle frontmatter
carry a `description:` field for the y/N preflight? Default
no — bottle names are kebab-case and self-describing, and