diff --git a/.github/agents/analyser.md b/.github/agents/analyser.md index 440726e..24d176e 100644 --- a/.github/agents/analyser.md +++ b/.github/agents/analyser.md @@ -36,12 +36,21 @@ Bullet points with concrete evidence. ### Risks / Technical Debt Items that could affect maintainability, correctness, or scalability. -### Score -Give an overall score between **1 and 10**, where: -- 9–10: exemplary, production-grade, well-maintained -- 7–8: solid, minor issues -- 5–6: mixed quality, notable concerns -- 3–4: fragile or poorly structured -- 1–2: critically deficient - -Be honest. If information is missing or unclear, state that explicitly. \ No newline at end of file +### Scores + +Rate each subcategory from **1 (critically deficient) to 10 (exemplary)**: + +| Subcategory | Score | Rationale | +|---|---|---| +| Code Quality | X/10 | ... | +| Test Coverage | X/10 | ... | +| Documentation | X/10 | ... | +| Architecture | X/10 | ... | +| Security | X/10 | ... | +| Dependency Management | X/10 | ... | +| CI/CD & Tooling | X/10 | ... | +| **Overall** | **X/10** | ... | + +Scale: 9–10 exemplary · 7–8 solid · 5–6 mixed · 3–4 fragile · 1–2 critical + +Be honest. If information is missing or unclear, state that explicitly. Omit subcategories that are not applicable. \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 185bc71..ec0580f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -124,7 +124,7 @@ The Copilot coding agent environment is automatically configured via official Gi These files must exist on the default branch. The agent does not need to run any setup commands manually. -For DevContainers and Codespaces, the `.devcontainer/` configuration and `bootstrap.sh` handle setup automatically. See `docs/DEVCONTAINER.md` for details. +For DevContainers and Codespaces, the `.devcontainer/` configuration and `bootstrap.sh` handle setup automatically. ## Project Structure @@ -133,7 +133,6 @@ For DevContainers and Codespaces, the `.devcontainer/` configuration and `bootst - `assets/`: Static assets - `book/`: Documentation source - `docker/`: Docker configuration -- `presentation/`: Presentation slides - `.rhiza/`: Rhiza-specific scripts and configurations ## Coding Standards @@ -173,8 +172,6 @@ Agentic workflow files are Markdown files in `.github/workflows/` with - `ci-doctor.md` — Automatic CI failure diagnosis - `issue-triage.md` — Automatic issue classification and labeling -For more details, see `docs/GH_AW.md`. - ## Key Files - `Makefile`: Main entry point for tasks. diff --git a/.semgrep.yml b/.github/semgrep.yml similarity index 100% rename from .semgrep.yml rename to .github/semgrep.yml diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 0cdc6d0..c54de38 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -34,7 +34,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth diff --git a/.github/workflows/renovate_rhiza_sync.yml b/.github/workflows/renovate_rhiza_sync.yml deleted file mode 100644 index af3f251..0000000 --- a/.github/workflows/renovate_rhiza_sync.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Rhiza Template Sync -# Automatically sync rhiza template files when Renovate updates .rhiza/template.yml - -on: - push: - branches: - - 'renovate/jebel-quant-rhiza-**' - - 'rhiza/**' - paths: - - '.rhiza/template.yml' - -permissions: - contents: write - -jobs: - sync-template: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - ref: ${{ github.ref }} - token: ${{ secrets.PAT_TOKEN || github.token }} - - - name: Check PAT_TOKEN configuration - shell: bash - env: - PAT_TOKEN: ${{ secrets.PAT_TOKEN }} - run: | - if [ -z "$PAT_TOKEN" ]; then - echo "::warning::PAT_TOKEN secret is not configured." - echo "::warning::If this sync modifies workflow files, the push will fail." - echo "::warning::See .rhiza/docs/TOKEN_SETUP.md for setup instructions." - else - echo "✓ PAT_TOKEN is configured." - fi - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - - - name: Get Rhiza version - id: rhiza-version - run: | - VERSION=$(cat .rhiza/.rhiza-version 2>/dev/null || echo "0.9.0") - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - - - name: Sync rhiza template - id: sync - run: | - set -euo pipefail - - RHIZA_VERSION="${{ steps.rhiza-version.outputs.version }}" - - echo "Running rhiza sync with version >=${RHIZA_VERSION}" - uvx "rhiza>=${RHIZA_VERSION}" sync . - - if git diff --quiet; then - echo "No changes detected after template sync" - echo "changes=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - - echo "Template changes detected" - echo "changes=true" >> "$GITHUB_OUTPUT" - - - name: Commit and push changes - if: steps.sync.outputs.changes == 'true' - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --global url."https://x-access-token:${{ secrets.PAT_TOKEN || github.token }}@github.com/".insteadOf "https://github.com/" - - git add -A - git commit -m "$(cat <<'EOF' - chore: sync rhiza template files - - Automatically synced template files after updating .rhiza/template.yml - - Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> - EOF - )" - - git push diff --git a/.github/workflows/rhiza_book.yml b/.github/workflows/rhiza_book.yml index 2fd67a5..2d7612d 100644 --- a/.github/workflows/rhiza_book.yml +++ b/.github/workflows/rhiza_book.yml @@ -43,7 +43,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth @@ -68,7 +68,7 @@ jobs: # This allows anyone to download the built documentation directly from # GitHub Actions without needing to run a full local build. - name: Upload book as workflow artifact - uses: actions/upload-artifact@v7.0.0 + uses: actions/upload-artifact@v7.0.1 with: name: book path: _book/ @@ -77,7 +77,7 @@ jobs: # Step 5b: Package all artifacts for GitHub Pages deployment # This prepares the combined outputs for deployment by creating a single artifact - name: Upload static files as artifact - uses: actions/upload-pages-artifact@v4.0.0 # Official GitHub Pages artifact upload action + uses: actions/upload-pages-artifact@v5.0.0 # Official GitHub Pages artifact upload action with: path: _book/ # Path to the directory containing all artifacts to deploy diff --git a/.github/workflows/rhiza_ci.yml b/.github/workflows/rhiza_ci.yml index 7e5c407..5760027 100644 --- a/.github/workflows/rhiza_ci.yml +++ b/.github/workflows/rhiza_ci.yml @@ -3,9 +3,11 @@ # # Workflow: Continuous Integration # -# Purpose: Run tests on multiple Python versions to ensure compatibility. +# Purpose: Run tests on multiple Python versions, check dependencies, run +# pre-commit hooks, verify documentation coverage, validate the +# project, run security scans, and check license compliance. # -# Trigger: On push and pull requests to main/master branches. +# Trigger: On push and pull_request. name: (RHIZA) CI @@ -15,9 +17,7 @@ permissions: on: push: - branches: [ main, master ] pull_request: - branches: [ main, master ] jobs: generate-matrix: @@ -32,13 +32,13 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth with: token: ${{ secrets.GH_PAT }} - + - id: versions env: UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} @@ -53,10 +53,11 @@ jobs: test: needs: generate-matrix - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: python-version: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} + os: [ubuntu-latest, macos-latest, windows-latest] fail-fast: false steps: @@ -68,7 +69,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" python-version: ${{ matrix.python-version }} - name: Configure git auth for private packages @@ -83,7 +84,7 @@ jobs: make test - name: Upload coverage report - if: matrix.python-version == '3.12' + if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest' uses: actions/upload-artifact@v7 with: name: coverage-report @@ -91,6 +92,74 @@ jobs: if-no-files-found: ignore + typecheck: + name: Type checking + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run ty type checker (make typecheck) + # Runs `uv run ty check src/` as defined in .rhiza/make.d/test.mk. + # ty is configured via [tool.ty.environment] in pyproject.toml. + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make typecheck + + deptry: + name: Check dependencies with deptry + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run deptry + run: make deptry + + pre-commit: + name: Pre-commit hooks + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Cache pre-commit environments + uses: actions/cache@v5 + with: + path: ~/.cache/pre-commit + key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }} + restore-keys: | + pre-commit-${{ runner.os }}- + + - name: Run pre-commit + run: | + make fmt + docs-coverage: runs-on: ubuntu-latest steps: @@ -100,7 +169,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth @@ -113,6 +182,87 @@ jobs: run: | make docs-coverage + validation: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + lfs: true + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Validate + shell: bash + run: | + make validate + + security: + name: Security scanning + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run security scans + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make security + + license: + name: License compliance scan + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run license check + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make license + + - name: Generate LICENSES.md + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: | + uv run --with pip-licenses pip-licenses --format markdown --output-file LICENSES.md + + - name: Upload LICENSES.md + uses: actions/upload-artifact@v7 + with: + name: LICENSES.md + path: LICENSES.md + if-no-files-found: ignore + coverage-badge: needs: test runs-on: ubuntu-latest @@ -128,7 +278,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: Download coverage report id: download-coverage diff --git a/.github/workflows/rhiza_codeql.yml b/.github/workflows/rhiza_codeql.yml index d4f1504..a2c78e3 100644 --- a/.github/workflows/rhiza_codeql.yml +++ b/.github/workflows/rhiza_codeql.yml @@ -22,7 +22,7 @@ # - Set to 'false' to disable entirely # - Leave unset for automatic behavior (recommended) # -# For more information, see docs/CUSTOMIZATION.md +# For more information, see docs/guides/CUSTOMIZATION.md # name: "(RHIZA) CODEQL" diff --git a/.github/workflows/rhiza_dep_compat_test.yml b/.github/workflows/rhiza_dep_compat_test.yml deleted file mode 100644 index 3aad209..0000000 --- a/.github/workflows/rhiza_dep_compat_test.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: "(RHIZA) DEPENDENCY COMPATIBILITY (WEEKLY)" - -# Resolves all dependencies fresh—ignoring the committed lockfile—and runs -# the full test suite. Failure here means a newly-released package version -# (e.g. pydantic v3, scipy v2, numpy v3) is incompatible with the current -# code, providing an early-warning signal before the lockfile is next -# refreshed by Renovate or a manual bump. -# -# See: https://github.com/Jebel-Quant/basanos/issues/ - -permissions: - contents: read - -on: - schedule: - - cron: "0 9 * * 3" # Every Wednesday at 09:00 UTC - workflow_dispatch: - -jobs: - dep-compat-test: - name: Test with latest compatible dependencies - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - lfs: true - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Resolve and install latest compatible dependencies - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: | - # --upgrade ignores the committed lockfile and resolves the newest - # versions that satisfy pyproject.toml constraints. - uv sync --upgrade - - - name: Show resolved package versions - run: | - echo "=== Installed package versions ===" - uv pip list - - - name: Run tests - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make test diff --git a/.github/workflows/rhiza_deptry.yml b/.github/workflows/rhiza_deptry.yml deleted file mode 100644 index 29e0b6c..0000000 --- a/.github/workflows/rhiza_deptry.yml +++ /dev/null @@ -1,48 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Deptry -# -# Purpose: This workflow identifies missing and obsolete dependencies in the project. -# It helps maintain a clean dependency tree by detecting unused packages and -# implicit dependencies that should be explicitly declared. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) DEPTRY" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - deptry: - name: Check dependencies with deptry - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run deptry - run: make deptry - # NOTE: make deptry is good style because it encapsulates the folders to check - # (e.g. src and book/marimo) and keeps CI in sync with local development. - # Since we have uv/uvx installed, the Makefile is optimised to use the - # pre-installed 'uv' and 'uvx' from the system PATH. diff --git a/.github/workflows/rhiza_license.yml b/.github/workflows/rhiza_license.yml deleted file mode 100644 index 11ddb4b..0000000 --- a/.github/workflows/rhiza_license.yml +++ /dev/null @@ -1,45 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: License compliance -# -# Purpose: This workflow checks that no copyleft-licensed dependencies -# (GPL, LGPL, AGPL) have been introduced via transitive updates. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) LICENSE" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - license: - name: License compliance scan - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run license check - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make license diff --git a/.github/workflows/rhiza_marimo.yml b/.github/workflows/rhiza_marimo.yml index b0c4c28..cf1677e 100644 --- a/.github/workflows/rhiza_marimo.yml +++ b/.github/workflows/rhiza_marimo.yml @@ -83,7 +83,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth @@ -116,7 +116,7 @@ jobs: - name: Upload notebook artefacts if: always() - uses: actions/upload-artifact@v7.0.0 + uses: actions/upload-artifact@v7.0.1 with: name: notebook-artefacts-${{ steps.artefact-folder.outputs.name }} path: results/${{ steps.artefact-folder.outputs.name }}/ diff --git a/.github/workflows/rhiza_pip_audit.yml b/.github/workflows/rhiza_pip_audit.yml deleted file mode 100644 index 7c8eeef..0000000 --- a/.github/workflows/rhiza_pip_audit.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "(RHIZA) PIP-AUDIT (WEEKLY)" - -permissions: - contents: read - -on: - schedule: - - cron: "0 9 * * 1" # Every Monday at 09:00 UTC (GitHub Actions: 0=Sunday, 1=Monday) - workflow_dispatch: - -jobs: - pip-audit: - name: Dependency vulnerability scan - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Run pip-audit - run: uvx pip-audit diff --git a/.github/workflows/rhiza_pre-commit.yml b/.github/workflows/rhiza_pre-commit.yml deleted file mode 100644 index df38fa0..0000000 --- a/.github/workflows/rhiza_pre-commit.yml +++ /dev/null @@ -1,52 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Pre-commit -# -# Purpose: This workflow runs pre-commit checks to ensure code quality -# and consistency across the codebase. It helps catch issues -# like formatting errors, linting issues, and other code quality -# problems before they are merged. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) -# -# Components: -# - 🔍 Run pre-commit checks using reusable action -# - 💾 Cache pre-commit environments to speed up runs - -name: "(RHIZA) PRE-COMMIT" -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - pre-commit: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - # Cache pre-commit environments and hooks - - name: Cache pre-commit environments - uses: actions/cache@v5 - with: - path: ~/.cache/pre-commit - key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }} - restore-keys: | - pre-commit-${{ runner.os }}- - - # Run pre-commit - - name: Run pre-commit - run: | - make fmt diff --git a/.github/workflows/rhiza_release.yml b/.github/workflows/rhiza_release.yml index 681b649..3146205 100644 --- a/.github/workflows/rhiza_release.yml +++ b/.github/workflows/rhiza_release.yml @@ -122,7 +122,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: Configure git auth for private packages uses: ./.github/actions/configure-git-auth @@ -196,7 +196,7 @@ jobs: - name: Upload SBOM artifacts if: hashFiles('pyproject.toml') != '' - uses: actions/upload-artifact@v7.0.0 + uses: actions/upload-artifact@v7.0.1 with: name: sbom path: | @@ -211,7 +211,7 @@ jobs: - name: Upload dist artifact if: steps.buildable.outputs.buildable == 'true' - uses: actions/upload-artifact@v7.0.0 + uses: actions/upload-artifact@v7.0.1 with: name: dist path: dist @@ -223,6 +223,17 @@ jobs: needs: [tag, build] steps: + - name: Checkout Code + uses: actions/checkout@v6.0.2 + with: + fetch-depth: 0 + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + + - name: Generate release notes with git-cliff + run: uvx git-cliff --latest --output RELEASE_NOTES.md + - name: Download SBOM artifact # Downloads sbom.cdx.json and sbom.cdx.xml into sbom/ directory uses: actions/download-artifact@v8.0.1 @@ -236,10 +247,9 @@ jobs: with: tag: ${{ needs.tag.outputs.tag }} name: ${{ needs.tag.outputs.tag }} - generateReleaseNotes: true + bodyFile: RELEASE_NOTES.md draft: true allowUpdates: true - omitBodyDuringUpdate: true artifacts: "sbom/*" # Decide at step-level whether to publish @@ -330,7 +340,7 @@ jobs: - name: Login to Container Registry if: steps.check_publish.outputs.should_publish == 'true' - uses: docker/login-action@v4.0.0 + uses: docker/login-action@v4.1.0 with: registry: ${{ steps.registry.outputs.registry }} username: ${{ github.repository_owner }} @@ -393,7 +403,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v8.0.0 with: - version: "0.11.2" + version: "0.11.6" - name: "Sync the virtual environment for ${{ github.repository }}" shell: bash diff --git a/.github/workflows/rhiza_security.yml b/.github/workflows/rhiza_security.yml deleted file mode 100644 index dd6cb11..0000000 --- a/.github/workflows/rhiza_security.yml +++ /dev/null @@ -1,46 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Security -# -# Purpose: This workflow runs security scans on the project including: -# - pip-audit: Check for known vulnerabilities in dependencies -# - bandit: Static analysis for common security issues in Python code -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) SECURITY" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - security: - name: Security scanning - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run security scans - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make security diff --git a/.github/workflows/rhiza_semgrep.yml b/.github/workflows/rhiza_semgrep.yml deleted file mode 100644 index 316d8e2..0000000 --- a/.github/workflows/rhiza_semgrep.yml +++ /dev/null @@ -1,48 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Semgrep -# -# Purpose: This workflow runs static analysis using Semgrep with local numpy -# rules (.semgrep.yml) to detect common NumPy-related bugs and -# security issues in Python code. -# Note: the retired p/numpy registry ruleset is replaced by a local -# rules file that covers the same concerns. -# -# Trigger: This workflow runs on every push and on pull requests to main/master -# branches (including from forks) - -name: "(RHIZA) SEMGREP" - -# Permissions: Only read access to repository contents is needed -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - semgrep: - name: Semgrep (numpy) - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run Semgrep - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make semgrep diff --git a/.github/workflows/rhiza_sync.yml b/.github/workflows/rhiza_sync.yml index b42ff92..2da8d0e 100644 --- a/.github/workflows/rhiza_sync.yml +++ b/.github/workflows/rhiza_sync.yml @@ -1,27 +1,107 @@ name: (RHIZA) SYNC -# This workflow synchronizes the repository with its template. -# IMPORTANT: When workflow files (.github/workflows/rhiza_*.yml) are modified, -# a Personal Access Token (PAT) with 'workflow' scope is required. -# The PAT_TOKEN secret must be set in repository secrets. -# See .github/rhiza/TOKEN_SETUP.md for setup instructions. +# Synchronizes the repository with its rhiza template. +# - On Renovate/rhiza branch push: auto-commits synced files directly to the branch. +# - On schedule/dispatch: opens a pull request with the synced changes. +# +# IMPORTANT: A PAT with 'workflow' scope (PAT_TOKEN) is required when workflow +# files are modified. See .rhiza/docs/TOKEN_SETUP.md for setup instructions. permissions: contents: write pull-requests: write on: + push: + branches: + - 'renovate/jebel-quant-rhiza-**' + - 'rhiza/**' + paths: + - '.rhiza/template.yml' + schedule: + - cron: '0 0 * * 1' # Weekly on Monday workflow_dispatch: inputs: create-pr: description: "Create a pull request" type: boolean default: true - schedule: - - cron: '0 0 * * 1' # Weekly on Monday jobs: - sync: - if: ${{ github.repository != 'jebel-quant/rhiza' }} + sync-direct: + name: Sync and commit (Renovate) + if: github.event_name == 'push' && github.repository != 'jebel-quant/rhiza' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + ref: ${{ github.ref }} + token: ${{ secrets.PAT_TOKEN || github.token }} + + - name: Check PAT_TOKEN configuration + shell: bash + env: + PAT_TOKEN: ${{ secrets.PAT_TOKEN }} + run: | + if [ -z "$PAT_TOKEN" ]; then + echo "::warning::PAT_TOKEN secret is not configured." + echo "::warning::If this sync modifies workflow files, the push will fail." + echo "::warning::See .rhiza/docs/TOKEN_SETUP.md for setup instructions." + else + echo "✓ PAT_TOKEN is configured." + fi + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + + - name: Get Rhiza version + id: rhiza-version + run: | + VERSION=$(cat .rhiza/.rhiza-version 2>/dev/null || echo "0.9.0") + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + + - name: Sync rhiza template + id: sync + run: | + set -euo pipefail + + RHIZA_VERSION="${{ steps.rhiza-version.outputs.version }}" + + echo "Running rhiza sync with version >=${RHIZA_VERSION}" + uvx "rhiza>=${RHIZA_VERSION}" sync . + + if git diff --quiet; then + echo "No changes detected after template sync" + echo "changes=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "Template changes detected" + echo "changes=true" >> "$GITHUB_OUTPUT" + + - name: Commit and push changes + if: steps.sync.outputs.changes == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global url."https://x-access-token:${{ secrets.PAT_TOKEN || github.token }}@github.com/".insteadOf "https://github.com/" + + git add -A + git commit -m "$(cat <<'EOF' + chore: sync rhiza template files + + Automatically synced template files after updating .rhiza/template.yml + + Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + EOF + )" + + git push + + sync-pr: + name: Sync and open PR (scheduled/manual) + if: github.event_name != 'push' && github.repository != 'jebel-quant/rhiza' runs-on: ubuntu-latest steps: @@ -44,7 +124,7 @@ jobs: if [ -z "$PAT_TOKEN" ]; then echo "::warning::PAT_TOKEN secret is not configured." echo "::warning::If this sync modifies workflow files, the push will fail." - echo "::warning::See .github/TOKEN_SETUP.md for setup instructions." + echo "::warning::See .rhiza/docs/TOKEN_SETUP.md for setup instructions." else echo "✓ PAT_TOKEN is configured." fi @@ -82,19 +162,19 @@ jobs: git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --global url."https://x-access-token:${{ secrets.PAT_TOKEN }}@github.com/".insteadOf "https://github.com/" + git config --global url."https://x-access-token:${{ secrets.PAT_TOKEN || github.token }}@github.com/".insteadOf "https://github.com/" git commit -m "chore: Update via rhiza" - + - name: Create pull request if: > (github.event_name == 'schedule' || inputs.create-pr == true) && steps.sync.outputs.changes_detected == 'true' - uses: peter-evans/create-pull-request@v8.1.0 + uses: peter-evans/create-pull-request@v8.1.1 with: token: ${{ secrets.PAT_TOKEN || github.token }} base: ${{ github.event.repository.default_branch }} branch: ${{ steps.branch.outputs.name }} delete-branch: true title: "chore: Sync with rhiza" - body-path: ${{ runner.temp }}/pr-description.md \ No newline at end of file + body-path: ${{ runner.temp }}/pr-description.md diff --git a/.github/workflows/rhiza_typecheck.yml b/.github/workflows/rhiza_typecheck.yml deleted file mode 100644 index 80bb16b..0000000 --- a/.github/workflows/rhiza_typecheck.yml +++ /dev/null @@ -1,50 +0,0 @@ -# This file is part of the jebel-quant/rhiza repository -# (https://github.com/jebel-quant/rhiza). -# -# Workflow: Type Checking -# -# Purpose: Run static type analysis using ty to enforce type safety. -# ty (https://github.com/astral-sh/ty) is a fast Python type checker -# from the Astral team (same team as ruff/uv). -# -# Type-checker settings live in [tool.ty.environment] in pyproject.toml. -# Locally, `make typecheck` runs the same check; it is also wired into -# `make validate` via the `post-validate::` hook in the repo Makefile. -# -# Trigger: On push and pull requests to main/master branches. - -name: "(RHIZA) TYPECHECK" - -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - typecheck: - name: Type checking - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6.0.2 - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run ty type checker (make typecheck) - # Runs `uv run ty check src/` as defined in .rhiza/make.d/test.mk. - # ty is configured via [tool.ty.environment] in pyproject.toml. - env: - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make typecheck diff --git a/.github/workflows/rhiza_validate.yml b/.github/workflows/rhiza_validate.yml deleted file mode 100644 index 53ceed8..0000000 --- a/.github/workflows/rhiza_validate.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: (RHIZA) VALIDATE - -permissions: - contents: read - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - validation: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - lfs: true - - - name: Install uv - uses: astral-sh/setup-uv@v8.0.0 - with: - version: "0.11.2" - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Validate - shell: bash - run: | - make validate diff --git a/.github/workflows/rhiza_weekly.yml b/.github/workflows/rhiza_weekly.yml new file mode 100644 index 0000000..589dc9c --- /dev/null +++ b/.github/workflows/rhiza_weekly.yml @@ -0,0 +1,118 @@ +name: "(RHIZA) WEEKLY" + +# Runs weekly checks that are too slow or noisy for every push: +# +# dep-compat-test — Resolves all dependencies fresh (ignoring the lockfile) +# and runs the full test suite. Catches newly-released +# packages that break compatibility before Renovate picks +# them up. Runs on schedule/dispatch only. +# +# link-check — Verifies that all hyperlinks in README.md are reachable. +# Runs on schedule/dispatch only. + +permissions: + contents: read + +on: + #push: + # branches: [main] + # paths: [README.md] + #pull_request: + # paths: [README.md] + schedule: + - cron: "0 8 * * 1" # Every Monday at 08:00 UTC + workflow_dispatch: + +jobs: + dep-compat-test: + name: Test with latest compatible dependencies + runs-on: ubuntu-latest + #if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + lfs: true + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Resolve and install latest compatible dependencies + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: | + # --upgrade ignores the committed lockfile and resolves the newest + # versions that satisfy pyproject.toml constraints. + uv sync --upgrade + + - name: Show resolved package versions + run: | + echo "=== Installed package versions ===" + uv pip list + + - name: Run tests + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make test + + semgrep: + name: Semgrep (numpy) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Configure git auth for private packages + uses: ./.github/actions/configure-git-auth + with: + token: ${{ secrets.GH_PAT }} + + - name: Run Semgrep + env: + UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} + run: make semgrep + + pip-audit: + name: Dependency vulnerability scan + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + version: "0.11.6" + + - name: Run pip-audit + run: uvx pip-audit + + link-check: + name: Check links in README.md + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6.0.2 + + - name: Check links in README.md + uses: lycheeverse/lychee-action@v2 + with: + args: >- + --verbose + --no-progress + --accept 200,206,429 + README.md + fail: true diff --git a/.gitignore b/.gitignore index 0d16b94..0dc346a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,12 +15,24 @@ __marimo__ _tests _book _pdoc +docs/notebooks/*.html +docs/reports +docs/notebooks.md +docs/reports.md _marimushka _mkdocs _benchmarks _jupyter _site +# LaTeX build artifacts +docs/paper/*.aux +docs/paper/*.fdb_latexmk +docs/paper/*.fls +docs/paper/*.log +docs/paper/*.out +docs/paper/*.toc + # temp file used by Junie .output.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 298f634..774f312 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,9 +8,10 @@ repos: - id: check-toml - id: check-yaml args: ['--unsafe'] + exclude: ^recipe/meta\.yaml$ - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 'v0.15.7' + rev: 'v0.15.10' hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix, --unsafe-fixes ] @@ -25,7 +26,7 @@ repos: args: ["--disable", "MD013"] - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.37.0 + rev: 0.37.1 hooks: - id: check-renovate args: [ "--verbose" ] @@ -34,7 +35,7 @@ repos: args: ["--verbose"] - repo: https://github.com/rhysd/actionlint - rev: v1.7.11 + rev: v1.7.12 hooks: - id: actionlint @@ -50,12 +51,12 @@ repos: args: ["--skip", "B101", "--exclude", ".venv,tests,.rhiza/tests,.git,.pytest_cache", "-c", "pyproject.toml"] - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.10.12 + rev: 0.11.6 hooks: - id: uv-lock - repo: https://github.com/Jebel-Quant/rhiza-hooks - rev: v0.3.0 # Use the latest release + rev: v0.3.2 # Use the latest release hooks: # Migrated from rhiza - id: check-rhiza-workflow-names diff --git a/.rhiza/.env b/.rhiza/.env index df5caf6..47ca6b0 100644 --- a/.rhiza/.env +++ b/.rhiza/.env @@ -1,8 +1,2 @@ -MARIMO_FOLDER=book/marimo/notebooks +MARIMO_FOLDER=docs/notebooks SOURCE_FOLDER=src - -# Book-specific variables -BOOK_TITLE=Project Documentation -BOOK_SUBTITLE=Generated by minibook -BOOK_TEMPLATE=.rhiza/templates/minibook/custom.html.jinja2 -# PDOC_TEMPLATE_DIR is now defined in .rhiza/make.d/08-docs.mk with a default value diff --git a/CODE_OF_CONDUCT.md b/.rhiza/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to .rhiza/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/.rhiza/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .rhiza/CONTRIBUTING.md diff --git a/.rhiza/docs/CONFIG.md b/.rhiza/docs/CONFIG.md index f6d8e20..0b866e9 100644 --- a/.rhiza/docs/CONFIG.md +++ b/.rhiza/docs/CONFIG.md @@ -29,9 +29,7 @@ The repository uses several automated workflows (located in `.github/workflows/` - **Pre-commit** (`rhiza_pre-commit.yml`) - Code quality checks - **Book** (`rhiza_book.yml`) - Documentation deployment - **Release** (`rhiza_release.yml`) - Package publishing -- **Deptry** (`rhiza_deptry.yml`) - Dependency checks - **Marimo** (`rhiza_marimo.yml`) - Interactive notebooks -- **Typecheck** (`rhiza_typecheck.yml`) - Static type analysis with ty ## Template Synchronization diff --git a/.rhiza/docs/WORKFLOWS.md b/.rhiza/docs/WORKFLOWS.md index 9025fe2..1752522 100644 --- a/.rhiza/docs/WORKFLOWS.md +++ b/.rhiza/docs/WORKFLOWS.md @@ -6,7 +6,7 @@ This guide covers recommended day-to-day development workflows for Rhiza project Rhiza uses [uv](https://docs.astral.sh/uv/) for fast, reliable Python dependency management. -> 📚 **For detailed information about dependency version constraints and rationale**, see [docs/DEPENDENCIES.md](../../docs/DEPENDENCIES.md) +> 📚 **For detailed information about dependency version constraints and rationale**, see [docs/DEPENDENCIES.md](../../docs/reference/DEPENDENCIES.md) ### Adding Dependencies diff --git a/.rhiza/make.d/README.md b/.rhiza/make.d/README.md index daf4ee7..e6a8b52 100644 --- a/.rhiza/make.d/README.md +++ b/.rhiza/make.d/README.md @@ -91,7 +91,6 @@ pre-install:: | `custom-env.mk` | Example environment customizations | | `custom-task.mk` | Example custom tasks | | `docker.mk` | Docker build and run targets | -| `docs.mk` | Documentation generation (pdoc) | | `github.mk` | GitHub CLI integrations | | `lfs.mk` | Git LFS management | | `marimo.mk` | Marimo notebook support | @@ -115,8 +114,6 @@ Files prefixed with `custom-` are **examples** showing how to customize Rhiza. D **Section Headers**: Title Case with `##@` - `##@ Bootstrap`, `##@ GitHub Helpers` -See [docs/ARCHITECTURE.md](../../docs/ARCHITECTURE.md#naming-conventions-and-organization-patterns) for comprehensive naming guidelines. - ### Available Hooks Add these to your root `Makefile` using double-colon syntax (`::`): - `pre-install` / `post-install`: Runs around `make install`. diff --git a/.rhiza/make.d/agentic.mk b/.rhiza/make.d/agentic.mk index f8374b8..5ddeea9 100644 --- a/.rhiza/make.d/agentic.mk +++ b/.rhiza/make.d/agentic.mk @@ -16,12 +16,11 @@ copilot: install-copilot ## open interactive prompt for copilot claude: install-claude ## open interactive prompt for claude code @"$(CLAUDE_BIN)" -analyse-repo: install-copilot ## run the analyser agent to update REPOSITORY_ANALYSIS.md - @"$(COPILOT_BIN)" --agent analyser \ - --model "$(DEFAULT_AI_MODEL)" \ - --prompt "Analyze the repository and update the journal." \ - --allow-tool 'write' --deny-tool 'remove' \ - --allow-all-paths +analyse-repo: install-claude ## run the analyser agent to update REPOSITORY_ANALYSIS.md + @"$(CLAUDE_BIN)" --print \ + --allowedTools "Write" \ + --agent .github/agents/analyser.md \ + "Analyze the repository and update REPOSITORY_ANALYSIS.md" summarise-changes: install-copilot ## summarise changes since the most recent release/tag @"$(COPILOT_BIN)" -p "Show me the commits since the last release/tag and summarise them" --allow-tool 'shell(git)' --model "$(DEFAULT_AI_MODEL)" --agent summarise diff --git a/.rhiza/make.d/book.mk b/.rhiza/make.d/book.mk index 26fb0b1..28c77f6 100644 --- a/.rhiza/make.d/book.mk +++ b/.rhiza/make.d/book.mk @@ -1,130 +1,99 @@ -## book.mk - Book-building targets -# This file is included by the main Makefile. -# It provides targets for exporting Marimo notebooks to HTML (marimushka) -# and compiling a companion book (minibook). +## book.mk - Book-building targets (MkDocs-based) -# Declare phony targets (they don't produce files) -.PHONY: marimushka mkdocs-build book test benchmark stress hypothesis-test docs +.PHONY: book mkdocs-build test benchmark stress hypothesis-test _book-reports _book-notebooks mkdocs-serve mkdocs -# Define default no-op targets for test-related book dependencies. -# These are used when test.mk is not available or tests are not installed, -# ensuring 'make book' succeeds even without a test environment. +# No-op stubs — overridden by test.mk / bench.mk when present test:: ; @: benchmark:: ; @: stress:: ; @: hypothesis-test:: ; @: -docs:: ; @: -# Define a default no-op marimushka target that will be used -# when book/marimo/marimo.mk doesn't exist or doesn't define marimushka -marimushka:: install-uv - @if [ ! -d "book/marimo" ]; then \ - printf "${BLUE}[INFO] No Marimo directory found, creating placeholder${RESET}\n"; \ - mkdir -p "${MARIMUSHKA_OUTPUT}"; \ - printf '%s\n' 'Marimo Notebooks' \ - '

