docs(prd-0011): drop the migration command requirement
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:
@@ -87,21 +87,13 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
|
|||||||
parser test. Frontmatter parsing is hand-rolled against the
|
parser test. Frontmatter parsing is hand-rolled against the
|
||||||
declared YAML subset.
|
declared YAML subset.
|
||||||
|
|
||||||
6. **Migration tool converts existing JSON to per-file MD.**
|
6. **Existing tests pass against the new layout.** Tests today
|
||||||
`./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
|
|
||||||
build manifests via JSON literals against `Manifest.from_json_obj`.
|
build manifests via JSON literals against `Manifest.from_json_obj`.
|
||||||
That entry point keeps working for tests (used to construct
|
That entry point keeps working for tests (used to construct
|
||||||
manifests programmatically); production resolution flows
|
manifests programmatically); production resolution flows
|
||||||
through the new directory-globbing loader.
|
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
|
`name`, `description`, `model`, `color`, and `memory` fields
|
||||||
from Claude Code's existing subagent spec are accepted in
|
from Claude Code's existing subagent spec are accepted in
|
||||||
our frontmatter alongside our own fields. Copying an agent
|
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.
|
pointer at the spec. We are not building a YAML library.
|
||||||
|
|
||||||
- **Compatibility with the old JSON layout at runtime.** The
|
- **Compatibility with the old JSON layout at runtime.** The
|
||||||
resolver no longer reads `claude-bottle.json` files. The
|
resolver no longer reads `claude-bottle.json` files. This is
|
||||||
migration tool is the bridge; after migration the JSON file
|
a breaking change; existing users hand-rewrite their JSON
|
||||||
is stale (and the user removes it). This is a breaking
|
into the new per-file layout (claude-bottle has a single
|
||||||
change for v1 users; the migration cost is one command + a
|
primary user today, so the migration is one person rewriting
|
||||||
manual delete.
|
one file). Documented as part of the README rewrite.
|
||||||
|
|
||||||
- **`$HOME/.claude/agents/` integration on the input side.** We
|
- **`$HOME/.claude/agents/` integration on the input side.** We
|
||||||
don't read agent files out of Claude Code's directory. Our
|
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.
|
5. Warn if `$CWD/.claude-bottle/bottles/` exists with files.
|
||||||
6. Return Manifest dataclass — same shape as today.
|
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
|
- **Docs.** README's manifest section rewrites against the new
|
||||||
layout. `claude-bottle.example.json` becomes
|
layout. `claude-bottle.example.json` becomes
|
||||||
`examples/bottles/dev.md` + `examples/agents/implementer.md`.
|
`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
|
- `tests/unit/test_yaml_subset_parser.py` — the parser
|
||||||
itself, including all the rejection cases listed above.
|
itself, including all the rejection cases listed above.
|
||||||
- `tests/unit/test_manifest_md_load.py` — directory-globbing
|
- `tests/unit/test_manifest_md_load.py` — directory-globbing
|
||||||
+ assembly, the 8 success criteria.
|
+ assembly, the seven success criteria.
|
||||||
- `tests/integration/test_migrate_manifest.py` — round-trip
|
|
||||||
JSON → MD; idempotency.
|
|
||||||
- Existing integration tests keep working (the only public
|
- Existing integration tests keep working (the only public
|
||||||
entry points they hit are `Manifest.resolve` and
|
entry points they hit are `Manifest.resolve` and
|
||||||
`Manifest.from_json_obj`).
|
`Manifest.from_json_obj`).
|
||||||
@@ -248,7 +219,9 @@ Each test runs against a temporary `$HOME` and a temporary `$CWD`:
|
|||||||
### Out of scope
|
### Out of scope
|
||||||
|
|
||||||
- Watching the directory for changes mid-session.
|
- 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.
|
- Validating that frontmatter `name:` matches the filename.
|
||||||
Soft check via a warn log if mismatched, but not enforced.
|
Soft check via a warn log if mismatched, but not enforced.
|
||||||
- A bottle/agent dependency graph beyond the existing `bottle:`
|
- 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
|
a programmatic entry point (used by tests). New
|
||||||
`Manifest.from_md_dirs(home_dir, cwd_dir)` for the loader.
|
`Manifest.from_md_dirs(home_dir, cwd_dir)` for the loader.
|
||||||
- **`claude_bottle/yaml_subset.py`** — new. The parser.
|
- **`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
|
- **`README.md`** — manifest section rewritten against the new
|
||||||
layout.
|
layout.
|
||||||
- **`claude-bottle.example.json`** — removed; replaced by an
|
- **`claude-bottle.example.json`** — removed; replaced by an
|
||||||
@@ -396,14 +366,15 @@ etc. all stay the same shape. Only the loader changes.
|
|||||||
|
|
||||||
### Backward compatibility
|
### 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
|
If `claude-bottle.json` exists in `$HOME` or `$CWD` *and* the
|
||||||
command.
|
new `.claude-bottle/` directory does not exist, the resolver
|
||||||
- If `claude-bottle.json` exists in `$HOME` or `$CWD` *and* the
|
dies with a clear pointer at the README's manifest section —
|
||||||
new directories don't exist, the resolver dies with a clear
|
not silently merging formats, not silently dropping the JSON
|
||||||
pointer at the migration command — not silently merging
|
content.
|
||||||
formats, not silently dropping the JSON content.
|
|
||||||
|
|
||||||
## Open questions
|
## 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
|
pattern will be "every bottle allows api.anthropic.com and
|
||||||
github.com"; do we want a way to share the list? Default no
|
github.com"; do we want a way to share the list? Default no
|
||||||
for v1; revisit if it bites.
|
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
|
## References
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user