From 3d50618af2eacdc9bdf66fda002921fed6895159 Mon Sep 17 00:00:00 2001 From: Franccesco Orozco Date: Thu, 24 Sep 2026 11:44:02 -0600 Subject: [PATCH 1/2] docs: fix stale facts in Claude instructions and dev docs Audit CLAUDE.md and the .claude/agents subagent definitions for outdated content: - Use `uv run basedpyright`; `uv run pyright` falls through to a global pyright that ignores the [tool.basedpyright] config CI uses (also fixed in README and CONTRIBUTING) - Release steps go through a PR and tag the merge commit, matching the PR-only rule and actual history; drop the duplicate bump procedure - Replace copied ruff/pyright config with a pointer to pyproject.toml - Fix nonexistent test IDs and fixture signatures - Add the transform-mixin step to the feature template - Replace hardcoded tag ranges, drop `git rebase -i` - Remove emphasis and the subagent table from the delegation section Co-Authored-By: Claude Opus 5.5 (1M context) --- .claude/agents/api-feature-developer.md | 45 +++-------------- .claude/agents/code-quality-reviewer.md | 37 ++------------ .claude/agents/sdk-test-engineer.md | 17 ++++--- .claude/agents/version-control-engineer.md | 59 +++++++--------------- CLAUDE.md | 23 ++------- CONTRIBUTING.md | 2 +- README.md | 4 +- 7 files changed, 47 insertions(+), 140 deletions(-) diff --git a/.claude/agents/api-feature-developer.md b/.claude/agents/api-feature-developer.md index e01a8ff..0c62599 100644 --- a/.claude/agents/api-feature-developer.md +++ b/.claude/agents/api-feature-developer.md @@ -15,13 +15,14 @@ You are an expert Python SDK developer specializing in building the Bloomy Growt 4. Ensure proper error handling using BloomyError hierarchy 5. Write comprehensive docstrings for mkdocstrings auto-generation -## Codebase Patterns You MUST Follow +## Codebase Patterns ### Architecture Overview - **Client**: `src/bloomy/client.py` (sync) and `src/bloomy/async_client.py` (async) - **Operations**: `src/bloomy/operations/` (sync) and `src/bloomy/operations/async_/` (async) - **Models**: `src/bloomy/models.py` - Pydantic models with PascalCase aliases - **Base Classes**: `BaseOperations` (sync) and `AsyncBaseOperations` (async) +- **Transform Mixins**: `src/bloomy/operations/mixins/_transform.py` - response-shaping logic shared by the sync and async classes ### Step-by-Step Feature Implementation @@ -35,44 +36,12 @@ class NewFeatureModel(BloomyBaseModel): created_date: datetime | None = Field(default=None, alias="CreateDate") ``` -**Step 2: Create Sync Operations** (`src/bloomy/operations/.py`) -```python -from ..models import NewFeatureModel -from ..utils.base_operations import BaseOperations - -class NewFeatureOperations(BaseOperations): - """Operations for managing new features.""" - - def list(self, user_id: int | None = None) -> list[NewFeatureModel]: - """List all items for a user. - - Args: - user_id: User ID. Defaults to authenticated user. +**Step 2: Create a Transform Mixin** (`src/bloomy/operations/mixins/_transform.py`) +- Put response-to-model transformation here so the sync and async classes share it - Returns: - List of NewFeatureModel objects. - """ - uid = user_id or self.user_id - response = self._client.get(f"endpoint/{uid}") - response.raise_for_status() - return [NewFeatureModel.model_validate(item) for item in response.json()] -``` - -**Step 3: Create Async Operations** (`src/bloomy/operations/async_/.py`) -```python -from ...models import NewFeatureModel -from ...utils.async_base_operations import AsyncBaseOperations - -class AsyncNewFeatureOperations(AsyncBaseOperations): - """Async operations for managing new features.""" - - async def list(self, user_id: int | None = None) -> list[NewFeatureModel]: - """List all items for a user.""" - uid = user_id or await self.get_user_id() - response = await self._client.get(f"endpoint/{uid}") - response.raise_for_status() - return [NewFeatureModel.model_validate(item) for item in response.json()] -``` +**Step 3: Create Sync and Async Operations** (`src/bloomy/operations/.py`, `src/bloomy/operations/async_/.py`) +- Each class inherits its base class and the mixin: `class FeatureOperations(BaseOperations, FeatureOperationsMixin)` +- Model them on an existing resource, e.g. `operations/headlines.py`, `operations/async_/headlines.py`, and `operations/mixins/headlines_transform.py` **Step 4: Register in Clients** - Add import and attribute to `src/bloomy/client.py` diff --git a/.claude/agents/code-quality-reviewer.md b/.claude/agents/code-quality-reviewer.md index 4044ca9..9648118 100644 --- a/.claude/agents/code-quality-reviewer.md +++ b/.claude/agents/code-quality-reviewer.md @@ -9,7 +9,7 @@ You are a senior code reviewer ensuring the Bloomy Python SDK maintains high sta ## Your Responsibilities -1. Run all quality gate checks (ruff, pyright, pytest) +1. Run all quality gate checks (ruff, basedpyright, pytest) 2. Review code for patterns, security, and maintainability 3. Identify issues and provide actionable feedback 4. Ensure SDK patterns are followed consistently @@ -27,7 +27,7 @@ uv run ruff format . uv run ruff check . --fix # 3. Type checking (strict mode) -uv run pyright +uv run basedpyright # 4. Run all tests with coverage uv run pytest @@ -36,36 +36,9 @@ uv run pytest uv run mkdocs build --strict ``` -## Ruff Configuration (from pyproject.toml) - -**Enabled Rules:** -- E, W: PEP 8 style -- F: Pyflakes (real errors) -- I: isort (import sorting) -- B: Bugbear (likely bugs) -- C4: Comprehensions -- UP: PyUpgrade (modern syntax) -- C901: McCabe complexity (max 10) -- SIM: Simplify -- N: PEP 8 naming -- DOC, D: Docstring format -- ARG: Unused arguments -- PERF: Performance -- ASYNC: Async best practices - -**Line Length**: 88 characters -**Quote Style**: Double quotes - -## Pyright Configuration - -- **Mode**: Strict -- **Python Version**: 3.12 -- **Scope**: `src/` only (excludes tests) -- **Key Checks**: - - reportMissingImports - - reportUnknownMemberType - - reportUnknownArgumentType - - reportUnknownVariableType +## Tool Configuration + +Ruff and basedpyright settings (rule selection, line length, strict mode, `src/`-only type checking) live in `pyproject.toml`; read them there. CI (`.github/workflows/quality.yml`) runs `ruff format . --check`, `ruff check .`, and `basedpyright`. ## Code Review Checklist diff --git a/.claude/agents/sdk-test-engineer.md b/.claude/agents/sdk-test-engineer.md index 148da44..9405ce4 100644 --- a/.claude/agents/sdk-test-engineer.md +++ b/.claude/agents/sdk-test-engineer.md @@ -40,7 +40,7 @@ uv run pytest uv run pytest tests/test_users.py # Run specific test -uv run pytest tests/test_users.py::TestUserOperations::test_details -v +uv run pytest tests/test_users.py::TestUserOperations::test_details_basic -v # Run with verbose output uv run pytest -v @@ -57,12 +57,12 @@ uv run pytest --cov=bloomy --cov-report=term-missing ### HTTP Client Mocks ```python @pytest.fixture -def mock_http_client() -> Mock: - """Mock httpx.Client for sync tests.""" +def mock_response() -> Mock: + """Mock(spec=httpx.Response) with is_success=True, status_code=200.""" @pytest.fixture -def mock_response() -> Mock: - """Mock httpx.Response.""" +def mock_http_client(mock_response: Mock) -> Mock: + """Mock httpx.Client whose methods return mock_response.""" ``` ### Sample Data Fixtures @@ -81,8 +81,11 @@ def sample_meeting_data() -> dict[str, Any]: ### User ID Mock (Important!) ```python @pytest.fixture -def mock_user_id() -> Mock: - """Prevents lazy-loading API calls to /users/mine.""" +def mock_user_id() -> Generator[PropertyMock, None, None]: + """Patches BaseOperations.user_id to return 123. + + Prevents lazy-loading API calls to /users/mine. + """ ``` ## Sync Test Pattern diff --git a/.claude/agents/version-control-engineer.md b/.claude/agents/version-control-engineer.md index 40f6625..d7876e2 100644 --- a/.claude/agents/version-control-engineer.md +++ b/.claude/agents/version-control-engineer.md @@ -62,24 +62,7 @@ chore: bump version to 0.19.0 - **MINOR** (0.X.0): New features, backward compatible - **PATCH** (0.0.X): Bug fixes, backward compatible -### Version Bump Process - -```bash -# 1. Ensure all changes are committed -git status - -# 2. Update version in pyproject.toml -# Edit: version = "0.20.0" - -# 3. Update CHANGELOG.md (see Changelog section below) - -# 4. Commit version bump and changelog -git add pyproject.toml CHANGELOG.md -git commit -m "chore: bump version to 0.20.0" - -# 5. Create git tag -git tag -a v0.20.0 -m "Release v0.20.0" -``` +Version bumps follow the Release Process below. ## Changelog Management @@ -169,7 +152,7 @@ EOF ### PR Review Checklist - All CI checks pass (when available) -- Quality gates pass locally (`ruff`, `pyright`, `pytest`) +- Quality gates pass locally (`ruff`, `basedpyright`, `pytest`) - Documentation is updated - Tests are included - Follows SDK patterns @@ -186,35 +169,34 @@ git pull origin main # 2. Run full quality check uv run ruff format . uv run ruff check . --fix -uv run pyright +uv run basedpyright uv run pytest uv run mkdocs build --strict # 3. Verify all tests pass # 4. Review recent commits for changelog -git log --oneline v0.19.0..HEAD +git log --oneline "$(git describe --tags --abbrev=0)"..HEAD ``` ### Release Steps +The release commit goes through a PR like any other change (see Safety Rules); tag the merged commit on `main`. + ```bash -# 1. Update CHANGELOG.md -# - Move items from [Unreleased] to new version section -# - Add release date: ## [0.20.0] - 2025-12-10 +# 1. On a branch, update CHANGELOG.md +# - Move items from [Unreleased] to new version section: ## [X.Y.Z] - YYYY-MM-DD # - Update comparison links at bottom - -# 2. Update version in pyproject.toml -# version = "0.20.0" - -# 3. Commit release +# 2. Update version in pyproject.toml: version = "X.Y.Z" +git checkout -b chore/release-vX.Y.Z git add CHANGELOG.md pyproject.toml -git commit -m "chore: release v0.20.0" - -# 4. Create annotated tag (simple message - changelog is in CHANGELOG.md) -git tag -a v0.20.0 -m "Release v0.20.0" - -# 5. Push with tags -git push origin main --tags +git commit -m "chore(release): bump version to X.Y.Z" +git push -u origin chore/release-vX.Y.Z +gh pr create --title "chore(release): bump version to X.Y.Z" --body "..." + +# 3. After the PR merges, tag the merge commit and push only the tag +git checkout main && git pull origin main +git tag -a vX.Y.Z -m "Release vX.Y.Z" # simple message - changelog is in CHANGELOG.md +git push origin vX.Y.Z ``` ### Automated GitHub Release @@ -238,7 +220,7 @@ When you push a tag matching `v*`, the GitHub Actions workflow (`.github/workflo git log --oneline -20 # View changes since last tag -git log --oneline v0.18.0..HEAD +git log --oneline "$(git describe --tags --abbrev=0)"..HEAD # Check current status git status @@ -246,9 +228,6 @@ git status # View diff of staged changes git diff --staged -# Interactive rebase (clean up commits) -git rebase -i HEAD~3 - # Amend last commit (careful!) git commit --amend diff --git a/CLAUDE.md b/CLAUDE.md index 611bbed..30cb0fd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,24 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Subagent Delegation (Manager Mode) -**IMPORTANT**: You should act as a manager, delegating implementation work to specialized subagents while focusing on coordination and review. - -### Available Subagents - -| Subagent | Use For | -|----------|---------| -| `api-feature-developer` | New SDK operations, API features, sync/async implementations | -| `mkdocs-documentation-writer` | Guides, API docs, README updates, changelog | -| `code-quality-reviewer` | Quality gates (ruff, pyright, pytest), code review | -| `sdk-test-engineer` | Writing tests, debugging failures, coverage | -| `version-control-engineer` | Commits, PRs, version bumping, releases | - -### Delegation Guidelines - -1. **PROACTIVELY delegate** to subagents for their specialized domains -2. **Chain workflows**: e.g., implement feature → write tests → review → commit -3. **Review outputs** rather than implementing directly -4. **Use parallel agents** when tasks are independent (e.g., tests + docs simultaneously) +Act as a manager: delegate implementation work to the project subagents in `.claude/agents/` and spend your own effort on coordination and review. The subagents carry this repo's conventions, and delegating keeps the main context free for reviewing their output. Changes of a line or two are faster to make directly. Run subagents in parallel when their tasks are independent, such as tests and docs for the same feature. ### Example Workflows @@ -42,7 +25,7 @@ uv run pytest uv run pytest tests/test_users.py # Run a specific test -uv run pytest tests/test_users.py::test_user_details -v +uv run pytest tests/test_users.py::TestUserOperations::test_details_basic -v # Format code uv run ruff format . @@ -51,7 +34,7 @@ uv run ruff format . uv run ruff check . --fix # Type checking (strict mode) -uv run pyright +uv run basedpyright # Build documentation uv run mkdocs serve diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d35f486..e56fbe3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,7 +61,7 @@ As for coding style guidelines make sure you: - Include type annotations for all public APIs - Run `uv run ruff format .` before committing - Run `uv run ruff check . --fix` to auto-fix linting issues -- Run `uv run pyright` for type checking +- Run `uv run basedpyright` for type checking ### Pull Request Process diff --git a/README.md b/README.md index 67a7404..7b7ade3 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ except BloomyError as e: This SDK uses: - **uv** for package management - **ruff** for formatting and linting -- **pyright** for type checking +- **basedpyright** for type checking - **pytest** for testing To set up the development environment: @@ -247,7 +247,7 @@ uv run ruff format . uv run ruff check . --fix # Type checking -uv run pyright +uv run basedpyright ``` ## Requirements From 649108a0eba716d13c03b65e260102f68caf00cb Mon Sep 17 00:00:00 2001 From: Franccesco Orozco Date: Thu, 24 Sep 2026 11:46:09 -0600 Subject: [PATCH 2/2] docs: remove duplication in subagent instructions - Point code-quality-reviewer to pyproject.toml and quality.yml instead of listing CI steps; consult them only when a setting is in question - Add the transform mixin to api-feature-developer's checklist and drop the Step 2 text that repeated the overview - Align version-control-engineer's commit example with the release steps, create the release branch first, and remove redundant steps - Name sdk-test-engineer fixtures and point to conftest.py instead of copying their signatures Co-Authored-By: Claude Opus 5.5 (1M context) --- .claude/agents/api-feature-developer.md | 5 ++--- .claude/agents/code-quality-reviewer.md | 2 +- .claude/agents/sdk-test-engineer.md | 22 +++++----------------- .claude/agents/version-control-engineer.md | 16 ++++++---------- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/.claude/agents/api-feature-developer.md b/.claude/agents/api-feature-developer.md index 0c62599..4455258 100644 --- a/.claude/agents/api-feature-developer.md +++ b/.claude/agents/api-feature-developer.md @@ -37,7 +37,6 @@ class NewFeatureModel(BloomyBaseModel): ``` **Step 2: Create a Transform Mixin** (`src/bloomy/operations/mixins/_transform.py`) -- Put response-to-model transformation here so the sync and async classes share it **Step 3: Create Sync and Async Operations** (`src/bloomy/operations/.py`, `src/bloomy/operations/async_/.py`) - Each class inherits its base class and the mixin: `class FeatureOperations(BaseOperations, FeatureOperationsMixin)` @@ -72,8 +71,8 @@ Always use the BloomyError hierarchy: ## Quality Checklist Before Completion - [ ] Pydantic model defined with proper aliases -- [ ] Sync operations class created -- [ ] Async operations class created (mirrors sync exactly) +- [ ] Transform mixin created +- [ ] Sync and async operations classes created, each inheriting its base class and the mixin (async mirrors sync exactly) - [ ] Both clients updated with new attribute - [ ] All `__init__.py` exports updated - [ ] Google-style docstrings on all public methods diff --git a/.claude/agents/code-quality-reviewer.md b/.claude/agents/code-quality-reviewer.md index 9648118..7f5792f 100644 --- a/.claude/agents/code-quality-reviewer.md +++ b/.claude/agents/code-quality-reviewer.md @@ -38,7 +38,7 @@ uv run mkdocs build --strict ## Tool Configuration -Ruff and basedpyright settings (rule selection, line length, strict mode, `src/`-only type checking) live in `pyproject.toml`; read them there. CI (`.github/workflows/quality.yml`) runs `ruff format . --check`, `ruff check .`, and `basedpyright`. +Ruff and basedpyright settings (rule selection, line length, strict mode, `src/`-only type checking) live in `pyproject.toml`, and the CI checks are in `.github/workflows/quality.yml`. Consult them when a rule or setting is in question. ## Code Review Checklist diff --git a/.claude/agents/sdk-test-engineer.md b/.claude/agents/sdk-test-engineer.md index 9405ce4..9f755a1 100644 --- a/.claude/agents/sdk-test-engineer.md +++ b/.claude/agents/sdk-test-engineer.md @@ -54,16 +54,11 @@ uv run pytest --cov=bloomy --cov-report=term-missing ## Fixtures (from conftest.py) -### HTTP Client Mocks -```python -@pytest.fixture -def mock_response() -> Mock: - """Mock(spec=httpx.Response) with is_success=True, status_code=200.""" +Read `tests/conftest.py` for exact signatures. -@pytest.fixture -def mock_http_client(mock_response: Mock) -> Mock: - """Mock httpx.Client whose methods return mock_response.""" -``` +### HTTP Client Mocks +- `mock_response`: a mocked `httpx.Response` that reports success +- `mock_http_client`: a mocked `httpx.Client` whose methods return `mock_response` ### Sample Data Fixtures ```python @@ -79,14 +74,7 @@ def sample_meeting_data() -> dict[str, Any]: ``` ### User ID Mock (Important!) -```python -@pytest.fixture -def mock_user_id() -> Generator[PropertyMock, None, None]: - """Patches BaseOperations.user_id to return 123. - - Prevents lazy-loading API calls to /users/mine. - """ -``` +`mock_user_id` patches `BaseOperations.user_id` to return 123, which prevents lazy-loading API calls to `/users/mine`. ## Sync Test Pattern diff --git a/.claude/agents/version-control-engineer.md b/.claude/agents/version-control-engineer.md index d7876e2..af951dd 100644 --- a/.claude/agents/version-control-engineer.md +++ b/.claude/agents/version-control-engineer.md @@ -48,7 +48,7 @@ fix(async): resolve race condition in concurrent requests docs(guide): add async bulk operations documentation -chore: bump version to 0.19.0 +chore(release): bump version to 0.19.0 ``` ## Version Management @@ -62,8 +62,6 @@ chore: bump version to 0.19.0 - **MINOR** (0.X.0): New features, backward compatible - **PATCH** (0.0.X): Bug fixes, backward compatible -Version bumps follow the Release Process below. - ## Changelog Management ### Changelog Location @@ -173,21 +171,19 @@ uv run basedpyright uv run pytest uv run mkdocs build --strict -# 3. Verify all tests pass -# 4. Review recent commits for changelog +# 3. Review recent commits for changelog git log --oneline "$(git describe --tags --abbrev=0)"..HEAD ``` ### Release Steps -The release commit goes through a PR like any other change (see Safety Rules); tag the merged commit on `main`. +The release commit goes through a PR like any other change (see Safety Rules). ```bash -# 1. On a branch, update CHANGELOG.md -# - Move items from [Unreleased] to new version section: ## [X.Y.Z] - YYYY-MM-DD -# - Update comparison links at bottom -# 2. Update version in pyproject.toml: version = "X.Y.Z" +# 1. Create the release branch git checkout -b chore/release-vX.Y.Z + +# 2. Update CHANGELOG.md (see "During Release" above) and set version = "X.Y.Z" in pyproject.toml git add CHANGELOG.md pyproject.toml git commit -m "chore(release): bump version to X.Y.Z" git push -u origin chore/release-vX.Y.Z