Marimo Notebooks

No notebooks found.

' \ - > "${MARIMUSHKA_OUTPUT}/index.html"; \ - fi - -# Define a default no-op mkdocs-build target that will be used -# when .rhiza/make.d/docs.mk doesn't exist or doesn't define mkdocs-build -mkdocs-build:: install-uv - @if [ ! -f "docs/mkdocs.yml" ]; then \ - printf "${BLUE}[INFO] No mkdocs.yml found, skipping MkDocs${RESET}\n"; \ - fi - -# Default output directory for Marimushka (HTML exports of notebooks) -MARIMUSHKA_OUTPUT ?= _marimushka - -# Default output directory for MkDocs -MKDOCS_OUTPUT ?= _mkdocs +BOOK_OUTPUT ?= _book -# ---------------------------- -# Book sections (declarative) -# ---------------------------- -# format: -# name | source index | book-relative index | source dir | book dir +# Additional uvx --with packages to inject into mkdocs build and serve. +# Projects can extend the package list without editing this template, e.g.: +# MKDOCS_EXTRA_PACKAGES = --with "mkdocs-graphviz" +MKDOCS_EXTRA_PACKAGES ?= -BOOK_SECTIONS := \ - "API|_pdoc/index.html|pdoc/index.html|_pdoc|pdoc" \ - "Coverage|_tests/html-coverage/index.html|tests/html-coverage/index.html|_tests/html-coverage|tests/html-coverage" \ - "Test Report|_tests/html-report/report.html|tests/html-report/report.html|_tests/html-report|tests/html-report" \ - "Benchmarks|_tests/benchmarks/report.html|tests/benchmarks/report.html|_tests/benchmarks|tests/benchmarks" \ - "Stress Tests|_tests/stress/report.html|tests/stress/report.html|_tests/stress|tests/stress" \ - "Hypothesis Tests|_tests/hypothesis/report.html|tests/hypothesis/report.html|_tests/hypothesis|tests/hypothesis" \ - "Notebooks|_marimushka/index.html|marimushka/index.html|_marimushka|marimushka" \ - "Official Documentation|_mkdocs/index.html|docs/index.html|_mkdocs|docs" +# Detect mkdocs config: prefer root-level, fall back to docs/mkdocs-base.yml +_MKDOCS_CFG := $(if $(wildcard mkdocs.yml),mkdocs.yml,$(if $(wildcard docs/mkdocs-base.yml),docs/mkdocs-base.yml,)) ##@ Book -# The 'book' target assembles the final documentation book. -# 1. Aggregates API docs, coverage, test reports, notebooks, and MkDocs site into _book. -# 2. Generates links.json to define the book structure. -# 3. Uses 'minibook' to compile the final HTML site. -book:: test benchmark stress hypothesis-test docs marimushka mkdocs-build ## compile the companion book - @printf "${BLUE}[INFO] Building combined documentation...${RESET}\n" - @rm -rf _book && mkdir -p _book - - @printf "{\n" > _book/links.json - @first=1; \ - for entry in $(BOOK_SECTIONS); do \ - name=$${entry%%|*}; \ - rest=$${entry#*|}; \ - src_index=$${rest%%|*}; rest=$${rest#*|}; \ - book_index=$${rest%%|*}; rest=$${rest#*|}; \ - src_dir=$${rest%%|*}; book_dir=$${rest#*|}; \ - if [ -f "$$src_index" ]; then \ - printf "${BLUE}[INFO] Adding $$name...${RESET}\n"; \ - mkdir -p "_book/$$book_dir"; \ - cp -r "$$src_dir/"* "_book/$$book_dir"; \ - if [ $$first -eq 0 ]; then \ - printf ",\n" >> _book/links.json; \ - fi; \ - printf " \"%s\": \"./%s\"" "$$name" "$$book_index" >> _book/links.json; \ - first=0; \ +_book-reports: test benchmark stress hypothesis-test + @mkdir -p docs/reports + @for src_dir in \ + "_tests/html-coverage:reports/coverage" \ + "_tests/html-report:reports/test-report" \ + "_tests/benchmarks:reports/benchmarks" \ + "_tests/stress:reports/stress" \ + "_tests/hypothesis:reports/hypothesis"; do \ + src=$${src_dir%%:*}; dest=docs/$${src_dir#*:}; \ + if [ -d "$$src" ] && [ -n "$$(ls -A "$$src" 2>/dev/null)" ]; then \ + printf "${BLUE}[INFO] Copying $$src -> $$dest${RESET}\n"; \ + mkdir -p "$$dest"; cp -r "$$src/." "$$dest/"; \ else \ - printf "${YELLOW}[WARN] Missing $$name, skipping${RESET}\n"; \ + printf "${YELLOW}[WARN] $$src not found, skipping${RESET}\n"; \ fi; \ - done; \ - if [ -n "$$GITHUB_REPOSITORY" ]; then \ - CF_REPO="$$GITHUB_REPOSITORY"; \ + done + @printf "# Reports\n\n" > docs/reports.md + @[ -f "docs/reports/test-report/report.html" ] && echo "- [Test Report](reports/test-report/report.html)" >> docs/reports.md || true + @[ -f "docs/reports/hypothesis/report.html" ] && echo "- [Hypothesis Report](reports/hypothesis/report.html)" >> docs/reports.md || true + @[ -f "docs/reports/benchmarks/report.html" ] && echo "- [Benchmarks](reports/benchmarks/report.html)" >> docs/reports.md || true + @[ -f "docs/reports/stress/report.html" ] && echo "- [Stress Report](reports/stress/report.html)" >> docs/reports.md || true + @[ -f "docs/reports/coverage/index.html" ] && echo "- [Coverage Report](reports/coverage/index.html)" >> docs/reports.md || true + +_book-notebooks: + @if [ -d "$(MARIMO_FOLDER)" ]; then \ + for nb in $(MARIMO_FOLDER)/*.py; do \ + name=$$(basename "$$nb" .py); \ + printf "${BLUE}[INFO] Exporting $$nb${RESET}\n"; \ + abs_output="$$(pwd)/docs/notebooks/$$name.html"; \ + mkdir -p docs/notebooks; \ + (cd "$$(dirname "$$nb")" && ${UV_BIN} run marimo export html --sandbox "$$(basename "$$nb")" -o "$$abs_output"); \ + done; \ + printf "# Marimo Notebooks\n\n" > docs/notebooks.md; \ + for html in docs/notebooks/*.html; do \ + name=$$(basename "$$html" .html); \ + echo "- [$$name]($$name.html)" >> docs/notebooks.md; \ + done; \ + fi + +book:: _book-reports _book-notebooks ## compile the companion book via MkDocs + @if [ -n "$(_MKDOCS_CFG)" ]; then \ + rm -rf "$(BOOK_OUTPUT)"; \ + ${UVX_BIN} --with "mkdocs-material<10.0" --with "pymdown-extensions>=10.0" --with "mkdocs<2.0" $(MKDOCS_EXTRA_PACKAGES) mkdocs build \ + -f "$(_MKDOCS_CFG)" \ + -d "$$(pwd)/$(BOOK_OUTPUT)"; \ else \ - CF_REPO=$$(git remote get-url origin 2>/dev/null | sed 's|.*github\.com[:/]||' | sed 's|\.git$$||'); \ - fi; \ - if [ -n "$$CF_REPO" ]; then \ - CF_URL="https://www.codefactor.io/repository/github/$$CF_REPO"; \ - HTTP_CODE=$$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$$CF_URL" 2>/dev/null || echo "000"); \ - if [ "$$HTTP_CODE" = "200" ]; then \ - if [ $$first -eq 0 ]; then printf ",\n" >> _book/links.json; fi; \ - printf " \"CodeFactor\": \"$$CF_URL\"" >> _book/links.json; \ - printf "${BLUE}[INFO] Adding CodeFactor...${RESET}\n"; \ - else \ - printf "${YELLOW}[WARN] CodeFactor page not accessible (HTTP $$HTTP_CODE), skipping${RESET}\n"; \ - fi; \ - fi; \ - printf "\n}\n" >> _book/links.json + printf "${YELLOW}[WARN] No mkdocs config found, skipping MkDocs build${RESET}\n"; \ + fi + @mkdir -p "$(BOOK_OUTPUT)" + @touch "$(BOOK_OUTPUT)/.nojekyll" + @printf "${GREEN}[SUCCESS] Book built at $(BOOK_OUTPUT)/${RESET}\n" + @tree $(BOOK_OUTPUT) - @printf "${BLUE}[INFO] Generated links.json:${RESET}\n" - @cat _book/links.json +mkdocs-build: install-uv ## build MkDocs documentation site + @if [ -n "$(_MKDOCS_CFG)" ]; then \ + rm -rf "$(BOOK_OUTPUT)"; \ + ${UVX_BIN} --with "mkdocs-material<10.0" --with "pymdown-extensions>=10.0" --with "mkdocs<2.0" $(MKDOCS_EXTRA_PACKAGES) mkdocs build \ + -f "$(_MKDOCS_CFG)" \ + -d "$$(pwd)/$(BOOK_OUTPUT)"; \ + else \ + printf "${RED}[ERROR] No mkdocs config found${RESET}\n"; \ + exit 1; \ + fi + @mkdir -p "$(BOOK_OUTPUT)" + @touch "$(BOOK_OUTPUT)/.nojekyll" + @printf "${GREEN}[SUCCESS] Docs built at $(BOOK_OUTPUT)/${RESET}\n" - @TEMPLATE_ARG=""; \ - if [ -f "$(BOOK_TEMPLATE)" ]; then \ - TEMPLATE_ARG="--template $(BOOK_TEMPLATE)"; \ - printf "${BLUE}[INFO] Using book template $(BOOK_TEMPLATE)${RESET}\n"; \ - fi; \ - if [ -n "$(LOGO_FILE)" ]; then \ - if [ -f "$(LOGO_FILE)" ]; then \ - cp "$(LOGO_FILE)" "_book/logo$$(echo $(LOGO_FILE) | sed 's/.*\./\./')"; \ - printf "${BLUE}[INFO] Copying logo: $(LOGO_FILE)${RESET}\n"; \ - else \ - printf "${YELLOW}[WARN] Logo file $(LOGO_FILE) not found, skipping${RESET}\n"; \ - fi; \ - fi; \ - "$(UVX_BIN)" minibook \ - --title "$(BOOK_TITLE)" \ - --subtitle "$(BOOK_SUBTITLE)" \ - $$TEMPLATE_ARG \ - --links "$$(python3 -c 'import json;print(json.dumps(json.load(open("_book/links.json"))))')" \ - --output "_book" +mkdocs-serve: install-uv ## serve MkDocs site with live reload + @if [ -n "$(_MKDOCS_CFG)" ]; then \ + ${UVX_BIN} --with "mkdocs-material<10.0" --with "pymdown-extensions>=10.0" --with "mkdocs<2.0" $(MKDOCS_EXTRA_PACKAGES) mkdocs serve \ + -f "$(_MKDOCS_CFG)"; \ + else \ + printf "${RED}[ERROR] No mkdocs config found${RESET}\n"; \ + exit 1; \ + fi - @touch "_book/.nojekyll" +mkdocs: mkdocs-serve ## alias for mkdocs-serve diff --git a/.rhiza/make.d/docs.mk b/.rhiza/make.d/docs.mk deleted file mode 100644 index 803a066..0000000 --- a/.rhiza/make.d/docs.mk +++ /dev/null @@ -1,96 +0,0 @@ -## docs.mk - Documentation generation targets -# This file is included by the main Makefile. -# It provides targets for generating API documentation using pdoc -# and building/serving MkDocs documentation sites. - -# Declare phony targets (they don't produce files) -.PHONY: docs mkdocs mkdocs-serve mkdocs-build - -# Default output directory for MkDocs (HTML site) -MKDOCS_OUTPUT ?= _mkdocs - -# MkDocs config file location -MKDOCS_CONFIG ?= docs/mkdocs.yml - -# Default pdoc template directory (can be overridden) -PDOC_TEMPLATE_DIR ?= book/pdoc-templates - -##@ Documentation - -# The 'docs' target generates API documentation using pdoc. -# 1. Identifies Python packages within the source folder. -# 2. Detects the docformat (google, numpy, or sphinx) from ruff.toml or defaults to google. -# 3. Installs pdoc and generates HTML documentation in _pdoc. -docs:: install ## create documentation with pdoc - # Clean up previous docs - rm -rf _pdoc; - - @if [ -d "${SOURCE_FOLDER}" ]; then \ - PKGS=""; for d in "${SOURCE_FOLDER}"/*; do [ -d "$$d" ] && PKGS="$$PKGS $$(basename "$$d")"; done; \ - if [ -z "$$PKGS" ]; then \ - printf "${YELLOW}[WARN] No packages found under ${SOURCE_FOLDER}, skipping docs${RESET}\n"; \ - else \ - TEMPLATE_ARG=""; \ - if [ -d "$(PDOC_TEMPLATE_DIR)" ]; then \ - TEMPLATE_ARG="-t $(PDOC_TEMPLATE_DIR)"; \ - printf "$(BLUE)[INFO] Using pdoc templates from $(PDOC_TEMPLATE_DIR)$(RESET)\n"; \ - fi; \ - DOCFORMAT="$(DOCFORMAT)"; \ - if [ -z "$$DOCFORMAT" ]; then \ - if [ -f "ruff.toml" ]; then \ - DOCFORMAT=$$(${UV_BIN} run python -c "import tomllib; print(tomllib.load(open('ruff.toml', 'rb')).get('lint', {}).get('pydocstyle', {}).get('convention', ''))"); \ - fi; \ - if [ -z "$$DOCFORMAT" ]; then \ - DOCFORMAT="google"; \ - fi; \ - printf "${BLUE}[INFO] Detected docformat: $$DOCFORMAT${RESET}\n"; \ - else \ - printf "${BLUE}[INFO] Using provided docformat: $$DOCFORMAT${RESET}\n"; \ - fi; \ - LOGO_ARG=""; \ - if [ -n "$(LOGO_FILE)" ]; then \ - if [ -f "$(LOGO_FILE)" ]; then \ - MIME=$$(file --mime-type -b "$(LOGO_FILE)"); \ - DATA=$$(base64 < "$(LOGO_FILE)" | tr -d '\n'); \ - LOGO_ARG="--logo data:$$MIME;base64,$$DATA"; \ - printf "${BLUE}[INFO] Embedding logo: $(LOGO_FILE)${RESET}\n"; \ - else \ - printf "${YELLOW}[WARN] Logo file $(LOGO_FILE) not found, skipping${RESET}\n"; \ - fi; \ - fi; \ - ${UV_BIN} pip install pdoc && \ - PYTHONPATH="${SOURCE_FOLDER}" ${UV_BIN} run pdoc --docformat $$DOCFORMAT --output-dir _pdoc $$TEMPLATE_ARG $$LOGO_ARG $$PKGS; \ - fi; \ - else \ - printf "${YELLOW}[WARN] Source folder ${SOURCE_FOLDER} not found, skipping docs${RESET}\n"; \ - fi - -# The 'mkdocs-build' target builds the MkDocs documentation site. -# 1. Checks if the mkdocs.yml config file exists. -# 2. Cleans up any previous output. -# 3. Builds the static site using mkdocs with material theme. -mkdocs-build:: install-uv ## build MkDocs documentation site - @printf "${BLUE}[INFO] Building MkDocs site...${RESET}\n" - @if [ -f "$(MKDOCS_CONFIG)" ]; then \ - rm -rf "$(MKDOCS_OUTPUT)"; \ - MKDOCS_OUTPUT_ABS="$$(pwd)/$(MKDOCS_OUTPUT)"; \ - ${UVX_BIN} --with "mkdocs-material<10.0" --with "pymdown-extensions>=10.0" --with "mkdocs<2.0" mkdocs build \ - -f "$(MKDOCS_CONFIG)" \ - -d "$$MKDOCS_OUTPUT_ABS"; \ - else \ - printf "${YELLOW}[WARN] $(MKDOCS_CONFIG) not found, skipping MkDocs build${RESET}\n"; \ - fi - -# The 'mkdocs-serve' target serves the documentation with live reload. -# Useful for local development and previewing changes. -mkdocs-serve: install-uv ## serve MkDocs site with live reload - @if [ -f "$(MKDOCS_CONFIG)" ]; then \ - ${UVX_BIN} --with "mkdocs-material<10.0" --with "pymdown-extensions>=10.0" --with "mkdocs<2.0" mkdocs serve \ - -f "$(MKDOCS_CONFIG)"; \ - else \ - printf "${RED}[ERROR] $(MKDOCS_CONFIG) not found${RESET}\n"; \ - exit 1; \ - fi - -# Convenience alias -mkdocs: mkdocs-serve ## alias for mkdocs-serve diff --git a/.rhiza/make.d/marimo.mk b/.rhiza/make.d/marimo.mk index 3758a8a..36ae74c 100644 --- a/.rhiza/make.d/marimo.mk +++ b/.rhiza/make.d/marimo.mk @@ -2,7 +2,7 @@ # This file is included by the main Makefile # Declare phony targets (they don't produce files) -.PHONY: marimo-validate marimo marimushka +.PHONY: marimo-validate marimo ##@ Marimo Notebooks marimo-validate: install ## validate all Marimo notebooks can run @@ -40,31 +40,3 @@ marimo: install ## fire up Marimo server else \ ${UV_BIN} run --no-project --with marimo --directory "${MARIMO_FOLDER}" marimo edit --no-token --headless; \ fi - -# The 'marimushka' target exports Marimo notebooks (.py files) to static HTML. -# 1. Detects notebooks in the MARIMO_FOLDER. -# 2. Converts them using 'marimushka export'. -# 3. Generates a placeholder index.html if no notebooks are found. -marimushka:: install-uv ## export Marimo notebooks to HTML - # Clean up previous marimushka output - rm -rf "${MARIMUSHKA_OUTPUT}"; - - @printf "${BLUE}[INFO] Exporting notebooks from ${MARIMO_FOLDER}...${RESET}\n" - @if [ ! -d "${MARIMO_FOLDER}" ]; then \ - printf "${YELLOW}[WARN] Directory '${MARIMO_FOLDER}' does not exist. Skipping marimushka.${RESET}\n"; \ - else \ - mkdir -p "${MARIMUSHKA_OUTPUT}"; \ - if ! ls "${MARIMO_FOLDER}"/*.py >/dev/null 2>&1; then \ - printf "${YELLOW}[WARN] No Python files found in '${MARIMO_FOLDER}'.${RESET}\n"; \ - printf '%s\n' 'Marimo Notebooks' \ - '

