refactor!: rename project to bot-bottle
Assisted-by: Codex
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user