Skip to content
Open
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
63 changes: 63 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```sh
make deps # Install dev dependencies (uv sync --dev --frozen)
make check # Full check: fmt + lint + test + test-e2e
make check-static # fmt + lint only
make fmt # Run ruff formatter
make lint # Run mypy + ruff + uv lock check
make lint-mypy # Type check only (args= supported)
make test # Run unit tests (args= supported)
make test-e2e # Run e2e tests (requires tool installed)
make docs-watch # Local docs server
```

Run a single test:
```sh
uv run --frozen pytest tests/path/to/test_file.py::test_name
```

Run CLI during development:
```sh
uv run nava-platform <args>
```

## Architecture

Entry point: `nava/platform/cli/__main__.py` → `cli/main.py` builds a `typer.Typer` with two sub-apps: `infra` and `app`.

**Layer structure:**

- `nava/platform/cli/` — CLI layer (typer commands, context, console, logging, config)
- `commands/infra/` — `install`, `update`, `add-app`, `info`, `migrate-from-legacy` subcommands
- `commands/app.py` — app-level subcommands
- `nava/platform/templates/` — core template logic
- `template.py` — `Template` class wraps copier; handles copy/update against a project
- `infra_template.py` — infra-specific template operations
- `state.py` — reads/writes `.nava` answer files that track installed template versions
- `template_name.py` — parses template name from URI
- `nava/platform/projects/` — project/app abstractions (`Project`, `InfraProject`)
- `nava/platform/copier_worker.py` — `NavaWorker` extends copier's `Worker` to support `src_exclude` filtering _before_ template rendering (upstream only filters after)
- `nava/platform/util/` — git helpers, wrappers, collections

**Key data flow:** CLI command → `CliContext` (log, console, output level) → `Template`/`InfraTemplate` → `NavaWorker` (wraps copier) → writes files to project dir + updates `.nava` state files.

**State tracking:** Installed template versions are stored in `.nava/` answer files within target projects, not in this repo.

**Copier pin:** `copier` is pinned to a specific git commit in `pyproject.toml` because a later commit breaks `NavaWorker`'s `src_exclude` setup.

## Testing

- Unit tests: `tests/` — mirrors `nava/` package structure
- E2e tests: `tests-e2e/` — shell scripts requiring the tool to be installed; `bin/test-e2e` orchestrates them
- `conftest.py` at `tests/` root contains shared fixtures

## Linting

- `ruff` for formatting and linting (line length 100, Google docstring convention)
- `mypy` in strict mode with `local_partial_types = true`; tests exempt from typed def requirements
- In CI, `make fmt` runs with `--check` and `make lint` runs without `--fix`
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ nava-platform infra install ./just-a-test
For comprehensive guides on using the platform CLI with existing projects:
- [Getting Started Guide](./docs/getting-started/index.md)
- [New Project Setup](./docs/getting-started/new-project.md)
- [Working with an Existing Template](./docs/getting-started/working-with-existing-template.md)
- [Migrating from Legacy Template](./docs/getting-started/migrating-from-legacy-template.md)

### Shell Completion
Expand Down
1 change: 1 addition & 0 deletions docs/getting-started/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ nav:
- index.md
- migrating-from-legacy-template.md
- new-project.md
- working-with-existing-template.md
4 changes: 3 additions & 1 deletion docs/getting-started/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
For projects using the legacy install/update scripts, see [Migrating old
templates to Nava Platform CLI](./migrating-from-legacy-template.md).

For starting a new project, see [Starting a new project](./new-project.md)
For starting a new project, see [Starting a new project](./new-project.md).

For developing or testing changes to an app template locally, see [Working with an existing template](./working-with-existing-template.md).
131 changes: 131 additions & 0 deletions docs/getting-started/working-with-existing-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Working with an existing app template

This guide covers how to develop and test changes to an app template (e.g., `template-application-rails`, `template-application-flask`) and apply those changes to a project using the Platform CLI.

## How template versioning works

