diff --git a/CHANGELOG.md b/CHANGELOG.md index 545a084..a5eb14f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,4 @@ All notable changes to Base Platform Tools will be documented in this file. - Added the Base-managed project manifest and validation contract. - Added the tooling boundary documentation. - Added the initial GitHub Actions validation workflow. +- Added the initial CLI layout for future Bash and Python platform tools. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3961356..e638ca7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,6 +60,39 @@ Prefer portable implementations when practical, but do not hide platform limitations. A useful macOS/Linux/WSL-only tool is acceptable when the limitation is explicit. +## CLI Layout + +Use the seeded CLI layout for new tools: + +- `bin/` contains thin public launchers only. +- `cli/bash/commands//` contains Bash command implementations. +- `cli/python/base_platform_tools//` contains Python command packages. +- `base_manifest.yaml` declares commands that Base can run with + `basectl run base-platform-tools `. + +Do not copy `basectl` or `base-wrapper` into this repository. Base owns those +entrypoints. Base Platform Tools reuses them through manifest-declared commands +and thin launchers. + +Python launchers should invoke: + +```bash +"$BASE_HOME/bin/base-wrapper" \ + --project "${BASE_PROJECT:-base-platform-tools}" \ + base_platform_tools. "$@" +``` + +When a Python launcher needs this repository's package root, prepend +`$repo_root/cli/python` to `PYTHONPATH` before calling `base-wrapper`. + +Bash tools that need the Base runtime may use: + +```bash +#!/usr/bin/env basectl +``` + +and should keep their implementation under `cli/bash/commands//`. + ## Validation Run: diff --git a/README.md b/README.md index 63645fa..73b4eab 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,9 @@ The boundary is intentional: ## Current Status -This repository is in its initial scaffold stage. It does not yet contain -production utility CLIs. +This repository is in its initial scaffold stage. It has the initial CLI layout +for future Bash and Python tools, but it does not yet contain production utility +CLIs. The existing `caff` and `sort` utilities remain in `codeforester/base` for now. They can be migrated here later through separate issues and pull requests once @@ -61,6 +62,12 @@ Or through Base: basectl test base-platform-tools ``` +List the commands declared by this repository: + +```bash +basectl run base-platform-tools --list +``` + ## What Belongs Here Good candidates for this repository include: @@ -92,8 +99,19 @@ Keep these outside Base Platform Tools: ```text . +├── bin/ +│ └── README.md ├── base_manifest.yaml +├── cli/ +│ ├── README.md +│ ├── bash/ +│ │ └── README.md +│ └── python/ +│ ├── README.md +│ └── base_platform_tools/ +│ └── __init__.py ├── docs/ +│ ├── cli-layout.md │ └── tooling-boundary.md ├── tests/ │ └── validate.sh @@ -103,6 +121,8 @@ Keep these outside Base Platform Tools: └── README.md ``` -Future tools should live under a structure that matches their implementation -language and operational domain. The exact layout should be introduced when the -first real tool is migrated or added. +Future tools should live under the seeded CLI structure, with per-tool +subdirectories added when the first real tool is migrated or created. + +See [CLI Layout](docs/cli-layout.md) for the command structure and launcher +conventions. diff --git a/base_manifest.yaml b/base_manifest.yaml index 8dc360c..274d3c7 100644 --- a/base_manifest.yaml +++ b/base_manifest.yaml @@ -7,4 +7,5 @@ test: command: tests/validate.sh commands: + cli-check: tests/validate.sh validate: tests/validate.sh diff --git a/bin/README.md b/bin/README.md new file mode 100644 index 0000000..dce40ff --- /dev/null +++ b/bin/README.md @@ -0,0 +1,35 @@ +# Public Launchers + +This directory is reserved for thin public launcher scripts. + +Base Platform Tools does not provide its own `basectl` or `base-wrapper`. +Launchers in this directory should delegate through the Base installation that +is already managing the workspace. + +## Python Launcher Pattern + +Use this shape for a Python tool when a public executable is useful: + +```bash +#!/usr/bin/env bash + +repo_root="$(cd "$(dirname "$0")/.." && pwd -P)" || exit 1 + +: "${BASE_HOME:?BASE_HOME is required. Run through basectl run or basectl activate.}" + +PYTHONPATH="$repo_root/cli/python${PYTHONPATH:+:$PYTHONPATH}" +export PYTHONPATH + +exec "$BASE_HOME/bin/base-wrapper" \ + --project "${BASE_PROJECT:-base-platform-tools}" \ + base_platform_tools. "$@" +``` + +The launcher stays small. The behavior belongs under +`cli/python/base_platform_tools//`. + +## Bash Launcher Pattern + +Most Bash tools can be exposed directly through `base_manifest.yaml` without a +public launcher. If a public launcher is useful, keep it small and delegate to +the implementation under `cli/bash/commands//`. diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000..517dd2e --- /dev/null +++ b/cli/README.md @@ -0,0 +1,27 @@ +# CLI Layer + +This directory contains command implementations for Base Platform Tools. + +Base owns `basectl` and `base-wrapper`. This repository owns optional tool +implementations that Base can orchestrate through `base_manifest.yaml`. + +Use this layout: + +```text +cli/ +├── bash/ +│ └── commands/ +│ └── / +│ ├── .sh +│ ├── README.md +│ └── tests/ +└── python/ + └── base_platform_tools/ + └── / + ├── __init__.py + ├── __main__.py + ├── engine.py + └── tests/ +``` + +See `docs/cli-layout.md` for launcher and manifest conventions. diff --git a/cli/bash/README.md b/cli/bash/README.md new file mode 100644 index 0000000..7daa4c6 --- /dev/null +++ b/cli/bash/README.md @@ -0,0 +1,30 @@ +# Bash Tools + +Bash tools belong under: + +```text +cli/bash/commands//.sh +``` + +When a Bash tool needs the Base runtime, use: + +```bash +#!/usr/bin/env basectl + +main() { + ... +} + +main "$@" +``` + +Expose runnable Bash tools through `base_manifest.yaml`: + +```yaml +commands: + example: cli/bash/commands/example/example.sh +``` + +Keep Bash tools focused on shell-native orchestration. Move structured parsing, +state modeling, and non-trivial data transformations into Python unless shell is +clearly the better substrate. diff --git a/cli/python/README.md b/cli/python/README.md new file mode 100644 index 0000000..cd267ca --- /dev/null +++ b/cli/python/README.md @@ -0,0 +1,37 @@ +# Python Tools + +Python tools belong under the `base_platform_tools` package: + +```text +cli/python/base_platform_tools// + __init__.py + __main__.py + engine.py + tests/ +``` + +Use package execution as the public Python contract: + +```bash +base_platform_tools. +``` + +Thin launchers should set this repository's Python source root and then invoke +Base's wrapper: + +```bash +PYTHONPATH="$repo_root/cli/python${PYTHONPATH:+:$PYTHONPATH}" +export PYTHONPATH + +exec "$BASE_HOME/bin/base-wrapper" \ + --project "${BASE_PROJECT:-base-platform-tools}" \ + base_platform_tools. "$@" +``` + +The wrapper selects the `base-platform-tools` project virtual environment from +`~/.base.d/base-platform-tools/.venv` unless Base overrides +`BASE_PROJECT_VENV_DIR` for tests or project execution. + +Python modules should keep import-time behavior cheap and side-effect free. +Command packages should expose a `main(argv) -> int` function and raise +`SystemExit(main())` from `__main__.py`. diff --git a/cli/python/base_platform_tools/__init__.py b/cli/python/base_platform_tools/__init__.py new file mode 100644 index 0000000..93bddba --- /dev/null +++ b/cli/python/base_platform_tools/__init__.py @@ -0,0 +1 @@ +"""Python package namespace for Base Platform Tools command implementations.""" diff --git a/docs/cli-layout.md b/docs/cli-layout.md new file mode 100644 index 0000000..0b38615 --- /dev/null +++ b/docs/cli-layout.md @@ -0,0 +1,139 @@ +# CLI Layout + +Base Platform Tools provides optional tool implementations for Base-managed +workspaces. It reuses Base for orchestration and Python environment selection. + +Do not copy `basectl` or `base-wrapper` into this repository. + +## Ownership + +| Concern | Owner | +| --- | --- | +| Workspace orchestration | Base | +| `basectl` control plane | Base | +| `base-wrapper` Python execution wrapper | Base | +| Optional platform tools | Base Platform Tools | +| Tool command declarations | `base_manifest.yaml` in this repository | + +## Directory Structure + +```text +bin/ + # optional thin launchers + +cli/ + bash/ + commands/ + / + .sh + README.md + tests/ + + python/ + base_platform_tools/ + / + __init__.py + __main__.py + engine.py + tests/ +``` + +Create only the directories that a real tool needs. The top-level scaffold +exists to make the expected shape clear before production tools are added. + +## Manifest Commands + +Expose tools through `base_manifest.yaml` so Base can list and run them: + +```yaml +commands: + example-bash: cli/bash/commands/example-bash/example-bash.sh + example-python: bin/example-python +``` + +Run them with: + +```bash +basectl run base-platform-tools example-bash +basectl run base-platform-tools example-python +``` + +Use `--` to pass tool-specific arguments: + +```bash +basectl run base-platform-tools example-python -- --format json +``` + +## Bash Tools + +Bash tools that need the Base runtime should use: + +```bash +#!/usr/bin/env basectl + +main() { + ... +} + +main "$@" +``` + +The command implementation should live under: + +```text +cli/bash/commands//.sh +``` + +Prefer Bash for shell-native orchestration and small wrappers. Prefer Python +for structured parsing, data modeling, provider clients, reporting, and logic +that needs focused unit tests. + +## Python Tools + +Python tools should run as packages under `base_platform_tools`: + +```text +cli/python/base_platform_tools// + __init__.py + __main__.py + engine.py +``` + +Use this launcher shape when a Python tool needs a public executable: + +```bash +#!/usr/bin/env bash + +repo_root="$(cd "$(dirname "$0")/.." && pwd -P)" || exit 1 + +: "${BASE_HOME:?BASE_HOME is required. Run through basectl run or basectl activate.}" + +PYTHONPATH="$repo_root/cli/python${PYTHONPATH:+:$PYTHONPATH}" +export PYTHONPATH + +exec "$BASE_HOME/bin/base-wrapper" \ + --project "${BASE_PROJECT:-base-platform-tools}" \ + base_platform_tools. "$@" +``` + +This does two things: + +1. Adds this repository's `cli/python` directory to `PYTHONPATH`. +2. Delegates interpreter selection to Base's `base-wrapper`, using the + `base-platform-tools` project virtual environment. + +Base's wrapper adds Base's own Python libraries. The launcher adds this +repository's Python package root. + +## Tests + +Each tool should have focused tests near the implementation: + +```text +cli/bash/commands//tests/ +cli/python/base_platform_tools//tests/ +``` + +Wire the useful test command into `base_manifest.yaml` when the tool is ready. +The repository-level `tests/validate.sh` should stay a lightweight contract +check for the whole repo. diff --git a/docs/tooling-boundary.md b/docs/tooling-boundary.md index 49a7b77..c8ef552 100644 --- a/docs/tooling-boundary.md +++ b/docs/tooling-boundary.md @@ -44,6 +44,23 @@ operations space: These tools may have different platform support than Base itself. +## CLI Boundary + +Base Platform Tools does not own a second control plane. It must not copy +`basectl` or `base-wrapper`. + +Instead: + +- Base owns `basectl`. +- Base owns `base-wrapper`. +- Base Platform Tools owns optional tool implementations. +- `base_manifest.yaml` declares runnable tool commands. +- Base invokes those commands through `basectl run base-platform-tools `. + +Bash tools may use the Base runtime through `#!/usr/bin/env basectl`. Python +tools should run through Base's `base-wrapper` using the `base-platform-tools` +project virtual environment. + ## Platform Support Policy Base should aim for macOS, Linux, WSL, and eventually native Windows support. diff --git a/tests/validate.sh b/tests/validate.sh index e904e1c..e06ade0 100755 --- a/tests/validate.sh +++ b/tests/validate.sh @@ -42,10 +42,16 @@ main() { local failed=0 require_file README.md || failed=1 + require_file bin/README.md || failed=1 require_file CONTRIBUTING.md || failed=1 require_file CHANGELOG.md || failed=1 require_file LICENSE || failed=1 require_file base_manifest.yaml || failed=1 + require_file cli/README.md || failed=1 + require_file cli/bash/README.md || failed=1 + require_file cli/python/README.md || failed=1 + require_file cli/python/base_platform_tools/__init__.py || failed=1 + require_file docs/cli-layout.md || failed=1 require_file docs/tooling-boundary.md || failed=1 require_file .github/workflows/tests.yml || failed=1 require_file tests/validate.sh || failed=1 @@ -54,9 +60,19 @@ main() { require_text base_manifest.yaml '^schema_version: 1$' || failed=1 require_text base_manifest.yaml '^ name: base-platform-tools$' || failed=1 require_text base_manifest.yaml '^ command: tests/validate\.sh$' || failed=1 + require_text base_manifest.yaml '^ cli-check: tests/validate\.sh$' || failed=1 require_text README.md 'Base owns the workstation control plane' || failed=1 + require_text README.md 'CLI Layout' || failed=1 + require_text bin/README.md 'base-wrapper' || failed=1 + require_text cli/README.md 'Base owns `basectl`' || failed=1 + require_text cli/bash/README.md '#!/usr/bin/env basectl' || failed=1 + require_text cli/python/README.md 'base_platform_tools.' || failed=1 + require_text docs/cli-layout.md 'Do not copy `basectl` or `base-wrapper`' || failed=1 + require_text docs/cli-layout.md 'PYTHONPATH="\$repo_root/cli/python' || failed=1 require_text docs/tooling-boundary.md 'Base is the workstation orchestration layer' || failed=1 + require_text docs/tooling-boundary.md 'Base Platform Tools does not own a second control plane' || failed=1 require_text CONTRIBUTING.md 'Platform Support' || failed=1 + require_text CONTRIBUTING.md 'CLI Layout' || failed=1 if [[ $failed -ne 0 ]]; then return 1