Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ The package requires Python 3.10 or newer and pins the supported Base-CLI line
to `>=0.4.3,<0.5`. This checkout targets demo release `v0.1.0`; demo release
versioning remains separate from framework versioning.

## Documentation

Follow the [documentation index](docs/README.md) for an ordered path from
adoption decision through the Northstar walkthrough, compatibility, and
release. To start with a minimal consumer rather than the full demo, use the
[copyable starter](docs/use-in-your-project.md).

For framework-level material, start at the
[Base-CLI repository](https://github.com/basefoundry/base-cli), its
[getting-started guide](https://github.com/basefoundry/base-cli#quick-start),
or the [public API reference](https://github.com/basefoundry/base-cli/blob/main/docs/api-reference.md).

## Repository shape

- `src/base_cli_demo/cli.py` contains the consumer-owned Click tree and the
Expand Down
28 changes: 28 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Documentation guide

Use this path to decide whether Base-CLI fits, then move from a tiny starter to
the complete Northstar consumer:

1. [Why Base-CLI?](why-base-cli.md) — the lifecycle work it supplies and what
Northstar keeps in the application.
2. [Should I use Base-CLI?](should-i-use-base-cli.md) — maturity, fit, costs,
and alternatives.
3. [Use Base-CLI in your project](use-in-your-project.md) — a minimal command
you can copy before exploring the larger demo.
4. [Five-minute learning path](learning-path.md) — install Northstar and follow
its human and automation scenarios.
5. [Lifecycle safety](lifecycle-safety.md) — dry-run, structured errors,
diagnostics, temporary files, and cleanup.
6. [Configuration](configuration.md) — the consumer-owned settings and
provenance boundary.
7. [Optional integrations](optional-integrations.md) — Typer, Rich, and
OpenTelemetry extras and fallback paths.
8. [Compatibility](compatibility.md) — the released Base-CLI range and
installed-wheel checks.
9. [Release process](release-process.md) — independent demo versioning,
reproducible packages, and guarded GitHub Release steps.

For the framework's complete material, start at the
[Base-CLI repository](https://github.com/basefoundry/base-cli), its
[getting-started guide](https://github.com/basefoundry/base-cli#quick-start),
or the [public API reference](https://github.com/basefoundry/base-cli/blob/main/docs/api-reference.md).
52 changes: 52 additions & 0 deletions docs/use-in-your-project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Use Base-CLI in your project

Northstar is intentionally production-shaped. If you want the smallest
transferable pattern, start with one Click command and let Base-CLI own the
invocation lifecycle.

Install the released framework line used by this demo:

```bash
python -m pip install "base-cli>=0.4.3,<0.5" "click>=8.1,<9"
```

Save this as `hello.py`:

```python
from __future__ import annotations

import base_cli
import click


@click.command()
@click.option("--name", default="world", show_default=True)
def hello(name: str) -> None:
click.echo(f"hello {name}")


app = base_cli.App(name="hello", version="0.1.0")
command = app.attach(hello)


if __name__ == "__main__":
raise SystemExit(base_cli.run_app(command))
```

Run it:

```console
$ python hello.py --name Ada
hello Ada
```

The runnable copy in [`examples/minimal_cli.py`](../examples/minimal_cli.py)
is exercised by the test suite. From the example, continue with the
[five-minute Northstar tour](learning-path.md) to see nested commands,
consumer-owned configuration, and structured output.

The `App` and `attach` calls establish the framework boundary; the Click
function remains your command. See the framework's
[consumer quickstart](https://github.com/basefoundry/base-cli/blob/main/docs/consumer-quickstart.md)
and [API reference](https://github.com/basefoundry/base-cli/blob/main/docs/api-reference.md)
for the public interfaces.
28 changes: 28 additions & 0 deletions examples/minimal_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Smallest runnable Click command attached to the Base-CLI lifecycle."""

from __future__ import annotations

import base_cli
import click


@click.command()
@click.option("--name", default="world", show_default=True)
def hello(name: str) -> None:
"""Greet one person."""

click.echo(f"hello {name}")


app = base_cli.App(name="hello", version="0.1.0")
command = app.attach(hello)


def main() -> int:
"""Run the minimal example through Base-CLI."""

return base_cli.run_app(command)


if __name__ == "__main__":
raise SystemExit(main())
45 changes: 35 additions & 10 deletions skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,41 @@
Use this file as the repo-local index for project-specific agent workflows.
Keep entries short, concrete, and owned by this repository.

## Suggested Entries

- Development workflow: issue selection, branch naming, validation, PR creation,
merge, and cleanup.
- Testing workflow: the commands that prove common changes are safe.
- Release workflow: read `docs/release-process.md` when the repository declares
release metadata, then follow its version, changelog, tag, release, and
package manager steps.
- Domain workflow: product-specific checks or demo expectations that agents
should not have to rediscover.
## Development workflow

- Start from a GitHub issue and use its single category label in the branch:
`<category>/<issue>-<YYYYMMDD>-<slug>`.
- Use a dedicated worktree from `origin/main`; keep each PR scoped to one issue.
- Link a completing PR with `Fixes #<number>`. Do not merge unless the user
explicitly asks for it.
- Preserve existing changes and leave the main checkout clean.

## Validation workflow

- Run `./tests/validate.sh` for the authoritative consumer gate.
- Run `uv run --extra dev pytest -q` for the complete default suite.
- Run `uv run --extra dev tests/package.sh` for wheel, sdist, and Twine checks.
- Run `uv lock --check` when changing dependencies or extras.
- Optional scenarios should be checked both without extras and with
`uv run --extra dev --extra typer --extra rich --extra telemetry pytest -q`.

## Product boundary

- Keep Northstar deterministic, offline, and independent of the Base workspace
runtime. It consumes released `base-cli` APIs only.
- Keep parser commands, service fixtures, and domain policy in this repository;
keep lifecycle behavior at the public `base_cli` boundary.
- Do not make ecosystem/catalog examples depend on unreleased platform
contracts.

## Release workflow

- Read `docs/release-process.md` before editing `VERSION`, release notes, tags,
or GitHub Releases.
- Verify package contents and `basectl release check/plan/notes` first.
- Use `basectl release publish --version X.Y.Z --dry-run` to review the plan.
Never create a tag or publish a GitHub Release without explicit user
authorization.

## Boundaries

Expand Down
26 changes: 26 additions & 0 deletions tests/test_minimal_starter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path


def test_minimal_starter_runs_with_the_installed_framework(tmp_path: Path) -> None:
script = Path(__file__).parents[1] / "examples" / "minimal_cli.py"
environment = os.environ.copy()
environment["BASE_CLI_CACHE_DIR"] = str(tmp_path / "cache")
environment["HOME"] = str(tmp_path / "home")
environment["USERPROFILE"] = str(tmp_path / "home")

result = subprocess.run(
[sys.executable, str(script), "--name", "Ada"],
capture_output=True,
cwd=tmp_path,
env=environment,
text=True,
check=False,
)

assert result.returncode == 0, result.stderr
assert result.stdout.strip() == "hello Ada"
Loading