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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 64 additions & 99 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,99 +1,64 @@
# AGENTS.md - AI Coding Agent Instructions

Condensed instructions for AI agents. See [README.md](README.md) and [CONTRIBUTING.md](CONTRIBUTING.md) for full details.

## Project Overview

Python package (3.11+) providing repository configuration and scaffolding for Frequenz projects: cookiecutter templates (actor, api, app, lib, model), nox sessions, protobuf/gRPC utilities, MkDocs and pytest utilities.

**Package:** `src/frequenz/repo/config/` (namespace package, `setuptools_scm` versioning)

## Quick Reference

```sh
# Setup
pip install -e .[dev] # All dev dependencies
pip install -e .[dev-noxfile] # Just noxfile deps

# Test
nox -s pytest_max # Full test suite
nox -R -s pytest_max # Reuse venv (faster)
pytest tests/ # Direct pytest
UPDATE_GOLDEN=1 pytest tests/integration/test_cookiecutter_generation.py::test_golden

# Lint (run before committing)
nox # All checks
nox -s formatting # black + isort
nox -s mypy # Type checking
nox -R -s mypy # Reuse venv
```

**Markers:** `integration`, `cookiecutter`

## Project Structure

```
src/frequenz/repo/config/ # Main package (_core.py, nox/, mkdocs/, pytest/, setuptools/, cli/)
tests/ # Unit tests, tests/integration/ for integration tests
tests_golden/ # Golden test fixtures
cookiecutter/ # Cookiecutter templates
```

## Code Patterns

```python
# File header (required)
# License: MIT
# Copyright © 2023 Frequenz Energy-as-a-Service GmbH
"""Module docstring."""

import dataclasses
from typing import Self, assert_never

# Dataclasses: always kw_only + frozen if intended to be immutable
@dataclasses.dataclass(kw_only=True, frozen=True)
class Config:
"""Docstring."""
opts: CommandsOptions = dataclasses.field(default_factory=CommandsOptions)

# Functions: strict typing, Google docstrings
def func(session: _nox.Session, /, *, flag: bool = True) -> list[str]:
"""Brief description.

Args:
session: The nox session.
flag: Optional flag.

Returns:
List of strings.
"""
```

| Type | Convention | Example |
|------|------------|---------|
| Files/functions | snake_case | `api_pages.py`, `find_dirs()` |
| Classes | PascalCase | `RepositoryType` |
| Constants | UPPER_SNAKE | `UPDATE_GOLDEN` |
| Private | `_` prefix | `_impl()` |

**Formatting:** black formatting using 4 spaces (Python), 2 spaces (YAML/TOML/JSON), 88 line length, 100 max, double quotes

When changing files that are regularly reset (like `RELEASE_NOTES.md` or `cookiecutter/migrate.py`), consult the git history to match the style used in the past.

## Commit Messages
- Use imperative mood: "Add", "Fix", "Update"
- Use a 50-character limit for the subject line (can go a bit over if necessary), and wrap body at 80 characters
- Include a brief description of the change in the body if needed, focus on the what and why, and avoid describing how, especially if it is obvious from the code/diff
- Separate changes into logical commits
- Consult the recent git history, specifically of the files being committed, to match style and conventions in commit messages used previously.

## Cookiecutter Template Changes