Marimo Notebooks

No notebooks found.

' \ - > "${MARIMUSHKA_OUTPUT}/index.html"; \ - else \ - CURRENT_DIR=$$(pwd); \ - OUTPUT_DIR="$$CURRENT_DIR/${MARIMUSHKA_OUTPUT}"; \ - cd "${MARIMO_FOLDER}" && \ - UVX_DIR=$$(dirname "$$(command -v uvx || echo "${INSTALL_DIR}/uvx")") && \ - "${UVX_BIN}" "marimushka>=0.3.3" export --notebooks "." --output "$$OUTPUT_DIR" --bin-path "$$UVX_DIR" && \ - cd "$$CURRENT_DIR"; \ - fi; \ - fi diff --git a/.rhiza/make.d/quality.mk b/.rhiza/make.d/quality.mk index 1efd063..32007f3 100644 --- a/.rhiza/make.d/quality.mk +++ b/.rhiza/make.d/quality.mk @@ -1,11 +1,14 @@ ## .rhiza/make.d/quality.mk - Quality and Formatting # This file provides targets for code quality checks, linting, and formatting. +# Configurable list of licenses that fail the compliance scan (semicolon-separated) +LICENSE_FAIL_ON ?= GPL;LGPL;AGPL + # Declare phony targets (they don't produce files) -.PHONY: all deptry fmt todos +.PHONY: all deptry fmt license todos suppression-audit ##@ Quality and Formatting -all: fmt deptry test docs-coverage security typecheck rhiza-test ## run all CI targets locally +all: fmt deptry test docs-coverage security license typecheck rhiza-test ## run all CI targets locally deptry: install-uv ## Run deptry @if [ -d ${SOURCE_FOLDER} ]; then \ @@ -38,3 +41,11 @@ todos: ## search and report all TODO/FIXME/HACK comments in the codebase awk -F: '{ printf "${YELLOW}%s${RESET}:${GREEN}%s${RESET}: %s\n", $$1, $$2, substr($$0, index($$0,$$3)) }' || \ printf "${GREEN}[SUCCESS] No TODO/FIXME/HACK comments found!${RESET}\n" @printf "\n${BLUE}[INFO] Search complete.${RESET}\n" + +suppression-audit: ## scan codebase for inline suppressions and report (grade, detail, histogram) + @printf "${BLUE}[INFO] Running suppression audit...${RESET}\n" + @${UV_BIN} run python .rhiza/utils/suppression_audit.py + +license: install ## run license compliance scan (fail on GPL, LGPL, AGPL) + @printf "${BLUE}[INFO] Running license compliance scan...${RESET}\n" + @${UV_BIN} run --with pip-licenses pip-licenses --fail-on="${LICENSE_FAIL_ON}" diff --git a/.rhiza/requirements/README.md b/.rhiza/requirements/README.md index 4feff9a..5c7a818 100644 --- a/.rhiza/requirements/README.md +++ b/.rhiza/requirements/README.md @@ -4,10 +4,10 @@ This folder contains the development dependencies for the Rhiza project, organiz ## Files -- **tests.txt** - Testing dependencies (pytest, pytest-cov, pytest-html) +- **tests.txt** - Testing dependencies (pytest, pytest-cov, pytest-html, pytest-mock, PyYAML, defusedxml, hypothesis, pytest-benchmark, pygal) - **marimo.txt** - Marimo notebook dependencies -- **docs.txt** - Documentation generation dependencies (pdoc) -- **tools.txt** - Development tools (pre-commit, python-dotenv) +- **docs.txt** - Documentation generation dependencies (pdoc, interrogate, mkdocs, mkdocs-material, mkdocstrings) +- **tools.txt** - Development tools (pre-commit, python-dotenv, typer, ty) ## Usage diff --git a/.rhiza/requirements/docs.txt b/.rhiza/requirements/docs.txt index 7d12b67..1b9d392 100644 --- a/.rhiza/requirements/docs.txt +++ b/.rhiza/requirements/docs.txt @@ -1,3 +1,5 @@ # Documentation dependencies for rhiza -pdoc>=16.0.0 interrogate>=1.7.0 +mkdocs>=1.6.0 +mkdocs-material>=9.5.0 +mkdocstrings[python]>=0.25.0 diff --git a/.rhiza/rhiza.mk b/.rhiza/rhiza.mk index ee22274..25282ea 100644 --- a/.rhiza/rhiza.mk +++ b/.rhiza/rhiza.mk @@ -1,7 +1,7 @@ ## Makefile for jebel-quant/rhiza # (https://github.com/jebel-quant/rhiza) # -# Purpose: Developer tasks using uv/uvx (install, test, docs, marimushka, book). +# Purpose: Developer tasks using uv/uvx (install, test, book). # Lines with `##` after a target are parsed into help text, # and lines starting with `##@` create section headers in the help output. # diff --git a/.rhiza/template.lock b/.rhiza/template.lock index 1b1d49a..71a03f6 100644 --- a/.rhiza/template.lock +++ b/.rhiza/template.lock @@ -1,7 +1,7 @@ -sha: bbe56565ed221032435bff43b00598e3efa046ef +sha: dccf929ce3bcbaf01ddf1240ac16354e0cf76bb1 repo: jebel-quant/rhiza host: github -ref: v0.8.16 +ref: v0.9.5 include: [] exclude: [] templates: @@ -24,23 +24,15 @@ files: - .github/hooks/session-end.sh - .github/hooks/session-start.sh - .github/secret_scanning.yml +- .github/semgrep.yml - .github/workflows/copilot-setup-steps.yml -- .github/workflows/renovate_rhiza_sync.yml - .github/workflows/rhiza_book.yml - .github/workflows/rhiza_ci.yml - .github/workflows/rhiza_codeql.yml -- .github/workflows/rhiza_dep_compat_test.yml -- .github/workflows/rhiza_deptry.yml -- .github/workflows/rhiza_license.yml - .github/workflows/rhiza_marimo.yml -- .github/workflows/rhiza_pip_audit.yml -- .github/workflows/rhiza_pre-commit.yml - .github/workflows/rhiza_release.yml -- .github/workflows/rhiza_security.yml -- .github/workflows/rhiza_semgrep.yml - .github/workflows/rhiza_sync.yml -- .github/workflows/rhiza_typecheck.yml -- .github/workflows/rhiza_validate.yml +- .github/workflows/rhiza_weekly.yml - .gitignore - .pre-commit-config.yaml - .python-version @@ -48,6 +40,8 @@ files: - .rhiza/.env - .rhiza/.gitignore - .rhiza/.rhiza-version +- .rhiza/CODE_OF_CONDUCT.md +- .rhiza/CONTRIBUTING.md - .rhiza/assets/rhiza-logo.svg - .rhiza/docs/ASSETS.md - .rhiza/docs/CONFIG.md @@ -62,7 +56,6 @@ files: - .rhiza/make.d/bootstrap.mk - .rhiza/make.d/custom-env.mk - .rhiza/make.d/custom-task.mk -- .rhiza/make.d/docs.mk - .rhiza/make.d/gh-aw.mk - .rhiza/make.d/github.mk - .rhiza/make.d/marimo.mk @@ -75,7 +68,6 @@ files: - .rhiza/requirements/tests.txt - .rhiza/requirements/tools.txt - .rhiza/rhiza.mk -- .rhiza/templates/minibook/custom.html.jinja2 - .rhiza/tests/README.md - .rhiza/tests/api/conftest.py - .rhiza/tests/api/test_gh_aw_targets.py @@ -85,8 +77,8 @@ files: - .rhiza/tests/conftest.py - .rhiza/tests/deps/test_dependency_health.py - .rhiza/tests/integration/test_book_targets.py +- .rhiza/tests/integration/test_docs_targets.py - .rhiza/tests/integration/test_lfs.py -- .rhiza/tests/integration/test_marimushka.py - .rhiza/tests/integration/test_sbom.py - .rhiza/tests/integration/test_test_mk.py - .rhiza/tests/integration/test_virtual_env_unexport.py @@ -107,23 +99,16 @@ files: - .rhiza/tests/sync/test_rhiza_version.py - .rhiza/tests/test_utils.py - .rhiza/tests/utils/test_git_repo_fixture.py -- .semgrep.yml -- CODE_OF_CONDUCT.md -- CONTRIBUTING.md - LICENSE - Makefile - SECURITY.md -- book/marimo/notebooks/rhiza.py -- docs/ARCHITECTURE.md -- docs/BOOK.md -- docs/CUSTOMIZATION.md -- docs/DEMO.md -- docs/GLOSSARY.md -- docs/MARIMO.md -- docs/QUICK_REFERENCE.md -- docs/SECURITY.md -- docs/TESTS.md +- docs/adr/0000-adr-template.md +- docs/assets/rhiza-logo.svg +- docs/development/MARIMO.md +- docs/development/TESTS.md +- docs/index.md +- docs/mkdocs-base.yml - pytest.ini - ruff.toml -synced_at: '2026-03-22T07:16:17Z' +synced_at: '2026-04-14T04:36:10Z' strategy: merge diff --git a/.rhiza/template.yml b/.rhiza/template.yml index bd157d2..d59b099 100644 --- a/.rhiza/template.yml +++ b/.rhiza/template.yml @@ -1,5 +1,5 @@ repository: "jebel-quant/rhiza" -ref: "v0.8.16" +ref: "v0.9.5" templates: - github diff --git a/.rhiza/templates/minibook/custom.html.jinja2 b/.rhiza/templates/minibook/custom.html.jinja2 deleted file mode 100644 index da34646..0000000 --- a/.rhiza/templates/minibook/custom.html.jinja2 +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - {{ title }} - - - - - - -
-
- - -
- Logo -
- - -
-
-

