diff --git a/docs/prds/0011-per-file-md-manifest.md b/docs/prds/0011-per-file-md-manifest.md index a71f733..7463526 100644 --- a/docs/prds/0011-per-file-md-manifest.md +++ b/docs/prds/0011-per-file-md-manifest.md @@ -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[]`, writes - `$HOME/.claude-bottle/bottles/.md` with frontmatter - rendered from the bottle dict, body empty (or a one-line - "Migrated from claude-bottle.json on " stub). - - For each home `agents[]`, writes - `$HOME/.claude-bottle/agents/.md` with frontmatter - (bottle, skills, etc.) and body = `prompt`. - - For each cwd `agents[]` (if cwd JSON existed), - writes `$CWD/.claude-bottle/agents/.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