See [CONTRIBUTING.md](CONTRIBUTING.md#modifying-cookiecutter-templates) for the full workflow. Summary:

1. Edit templates in `cookiecutter/{{cookiecutter.github_repo_name}}/`
2. Update golden files: `UPDATE_GOLDEN=1 pytest tests/integration/test_cookiecutter_generation.py::test_golden`
3. Write migration in `cookiecutter/migrate.py` (idempotent; use `manual_step()` for non-automatable changes)
4. Validate: `python3 cookiecutter/migrate.py && git diff .github/`
5. Update `RELEASE_NOTES.md`
6. Commit separately: templates first, then this repo's migration result
# AGENTS.md - Repository Knowledge Base

## OVERVIEW
Opinionated repository configuration and scaffolding for Frequenz projects.
Core stack: Python 3.11+, cookiecutter, nox, mkdocs, protobuf/gRPC.
Relevant history: Branch `v0.x.x`, Commit `6fb38df5`.

## STRUCTURE
- `src/frequenz/repo/config/`: Main package; nox, mkdocs, pytest, setuptools, CLI helpers.
- `cookiecutter/`: Template sources, hooks, local extensions, migration logic.
- `cookiecutter/{{cookiecutter.github_repo_name}}/`: Embedded generated-repo skeleton.
- `tests/`: Unit tests plus `tests/integration/` for template generation.
- `tests_golden/`: Reference outputs for integration tests; generated, do not edit directly.
- `docs/`: MkDocs source tree.
- `.github/`: Workflows, issue templates, release-note templates.

## WHERE TO LOOK
- Template author workflow: `cookiecutter/`, `cookiecutter/migrate.py`, `tests/integration/test_cookiecutter_generation.py`.
- Generated scaffold files: `cookiecutter/{{cookiecutter.github_repo_name}}/`.
- Default nox behavior: `src/frequenz/repo/config/nox/default.py`, `nox/session.py`.
- Docs generation/versioning: `src/frequenz/repo/config/mkdocs/`, `docs/_scripts/`, `mkdocs.yml`.
- Template migrations: `cookiecutter/migrate.py`, `.github/cookiecutter-migrate.template.py`.
- Golden-test contract: `tests/integration/test_cookiecutter_generation.py`, `tests_golden/`.
- Release/CI policy: `.github/workflows/`, `RELEASE_NOTES.md`, `.github/RELEASE_NOTES.template.md`.

## CODE MAP
- `RepositoryType`: `src/frequenz/repo/config/_core.py`.
- `GitHubActionsFormatter`: `src/frequenz/repo/config/github.py`.
- `CompileProto`: `src/frequenz/repo/config/setuptools/grpc_tools.py`.
- `get_sybil_arguments()`: `src/frequenz/repo/config/pytest/examples.py`.

## CONVENTIONS
- Header: License + copyright header required.
- Dataclasses: prefer `kw_only=True`; use `frozen=True` for immutables.
- Functions: strict typing, Google-style docstrings, positional-only/keyword-only when useful.
- Tool config: prefer `pyproject.toml` as the canonical configuration source.
- Versioning: `setuptools_scm` managed; avoid manual version bumps.
- Formatting: Black/isort, double quotes, 4 spaces in Python, 2 spaces in YAML/TOML/JSON.
- `RELEASE_NOTES.md` and `cookiecutter/migrate.py`: reset after a release from templates in `.github/`, consult the git history to match the style used in the past if you need to change them.
- When this project changes, `cookiecutter/` or `src/`, downstream projects are affected. Always add migration steps to `cookiecutter/migrate.py` when necessary.

## ANTI-PATTERNS
- Do not edit `tests_golden/` by hand.
- Do not treat `cookiecutter/{{cookiecutter.github_repo_name}}/` as the live repo root.
- Do not bypass `cookiecutter/migrate.py` when template changes affect existing repos.
- Do not edit generated outputs under `build/` or `site/` as primary sources.
- Do not bypass updating AGENTS.md files when changing structure or conventions.
- Do not bypass updating `docs/` when changing public APIs or user-facing features.
- Do not skip updating `cookiecutter/migrate.py` when changes need to be propagated to existing generated repos.
- Do not add generic repo-agnostic guidance.

## UNIQUE STYLES
- Telegraphic internal documentation style.
- Idempotent migrations via `migrate.py` with `manual_step()` markers.
- Template workflow splits naturally into template edit, golden update, migration result.

## COMMANDS
- `pip install -e .[dev]`: Full dev environment.
- `nox`: Run full tests/checks (formatting, flake8, mypy, pylint, pytest).
- `nox -s pytest_max`: Full test suite.
- `UPDATE_GOLDEN=1 pytest tests/integration/test_cookiecutter_generation.py::test_golden`: Refresh golden fixtures.
- `python3 cookiecutter/migrate.py`: Validate migration logic.
- `mkdocs build`: Build docs locally.
- Consult `CONTRIBUTING.md` for full cookiecutter, docs, and release workflows.
2 changes: 2 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ But you might still need to adapt your code:

- The cookiecutter now asks whether a repository is private, defaults that answer from the selected license, and uses it to toggle private-repository workflow behavior, public publishing jobs, and the link to GitHub Discussions in the issue template chooser.
- All dependencies have been updated in the templates.
- API projects now ship a dedicated `grpc-migration.yaml` workflow that runs after Dependabot bumps `grpcio`/`grpcio-tools`/`protobuf` and rewrites the matching runtime `>=` floors in `pyproject.toml`.
- API projects should now use the new API-specific *Protect version branches* ruleset variant, which includes the required `Fix gRPC/protobuf runtime floors` check without affecting non-API Python projects.

## Bug Fixes

Expand Down
37 changes: 37 additions & 0 deletions cookiecutter/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# AGENTS.md - Cookiecutter Template Guide

## OVERVIEW
This subtree is the template-authoring area for `frequenz-repo-config`.
`{{cookiecutter.github_repo_name}}/` is the generated-repo blueprint, not the live repo root.

## STRUCTURE
- `cookiecutter.json`: prompt variables, defaults, extension wiring.
- `hooks/`: pre/post generation validation and fixups.
- `local_extensions.py`: Jinja filters, globals, deterministic golden-test behavior.
- `migrate.py`: upgrade path for existing generated repositories.
- `variable-reference.md`: prompt-field documentation reused in user docs.
- `{{cookiecutter.github_repo_name}}/`: scaffold content shipped to generated projects.

## WHERE TO LOOK
- Add or rename a template variable: `cookiecutter.json`, `local_extensions.py`, `variable-reference.md`.
- Change generated files: `{{cookiecutter.github_repo_name}}/`.
- Change generation-time validation/fixups: `hooks/pre_gen_project.py`, `hooks/post_gen_project.py`.
- Update existing projects after a template change: `migrate.py`, `.github/cookiecutter-migrate.template.py`.
- Verify scaffold output: `tests/integration/test_cookiecutter_generation.py`, `tests_golden/`.

## WORKFLOW
- Edit template sources in this subtree.
- Refresh golden fixtures with `UPDATE_GOLDEN=1 pytest tests/integration/test_cookiecutter_generation.py::test_golden`.
- Update `cookiecutter/migrate.py` when existing repos need the same change (idempotent; use `manual_step()` for non-automatable changes).
- Validate migration locally with `python3 cookiecutter/migrate.py` and inspect the resulting diff.
- Update `RELEASE_NOTES.md` when the template behavior changes.
- Commit separately (3 commits): templates first, `migrate.py`, and finally this repo's migration result.

## ANTI-PATTERNS
- Do not place maintainer-only guidance inside `{{cookiecutter.github_repo_name}}/` unless it is meant to ship in generated repos.
- Do not change prompt variables without checking `variable-reference.md`, hooks/extensions, and migration impact.
- Do not skip multi-type verification; template edits can affect actor/api/app/lib/model outputs differently.

## NOTES
- `GOLDEN_TEST` handling in `local_extensions.py` and hooks keeps generated output deterministic during fixture refreshes.
- API templates have extra structure (`proto/`, `py/`, `pytests/`) and often need migration care beyond the library/app/actor/model cases.
5 changes: 5 additions & 0 deletions cookiecutter/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,11 @@ def remove_unneeded_files() -> None:

if cookiecutter.type != "api":
_shutil.rmtree("proto")
# The grpc-migration workflow is templated to render an empty file
# for non-API projects (see the `if cookiecutter.type == "api"`
# guard at the top of the template). Drop the leftover empty file
# so generated non-API projects don't carry it around.
_pathlib.Path(".github/workflows/grpc-migration.yaml").unlink()


def adjust_src_root() -> None:
Expand Down
Loading
Loading