{{ title }}

- {% if description %} -
{{ description }}
- {% endif %} -
-
- - - - - - Home Repo - -
-
- - {% if links %} -
- {% for name, url in links %} - -
- {{ name[0] | upper }} -
-
-
{{ name }}
-
-
- {% endfor %} -
- {% endif %} - - -
-
- - \ No newline at end of file diff --git a/.rhiza/tests/README.md b/.rhiza/tests/README.md index 7b5fd0d..1cf5c26 100644 --- a/.rhiza/tests/README.md +++ b/.rhiza/tests/README.md @@ -24,7 +24,6 @@ Tests requiring sandboxed git repositories or subprocess execution. These tests - `test_release.py` — Release script functionality - `test_book_targets.py` — Documentation book build targets -- `test_marimushka.py` — Marimushka target execution ### `sync/` Template sync, workflows, versioning, and content validation tests. These tests ensure that template synchronization and content validation work correctly. diff --git a/.rhiza/tests/api/conftest.py b/.rhiza/tests/api/conftest.py index 798bc75..f3a5c5d 100644 --- a/.rhiza/tests/api/conftest.py +++ b/.rhiza/tests/api/conftest.py @@ -43,7 +43,6 @@ ".rhiza/make.d/agentic.mk", ".rhiza/make.d/gh-aw.mk", ".rhiza/make.d/docker.mk", - ".rhiza/make.d/docs.mk", ] diff --git a/.rhiza/tests/api/test_makefile_targets.py b/.rhiza/tests/api/test_makefile_targets.py index 7a90200..1ea7747 100644 --- a/.rhiza/tests/api/test_makefile_targets.py +++ b/.rhiza/tests/api/test_makefile_targets.py @@ -189,6 +189,27 @@ def test_coverage_badge_skips_without_source_folder(self, logger, tmp_path): assert "nonexistent_src" in out assert "skipping coverage-badge" in out + def test_suppression_audit_target_dry_run(self, logger): + """Suppression-audit target should invoke the Python audit script via uv run in dry-run output.""" + proc = run_make(logger, ["suppression-audit"]) + out = proc.stdout + assert "uv run python" in out + assert "suppression_audit.py" in out + + def test_license_target_dry_run(self, logger): + """License target should invoke pip-licenses via uv run --with in dry-run output.""" + proc = run_make(logger, ["license"]) + out = proc.stdout + assert "uv run --with pip-licenses pip-licenses" in out + assert "--fail-on=" in out + assert "GPL" in out + + def test_license_fail_on_is_configurable(self, logger): + """License target should use the LICENSE_FAIL_ON variable for the fail-on list.""" + proc = run_make(logger, ["license", "LICENSE_FAIL_ON=MIT;Apache"]) + out = proc.stdout + assert '--fail-on="MIT;Apache"' in out + class TestMakefileRootFixture: """Tests for root fixture usage in Makefile tests.""" diff --git a/.rhiza/tests/integration/test_book_targets.py b/.rhiza/tests/integration/test_book_targets.py index 49cbb41..d62cc8f 100644 --- a/.rhiza/tests/integration/test_book_targets.py +++ b/.rhiza/tests/integration/test_book_targets.py @@ -30,7 +30,7 @@ def test_no_book_folder(git_repo, book_makefile): # Targets are now always defined via .rhiza/make.d/ # Use dry-run to verify they exist and can be parsed - for target in ["book", "docs", "marimushka"]: + for target in ["book"]: result = subprocess.run([MAKE, "-n", target], cwd=git_repo, capture_output=True, text=True) # nosec # Target should exist (not "no rule to make target") assert "no rule to make target" not in result.stderr.lower(), ( @@ -57,7 +57,7 @@ def test_book_folder_but_no_mk(git_repo, book_makefile): # Targets are now always defined via .rhiza/make.d/ # Use dry-run to verify they exist and can be parsed - for target in ["book", "docs", "marimushka"]: + for target in ["book"]: result = subprocess.run([MAKE, "-n", target], cwd=git_repo, capture_output=True, text=True) # nosec # Target should exist (not "no rule to make target") assert "no rule to make target" not in result.stderr.lower(), ( @@ -80,7 +80,7 @@ def test_book_folder(git_repo, book_makefile): targets = phony_line.split(":")[1].strip().split() all_targets.update(targets) - expected_targets = {"book", "marimushka", "mkdocs-build", "test", "benchmark", "stress", "hypothesis-test", "docs"} + expected_targets = {"book", "mkdocs-build", "test", "benchmark", "stress", "hypothesis-test"} assert expected_targets.issubset(all_targets), ( f"Expected phony targets to include {expected_targets}, got {all_targets}" ) @@ -93,7 +93,7 @@ def test_book_noop_targets_defined(book_makefile): test.mk is not available or tests are not installed. """ content = book_makefile.read_text() - for target in ["test", "benchmark", "stress", "hypothesis-test", "docs"]: + for target in ["test", "benchmark", "stress", "hypothesis-test"]: assert f"{target}::" in content, ( f"book.mk should define a no-op '::' fallback for '{target}' to ensure build resilience" ) diff --git a/.rhiza/tests/integration/test_docs_targets.py b/.rhiza/tests/integration/test_docs_targets.py new file mode 100644 index 0000000..60ab5ff --- /dev/null +++ b/.rhiza/tests/integration/test_docs_targets.py @@ -0,0 +1,69 @@ +"""Tests for book.mk Makefile targets and the MKDOCS_EXTRA_PACKAGES variable.""" + +import shutil +import subprocess # nosec + +import pytest + +MAKE = shutil.which("make") or "/usr/bin/make" + + +@pytest.fixture +def book_makefile(git_repo): + """Return the book.mk path or skip tests if missing.""" + makefile = git_repo / ".rhiza" / "make.d" / "book.mk" + if not makefile.exists(): + pytest.skip("book.mk not found, skipping test") + return makefile + + +def test_mkdocs_extra_packages_variable_defined(book_makefile): + """Test that MKDOCS_EXTRA_PACKAGES is declared with a default-empty value.""" + content = book_makefile.read_text() + assert "MKDOCS_EXTRA_PACKAGES ?=" in content, "book.mk should declare MKDOCS_EXTRA_PACKAGES with a ?= default" + + +def test_mkdocs_extra_packages_used_in_build(book_makefile): + """Test that MKDOCS_EXTRA_PACKAGES is spliced into the mkdocs build uvx command.""" + content = book_makefile.read_text() + # The variable must appear on the same line as 'mkdocs build' + build_lines = [line for line in content.splitlines() if "mkdocs build" in line] + assert build_lines, "book.mk should contain a 'mkdocs build' invocation" + assert any("$(MKDOCS_EXTRA_PACKAGES)" in line for line in build_lines), ( + "mkdocs build line should include $(MKDOCS_EXTRA_PACKAGES)" + ) + + +def test_mkdocs_extra_packages_used_in_serve(book_makefile): + """Test that MKDOCS_EXTRA_PACKAGES is spliced into the mkdocs-serve uvx command.""" + content = book_makefile.read_text() + serve_lines = [line for line in content.splitlines() if "mkdocs serve" in line] + assert serve_lines, "book.mk should contain a 'mkdocs serve' invocation" + assert any("$(MKDOCS_EXTRA_PACKAGES)" in line for line in serve_lines), ( + "mkdocs serve line should include $(MKDOCS_EXTRA_PACKAGES)" + ) + + +def test_mkdocs_build_dry_run_with_extra_packages(git_repo, book_makefile): + """Test that passing MKDOCS_EXTRA_PACKAGES on the command line is accepted by make. + + Validates both a single package and multiple packages to confirm the variable + correctly extends the uvx invocation in all cases. + """ + for extra in [ + "--with mkdocs-graphviz", + "--with mkdocs-graphviz --with mkdocs-mermaid2", + ]: + result = subprocess.run( # nosec + [MAKE, "-n", "book", f"MKDOCS_EXTRA_PACKAGES={extra}"], + cwd=git_repo, + capture_output=True, + text=True, + ) + assert "no rule to make target" not in result.stderr.lower(), "book should be a defined target" + assert result.returncode == 0, f"Dry-run failed: {result.stderr}" + # Each extra package flag should appear in the dry-run output + for pkg in ["mkdocs-graphviz", "mkdocs-mermaid2"][: len(extra.split("--with")) - 1]: + assert pkg in result.stdout, ( + f"MKDOCS_EXTRA_PACKAGES package '{pkg}' should be visible in the dry-run command" + ) diff --git a/.rhiza/tests/integration/test_marimushka.py b/.rhiza/tests/integration/test_marimushka.py deleted file mode 100644 index 6abdaa9..0000000 --- a/.rhiza/tests/integration/test_marimushka.py +++ /dev/null @@ -1,93 +0,0 @@ -"""Tests for the marimushka Makefile target using a sandboxed environment. - -This file and its associated tests flow down via a SYNC action from the jebel-quant/rhiza repository -(https://github.com/jebel-quant/rhiza). - -Provides test fixtures for testing git-based workflows and version management. -""" - -import os -import shutil -import subprocess # nosec - -import pytest - -# Get shell path and make command once at module level -SHELL = shutil.which("sh") or "/bin/sh" -MAKE = shutil.which("make") or "/usr/bin/make" - - -def test_marimushka_target_success(git_repo): - """Test successful execution of the marimushka Makefile target.""" - # only run this test if the marimo folder is present - if not (git_repo / "book" / "marimo").exists(): - pytest.skip("marimo folder not found, skipping test") - - # Setup directories in the git repo - marimo_folder = git_repo / "book" / "marimo" / "notebooks" - marimo_folder.mkdir(parents=True, exist_ok=True) - (marimo_folder / "notebook.py").touch() - - output_folder = git_repo / "_marimushka" - - # Run the make target - env = os.environ.copy() - env["MARIMO_FOLDER"] = "book/marimo/notebooks" - env["MARIMUSHKA_OUTPUT"] = "_marimushka" - - # Create dummy bin/uv and bin/uvx if they don't exist - (git_repo / "bin").mkdir(exist_ok=True) - (git_repo / "bin" / "uv").touch() - (git_repo / "bin" / "uv").chmod(0o755) - (git_repo / "bin" / "uvx").touch() - (git_repo / "bin" / "uvx").chmod(0o755) - - # Put our bin on the PATH so 'command -v uvx' finds it in the test - env["PATH"] = f"{git_repo}/bin:{env.get('PATH', '')}" - - # In tests, we don't want to actually run marimushka as it's not installed in the mock env - # But we want to test that the Makefile logic works. - # We can mock the marimushka CLI call by creating a script that generates the expected files. - with open(git_repo / "bin" / "marimushka", "w") as f: - f.write( - f"#!/bin/sh\nmkdir -p {output_folder}/notebooks\n" - f"touch {output_folder}/index.html\n" - f"touch {output_folder}/notebooks/notebook.html\n" - ) - (git_repo / "bin" / "marimushka").chmod(0o755) - - # Override UVX_BIN to use our mock marimushka CLI - env["UVX_BIN"] = str(git_repo / "bin" / "marimushka") - - result = subprocess.run([MAKE, "marimushka"], env=env, cwd=git_repo, capture_output=True, text=True) # nosec - - assert result.returncode == 0 - assert "Exporting notebooks" in result.stdout - assert (output_folder / "index.html").exists() - assert (output_folder / "notebooks" / "notebook.html").exists() - - -def test_marimushka_no_python_files(git_repo): - """Test marimushka target behavior when MARIMO_FOLDER has no python files.""" - if not (git_repo / "book" / "marimo").exists(): - pytest.skip("marimo folder not found, skipping test") - - marimo_folder = git_repo / "book" / "marimo" / "notebooks" - marimo_folder.mkdir(parents=True, exist_ok=True) - - # Delete all .py files in the marimo folder - for file in marimo_folder.glob("*.py"): - file.unlink() - - # No .py files created - - output_folder = git_repo / "_marimushka" - - env = os.environ.copy() - env["MARIMO_FOLDER"] = "book/marimo/notebooks" - env["MARIMUSHKA_OUTPUT"] = "_marimushka" - - result = subprocess.run([MAKE, "marimushka"], env=env, cwd=git_repo, capture_output=True, text=True) # nosec - - assert result.returncode == 0 - assert (output_folder / "index.html").exists() diff --git a/.rhiza/tests/security/test_security_patterns.py b/.rhiza/tests/security/test_security_patterns.py index 27cbc31..940098f 100644 --- a/.rhiza/tests/security/test_security_patterns.py +++ b/.rhiza/tests/security/test_security_patterns.py @@ -89,12 +89,10 @@ def test_security_policy_exists(self) -> None: """ repo_root = pathlib.Path(__file__).parent.parent.parent.parent root_security = repo_root / "SECURITY.md" - github_security = repo_root / ".github" / "SECURITY.md" - docs_security = repo_root / "docs" / "SECURITY.md" - assert root_security.exists() or github_security.exists() or docs_security.exists(), ( - "No SECURITY.md found. Create SECURITY.md in the repository root, " - ".github/, or docs/ to publish a responsible disclosure policy." + assert root_security.exists(), ( + "No SECURITY.md found. Create SECURITY.md in the repository root " + "to publish a responsible disclosure policy." ) def test_secret_scanning_config_exists(self) -> None: diff --git a/.rhiza/tests/sync/conftest.py b/.rhiza/tests/sync/conftest.py index 9bb3b2f..fafa07a 100644 --- a/.rhiza/tests/sync/conftest.py +++ b/.rhiza/tests/sync/conftest.py @@ -58,7 +58,6 @@ def setup_sync_env(logger, root, tmp_path: Path): "github.mk", "agentic.mk", "docker.mk", - "docs.mk", ] (tmp_path / ".rhiza" / "make.d").mkdir(parents=True, exist_ok=True) for mk_file in split_makefiles: diff --git a/Makefile b/Makefile index 6da15f2..33fde18 100644 --- a/Makefile +++ b/Makefile @@ -18,22 +18,6 @@ post-validate:: ## Custom targets -##@ Quality - -.PHONY: semgrep -semgrep: install ## run Semgrep static analysis (numpy rules) - @printf "${BLUE}[INFO] Running Semgrep (numpy rules)...${RESET}\n" - @if [ -d ${SOURCE_FOLDER} ]; then \ - ${UVX_BIN} semgrep --config .semgrep.yml ${SOURCE_FOLDER}; \ - else \ - printf "${YELLOW}[WARN] SOURCE_FOLDER '${SOURCE_FOLDER}' not found, skipping semgrep.${RESET}\n"; \ - fi - -.PHONY: license -license: install ## run license compliance scan (fail on GPL, LGPL, AGPL) - @printf "${BLUE}[INFO] Running license compliance scan...${RESET}\n" - @${UV_BIN} run --with pip-licenses pip-licenses --fail-on="GPL;LGPL;AGPL" - .PHONY: adr adr: install-gh-aw ## Create a new Architecture Decision Record (ADR) using AI assistance @echo "Creating a new ADR..." diff --git a/SECURITY.md b/SECURITY.md index c678559..541b1c1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,14 +1,16 @@ # Security Policy +Overwrite this file using Claude and adjust for the Rhiza dependant. + ## Supported Versions We actively support the following versions with security updates: | Version | Supported | | ------- | ------------------ | +| 0.9.x | :white_check_mark: | | 0.8.x | :white_check_mark: | -| 0.7.x | :white_check_mark: | -| < 0.7 | :x: | +| < 0.8 | :x: | ## Reporting a Vulnerability diff --git a/book/marimo/notebooks/rhiza.py b/book/marimo/notebooks/rhiza.py deleted file mode 100644 index 12a50e1..0000000 --- a/book/marimo/notebooks/rhiza.py +++ /dev/null @@ -1,657 +0,0 @@ -# /// script -# requires-python = ">=3.11" -# dependencies = [ -# "marimo==0.18.4", -# "numpy>=1.24.0", -# "plotly>=5.18.0", -# "pandas>=2.0.0", -# ] -# /// - -import marimo - -__generated_with = "0.18.4" -app = marimo.App(width="medium") - -with app.setup: - import marimo as mo - import numpy as np - import pandas as pd - import plotly.graph_objects as go - - -@app.cell -def cell_02(): - """Render the showcase introduction Markdown content.""" - mo.md( - r""" - # 🎨 Marimo Showcase - - Welcome to the **Marimo Showcase Notebook**! This interactive notebook demonstrates - the most powerful and useful features of [Marimo](https://marimo.io/). - - **Marimo** is a reactive Python notebook that combines the best of Jupyter notebooks - with the power of reactive programming. Every cell automatically updates when its - dependencies change, creating a seamless interactive experience. - - ## Why Marimo? - - - ✨ **Reactive by default** - No manual cell re-runs - - 🎯 **Pure Python** - Notebooks are `.py` files - - 🔄 **Reproducible** - Consistent execution order - - 🎨 **Rich UI elements** - Beautiful interactive components - - 📦 **Version control friendly** - Easy to diff and merge - """ - ) - - -@app.cell -def cell_03(): - """Render a horizontal rule to separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_04(): - """Introduce the Interactive UI Elements section.""" - mo.md( - r""" - ## 🎚️ Interactive UI Elements - - Marimo provides rich UI components that automatically trigger reactive updates. - """ - ) - - -@app.cell -def cell_05(): - """Create and display a numeric slider UI component.""" - # Slider for numeric input - slider = mo.ui.slider(start=0, stop=100, value=50, label="Adjust the value:", show_value=True) - slider - return (slider,) - - -@app.cell -def cell_06(slider): - """Display the current slider value reactively.""" - mo.md( - f""" - The slider value is: **{slider.value}** - - This text updates automatically when you move the slider! ✨ - """ - ) - - -@app.cell -def cell_07(): - """Create and display a dropdown for language selection.""" - # Dropdown for selection - dropdown = mo.ui.dropdown( - options=["Python", "JavaScript", "Rust", "Go", "TypeScript"], - value="Python", - label="Choose your favorite language:", - ) - dropdown - return (dropdown,) - - -@app.cell -def cell_08(dropdown): - """Display the currently selected language from the dropdown.""" - mo.md( - f""" - You selected: **{dropdown.value}** 🎉 - - Great choice! {dropdown.value} is an excellent programming language. - """ - ) - - -@app.cell -def cell_09(): - """Create and display a text input field for the user's name.""" - # Text input - text_input = mo.ui.text(value="Marimo", label="Enter your name:", placeholder="Type something...") - text_input - return (text_input,) - - -@app.cell -def cell_10(text_input): - """Display a personalized greeting using the current text input value.""" - mo.md(f"""Hello, **{text_input.value}**! 👋""") - - -@app.cell -def cell_11(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_12(): - """Introduce the Data Visualisation section.""" - mo.md( - r""" - ## 📊 Data Visualisation - - Marimo works seamlessly with popular visualisation libraries like Plotly, - Altair, and Matplotlib. Let's create interactive plots! - """ - ) - - -@app.cell -def cell_14(): - """Create sliders for wave frequency and amplitude controls for the plot.""" - # Interactive controls for the plot - frequency_slider = mo.ui.slider(start=1, stop=10, value=2, label="Wave frequency:", show_value=True) - - amplitude_slider = mo.ui.slider(start=1, stop=5, value=1, label="Wave amplitude:", show_value=True) - - mo.vstack([frequency_slider, amplitude_slider]) - return amplitude_slider, frequency_slider - - -@app.cell -def cell_15(amplitude_slider, frequency_slider): - """Build a reactive Plotly sine wave based on the slider values.""" - # Generate reactive plot based on slider values - x = np.linspace(0, 4 * np.pi, 1000) - y = amplitude_slider.value * np.sin(frequency_slider.value * x) - - fig = go.Figure() - fig.add_trace(go.Scatter(x=x, y=y, mode="lines", line={"color": "#2FA4A9", "width": 2}, name="Sine Wave")) - - fig.update_layout( - title=f"Sine Wave: y = {amplitude_slider.value} × sin({frequency_slider.value}x)", - xaxis_title="x", - yaxis_title="y", - template="plotly_white", - height=400, - showlegend=False, - ) - - fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor="rgba(128,128,128,0.2)") - fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor="rgba(128,128,128,0.2)") - - mo.vstack( - [ - mo.md( - f""" - ### Interactive Sine Wave - - Adjust the sliders above to change the wave properties! - - Current parameters: - - Frequency: {frequency_slider.value} - - Amplitude: {amplitude_slider.value} - """ - ), - mo.ui.plotly(fig), - ] - ) - return fig, x, y - - -@app.cell -def cell_16(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_17(): - """Introduce the DataFrames section.""" - mo.md( - r""" - ## 📋 Working with DataFrames - - Marimo provides excellent support for working with Pandas DataFrames. - """ - ) - - -@app.cell -def cell_18(): - """Create a sample Pandas DataFrame for use in subsequent cells.""" - # Create sample data - data = pd.DataFrame( - { - "Product": ["Widget A", "Widget B", "Widget C", "Widget D", "Widget E"], - "Sales": [250, 180, 420, 350, 290], - "Revenue": [5000, 3600, 8400, 7000, 5800], - "Rating": [4.5, 4.2, 4.8, 4.6, 4.3], - } - ) - return data - - -@app.cell -def cell_19(): - """Render introductory text for the sample sales dataset.""" - mo.md( - r""" - ### Sample Sales Data - - Here's our dataset displayed as an interactive table: - """ - ) - - -@app.cell -def cell_20(data): - """Display the sample dataset as an interactive table.""" - # Display as interactive table - mo.ui.table(data) - - -@app.cell -def cell_21(data): - """Render a Plotly bar chart showing sales by product.""" - # Create a bar chart with Plotly - colours = ["#2FA4A9", "#3FB5BA", "#4FC6CB", "#5FD7DC", "#6FE8ED"] - - fig_bar = go.Figure() - fig_bar.add_trace( - go.Bar( - x=data["Product"], - y=data["Sales"], - marker_color=colours, - text=data["Sales"], - textposition="auto", - ) - ) - - fig_bar.update_layout( - title="Sales by Product", - xaxis_title="Product", - yaxis_title="Sales", - template="plotly_white", - height=500, - showlegend=False, - ) - - mo.ui.plotly(fig_bar) - return colours, fig_bar - - -@app.cell -def cell_22(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_23(): - """Introduce the layout components section.""" - mo.md( - r""" - ## 🎯 Layout Components - - Marimo provides powerful layout primitives to organise your content. - """ - ) - - -@app.cell -def cell_24(): - """Demonstrate a two-column layout with left and right content.""" - # Using columns for side-by-side layout - left_content = mo.md( - r""" - ### Left Column - - This is the left side of a two-column layout. - - - Feature 1 - - Feature 2 - - Feature 3 - """ - ) - - right_content = mo.md( - r""" - ### Right Column - - This is the right side of a two-column layout. - - - Benefit A - - Benefit B - - Benefit C - """ - ) - - mo.hstack([left_content, right_content], justify="space-between") - return left_content, right_content - - -@app.cell -def cell_25(): - """Demonstrate tabs with Introduction, Details, and Summary content.""" - # Using tabs for organised content - tab1 = mo.md( - r""" - ## Tab 1: Introduction - - This is the content of the first tab. Tabs are great for organising - related content without cluttering the interface. - - **Key points:** - - Clean organisation - - Reduced clutter - - Easy navigation - """ - ) - - tab2 = mo.md( - r""" - ## Tab 2: Details - - Here's more detailed information in the second tab. - - You can include any content here: - - Code examples - - Visualisations - - Interactive elements - """ - ) - - tab3 = mo.md( - r""" - ## Tab 3: Summary - - The final tab with summary information. - - Tabs are perfect for: - 1. Step-by-step guides - 2. Different views of data - 3. Organising complex notebooks - """ - ) - - mo.ui.tabs({"Introduction": tab1, "Details": tab2, "Summary": tab3}) - return tab1, tab2, tab3 - - -@app.cell -def cell_26(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_27(): - """Introduce the forms and user input section.""" - mo.md( - r""" - ## 📝 Forms and User Input - - Marimo forms allow you to batch multiple inputs and submit them together. - """ - ) - - -@app.cell -def cell_28(): - """Build and display a multi-input form for collecting user information.""" - # Create a form with multiple inputs - form = mo.ui.dictionary( - { - "name": mo.ui.text(label="Your name:", placeholder="Enter name"), - "age": mo.ui.slider(start=18, stop=100, value=25, label="Your age:"), - "email": mo.ui.text(label="Email:", placeholder="email@example.com"), - "subscribe": mo.ui.checkbox(label="Subscribe to newsletter"), - "interests": mo.ui.multiselect( - options=["Data Science", "Machine Learning", "Web Development", "DevOps"], label="Your interests:" - ), - } - ) - mo.vstack([mo.md("### User Information Form"), form]) - return (form,) - - -@app.cell -def cell_29(form): - """Display current form values reactively as the user edits the form.""" - # Display form values - updates reactively as you type/change values - if form.value and any(form.value.values()): - interests_text = ", ".join(form.value["interests"]) if form.value["interests"] else "None selected" - - mo.md( - f""" - ### Current Form Values ✅ - - The values update automatically as you interact with the form! - - - **Name:** {form.value["name"] or "(not entered)"} - - **Age:** {form.value["age"]} - - **Email:** {form.value["email"] or "(not entered)"} - - **Newsletter:** {"Subscribed ✅" if form.value["subscribe"] else "Not subscribed"} - - **Interests:** {interests_text} - - Notice how the values update reactively as you change them! - """ - ) - else: - mo.md("*The form values will appear here as you interact with them.*") - - -@app.cell -def cell_30(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_31(): - """Introduce the Markdown and LaTeX support section.""" - mo.md( - r""" - ## 🎓 Markdown & LaTeX Support - - Marimo has excellent support for rich text formatting using Markdown and LaTeX. - """ - ) - - -@app.cell -def cell_32(): - """Render rich Markdown with LaTeX equations, code blocks, and formatting examples.""" - mo.md( - r""" - ### Mathematical Equations - - You can write beautiful equations using LaTeX: - - **Pythagorean theorem:** - - $$a^2 + b^2 = c^2$$ - - **Euler's identity:** - - $$e^{i\pi} + 1 = 0$$ - - **Quadratic formula:** - - $$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$ - - **Inline math:** The famous $E = mc^2$ equation by Einstein. - - ### Code Blocks - - You can also include syntax-highlighted code: - - ```python - def fibonacci(n): - if n <= 1: - return n - return fibonacci(n-1) + fibonacci(n-2) - ``` - - ### Rich Formatting - - - **Bold text** - - *Italic text* - - ~~Strikethrough text~~ - - `Inline code` - - [Links](https://marimo.io/) - - > This is a blockquote with important information! - """ - ) - - -@app.cell -def cell_33(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_34(): - """Introduce the Advanced Features section.""" - mo.md( - r""" - ## 🎪 Advanced Features - - Here are some more advanced Marimo features worth exploring. - """ - ) - - -@app.cell -def cell_35(): - """Render an informational callout about Marimo notebooks being plain Python files.""" - # Callout boxes for important information - mo.callout( - mo.md( - r""" - ### 💡 Pro Tip - - Marimo notebooks are **just Python files**! This means: - - Easy version control with Git - - Standard code review workflows - - No hidden JSON metadata - - Compatible with all Python tools - """ - ), - kind="info", - ) - - -@app.cell -def cell_36(): - """Display an accordion with notes on reactivity, performance, and dependencies.""" - # Accordion for collapsible content - mo.accordion( - { - "🔍 Click to learn about Reactive Programming": mo.md( - r""" - Marimo uses **reactive programming** to automatically track dependencies - between cells. When you change a value in one cell, all dependent cells - automatically update! - - This eliminates the common notebook problem of running cells out of order. - """ - ), - "🚀 Click to learn about Performance": mo.md( - r""" - Marimo only re-runs cells that are affected by changes, making it - efficient even for large notebooks. This intelligent execution means - you get fast feedback without wasting computation. - """ - ), - "📦 Click to learn about Dependencies": mo.md( - r""" - You can specify dependencies right in the notebook using inline metadata. - This makes notebooks self-contained and reproducible, as seen in the - header of this notebook! - """ - ), - } - ) - - -@app.cell -def cell_37(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_38(): - """Introduce the artefacts section.""" - mo.md( - r""" - ## 📂 Notebook Artefacts - - When running via `rhiza_marimo`, each notebook gets a dedicated output folder - provided via the `NOTEBOOK_OUTPUT_FOLDER` environment variable. You can use this - folder to persist intermediate results, plots, CSVs, and any other artefacts so - they are available after the notebook run completes. - - The cell below demonstrates writing a sample DataFrame to that folder as a CSV. - """ - ) - - -@app.cell -def cell_39(data): - """Write the sample DataFrame to the artefact folder if NOTEBOOK_OUTPUT_FOLDER is set.""" - import os - from pathlib import Path - - output_folder = os.environ.get("NOTEBOOK_OUTPUT_FOLDER") - if output_folder: - artefact_path = Path(output_folder) / "sales_data.csv" - data.to_csv(artefact_path, index=False) - _msg = mo.md(f"✅ DataFrame saved to `{artefact_path}`") - else: - artefact_path = None - _msg = mo.md( - "ℹ️ `NOTEBOOK_OUTPUT_FOLDER` is not set — artefact saving is skipped " - "(this variable is set automatically by `rhiza_marimo`)." - ) - return artefact_path, _msg - - -@app.cell -def cell_40(): - """Render a horizontal rule to visually separate sections.""" - mo.md(r"""---""") - - -@app.cell -def cell_41(): - """Render the conclusion section of the Marimo showcase notebook.""" - mo.md( - r""" - ## 🎉 Conclusion - - This notebook has demonstrated many of Marimo's most useful features: - - ✅ **Interactive UI elements** - Sliders, dropdowns, text inputs, and more - ✅ **Reactive programming** - Automatic cell updates when dependencies change - ✅ **Data visualisation** - Seamless integration with Plotly, Matplotlib, etc. - ✅ **Layout components** - Columns, tabs, accordions for organising content - ✅ **Forms** - Batched input collection with submission - ✅ **Rich formatting** - Markdown and LaTeX support - ✅ **Pure Python** - Notebooks are version-control friendly `.py` files - - ### Next Steps - - To learn more about Marimo: - - Visit the [official documentation](https://docs.marimo.io/) - - Explore the [example gallery](https://marimo.io/examples) - - Join the [community Discord](https://discord.gg/JE7nhX6mD8) - - **Happy exploring! 🚀** - """ - ) - - -if __name__ == "__main__": - app.run() diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md deleted file mode 100644 index 76d971f..0000000 --- a/docs/ARCHITECTURE.md +++ /dev/null @@ -1,515 +0,0 @@ -# Rhiza Architecture - -Visual diagrams of Rhiza's architecture and component interactions. - -## System Overview - -```mermaid -flowchart TB - subgraph User["User Interface"] - make[make commands] - local[local.mk] - end - - subgraph Core[".rhiza/ Core"] - rhizamk[rhiza.mk
Core Logic] - maked[make.d/*.mk
Extensions] - reqs[requirements/
Dependencies] - template[template-bundles.yml
Bundle Config] - end - - subgraph Config["Configuration"] - pyproject[pyproject.toml] - ruff[ruff.toml] - precommit[.pre-commit-config.yaml] - editorconfig[.editorconfig] - end - - subgraph CI["GitHub Actions"] - ci[CI Workflow] - release[Release Workflow] - security[Security Workflow] - sync[Sync Workflow] - end - - make --> rhizamk - local -.-> rhizamk - rhizamk --> maked - maked --> reqs - maked --> pyproject - ci --> make - release --> make - security --> make - sync --> template -``` - -## Makefile Hierarchy - -```mermaid -flowchart TD - subgraph Entry["Entry Point"] - Makefile[Makefile
9 lines] - end - - subgraph Core["Core Logic"] - rhizamk[.rhiza/rhiza.mk
268 lines] - end - - subgraph Extensions["Auto-loaded Extensions"] - config[00-19: Configuration] - tasks[20-79: Task Definitions] - hooks[80-99: Hook Implementations] - end - - subgraph Local["Local Customization"] - localmk[local.mk
Not synced] - end - - Makefile -->|includes| rhizamk - rhizamk -->|includes| config - rhizamk -->|includes| tasks - rhizamk -->|includes| hooks - rhizamk -.->|optional| localmk -``` - -## Hook System - -```mermaid -flowchart LR - subgraph Hooks["Double-Colon Targets"] - pre_install[pre-install::] - post_install[post-install::] - pre_sync[pre-sync::] - post_sync[post-sync::] - pre_release[pre-release::] - post_release[post-release::] - pre_bump[pre-bump::] - post_bump[post-bump::] - end - - subgraph Targets["Main Targets"] - install[make install] - sync[make sync] - release[make release] - publish[make publish] - bump[make bump] - end - - pre_install --> install --> post_install - pre_sync --> sync --> post_sync - pre_release --> release --> post_release - pre_bump --> bump --> post_bump -``` - -## Release Pipeline - -```mermaid -flowchart TD - tag[Push Tag v*] --> validate[Validate Tag] - validate --> build[Build Package] - build --> draft[Draft GitHub Release] - draft --> pypi[Publish to PyPI] - draft --> devcontainer[Publish Devcontainer] - pypi --> finalize[Finalize Release] - devcontainer --> finalize - - subgraph Conditions - pypi_cond{Has dist/ &
not Private?} - dev_cond{PUBLISH_DEVCONTAINER
= true?} - end - - draft --> pypi_cond - pypi_cond -->|yes| pypi - pypi_cond -->|no| finalize - draft --> dev_cond - dev_cond -->|yes| devcontainer - dev_cond -->|no| finalize -``` - -## Template Sync Flow - -```mermaid -flowchart LR - upstream[Upstream Rhiza
jebel-quant/rhiza] -->|template.yml| sync[make sync] - sync -->|updates| downstream[Downstream Project] - - subgraph Synced["Synced Files"] - workflows[.github/workflows/] - rhiza[.rhiza/] - configs[Config Files] - end - - subgraph Preserved["Preserved"] - localmk[local.mk] - src[src/] - tests[tests/] - end - - sync --> Synced - downstream --> Preserved -``` - -## Directory Structure - -```mermaid -flowchart TD - root[Project Root] - - root --> rhiza[.rhiza/] - root --> github[.github/] - root --> src[src/] - root --> tests[tests/] - root --> docs[docs/] - root --> book[book/] - - rhiza --> rhizamk[rhiza.mk] - rhiza --> maked[make.d/] - rhiza --> reqs[requirements/] - rhiza --> rtests[tests/] - rhiza --> rdocs[docs/] - rhiza --> templates[templates/] - rhiza --> assets[assets/] - - github --> workflows[workflows/] - workflows --> ci[rhiza_ci.yml] - workflows --> release[rhiza_release.yml] - workflows --> security[rhiza_security.yml] - workflows --> more[... 11 more] - - maked --> agentic[agentic.mk] - maked --> book[book.mk] - maked --> bootstrap[bootstrap.mk] - maked --> docker[docker.mk] - maked --> docs_mk[docs.mk] - maked --> github_mk[github.mk] - maked --> marimo[marimo.mk] - maked --> test[test.mk] - maked --> more_mk[... 6 more] -``` - -## .rhiza/ Directory Structure and Dependencies - -```mermaid -flowchart TB - subgraph rhiza[".rhiza/ Directory"] - direction TB - - subgraph core["Core Files"] - rhizamk[rhiza.mk
Core Logic - 153 lines] - cfg[.cfg.toml
Configuration] - env[.env
Environment] - version[.rhiza-version
Version] - bundles[template-bundles.yml
Bundle Definitions] - end - - subgraph maked["make.d/ (14 files, ~41KB)"] - direction LR - agentic[agentic.mk
AI Agents] - bootstrap[bootstrap.mk
Installation] - test[test.mk
Testing] - book_mk[book.mk
Documentation] - docker_mk[docker.mk
Containers] - quality[quality.mk
Code Quality] - releasing[releasing.mk
Releases] - more[...] - end - - subgraph requirements["requirements/ (4 files)"] - direction LR - tests_txt[tests.txt
pytest, coverage] - marimo_txt[marimo.txt
notebooks] - docs_txt[docs.txt
pdoc] - tools_txt[tools.txt
pre-commit] - end - - subgraph tests_dir["tests/ (23 files)"] - direction LR - api[api/
Makefile Tests] - integration[integration/
E2E Tests] - structure[structure/
Layout Tests] - sync[sync/
Sync Tests] - deps[deps/
Dependency Tests] - end - - subgraph other["Other Directories"] - direction LR - docs_dir[docs/
7 MD files] - templates_dir[templates/
minibook] - assets_dir[assets/
Logo] - end - end - - subgraph project["Project Files"] - Makefile[Makefile
Entry Point] - pyproject[pyproject.toml
Dependencies] - ruff_toml[ruff.toml
Linting] - pytest_ini[pytest.ini
Test Config] - python_version[.python-version
Python 3.13] - end - - Makefile -->|includes| rhizamk - rhizamk -->|auto-loads| maked - maked -->|reads| pyproject - maked -->|reads| python_version - test -->|uses| pytest_ini - test -->|installs| tests_txt - book_mk -->|installs| docs_txt - book_mk -->|uses| marimo_txt - quality -->|uses| ruff_toml - bootstrap -->|installs| tools_txt - tests_dir -->|validates| core - tests_dir -->|validates| maked -``` - -## CI/CD Workflow Triggers - -```mermaid -flowchart TD - subgraph Triggers - push[Push] - pr[Pull Request] - schedule[Schedule] - manual[Manual] - tag[Tag v*] - end - - subgraph Workflows - ci[CI] - security[Security] - codeql[CodeQL] - release[Release] - deptry[Deptry] - precommit[Pre-commit] - end - - push --> ci - push --> security - push --> codeql - pr --> ci - pr --> deptry - pr --> precommit - schedule --> security - manual --> ci - tag --> release -``` - -## Python Execution Model - -```mermaid -flowchart LR - subgraph Commands - make[make test] - direct[Direct Python] - end - - subgraph UV["uv Layer"] - uv_run[uv run] - uvx[uvx] - end - - subgraph Tools - pytest[pytest] - ruff[ruff] - hatch[hatch] - end - - make --> uv_run - uv_run --> pytest - uv_run --> ruff - uvx --> hatch - - direct -.->|Never| pytest - - style direct stroke-dasharray: 5 5 -``` - -## Naming Conventions and Organization Patterns - -### Makefile Naming (`.rhiza/make.d/`) - -Makefiles follow these conventions: - -1. **Lowercase with hyphens**: All makefile names use lowercase letters with hyphens for word separation - - ✅ `bootstrap.mk`, `custom-task.mk`, `github.mk` - - ❌ `Bootstrap.mk`, `customTask.mk`, `GitHub.mk` - -2. **Descriptive domain names**: Each file represents a logical domain or feature area - - `agentic.mk` - AI agent integrations - - `bootstrap.mk` - Installation and setup - - `docker.mk` - Docker containerization - - `marimo.mk` - Marimo notebooks - - `test.mk` - Testing infrastructure - -3. **Example vs. Production files**: - - Files prefixed with `custom-` are **examples** for user customization - - `custom-env.mk` - Example environment variable customizations - - `custom-task.mk` - Example custom task definitions - - Users should create their own files or modify the root `Makefile` for customizations - -### Target Naming - -Make targets follow consistent patterns: - -1. **Lowercase with hyphens**: Target names use lowercase with hyphens - - ✅ `install-uv`, `docker-build`, `view-prs` - - ❌ `installUv`, `docker_build`, `viewPRs` - -2. **Verb-noun pattern**: Action-oriented targets use verb-noun format - - `install-uv` - Install the uv tool - - `docker-build` - Build Docker image - - `view-prs` - View pull requests - -3. **Namespace prefixes**: Related targets share a common prefix - - Docker: `docker-build`, `docker-run`, `docker-clean` - - LFS: `lfs-install`, `lfs-pull`, `lfs-track`, `lfs-status` - - GitHub: `gh-install`, `view-prs`, `view-issues`, `failed-workflows` - -### Section Headers (`##@`) - -Section headers in makefiles group related targets in help output: - -1. **Title Case**: Section names use Title Case - - `##@ Bootstrap` - - `##@ GitHub Helpers` - - `##@ Marimo Notebooks` - -2. **Descriptive grouping**: Sections group logically related commands - - **Bootstrap** - Installation and setup - - **Development and Testing** - Core dev workflow - - **Documentation** - Doc generation - - **GitHub Helpers** - GitHub CLI integrations - - **Quality and Formatting** - Code quality tools - -### Hook Naming - -Hook targets use double-colon syntax and follow a `pre-`/`post-` pattern: - -```makefile -pre-install:: # Runs before make install -post-install:: # Runs after make install -pre-sync:: # Runs before make sync -post-sync:: # Runs after make sync -pre-release:: # Runs before make release -post-release:: # Runs after make release -``` - -**Key principles**: -- Always use double-colon (`::`) to allow multiple definitions -- Hooks are defined as phony targets -- Empty default implementations use `; @:` syntax - -### File Organization Patterns - -1. **Directory naming**: - - Lowercase with hyphens: `make.d/`, `template-bundles.yml` - - Plural for collections: `requirements/`, `templates/`, `tests/` - -2. **Test organization** (`.rhiza/tests/`): - - Tests grouped by **purpose**, not by feature - - `api/` - Makefile API tests - - `structure/` - Project structure validation - - `integration/` - End-to-end workflows - - `sync/` - Template synchronization - - `deps/` - Dependency validation - -3. **Requirements organization** (`.rhiza/requirements/`): - - Named by **purpose**: `tests.txt`, `docs.txt`, `marimo.txt`, `tools.txt` - - Not by library: ❌ `pytest.txt`, `pdoc.txt` - -### Template Bundle Naming - -Template bundles in `template-bundles.yml` follow these conventions: - -1. **Lowercase singular**: `core`, `github`, `tests`, `marimo`, `book` -2. **Domain-focused**: Named after the feature domain, not implementation - - ✅ `marimo` (notebooks) - - ✅ `book` (documentation) - - ❌ `notebooks`, `documentation-generation` - -3. **Bundle metadata**: - - `description` - Clear, concise explanation - - `standalone` - Whether bundle can be used independently - - `requires` - Hard dependencies on other bundles - - `recommends` - Soft dependencies that enhance functionality - -### Variable Naming - -Makefile variables follow these patterns: - -1. **SCREAMING_SNAKE_CASE**: All uppercase with underscores - - `INSTALL_DIR`, `UV_BIN`, `PYTHON_VERSION`, `VENV` - -2. **Suffix patterns**: - - `_BIN` - Executable paths: `UV_BIN`, `UVX_BIN`, `COPILOT_BIN` - - `_DIR` - Directory paths: `INSTALL_DIR`, `DOCKER_FOLDER` - - `_VERSION` - Version strings: `PYTHON_VERSION`, `RHIZA_VERSION` - -3. **Namespace prefixes**: Related variables share prefixes - - UV tooling: `UV_BIN`, `UVX_BIN`, `UV_LINK_MODE` - - Color codes: `BLUE`, `GREEN`, `RED`, `YELLOW`, `RESET`, `BOLD` - -### Documentation Naming - -Documentation files use SCREAMING_SNAKE_CASE: - -- `README.md` - Directory/project overview -- `ARCHITECTURE.md` - Architecture diagrams -- `CUSTOMIZATION.md` - Customization guide -- `QUICK_REFERENCE.md` - Command reference -- `SECURITY.md` - Security policy - -### Workflow Naming (`.github/workflows/`) - -GitHub Actions workflows use the pattern `rhiza_.yml`: - -- `rhiza_ci.yml` - Continuous integration -- `rhiza_release.yml` - Release automation -- `rhiza_security.yml` - Security scanning -- `rhiza_sync.yml` - Template synchronization -- `rhiza_deptry.yml` - Dependency checking - -**Rationale**: The `rhiza_` prefix clearly identifies template-managed workflows, distinguishing them from user-defined workflows. - -## Key Design Principles - -### 1. Single Source of Truth - -- **Python version**: `.python-version` file (not hardcoded) -- **Rhiza version**: `.rhiza/.rhiza-version` file -- **Dependencies**: `pyproject.toml` (not duplicated in makefiles) -- **Bundle definitions**: `template-bundles.yml` (not scattered) - -### 2. Auto-Loading Pattern - -Makefiles in `.rhiza/make.d/` are automatically included: - -```makefile -# In .rhiza/rhiza.mk (last line) --include .rhiza/make.d/*.mk -``` - -This allows: -- Adding new features by dropping in a `.mk` file -- No manual maintenance of include lists -- Clean separation of concerns - -### 3. Extension Points - -Users can extend Rhiza without modifying template files: - -1. **Root Makefile**: Add custom targets before `include .rhiza/rhiza.mk` -2. **local.mk**: Local shortcuts (not committed, auto-loaded) -3. **Hooks**: Use double-colon targets (`post-install::`, etc.) - -### 4. Fail-Safe Defaults - -- Missing tools are detected and installation offered -- Missing directories are created automatically -- Graceful degradation when optional features are unavailable - -### 5. Documentation as Code - -- Every target has a `##` help comment -- Section headers (`##@`) organize help output -- README files in every major directory -- Comprehensive INDEX.md for quick reference diff --git a/docs/BOOK.md b/docs/BOOK.md deleted file mode 100644 index 81273af..0000000 --- a/docs/BOOK.md +++ /dev/null @@ -1,67 +0,0 @@ -# Project Book and Documentation - -This directory contains the source and templates for generating the Rhiza companion book and API documentation. - -## Structure - -- `marimo/`: Interactive [Marimo](https://marimo.io/) notebooks that are included in the book. -- `minibook-templates/`: Jinja2 templates for the minibook generation. -- `pdoc-templates/`: Custom templates for [pdoc](https://pdoc.dev/) API documentation. -- `book.mk`: Specialised Makefile for building the book and documentation. - -## Building the Book - -You can build the complete documentation book using the main project Makefile: - -```bash -make book -``` - -This process involves: -1. Exporting Marimo notebooks to HTML. -2. Generating API documentation from the source code. -3. Combining them into a cohesive "book" structure. - -## Documentation Customisation - -You can customise the look and feel of your documentation by providing your own templates. - -### API Documentation (pdoc) - -The `make docs` command checks for a directory at `book/pdoc-templates`. If found, it uses the templates within that directory to generate the API documentation. - -To customise the API docs: -1. Create the directory: `mkdir -p book/pdoc-templates` -2. Add your Jinja2 templates (e.g., `module.html.jinja2`) to this directory. - -See the [pdoc documentation](https://pdoc.dev/docs/pdoc.html#templates) for more details on templating. - -### Project Logo - -The documentation generation supports embedding a project logo in the sidebar. - -**Default Behavior:** -By default, the build looks for `assets/rhiza-logo.svg`. - -**Customization:** -You can change the logo by setting the `LOGO_FILE` variable in your project's `Makefile` or `local.mk`. - -```makefile -# Example: Use a custom PNG logo -LOGO_FILE := assets/my-company-logo.png -``` - -To disable the logo entirely, set the variable to an empty string: - -```makefile -# Example: Disable logo -LOGO_FILE := -``` - -### Companion Book (minibook) - -The `make book` command checks for a template at `book/minibook-templates/custom.html.jinja2`. If found, it uses this template for the minibook generation. - -To customise the book: -1. Create the directory: `mkdir -p book/minibook-templates` -2. Create your custom template at `book/minibook-templates/custom.html.jinja2`. diff --git a/docs/CUSTOMIZATION.md b/docs/CUSTOMIZATION.md deleted file mode 100644 index a446e29..0000000 --- a/docs/CUSTOMIZATION.md +++ /dev/null @@ -1,166 +0,0 @@ -# Customization Guide - -This guide covers advanced customization options for Rhiza-based projects. - -## 🛠️ Makefile Hooks & Extensions - -Rhiza uses a modular Makefile system with extension points (hooks) that let you customize workflows without modifying core files. - -**Important**: All customizations should be made in your root `Makefile`, not in `.rhiza/`. The `.rhiza/` directory is template-managed and will be overwritten during sync operations. - -### Available Hooks - -You can hook into standard workflows using double-colon syntax (`::`) in your root `Makefile`: - -- `pre-install / post-install` - Runs around `make install` -- `pre-sync / post-sync` - Runs around repository synchronization -- `pre-validate / post-validate` - Runs around validation checks -- `pre-release / post-release` - Runs around release process -- `pre-bump / post-bump` - Runs around version bumping - -### Example: Installing System Dependencies - -Add to your root `Makefile` (before the `include .rhiza/rhiza.mk` line): - -```makefile -pre-install:: - @if ! command -v dot >/dev/null 2>&1; then \ - echo "Installing graphviz..."; \ - sudo apt-get update && sudo apt-get install -y graphviz; \ - fi -``` - -This hook runs automatically before `make install`, ensuring graphviz is available. - -### Example: Post-Release Tasks - -Add to your root `Makefile`: - -```makefile -post-release:: - @echo "Running post-release tasks..." - @./scripts/notify-team.sh - @./scripts/update-changelog.sh -``` - -This runs automatically after `make release` completes. - -### Example: Custom Build Steps - -Add to your root `Makefile`: - -```makefile -post-install:: - @echo "Installing specialized dependencies..." - @uv pip install some-private-lib - -##@ Custom Tasks -train-model: ## Train the ML model - @uv run python scripts/train.py -``` - -## 🔒 CodeQL Configuration - -The CodeQL workflow (`.github/workflows/rhiza_codeql.yml`) performs security analysis on your code. However, **CodeQL requires GitHub Advanced Security**, which is: - -- ✅ **Available for free** on public repositories -- ⚠️ **Requires GitHub Enterprise license** for private repositories - -### Automatic Behavior - -By default, the CodeQL workflow: -- **Runs automatically** on public repositories -- **Skips automatically** on private repositories (unless you have Advanced Security) - -### Controlling CodeQL - -You can override the default behavior using a repository variable: - -1. Go to your repository → **Settings** → **Secrets and variables** → **Actions** → **Variables** tab -2. Create a new repository variable named `CODEQL_ENABLED` -3. Set the value: - - `true` - Force CodeQL to run (use if you have Advanced Security on a private repo) - - `false` - Disable CodeQL entirely (e.g., if it's causing issues) - -### For Private Repositories with Advanced Security - -If you have a GitHub Enterprise license with Advanced Security enabled: - -```bash -# Enable CodeQL for your private repository -gh variable set CODEQL_ENABLED --body "true" -``` - -### For Users Without Advanced Security - -No action needed! The workflow will automatically skip for private repositories. If you want to completely disable it: - -```bash -# Disable CodeQL workflow -gh variable set CODEQL_ENABLED --body "false" -``` - -Or delete the workflow file: - -```bash -# Remove CodeQL workflow -git rm .github/workflows/rhiza_codeql.yml -git commit -m "Remove CodeQL workflow" -``` - -## ⚙️ Configuration Variables - -You can configure certain aspects of the Makefile by overriding variables. These can be set in your main `Makefile` (before the `include` line), a `local.mk` file (for local developer overrides), or passed as environment variables / command-line arguments. - -### Global Configuration - -Add these to your root `Makefile` (before `include .rhiza/rhiza.mk`) or `local.mk`: - -```makefile -# Override default Python version -PYTHON_VERSION = 3.12 - -# Override test coverage threshold (default: 90) -COVERAGE_FAIL_UNDER = 80 - -# Include the Rhiza API (template-managed) -include .rhiza/rhiza.mk -``` - -### On-Demand Configuration - -You can also pass variables directly to `make` for one-off commands: - -```bash -# Run tests requiring only 80% coverage -make test COVERAGE_FAIL_UNDER=80 -``` - -## 🎨 Documentation Customization - -You can customize the API documentation and companion book. - -### Project Logo - -The API documentation includes a logo in the sidebar. You can override the default logo (`assets/rhiza-logo.svg`) by setting the `LOGO_FILE` variable in your Makefile or `local.mk`: - -```makefile -LOGO_FILE := assets/my-custom-logo.png -``` - -### Custom Templates - -You can customize the look and feel of the API documentation by providing your own Jinja2 templates. -Place your custom templates in the `book/pdoc-templates` directory. - -For example, to override the main module template, create `book/pdoc-templates/module.html.jinja2`. - -See the [pdoc documentation on templates](https://pdoc.dev/docs/pdoc.html#edit-pdocs-html-template) for full details on how to override specific parts of the documentation. - -For more details on customizing the documentation, see [book/README.md](../book/README.md). - -## 📖 Complete Documentation - -For detailed information about extending and customizing the Makefile system, see [.rhiza/make.d/README.md](../.rhiza/make.d/README.md). - -For a tutorial walkthrough of these extension points — including the rule about template-managed files, the exclude mechanism, and forking the template for your organisation — see [rhiza-education Lesson 10: Customising Safely](https://github.com/Jebel-Quant/rhiza-education/blob/main/lessons/10-customizing-safely.md). diff --git a/docs/DEMO.md b/docs/DEMO.md deleted file mode 100644 index 4682d4d..0000000 --- a/docs/DEMO.md +++ /dev/null @@ -1,189 +0,0 @@ -# Rhiza Demo - -## Quick Demo (asciinema) - -[![asciicast](https://asciinema.org/a/placeholder.svg)](https://asciinema.org/a/placeholder) - -> **Note**: Replace the placeholder link above with your actual asciinema recording. - -## Recording Instructions - -### Prerequisites - -```bash -# Install asciinema -brew install asciinema # macOS -# or: pip install asciinema -``` - -### Record the Demo - -```bash -# Start recording -asciinema rec rhiza-demo.cast - -# Run the demo script (see below) -# Press Ctrl+D or type 'exit' when done - -# Upload to asciinema.org -asciinema upload rhiza-demo.cast -``` - -### Demo Script - -Run these commands during recording: - -```bash -# 1. Show available commands -make help - -# 2. Install dependencies (fast with uv) -make install - -# 3. Run tests -make test - -# 4. Format and lint -make fmt - -# 5. Check dependencies -make deptry - -# 6. Show version bump options -make bump BUMP=patch --dry-run - -# 7. Validate project structure -make validate -``` - -### Automated Demo Script - -Save as `demo.sh` and run with `asciinema rec -c ./demo.sh`: - -```bash -#!/bin/bash -# Rhiza Demo Script -# Usage: asciinema rec -c ./demo.sh rhiza-demo.cast - -set -e - -# Simulate typing with delays -type_cmd() { - echo -e "\n\033[1;32m$\033[0m $1" - sleep 0.5 - eval "$1" - sleep 1 -} - -clear -echo "═══════════════════════════════════════" -echo " Rhiza - Living Templates " -echo "═══════════════════════════════════════" -sleep 2 - -type_cmd "make help | head -40" -sleep 2 - -type_cmd "make install" -sleep 2 - -type_cmd "make test" -sleep 2 - -type_cmd "make fmt" -sleep 2 - -type_cmd "make deptry" -sleep 2 - -echo -e "\n\033[1;34mDemo complete!\033[0m" -sleep 2 -``` - -## Alternative: GIF Recording - -### Using terminalizer - -```bash -# Install -npm install -g terminalizer - -# Record -terminalizer record rhiza-demo - -# Generate GIF -terminalizer render rhiza-demo -o rhiza-demo.gif -``` - -### Using vhs (by Charmbracelet) - -Create `demo.tape`: - -```tape -# Rhiza Demo -Output rhiza-demo.gif - -Set FontSize 14 -Set Width 1200 -Set Height 600 -Set Theme "Dracula" - -Type "make help | head -30" -Enter -Sleep 3s - -Type "make install" -Enter -Sleep 5s - -Type "make test" -Enter -Sleep 5s - -Type "make fmt" -Enter -Sleep 3s - -Type "echo 'Done!'" -Enter -Sleep 2s -``` - -Run with: - -```bash -brew install vhs # or: go install github.com/charmbracelet/vhs@latest -vhs demo.tape -``` - -## Embedding in README - -### Asciinema (recommended) - -```markdown -[![asciicast](https://asciinema.org/a/YOUR_ID.svg)](https://asciinema.org/a/YOUR_ID) -``` - -### GIF - -```markdown -![Rhiza Demo](docs/rhiza-demo.gif) -``` - -### Video (GitHub supports mp4) - -```markdown -https://user-images.githubusercontent.com/YOUR_ID/VIDEO_ID.mp4 -``` - -## Suggested Demo Flow - -1. **Introduction** (5s) - Show project structure with `ls -la` -2. **Help** (5s) - `make help` to show available commands -3. **Install** (10s) - `make install` showing fast uv setup -4. **Test** (10s) - `make test` with coverage output -5. **Format** (5s) - `make fmt` for linting -6. **Quality** (5s) - `make deptry` for dependency check -7. **Outro** (3s) - Summary message - -Total: ~45 seconds diff --git a/docs/GLOSSARY.md b/docs/GLOSSARY.md deleted file mode 100644 index 5dce0bc..0000000 --- a/docs/GLOSSARY.md +++ /dev/null @@ -1,174 +0,0 @@ -# Rhiza Glossary - -A comprehensive glossary of terms used in the Rhiza template system. - -## Core Concepts - -### rhiza (template repository) -The GitHub repository (`jebel-quant/rhiza`) that contains the curated set of configuration files, Makefile modules, CI/CD workflows, and other tooling files that downstream projects sync from. This is the *content* — the files you receive. See also: [rhiza-cli](#rhiza-cli). - -### rhiza-cli -A standalone Python package (published on PyPI as `rhiza-cli`) that provides the `rhiza` command-line interface. It is the *engine* that reads `.rhiza/template.yml` and performs operations such as `init`, `sync`, `bump`, and `release`. Invoked via `uvx rhiza ...` without requiring a permanent installation. Versioned independently from the template repository. See also: [rhiza (template repository)](#rhiza-template-repository). - -### Living Templates -A template approach where configuration files remain synchronized with an upstream source over time, as opposed to traditional "one-shot" template generators (like cookiecutter or copier) that generate files once and then disconnect from the source. - -### Template Sync -The process of pulling updates from the upstream Rhiza repository into a downstream project. Executed via `make sync`. Allows projects to receive ongoing improvements without manual copying. - -### Downstream Project -A project that has adopted Rhiza templates. It receives updates from the upstream Rhiza repository through template sync. - -### Upstream Repository -The source Rhiza repository (`jebel-quant/rhiza`) that contains the canonical template configurations. Changes here propagate to downstream projects via sync. - -## Directory Structure - -### `.rhiza/` -The core directory containing Rhiza's template system files. This directory is synced from upstream and should generally not be modified directly. - -### `.rhiza/rhiza.mk` -The main Makefile containing core Rhiza functionality. Included by the project's root `Makefile`. Contains 268+ lines of make targets and logic. - -### `.rhiza/make.d/` -Directory for modular Makefile extensions. Files are auto-loaded in numeric order: -- `00-19`: Configuration files -- `20-79`: Task definitions -- `80-99`: Hook implementations - -### `.rhiza/utils/` -Python utility scripts for Rhiza operations. - -### `.rhiza/template.yml` -Configuration file defining which files to sync from upstream, include/exclude patterns, and sync behavior. - -### `local.mk` -Optional file for project-specific Makefile extensions. Not synced from upstream, allowing local customization without conflicts. - -## Makefile System - -### Double-Colon Targets (`::`) -Make targets defined with `::` instead of `:`. These are "hook" targets that can be extended by downstream projects without overriding the original implementation. - -### Hook Targets -Extension points in the Makefile system. Available hooks: -- `pre-install::` / `post-install::` - Before/after dependency installation -- `pre-sync::` / `post-sync::` - Before/after template sync -- `pre-validate::` / `post-validate::` - Before/after project validation -- `pre-release::` / `post-release::` - Before/after release creation -- `pre-bump::` / `post-bump::` - Before/after version bump - -### Make Target -A named command in the Makefile (e.g., `make test`, `make fmt`). Rhiza provides 40+ targets out of the box. - -## Version Management - -### Version Bump -Incrementing the version number in `pyproject.toml`. Types: -- `major`: Breaking changes (1.0.0 → 2.0.0) -- `minor`: New features (1.0.0 → 1.1.0) -- `patch`: Bug fixes (1.0.0 → 1.0.1) - -### Release Tag -A git tag prefixed with `v` (e.g., `v1.2.3`) that triggers the release workflow. - -### Version Matrix -A JSON array of Python versions to test against, generated from `pyproject.toml`'s `requires-python` field. Used in CI for matrix testing. - -## CI/CD - -### OIDC Publishing -OpenID Connect-based authentication for PyPI publishing. Uses GitHub's identity provider instead of stored API tokens. More secure than traditional token-based auth. - -### Trusted Publisher -A PyPI configuration that allows a specific GitHub repository/workflow to publish packages without API tokens, using OIDC authentication. - -### Matrix Testing -Running CI tests across multiple Python versions simultaneously. Rhiza supports Python 3.11, 3.12, 3.13, and 3.14. - -### SLSA Provenance -Supply-chain Levels for Software Artifacts. Cryptographic attestations proving that build artifacts were produced by a specific CI workflow. Enables supply chain verification. - -### SBOM (Software Bill of Materials) -A formal record of components used to build software. Generated in SPDX or CycloneDX formats for supply chain transparency. - -## Tools - -### uv -A fast Python package installer and resolver from Astral. Rhiza uses `uv` for all Python operations: -- `uv sync` - Install dependencies -- `uv run` - Execute Python code -- `uvx` - Run external tools - -### Ruff -A fast Python linter and formatter from Astral. Replaces flake8, isort, black, and many other tools. Configured in `ruff.toml`. - -### Hatch -A Python build backend used to create distribution packages (wheels and sdists). Invoked via `uv build`. - -### Deptry -A tool that checks for unused and missing dependencies in Python projects. Integrated in CI via `make deptry`. - -### Bandit -A security linter for Python code. Finds common security issues. Integrated in pre-commit and CI. - -### CodeQL -GitHub's semantic code analysis engine. Scans for security vulnerabilities in Python code and GitHub Actions workflows. - -### Marimo -A reactive Python notebook format. Rhiza includes support for marimo notebooks in the `book/` directory. - -## Configuration Files - -### `pyproject.toml` -The central Python project configuration file (PEP 518/621). Contains project metadata, dependencies, and tool configurations. - -### `uv.lock` -Lock file containing exact versions of all dependencies. Ensures reproducible builds across environments. - -### `.python-version` -Single-line file specifying the default Python version for the project. Used by `uv` and other tools. - -### `ruff.toml` -Configuration for the Ruff linter/formatter. Defines enabled rules, line length, and per-file exceptions. - -### `pytest.ini` -Configuration for pytest test runner. Sets logging levels and output options. - -### `.pre-commit-config.yaml` -Configuration for pre-commit hooks. Defines checks that run before each git commit. - -### `.editorconfig` -Cross-editor configuration for consistent coding style (indentation, line endings, etc.). - -### `renovate.json` -Configuration for Renovate, an automated dependency update bot. - -## Workflows - -### CI Workflow -Continuous Integration workflow that runs tests on every push and pull request. - -### Release Workflow -Multi-phase workflow triggered by version tags. Builds packages, creates GitHub releases, publishes to PyPI, and optionally publishes devcontainer images. - -### Sync Workflow -Workflow that synchronizes template files from upstream Rhiza repository. - -### Security Workflow -Workflow running security scans (pip-audit, bandit) on the codebase. - -## Commands Reference - -| Command | Description | -|---------|-------------| -| `make install` | Install dependencies and set up environment | -| `make test` | Run pytest with coverage | -| `make fmt` | Format and lint code with ruff | -| `make sync` | Sync templates from upstream | -| `make bump` | Bump version number | -| `make release` | Create and push release tag | -| `make publish` | Bump version, create tag and push in one step | -| `make release-status` | Show release workflow status and latest release | -| `make deptry` | Check for unused/missing dependencies | -| `make help` | Show all available targets | diff --git a/docs/QUICK_REFERENCE.md b/docs/QUICK_REFERENCE.md deleted file mode 100644 index bf49247..0000000 --- a/docs/QUICK_REFERENCE.md +++ /dev/null @@ -1,156 +0,0 @@ -# Rhiza Quick Reference Card - -A concise reference for common Rhiza operations. - -## Essential Commands - -| Command | Description | -|---------|-------------| -| `make install` | Install dependencies and set up environment | -| `make test` | Run pytest with coverage | -| `make fmt` | Format and lint code with ruff | -| `make help` | Show all available targets | - -## Version & Release - -| Command | Description | -|---------|-------------| -| `make publish` | Bump version, create tag and push in one step | -| `make bump` | Bump version (prompts for major/minor/patch) | -| `make bump BUMP=patch` | Bump patch version directly | -| `make bump BUMP=minor` | Bump minor version directly | -| `make bump BUMP=major` | Bump major version directly | -| `make release` | Create and push release tag | -| `make release-status` | Show release workflow status and latest release | - -## Code Quality - -| Command | Description | -|---------|-------------| -| `make fmt` | Format + lint with auto-fix | -| `make deptry` | Check for unused/missing dependencies | -| `make pre-commit` | Run all pre-commit hooks | - -## Template Sync - -| Command | Description | -|---------|-------------| -| `make sync` | Sync templates from upstream Rhiza | - -## GitHub Agentic Workflows (gh-aw) - -| Command | Description | -|---------|-------------| -| `make install-gh-aw` | Install the gh-aw CLI extension | -| `make gh-aw-init` | Initialize repository for gh-aw | -| `make gh-aw-setup` | Guided setup for secrets and engine configuration | -| `make gh-aw-compile` | Compile workflow `.md` files into `.lock.yml` GitHub Actions | -| `make gh-aw-validate` | Validate that `.lock.yml` files are up-to-date | -| `make gh-aw-status` | Show status of all agentic workflows | -| `make gh-aw-run WORKFLOW=` | Run a specific agentic workflow locally | -| `make gh-aw-logs` | Show logs for recent agentic workflow runs | - -## Running Tests - -```bash -# All tests -make test - -# Specific file -uv run pytest tests/path/to/test.py -v - -# Specific test function -uv run pytest tests/path/to/test.py::test_name -v - -# With output -uv run pytest -v -s -``` - -## Directory Structure - -```text -.rhiza/ -├── rhiza.mk # Core Makefile logic -├── make.d/ # Modular extensions (auto-loaded) -│ ├── 00-19*.mk # Configuration -│ ├── 20-79*.mk # Task definitions -│ └── 80-99*.mk # Hook implementations -├── utils/ # Python utilities -└── template.yml # Sync configuration -``` - -## Hook Targets - -Extend these with `::` syntax in `local.mk` or `.rhiza/make.d/`: - -| Hook | When it runs | -|------|--------------| -| `pre-install::` | Before dependency installation | -| `post-install::` | After dependency installation | -| `pre-sync::` | Before template sync | -| `post-sync::` | After template sync | -| `pre-validate::` | Before project validation | -| `post-validate::` | After project validation | -| `pre-release::` | Before release creation | -| `post-release::` | After release creation | -| `pre-bump::` | Before version bump | -| `post-bump::` | After version bump | - -## Key Files - -| File | Purpose | -|------|---------| -| `pyproject.toml` | Project metadata, dependencies, version | -| `uv.lock` | Locked dependency versions | -| `.python-version` | Default Python version | -| `ruff.toml` | Linter/formatter configuration | -| `local.mk` | Local Makefile customizations (not synced) | - -## Python Execution - -Always use `uv` for Python operations: - -```bash -uv run python script.py # Run Python script -uv run pytest # Run tests -uv build # Build distribution packages -``` - -## Version Format - -- Source of truth: `version` field in `pyproject.toml` -- Git tags: `v` prefix (e.g., `v1.2.3`) -- Semantic versioning: `MAJOR.MINOR.PATCH` - -## CI Workflows - -| Workflow | Trigger | -|----------|---------| -| CI | Push, Pull Request | -| Release | Tag `v*` | -| Security | Schedule, Push | -| Sync | Manual | - -## Common Patterns - -### Add a custom make target - -Create `.rhiza/make.d/50-custom.mk`: -```makefile -my-target: - @echo "Custom target" -``` - -### Extend a hook - -Add to `local.mk`: -```makefile -post-install:: - @echo "Additional setup after install" -``` - -### Skip CI on commit - -```bash -git commit -m "docs: update readme [skip ci]" -``` diff --git a/docs/SECURITY.md b/docs/SECURITY.md deleted file mode 100644 index b7dc377..0000000 --- a/docs/SECURITY.md +++ /dev/null @@ -1,98 +0,0 @@ -# Security Policy - -## Supported Versions - -We actively support the following versions with security updates: - -| Version | Supported | -| ------- | ------------------ | -| 0.8.x | :white_check_mark: | -| 0.7.x | :white_check_mark: | -| < 0.7 | :x: | - -## Reporting a Vulnerability - -We take security vulnerabilities seriously. If you discover a security issue, please report it responsibly. - -### How to Report - -**Do NOT report security vulnerabilities through public GitHub issues.** - -Instead, please report them via one of the following methods: - -1. **GitHub Security Advisories** (Preferred) - - Go to the [Security Advisories](https://github.com/jebel-quant/rhiza/security/advisories) page - - Click "New draft security advisory" - - Fill in the details and submit - -2. **Email** - - Send details to the repository maintainers - - Include "SECURITY" in the subject line - -### What to Include - -Please include the following information in your report: - -- **Description**: A clear description of the vulnerability -- **Impact**: The potential impact of the vulnerability -- **Steps to Reproduce**: Detailed steps to reproduce the issue -- **Affected Versions**: Which versions are affected -- **Suggested Fix**: If you have one (optional) - -### What to Expect - -- **Acknowledgment**: We will acknowledge receipt within 48 hours -- **Initial Assessment**: We will provide an initial assessment within 7 days -- **Resolution Timeline**: We aim to resolve critical issues within 30 days -- **Credit**: We will credit reporters in the security advisory (unless you prefer to remain anonymous) - -### Scope - -This security policy applies to: - -- The Rhiza template system and configuration files -- GitHub Actions workflows provided by this repository -- Shell scripts in `.rhiza/scripts/` -- Python utilities in `.rhiza/utils/` - -### Out of Scope - -The following are generally out of scope: - -- Vulnerabilities in upstream dependencies (report these to the respective projects) -- Issues that require physical access to a user's machine -- Social engineering attacks -- Denial of service attacks that require significant resources - -## Security Measures - -This project implements several security measures: - -### Code Scanning -- **CodeQL**: Automated code scanning for Python and GitHub Actions -- **Bandit**: Python security linter integrated in CI and pre-commit -- **pip-audit**: Dependency vulnerability scanning - -### Supply Chain Security -- **SLSA Provenance**: Build attestations for release artifacts (public repositories only) -- **Locked Dependencies**: `uv.lock` ensures reproducible builds -- **Renovate**: Automated dependency updates with security patches - -### Release Security -- **OIDC Publishing**: PyPI trusted publishing without stored credentials -- **Signed Commits**: GPG signing supported for releases -- **Tag Protection**: Releases require version tag validation - -## Security Best Practices for Users - -When using Rhiza templates in your projects: - -1. **Keep Updated**: Regularly sync with upstream templates -2. **Review Changes**: Review template sync PRs before merging -3. **Enable Security Features**: Enable CodeQL and Dependabot in your repositories -4. **Use Locked Dependencies**: Always commit `uv.lock` for reproducible builds -5. **Configure Branch Protection**: Require PR reviews and status checks - -## Acknowledgments - -We thank the security researchers and community members who help keep Rhiza secure. diff --git a/docs/adr/0000-adr-template.md b/docs/adr/0000-adr-template.md new file mode 100644 index 0000000..4b4cbde --- /dev/null +++ b/docs/adr/0000-adr-template.md @@ -0,0 +1,19 @@ +# [NUMBER]. [TITLE] + +Date: [YYYY-MM-DD] + +## Status + +[Proposed | Accepted | Deprecated | Superseded by [ADR-XXXX](XXXX-title.md)] + +## Context + +What is the issue that we're seeing that is motivating this decision or change? + +## Decision + +What is the change that we're proposing and/or doing? + +## Consequences + +What becomes easier or more difficult to do because of this change? diff --git a/docs/assets/rhiza-logo.svg b/docs/assets/rhiza-logo.svg new file mode 100644 index 0000000..ff1c9f5 --- /dev/null +++ b/docs/assets/rhiza-logo.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/MARIMO.md b/docs/development/MARIMO.md similarity index 95% rename from docs/MARIMO.md rename to docs/development/MARIMO.md index d9eb024..df69cce 100644 --- a/docs/MARIMO.md +++ b/docs/development/MARIMO.md @@ -33,14 +33,14 @@ From the repository root: make marimo ``` -This will start the Marimo server and open all notebooks in the `book/marimo` directory. +This will start the Marimo server and open all notebooks in the `docs/notebooks` directory. ### Running a Specific Notebook To run a single notebook: ```bash -marimo edit book/marimo/rhiza.py +marimo edit docs/notebooks/rhiza.py ``` ### Using uv (Recommended) @@ -48,7 +48,7 @@ marimo edit book/marimo/rhiza.py The notebooks include inline dependency metadata, making them self-contained: ```bash -uv run book/marimo/rhiza.py +uv run docs/notebooks/rhiza.py ``` This will automatically install the required dependencies and run the notebook. @@ -100,7 +100,7 @@ To create a new Marimo notebook: 1. Create a new `.py` file in this directory: ```bash - marimo edit book/marimo/my_notebook.py + marimo edit docs/notebooks/my_notebook.py ``` 2. Add inline metadata at the top: @@ -118,7 +118,7 @@ To create a new Marimo notebook: 4. Test it runs in a clean environment: ```bash - uv run book/marimo/my_notebook.py + uv run docs/notebooks/my_notebook.py ``` 5. Commit and push - the CI will validate it automatically diff --git a/docs/TESTS.md b/docs/development/TESTS.md similarity index 100% rename from docs/TESTS.md rename to docs/development/TESTS.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..0e0b6b4 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,2 @@ +--8<-- "README.md" + diff --git a/docs/mkdocs-base.yml b/docs/mkdocs-base.yml new file mode 100644 index 0000000..6d7143d --- /dev/null +++ b/docs/mkdocs-base.yml @@ -0,0 +1,71 @@ +# docs/mkdocs-base.yml — Base MkDocs configuration for rhiza-based projects. +# +# USAGE (standalone) +# Build or serve this file directly if you have no root-level mkdocs.yml: +# uvx --with mkdocs-material mkdocs serve -f docs/mkdocs-base.yml +# The rhiza build system (make book) will pick this file up automatically +# as a fallback when no root-level mkdocs.yml is found. +# +# USAGE (with INHERIT) +# To extend this config from a root-level mkdocs.yml, add the following +# at the top of your mkdocs.yml and override only what you need: +# +# INHERIT: docs/mkdocs-base.yml +# +# site_name: My Project +# site_url: https://example.github.io/my-project/ +# repo_url: https://github.com/example/my-project +# repo_name: example/my-project +# +# docs_dir: docs # always set this explicitly — base uses docs_dir: . which +# # resolves relative to docs/mkdocs-base.yml, not mkdocs.yml +# +# nav: # nav is fully replaced — not merged — by the child config +# - Home: index.md +# - Guide: guide.md +# +# Any key you omit in mkdocs.yml is inherited from this file. +# The 'nav' key is always fully replaced when defined in the child. + +site_name: Rhiza +docs_dir: . +site_dir: _mkdocs + +theme: + name: material + features: + - navigation.tabs + - navigation.sections + - navigation.top + - search.suggest + - search.highlight + logo: assets/rhiza-logo.svg + favicon: assets/rhiza-logo.svg + +plugins: + - search + +markdown_extensions: + - md_in_html + - pymdownx.highlight + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.snippets: + base_path: ["."] + - admonition + - toc: + permalink: true + toc_depth: 3 + +extra_javascript: + - https://unpkg.com/mermaid@11.4.0/dist/mermaid.esm.min.mjs + +# nav is overwritten completely in mkdocs.yml +nav: + - Home: index.md + - Notebooks: notebooks.md + - Reports: reports.md + - Paper: paper/rhiza.pdf diff --git a/ruff.toml b/ruff.toml index 04f8901..4563178 100644 --- a/ruff.toml +++ b/ruff.toml @@ -115,7 +115,7 @@ line-ending = "auto" "RUF012", # Allow mutable class attributes in project tests ] # Marimo notebooks - allow flexible coding patterns for interactive exploration -"**/marimo/**/*.py" = [ +"**/notebooks/*.py" = [ "D100", # No module docstring - marimo requires `import marimo` as the first statement "N803", # Allow non-lowercase variable names in notebooks "S101", # Allow assert statements in notebooks