docs(prd-0011): drop the migration command requirement
test / unit (pull_request) Successful in 13s
test / integration (pull_request) Successful in 23s

claude-bottle has a single primary user today; an automated
JSON → MD migration tool is overkill. Hand-rewriting one file
is the migration cost. The resolver still dies with a pointer
at the README's manifest section if a stale claude-bottle.json
is found alongside no .claude-bottle/ directory, so the breaking
change isn't silent.

Drops: SC #6 (migration tool), the "Migration command" In Scope
sub-bullet, the migrate_manifest.py / cli wiring entries from
Existing code touched, the tests/integration/test_migrate_manifest.py
entry from Tests, the destructive-vs-additive open question.
Renumbers the remaining success criteria 6, 7 (formerly 7, 8).
Backward-compat section rewritten around hand-rewrite.
This commit is contained in:
2026-05-24 21:46:22 -04:00
parent 894bdea288
commit afa8ca67a4
+19 -53
View File
@@ -87,21 +87,13 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
parser test. Frontmatter parsing is hand-rolled against the
declared YAML subset.
6. **Migration tool converts existing JSON to per-file MD.**
`./cli.py migrate-manifest` reads `$HOME/claude-bottle.json`
(and `$CWD/claude-bottle.json` if present), writes a tree of
per-file MD docs to the new locations, then prints what was
moved. Idempotent: rerunning is a no-op when the new layout
already exists. Does not delete the old JSON files
automatically (user-driven cleanup).
7. **Existing tests pass against the new layout.** Tests today
6. **Existing tests pass against the new layout.** Tests today
build manifests via JSON literals against `Manifest.from_json_obj`.
That entry point keeps working for tests (used to construct
manifests programmatically); production resolution flows
through the new directory-globbing loader.
8. **Agent files double as Claude Code subagent files.** The
7. **Agent files double as Claude Code subagent files.** The
`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
@@ -119,11 +111,11 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
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. The
migration tool is the bridge; after migration the JSON file
is stale (and the user removes it). This is a breaking
change for v1 users; the migration cost is one command + a
manual delete.
resolver no longer reads `claude-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
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
@@ -208,25 +200,6 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
5. Warn if `$CWD/.claude-bottle/bottles/` exists with files.
6. Return Manifest dataclass — same shape as today.
- **Migration command.** `./cli.py migrate-manifest`:
- Reads `$HOME/claude-bottle.json` and (if present)
`$CWD/claude-bottle.json`.
- Creates `$HOME/.claude-bottle/{bottles,agents}/` dirs.
- For each `bottles[<name>]`, writes
`$HOME/.claude-bottle/bottles/<name>.md` with frontmatter
rendered from the bottle dict, body empty (or a one-line
"Migrated from claude-bottle.json on <date>" stub).
- For each home `agents[<name>]`, writes
`$HOME/.claude-bottle/agents/<name>.md` with frontmatter
(bottle, skills, etc.) and body = `prompt`.
- For each cwd `agents[<name>]` (if cwd JSON existed),
writes `$CWD/.claude-bottle/agents/<name>.md`.
- Refuses to overwrite existing MD files; if a target
already exists, prints what would have been written and
bails on that file (continues with the others).
- Prints a summary at the end: N bottles written, M agents
written, what was skipped.
- **Docs.** README's manifest section rewrites against the new
layout. `claude-bottle.example.json` becomes
`examples/bottles/dev.md` + `examples/agents/implementer.md`.
@@ -238,9 +211,7 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
- `tests/unit/test_yaml_subset_parser.py` — the parser
itself, including all the rejection cases listed above.
- `tests/unit/test_manifest_md_load.py` — directory-globbing
+ assembly, the 8 success criteria.
- `tests/integration/test_migrate_manifest.py` — round-trip
JSON → MD; idempotency.
+ assembly, the seven success criteria.
- Existing integration tests keep working (the only public
entry points they hit are `Manifest.resolve` and
`Manifest.from_json_obj`).
@@ -248,7 +219,9 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
### Out of scope
- Watching the directory for changes mid-session.
- A migration tool for moving back (MD → JSON).
- An automated migration command. Existing JSON users
hand-rewrite into the new layout. The README rewrite
documents the new shape; that's the migration surface.
- Validating that frontmatter `name:` matches the filename.
Soft check via a warn log if mismatched, but not enforced.
- A bottle/agent dependency graph beyond the existing `bottle:`
@@ -378,9 +351,6 @@ def parse_frontmatter(text: str) -> tuple[dict[str, object], str]:
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.
- **`claude_bottle/cli/migrate_manifest.py`** — new. The
migration command.
- **`claude_bottle/cli/__init__.py`** — wire the new subcommand.
- **`README.md`** — manifest section rewritten against the new
layout.
- **`claude-bottle.example.json`** — removed; replaced by an
@@ -396,14 +366,15 @@ etc. all stay the same shape. Only the loader changes.
### Backward compatibility
This is a breaking change for v1 users. Mitigations:
This is a breaking change for v1 users. claude-bottle has a
single primary user today, so migration is one person rewriting
one file — no automated migration command is in scope.
- `./cli.py migrate-manifest` does the heavy lifting in one
command.
- If `claude-bottle.json` exists in `$HOME` or `$CWD` *and* the
new directories don't exist, the resolver dies with a clear
pointer at the migration command — not silently merging
formats, not silently dropping the JSON content.
If `claude-bottle.json` exists in `$HOME` or `$CWD` *and* the
new `.claude-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.
## Open questions
@@ -427,11 +398,6 @@ This is a breaking change for v1 users. Mitigations:
pattern will be "every bottle allows api.anthropic.com and
github.com"; do we want a way to share the list? Default no
for v1; revisit if it bites.
- **Migration tool destructive vs additive.** Default
additive (writes new files, leaves old JSON in place). If
users find the half-migrated state confusing, switch to
printing a "delete claude-bottle.json now" reminder at the
end of the migration.
## References