|
1 | 1 | # CLAUDE.md |
2 | 2 |
|
3 | | -## What this project does |
| 3 | +Generates typed Python CLIs from OpenAPI 3.x specs. Nested request bodies become flat `--flags`. |
4 | 4 |
|
5 | | -`openapi-cli-gen` takes any OpenAPI 3.x spec and generates a typed Python CLI where nested request bodies become flat `--flags`. It works as a library (`build_cli()`), a runtime tool (`run`), or a code generator (`generate`). |
6 | | - |
7 | | -## Quick reference |
| 5 | +## Commands |
8 | 6 |
|
9 | 7 | ```bash |
10 | | -# Run tests |
11 | | -.venv/bin/python -m pytest tests/ -q |
12 | | - |
13 | | -# Install in dev mode |
14 | | -uv pip install -e . --python .venv/bin/python |
15 | | - |
16 | | -# Regenerate all 6 wrapper CLIs (reads wrappers/manifest.yaml) |
17 | | -.venv/bin/python scripts/regenerate.py |
18 | | - |
19 | | -# Regenerate + publish to PyPI + push to GitHub repos |
20 | | -.venv/bin/python scripts/regenerate.py --publish --push |
21 | | - |
22 | | -# Regenerate one wrapper |
23 | | -.venv/bin/python scripts/regenerate.py --only qdrant-rest-cli |
24 | | - |
25 | | -# Dry run (show what would happen) |
26 | | -.venv/bin/python scripts/regenerate.py --dry-run |
| 8 | +.venv/bin/python -m pytest tests/ -q # run tests (50, ~1s) |
| 9 | +uv pip install -e . --python .venv/bin/python # dev install |
| 10 | +.venv/bin/python scripts/regenerate.py # regenerate all wrapper CLIs |
| 11 | +.venv/bin/python scripts/regenerate.py --publish --push # + PyPI + GitHub |
| 12 | +.venv/bin/python scripts/regenerate.py --only qdrant-rest-cli # single wrapper |
27 | 13 | ``` |
28 | 14 |
|
29 | 15 | ## Architecture |
30 | 16 |
|
31 | 17 | ``` |
32 | | -spec/loader.py → load OpenAPI spec (file or URL), resolve $refs |
33 | | -spec/parser.py → extract EndpointInfo list from resolved spec |
34 | | -engine/models.py → generate Pydantic models via datamodel-code-generator (disk cached) |
35 | | -engine/registry.py → group commands by tag, attach models |
36 | | -engine/builder.py → build_cli() / build_command_group() — the public API |
37 | | -engine/dispatch.py → manual CLI dispatch (group → command → execute) |
38 | | -engine/auth.py → bearer, api-key, basic auth from env vars |
39 | | -output/formatter.py → json/yaml/table/raw output |
40 | | -codegen/generator.py → generate installable package from spec (Jinja2 templates) |
41 | | -cli.py → typer CLI: generate, run, inspect commands |
| 18 | +spec/loader.py → load spec (file/URL), resolve $refs |
| 19 | +spec/parser.py → extract endpoints from spec |
| 20 | +engine/models.py → Pydantic models via datamodel-code-generator (disk cached in ~/.cache/openapi-cli-gen/) |
| 21 | +engine/builder.py → build_cli() / build_command_group() public API |
| 22 | +engine/dispatch.py → CLI dispatch (group → command → HTTP call) |
| 23 | +engine/auth.py → bearer, api-key, basic auth |
| 24 | +codegen/generator.py → generate installable package (Jinja2 templates) |
| 25 | +cli.py → typer CLI: generate, run, inspect |
42 | 26 | ``` |
43 | 27 |
|
44 | | -## Wrapper CLIs |
45 | | - |
46 | | -Six pre-built CLIs generated from this tool, each in its own GitHub repo and on PyPI: |
| 28 | +## Wrappers |
47 | 29 |
|
48 | | -| Name | Repo | Spec source | |
49 | | -|------|------|-------------| |
50 | | -| openai-rest-cli | shivaam/openai-rest-cli | openai/openai-openapi | |
51 | | -| meilisearch-rest-cli | shivaam/meilisearch-rest-cli | meilisearch/open-api | |
52 | | -| adguard-home-cli | shivaam/adguard-home-cli | AdguardTeam/AdGuardHome | |
53 | | -| immich-rest-cli | shivaam/immich-rest-cli | immich-app/immich | |
54 | | -| qdrant-rest-cli | shivaam/qdrant-rest-cli | qdrant/qdrant | |
55 | | -| typesense-rest-cli | shivaam/typesense-rest-cli | typesense/typesense-api-spec | |
| 30 | +Six CLIs, each in its own repo/PyPI package. Config in `wrappers/manifest.yaml`. |
56 | 31 |
|
57 | | -All config lives in `wrappers/manifest.yaml` — spec URLs, base URLs, versions, repo names. Hand-written READMEs live in `wrappers/<name>/README.md` and get copied into generated packages automatically. |
| 32 | +| Name | Repo | |
| 33 | +|------|------| |
| 34 | +| openai-rest-cli | shivaam/openai-rest-cli | |
| 35 | +| meilisearch-rest-cli | shivaam/meilisearch-rest-cli | |
| 36 | +| adguard-home-cli | shivaam/adguard-home-cli | |
| 37 | +| immich-rest-cli | shivaam/immich-rest-cli | |
| 38 | +| qdrant-rest-cli | shivaam/qdrant-rest-cli | |
| 39 | +| typesense-rest-cli | shivaam/typesense-rest-cli | |
58 | 40 |
|
59 | | -**To update all wrappers after a new release:** |
60 | | -1. Bump version in `pyproject.toml` + `src/openapi_cli_gen/__init__.py` |
61 | | -2. Publish `openapi-cli-gen` to PyPI |
62 | | -3. Bump `version` field in `wrappers/manifest.yaml` for each wrapper |
63 | | -4. Run `python scripts/regenerate.py --publish --push` |
64 | | - |
65 | | -## Versioning |
66 | | - |
67 | | -- `openapi-cli-gen` version: `pyproject.toml` and `src/openapi_cli_gen/__init__.py` (keep in sync) |
68 | | -- Wrapper versions: `wrappers/manifest.yaml` → `version` field per wrapper |
69 | | -- Generated packages pin `openapi-cli-gen>={current_version}` |
70 | | -- PyPI doesn't allow re-uploading the same version — always bump before publishing |
71 | | - |
72 | | -## Publishing |
73 | | - |
74 | | -PyPI token is in `~/.pypirc`. Build + upload: |
75 | | -```bash |
76 | | -python -m build && python -m twine upload dist/* |
77 | | -``` |
| 41 | +Hand-written READMEs in `wrappers/<name>/README.md` are copied into generated packages. |
78 | 42 |
|
79 | | -## Testing |
| 43 | +## Releasing |
80 | 44 |
|
81 | | -- Unit tests: `tests/` (50 tests, ~1s) |
82 | | -- Live regression: `experiments/regression_test.py` (needs running API instances) |
83 | | -- Test spec: `tests/conftest.py` has a minimal OpenAPI spec fixture |
| 45 | +1. Bump version in both `pyproject.toml` and `src/openapi_cli_gen/__init__.py` |
| 46 | +2. `python -m build && python -m twine upload dist/*` |
| 47 | +3. Bump `version` in `wrappers/manifest.yaml` (PyPI rejects duplicate versions) |
| 48 | +4. `python scripts/regenerate.py --publish --push` |
84 | 49 |
|
85 | | -## Key conventions |
| 50 | +## Conventions |
86 | 51 |
|
87 | | -- Python package uses underscores (`openapi_cli_gen`), CLI/PyPI names use dashes (`openapi-cli-gen`) |
88 | | -- Generated CLIs read auth from `{PREFIX}_TOKEN`, `{PREFIX}_API_KEY`, `{PREFIX}_USERNAME`/`{PREFIX}_PASSWORD` env vars |
89 | | -- SSL config via `{PREFIX}_VERIFY_SSL`, `{PREFIX}_CA_CERT`, `{PREFIX}_CLIENT_CERT`, `{PREFIX}_CLIENT_KEY` |
90 | | -- `--root` flag on every POST/PUT/PATCH command accepts raw JSON, bypassing typed flags |
91 | | -- Model generation is disk-cached in `~/.cache/openapi-cli-gen/models/` |
| 52 | +- Dashes for CLI/PyPI names, underscores for Python packages |
| 53 | +- Auth env vars: `{PREFIX}_TOKEN`, `{PREFIX}_API_KEY`, `{PREFIX}_USERNAME`/`{PREFIX}_PASSWORD` |
| 54 | +- SSL env vars: `{PREFIX}_VERIFY_SSL`, `{PREFIX}_CA_CERT`, `{PREFIX}_CLIENT_CERT`, `{PREFIX}_CLIENT_KEY` |
| 55 | +- `--root` flag on POST/PUT/PATCH accepts raw JSON, bypassing typed flags |
0 commit comments