From 064efdadfd4a07165d115ce7da75cbefb7f5bd07 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Thu, 5 Mar 2026 06:46:57 -0800 Subject: [PATCH] added claude commands associated with project maintenance --- .claude/commands/new-issues.md | 113 ++++++++++++++++++++++++++++++ .claude/commands/release-major.md | 109 ++++++++++++++++++++++++++++ .claude/commands/release-minor.md | 109 ++++++++++++++++++++++++++++ .claude/commands/release-patch.md | 106 ++++++++++++++++++++++++++++ .claude/commands/rockout.md | 111 +++++++++++++++++++++++++++++ 5 files changed, 548 insertions(+) create mode 100644 .claude/commands/new-issues.md create mode 100644 .claude/commands/release-major.md create mode 100644 .claude/commands/release-minor.md create mode 100644 .claude/commands/release-patch.md create mode 100644 .claude/commands/rockout.md diff --git a/.claude/commands/new-issues.md b/.claude/commands/new-issues.md new file mode 100644 index 00000000..9fd26b8f --- /dev/null +++ b/.claude/commands/new-issues.md @@ -0,0 +1,113 @@ +# New Issues: Feature Gap Analysis and Issue Creation + +Audit the README feature matrix, identify gaps and opportunities, and file +GitHub issues for the best candidates. The prompt is: $ARGUMENTS + +--- + +## Step 1 -- Read the feature matrix + +1. Read `README.md` and extract every function listed in the feature matrix tables. +2. For each function, record: + - Category (Surface, Hydrology, Focal, etc.) + - Backend support (which of the four columns are native, fallback, or missing) +3. Read the source files referenced in the matrix to confirm what actually exists + (the README can drift from reality). + +## Step 2 -- Identify backend gaps + +1. List every function where one or more backends show 🔄 (fallback) or blank + (unsupported). +2. Prioritize gaps where: + - The function already has 3 of 4 backends (low effort to complete the set) + - The missing backend is CuPy or Dask+CuPy (GPU support matters for large rasters) + - The function is commonly used by GIS analysts (slope, aspect, flow direction, etc.) +3. Draft 1-3 maintenance issues for the highest-value backend completions. + +## Step 3 -- Identify missing features + +Think about what GIS analysts and Python spatial data scientists actually need +that the library does not yet provide. Consider: + +- **Surface analysis gaps:** contour line extraction, profile/cross-section tools, + terrain shadow analysis, sky-view factor, landform classification + (Weiss 2001, Jasiewicz & Stepinski 2013) +- **Hydrology gaps:** HAND (Height Above Nearest Drainage) generation (not just + flood-depth-from-HAND), depression filling / breach, channel width estimation, + compound topographic index (CTI / wetness index) +- **Focal / neighborhood gaps:** directional filters, morphological operators + (erode, dilate, open, close), texture metrics (entropy, GLCM), circular + or annular kernels +- **Multispectral gaps:** water indices (NDWI, MNDWI), built-up indices (NDBI), + snow index (NDSI), tasseled cap, PCA, band math DSL +- **Interpolation gaps:** natural neighbor, RBF (radial basis function), + trend surface +- **Zonal gaps:** zonal geometry (area, perimeter, centroid), majority/minority + filter, zonal histogram +- **Network / connectivity:** cost-path corridor, least-cost corridor, + visibility network (intervisibility between multiple points) +- **Time series:** temporal compositing (median, max-NDVI), change detection, + phenology metrics +- **I/O and interop:** raster clipping to polygon, raster merge/mosaic, + coordinate reprojection helpers + +Do NOT suggest features that duplicate what GDAL/rasterio already do well +unless there is a clear benefit to having a pure-Python/Numba version (e.g. +GPU support, Dask integration, no C dependency). + +Select the 3-5 most impactful feature suggestions. Rank by: +1. How often GIS analysts need the operation (daily-use beats niche) +2. How well it fits the library's existing architecture +3. Whether it fills a gap no other GDAL-free Python library covers + +## Step 4 -- Draft the issues + +For each candidate (both maintenance and new-feature), draft a GitHub issue +following the `.github/ISSUE_TEMPLATE/feature-proposal.md` template: + +- **Title:** short, imperative (e.g. "Add NDWI water index to multispectral module") +- **Labels:** `enhancement` plus any topical labels that fit +- **Body sections:** + - Reason or Problem + - Proposal (Design, Usage, Value) + - Stakeholders and Impacts + - Drawbacks + - Alternatives + - Unresolved Questions + +Keep each issue body concise. Cite specific algorithms or papers where +relevant. Include a short code snippet showing the proposed API. + +## Step 5 -- Humanize and create + +1. Collect all drafted issue bodies into a batch. +2. **Run each issue body through the `/humanizer` skill** to strip AI writing + patterns before creating the issue. +3. Create each issue with `gh issue create`, passing the humanized title, + body, and labels. +4. Record the issue numbers and URLs. + +## Step 6 -- Summary + +Print a table of all created issues: + +``` +| # | Title | Labels | URL | +|---|-------|--------|-----| +``` + +Then briefly explain the rationale: why these issues were chosen, what +analyst workflows they unblock, and any issues you considered but dropped +(with a one-line reason for each). + +--- + +## General rules + +- Do not create duplicate issues. Before filing, search existing issues with + `gh issue list --limit 100 --state all` and skip anything already covered. +- Run `/humanizer` on every issue title and body before creating it. +- If $ARGUMENTS contains specific focus areas (e.g. "hydrology only"), + restrict the analysis to those categories. +- If $ARGUMENTS is empty, run the full analysis across all categories. +- Prefer fewer, higher-quality issues over a long wishlist. diff --git a/.claude/commands/release-major.md b/.claude/commands/release-major.md new file mode 100644 index 00000000..cd9ec0e1 --- /dev/null +++ b/.claude/commands/release-major.md @@ -0,0 +1,109 @@ +# Release: Major + +Cut a major release (X.Y.Z -> X+1.0.0). Follow every step below in order. + +$ARGUMENTS + +--- + +## Step 1 -- Determine the new version + +1. Run `git tag --sort=-v:refname | head -5` to find the latest tag. +2. Parse the current version (format `vX.Y.Z`). +3. Increment the **major** component and reset minor+patch: `X.Y.Z` -> `(X+1).0.0`. +4. Store the new version string (without `v` prefix) for later steps. + +## Step 2 -- Create a release branch + +```bash +git checkout master && git pull +git checkout -b release/vX.Y.Z +``` + +## Step 3 -- Update CHANGELOG.md + +1. Run `git log --pretty=format:"- %s" ..HEAD` to collect + changes since the last release. +2. Add a new section at the top of CHANGELOG.md (below the header line) + matching the existing format: + ``` + ### Version X.Y.Z - YYYY-MM-DD + + #### New Features + - feature description (#PR) + + #### Bug Fixes & Improvements + - fix description (#PR) + ``` +3. Use today's date. Categorize entries under "New Features" and/or + "Bug Fixes & Improvements" as appropriate. +4. Run `/humanizer` on the changelog text before writing it. + +## Step 4 -- Commit and push + +```bash +git add CHANGELOG.md +git commit -m "Update CHANGELOG for vX.Y.Z release" +git push -u origin release/vX.Y.Z +``` + +## Step 5 -- Verify CI + +1. Run `gh pr create --title "Release vX.Y.Z" --body "Changelog update for vX.Y.Z major release."` to open a PR against master. +2. Wait for CI: + ```bash + gh pr checks --watch + ``` +3. If CI fails, fix the issue, amend or add a commit, push, and re-check. + +## Step 6 -- Merge the release branch + +```bash +gh pr merge --merge --delete-branch +``` + +## Step 7 -- Tag the release + +```bash +git checkout master && git pull +git tag -a vX.Y.Z -m "Version X.Y.Z" +git push origin vX.Y.Z +``` + +Do **not** sign the tag (`-s` flag omitted). + +## Step 8 -- Create a GitHub release + +```bash +gh release create vX.Y.Z --title "vX.Y.Z" --notes-file <(changelog_excerpt) +``` + +Use the CHANGELOG section for this version as the release notes body. +Run `/humanizer` on the notes before creating the release. + +## Step 9 -- Verify PyPI + +1. The `pypi-publish.yml` workflow triggers automatically on tag push. +2. Watch the workflow: + ```bash + gh run list --workflow=pypi-publish.yml --limit 1 + gh run watch + ``` +3. Confirm the new version appears: + ```bash + pip index versions xarray-spatial 2>/dev/null || echo "Check https://pypi.org/project/xarray-spatial/" + ``` + +## Step 10 -- Summary + +Print the new version, links to the PR, GitHub release, and PyPI page. + +--- + +## General rules + +- Run `/humanizer` on all text destined for GitHub: PR title/body, release + notes, commit messages, and any comments left on issues or PRs. +- Any temporary files created during the release (build artifacts, scratch + files) must use unique names including the version number to avoid + collisions (e.g. `changelog-draft-1.0.0.md`). diff --git a/.claude/commands/release-minor.md b/.claude/commands/release-minor.md new file mode 100644 index 00000000..a8573869 --- /dev/null +++ b/.claude/commands/release-minor.md @@ -0,0 +1,109 @@ +# Release: Minor + +Cut a minor release (X.Y.Z -> X.Y+1.0). Follow every step below in order. + +$ARGUMENTS + +--- + +## Step 1 -- Determine the new version + +1. Run `git tag --sort=-v:refname | head -5` to find the latest tag. +2. Parse the current version (format `vX.Y.Z`). +3. Increment the **minor** component and reset patch: `X.Y.Z` -> `X.(Y+1).0`. +4. Store the new version string (without `v` prefix) for later steps. + +## Step 2 -- Create a release branch + +```bash +git checkout master && git pull +git checkout -b release/vX.Y.Z +``` + +## Step 3 -- Update CHANGELOG.md + +1. Run `git log --pretty=format:"- %s" ..HEAD` to collect + changes since the last release. +2. Add a new section at the top of CHANGELOG.md (below the header line) + matching the existing format: + ``` + ### Version X.Y.Z - YYYY-MM-DD + + #### New Features + - feature description (#PR) + + #### Bug Fixes & Improvements + - fix description (#PR) + ``` +3. Use today's date. Categorize entries under "New Features" and/or + "Bug Fixes & Improvements" as appropriate. +4. Run `/humanizer` on the changelog text before writing it. + +## Step 4 -- Commit and push + +```bash +git add CHANGELOG.md +git commit -m "Update CHANGELOG for vX.Y.Z release" +git push -u origin release/vX.Y.Z +``` + +## Step 5 -- Verify CI + +1. Run `gh pr create --title "Release vX.Y.Z" --body "Changelog update for vX.Y.Z minor release."` to open a PR against master. +2. Wait for CI: + ```bash + gh pr checks --watch + ``` +3. If CI fails, fix the issue, amend or add a commit, push, and re-check. + +## Step 6 -- Merge the release branch + +```bash +gh pr merge --merge --delete-branch +``` + +## Step 7 -- Tag the release + +```bash +git checkout master && git pull +git tag -a vX.Y.Z -m "Version X.Y.Z" +git push origin vX.Y.Z +``` + +Do **not** sign the tag (`-s` flag omitted). + +## Step 8 -- Create a GitHub release + +```bash +gh release create vX.Y.Z --title "vX.Y.Z" --notes-file <(changelog_excerpt) +``` + +Use the CHANGELOG section for this version as the release notes body. +Run `/humanizer` on the notes before creating the release. + +## Step 9 -- Verify PyPI + +1. The `pypi-publish.yml` workflow triggers automatically on tag push. +2. Watch the workflow: + ```bash + gh run list --workflow=pypi-publish.yml --limit 1 + gh run watch + ``` +3. Confirm the new version appears: + ```bash + pip index versions xarray-spatial 2>/dev/null || echo "Check https://pypi.org/project/xarray-spatial/" + ``` + +## Step 10 -- Summary + +Print the new version, links to the PR, GitHub release, and PyPI page. + +--- + +## General rules + +- Run `/humanizer` on all text destined for GitHub: PR title/body, release + notes, commit messages, and any comments left on issues or PRs. +- Any temporary files created during the release (build artifacts, scratch + files) must use unique names including the version number to avoid + collisions (e.g. `changelog-draft-0.9.0.md`). diff --git a/.claude/commands/release-patch.md b/.claude/commands/release-patch.md new file mode 100644 index 00000000..2e9d8c0e --- /dev/null +++ b/.claude/commands/release-patch.md @@ -0,0 +1,106 @@ +# Release: Patch + +Cut a patch release (X.Y.Z -> X.Y.Z+1). Follow every step below in order. + +$ARGUMENTS + +--- + +## Step 1 -- Determine the new version + +1. Run `git tag --sort=-v:refname | head -5` to find the latest tag. +2. Parse the current version (format `vX.Y.Z`). +3. Increment the **patch** component: `X.Y.Z` -> `X.Y.(Z+1)`. +4. Store the new version string (without `v` prefix) for later steps. + +## Step 2 -- Create a release branch + +```bash +git checkout master && git pull +git checkout -b release/vX.Y.Z +``` + +## Step 3 -- Update CHANGELOG.md + +1. Run `git log --pretty=format:"- %s" ..HEAD` to collect + changes since the last release. +2. Add a new section at the top of CHANGELOG.md (below the header line) + matching the existing format: + ``` + ### Version X.Y.Z - YYYY-MM-DD + + #### Bug Fixes & Improvements + - change description (#PR) + ``` +3. Use today's date. Categorize entries under "New Features" and/or + "Bug Fixes & Improvements" as appropriate. +4. Run `/humanizer` on the changelog text before writing it. + +## Step 4 -- Commit and push + +```bash +git add CHANGELOG.md +git commit -m "Update CHANGELOG for vX.Y.Z release" +git push -u origin release/vX.Y.Z +``` + +## Step 5 -- Verify CI + +1. Run `gh pr create --title "Release vX.Y.Z" --body "Changelog update for vX.Y.Z patch release."` to open a PR against master. +2. Wait for CI: + ```bash + gh pr checks --watch + ``` +3. If CI fails, fix the issue, amend or add a commit, push, and re-check. + +## Step 6 -- Merge the release branch + +```bash +gh pr merge --merge --delete-branch +``` + +## Step 7 -- Tag the release + +```bash +git checkout master && git pull +git tag -a vX.Y.Z -m "Version X.Y.Z" +git push origin vX.Y.Z +``` + +Do **not** sign the tag (`-s` flag omitted). + +## Step 8 -- Create a GitHub release + +```bash +gh release create vX.Y.Z --title "vX.Y.Z" --notes-file <(changelog_excerpt) +``` + +Use the CHANGELOG section for this version as the release notes body. +Run `/humanizer` on the notes before creating the release. + +## Step 9 -- Verify PyPI + +1. The `pypi-publish.yml` workflow triggers automatically on tag push. +2. Watch the workflow: + ```bash + gh run list --workflow=pypi-publish.yml --limit 1 + gh run watch + ``` +3. Confirm the new version appears: + ```bash + pip index versions xarray-spatial 2>/dev/null || echo "Check https://pypi.org/project/xarray-spatial/" + ``` + +## Step 10 -- Summary + +Print the new version, links to the PR, GitHub release, and PyPI page. + +--- + +## General rules + +- Run `/humanizer` on all text destined for GitHub: PR title/body, release + notes, commit messages, and any comments left on issues or PRs. +- Any temporary files created during the release (build artifacts, scratch + files) must use unique names including the version number to avoid + collisions (e.g. `changelog-draft-0.8.1.md`). diff --git a/.claude/commands/rockout.md b/.claude/commands/rockout.md new file mode 100644 index 00000000..b194d6d2 --- /dev/null +++ b/.claude/commands/rockout.md @@ -0,0 +1,111 @@ +# Rockout: End-to-End Issue-to-Implementation Workflow + +Take the user's prompt describing an enhancement, bug, or suggestion and drive it +through all seven steps below. The prompt is: $ARGUMENTS + +--- + +## Step 1 -- Create a GitHub Issue + +1. Decide the issue type from the prompt: + - **enhancement** -- new feature or improvement + - **bug** -- something broken + - **suggestion / proposal** -- idea that needs design discussion +2. Pick labels from the repo's existing set. Always include the type label + (`enhancement`, `bug`, or `proposal`). Add topical labels when they fit + (e.g. `gpu`, `performance`, `focal tools`, `hydrology`, etc.). +3. Draft the title and body. Use the repo's issue templates as structure guides: + - Enhancement/proposal: follow `.github/ISSUE_TEMPLATE/feature-proposal.md` + - Bug: follow `.github/ISSUE_TEMPLATE/bug_report.md` +4. **Run the body text through the `/humanizer` skill** before creating the issue + to strip AI writing patterns. +5. Create the issue with `gh issue create` using the drafted title, body, and labels. +6. Capture the new issue number for later steps. + +## Step 2 -- Create a Git Worktree + +1. Create a new branch and worktree using the issue number: + ``` + git worktree add .claude/worktrees/issue- -b issue- + ``` +2. Switch the working directory to the new worktree for all remaining steps. + +## Step 3 -- Implement the Change + +1. Read the relevant source files to understand the existing code. +2. Follow the project's backend-dispatch pattern (`ArrayTypeFunctionMapping`) + when adding or modifying spatial operations. +3. Support all four backends where feasible: numpy, cupy, dask+numpy, dask+cupy. +4. Use `@ngjit` for CPU kernels and `@cuda.jit` for GPU kernels. +5. For dask support, use `map_overlap` with `depth` and `boundary=np.nan` + when the operation needs neighborhood access. +6. Keep changes focused -- don't refactor surrounding code unnecessarily. +7. Review the implementation for OOM risks, especially dask code paths. + Watch for patterns that accidentally materialize full arrays (e.g. + calling `.values` or `.compute()` inside a loop, building large + intermediate numpy arrays from dask inputs, unbounded `map_overlap` + depth relative to chunk size). Prefer lazy operations that keep data + chunked until final output. + +## Step 4 -- Add Test Coverage + +1. Add or update tests in `xrspatial/tests/`. +2. Use the project's cross-backend test helpers from `general_checks.py`. +3. Use existing fixtures from `conftest.py` (`elevation_raster`, `random_data`, etc.). +4. Any temporary files must have unique names. Include the issue number in + the filename (e.g. `tmp_940_result.tif`) to avoid collisions with + parallel test runs or other worktrees. +5. Cover: + - Correctness against known values or reference implementations + - Edge cases (NaN handling, empty input, single-cell rasters) + - All supported backends when the implementation spans multiple backends +6. Run the tests with `pytest` to verify they pass before moving on. + +## Step 5 -- Update Documentation + +1. Check `docs/source/reference/` for the relevant `.rst` file. +2. Add or update the API entry for any new public functions. +3. If a new module was created, add a new `.rst` file and include it in the + appropriate `toctree`. + +## Step 6 -- Create a User Guide Notebook + +The project has an `examples/user_guide/` directory with numbered notebooks. + +1. Determine the next available notebook number by listing the directory. +2. Create a new `.ipynb` notebook following the established pattern: + - Markdown cell with title and explanation of the feature + - Import cell + - Synthetic data generation with visualization + - Demonstrate each mode/option of the feature + - Show a practical use case or comparison +3. Use `matplotlib` for plots, consistent with existing notebooks. +4. Keep the notebook self-contained (no external data dependencies). + +**Skip this step** if the change is a pure bug fix with no new user-facing API. + +## Step 7 -- Update the README Feature Matrix + +1. Open `README.md` and find the appropriate category section in the feature matrix. +2. Add a new row for any new function, following the existing format: + ``` + | [Name](xrspatial/module.py) | Description | ✅️ | ✅️ | ✅️ | ✅️ | + ``` + Use ✅️ for native backends, 🔄 for CPU-fallback, and leave blank for unsupported. +3. If the change modifies backend support for an existing function, update the + corresponding checkmarks. + +**Skip this step** if no new functions were added and no backend support changed. + +--- + +## General Rules + +- Work entirely within the worktree created in Step 2. +- Commit progress after each major step with a clear commit message referencing + the issue number (e.g. `Add flood velocity function (#42)`). +- Run `/humanizer` on any text destined for GitHub (issue body, PR description, + commit messages) to remove AI writing artifacts. +- If any step is not applicable (e.g. no docs update needed for a typo fix), + note why and skip it. +- At the end, print a summary of what was done and where the worktree lives.