The Platform CLI uses [Copier](https://copier.readthedocs.io/en/stable/) under the hood, which relies on **Git tags** for version resolution. When you run an `install` or `update` command, the CLI clones the template repository and **checks out the latest tagged version** by default — not `main` or any other branch.

This means:

- **Tags are the source of truth.** The CLI will not pick up commits on `main` unless those commits are included in a tagged release.
- **A new tag must be created** in the template repository for the CLI to recognize and install new changes.
- Tags should follow [PEP 440](https://peps.python.org/pep-0440/) versioning (e.g., `v0.1.0`, `v0.2.0`). Non-compliant tags are ignored during version resolution.

> [!IMPORTANT]
> Simply merging changes to `main` in a template repository is **not sufficient** for those changes to be picked up by the CLI. A new version tag must be pushed to the repository.

### Example: releasing a new template version

After merging your changes to the template's `main` branch:

```sh
# In the template repository
git tag v0.3.0
git push origin v0.3.0
```

Projects can then pick up this version:

```sh
nava-platform app update . myapp
```

## Developing with a local template

When working on template changes, you don't need to push to a remote or create tags. The CLI supports pointing directly at a **local directory** and a specific **branch or ref**, which is ideal for development and testing.

### Setting up a local checkout

Clone the app template repository (or use an existing clone):

```sh
git clone https://github.com/navapbc/template-application-rails ~/templates/template-application-rails
```

Create a branch for your changes:

```sh
cd ~/templates/template-application-rails
git checkout -b my-feature-branch
```

Make your template changes and commit them.

> [!NOTE]
> Template changes must be committed to your local branch. Copier works from Git history, so uncommitted changes will not be applied.

### Using a Git worktree (alternative)

If you'd rather keep your default branch intact, you can use a [Git worktree](https://git-scm.com/docs/git-worktree) instead of a new clone:

```sh
cd ~/templates/template-application-rails
git worktree add ../template-application-rails-feature my-feature-branch
```

This creates a separate working directory at `../template-application-rails-feature` checked out to `my-feature-branch`, while leaving your original clone on its current branch.

### Installing from a local template

Use `--template-uri` to point to your local checkout, and `--version` to specify the branch:

```sh
nava-platform app install \
--template-uri ~/templates/template-application-rails \
--version my-feature-branch \
--commit \
. myapp
```

### Updating from a local template

Similarly, to update an existing project using your local template changes:

```sh
nava-platform app update \
--template-uri ~/templates/template-application-rails \
--version my-feature-branch \
--commit \
. myapp
```

> [!TIP]
> Use `--version HEAD` to always apply the latest commit on the default branch of your local checkout, regardless of tags.

### Key CLI options for local development

| Option | Description |
|---|---|
| `--template-uri` | Path or URL to the template source. Can be a local path (e.g., `~/templates/template-application-rails`) or a remote URL. |
| `--version` | Template version to use. Accepts a branch name, tag, commit hash, or `HEAD`. Defaults to the latest tag. |
| `--template-name` | Override the template name if your local directory has a different name than the upstream repository (e.g., if your worktree folder is named differently). |
| `--commit` | Automatically commit the generated changes with a standard message. |

## Infra template local development

The infra template works the same way. The default `--template-uri` for `infra` commands is `https://github.com/navapbc/template-infra`, but you can override it:

```sh
nava-platform infra install \
--template-uri ~/templates/template-infra \
--version my-feature-branch \
--commit \
. myapp
```

```sh
nava-platform infra update \
--template-uri ~/templates/template-infra \
--version my-feature-branch \
.
```

## Summary

| Scenario | What to do |
|---|---|
| Use the latest released template version | Just run `install` or `update` — the CLI defaults to the latest tag. |
| Release a new template version for all projects | Tag a new version in the template repo and push it. |
| Test local template changes during development | Use `--template-uri` pointed at your local clone and `--version` set to your branch. |
| Always use the latest commit (skip tag resolution) | Pass `--version HEAD`. |
Loading